This took me a little while to figure out, but I have to give credit to Michael at Stunnware for being about the only person who's displayed some example of how to utilize the CRM Service to update the ISV.Config customizations. What I would like to do is demonstrate how to merge customizations from an XML file into the existing ISV.Config.
I think this is a pretty neat set up, considering when you import ISV.Config customizations, the existing ISV.Config data is overwritten. So it's super-important to take existing customizations into account when you import your own.
So, let's get down to business....
Create Customization File
We're going to create a text file that contains the xml for a custom menu in CRM. This file will only contain the ISV.Config code that we are inserting, so much of the ISV.Config structure will be absent - it's already in the xml on the server, so why bother putting it here? We'll name the file isv.snippet.xml and here's the customizations that we will put in the file:
<Menu>
<Titles>
<Title LCID="1033" Text="My Custom Menu" />
</Titles>
<MenuItem JavaScript="alert('Foo!');">
<Titles>
<Title LCID="1033" Text="My Menu Item" />
</Titles>
</MenuItem>
</Menu>
What we're doing here is just creating a menu labeled "My Custom Menu", with a single menu item labeled "My Menu Item". Clicking on "Mu Menu Item" will display a JavaScript alert saying "Foo!". Okay, not the most creative stuff, but you get the point.
Retrieve Existing ISV.Config XML
So, now we've got our xml that we're going to merge into the existing ISV.Config xml. Let's go ahead and retrieve the existing ISV.Config:
// set up service
CrmService oCrmService = new CrmService();
oCrmService.Url = "http://crmserver/MSCRMServices/2007/CrmService.asmx";
oCrmService.Credentials = System.Net.CredentialCache.DefaultCredentials;
CrmService.CrmAuthenticationToken oServiceToken = new CrmService.CrmAuthenticationToken();
oServiceToken.OrganizationName = sOrganization;
oCrmService.CrmAuthenticationTokenValue = oServiceToken;
// retrieve isvconfig xml
QueryExpression query = new QueryExpression();
ColumnSet cols = new ColumnSet();
cols.Attributes = new string[] { "configxml" };
query.ColumnSet = cols;
query.EntityName = EntityName.isvconfig.ToString();
query.PageInfo = new PagingInfo();
query.PageInfo.Count = 1;
query.PageInfo.PageNumber = 1;
BusinessEntityCollection items = oCrmService.RetrieveMultiple(query);
isvconfig config;
if (items.BusinessEntities.Length > 0)
{
config = (isvconfig)items.BusinessEntities[0];
}
Okay, we've got our configuration xml loaded into an isvconfig class variable named config. Now we can work our magic.
Merge Our Configurations
What we'll do here is read our configurations from the isv.snippet.xml file into the existing ISV.Config xml. Don't over-think this, it's really quite simple. In the following code, I'm going to load our custom xml into a string variable, the config xml into an xml document, then use the SelectSingleNode method to grab the existing custom menus and I'm appending my custom xml to the InnerXml property of the node:
// read xml from file
string sMenuXml = "";
using (StreamReader oReader = File.OpenText("isv.snippet.xml"))
{
sMenuXml = oReader.ReadToEnd();
}
// load config xml into xml document
XmlDocument oConfigXml = new XmlDocument();
oConfigXml.LoadXml(config.configxml);
// merge customizations
XmlNode oCustomMenus = oConfigXml.SelectSingleNode("//CustomMenus");
string sExistingXml = oCustomMenus.InnerXml;
string sMergedXml = sExistingXml + sMenuXml;
oCustomMenus.InnerXml = sMergedXml;
See, I told you it was simple. :)
Save the Updated ISV.Config
Now that we've updated our ISV.Config, we need to save it back to the server.
// save isvconfig
config.configxml = oConfigXml.InnerXml;
oCrmService.Update(config);
So that's it. Even though I demonstrated this with a custom menu, this is really pretty simple to incorporate with other areas of the ISV.config. Use your imagination! Enjoy.
Comments