In certain scenarios you might need to update a plugin/workflow assembly deployed to the CRM database programmatically. A good example is for CI build/deployment purposes.
From a CI build/deployment perspective, an issue with deploying the assembly to the database, and promoting the assembly via an exported CRM solution, is that the code checked in into source control may not match the code being deployed via the CRM solution. This is because the export/import of a CRM solution is quite disconnected from the checking in and CI build/deploy of the source code.
To address this issue, we could incorporate a step into the CI deploy process which would programmatically update the assembly in the CRM database using the output of the CI build.
Show me the code!
An assembly is stored in the CRM database as a record, and the entity type is pluginassembly. You can use the Metadata Browser to view the attributes of this entity, but the main ones are:
- name: for example MyCompany.Project1.Library1
- version: for example 1.0.0.0
- publickeytoken: for example ae3b5d802871029c
- culture: for example neutral
- content: the actual binary of the assembly is stored in this attribute as Base64 encoded string
Using the first 4 attributes above we can retrieve the assembly record, and then update the assembly binary in the database by updating the content attribute.
Below is the code to retrieve the assembly record for a given assembly on disk, and update its binary in the CRM database. Review the in-code comment.
const string ASSEMBLY_PATH_ON_DISK = @"C:\Output\MyAssembly.dll"; //Use the .NET Framework's AssemblyName class to retrieve the strong name parts for our assembly var assemblyName = AssemblyName.GetAssemblyName(ASSEMBLY_PATH_ON_DISK); //Convert the assembly's public key token to a string var publicKeyTokenString = ""; var token = assemblyName.GetPublicKeyToken(); for (int i = 0; i < token.GetLength(0); i++) { publicKeyTokenString += token[i].ToString("x2"); } //Now connect to CRM to retrieve the assembly record var connection = CrmConnection.Parse(ConfigurationManager.ConnectionStrings["CRM"].ConnectionString); using (var service = new OrganizationService(connection)) { //Create a query to retrieve the assembly record matching our assembly's strong name var query = new QueryExpression("pluginassembly") { ColumnSet = new ColumnSet("name", "publickeytoken", "version", "culture"), Criteria = new FilterExpression(LogicalOperator.And) { Conditions = { new ConditionExpression("name", ConditionOperator.Equal, assemblyName.Name), new ConditionExpression("publickeytoken", ConditionOperator.Equal, publicKeyTokenString), new ConditionExpression("version", ConditionOperator.Equal, assemblyName.Version.ToString()), new ConditionExpression("culture", ConditionOperator.Equal, String.IsNullOrEmpty(assemblyName.CultureName) ? "neutral" : assemblyName.CultureName) } } }; //TODO: Handle case where matching record was not found var assemblyRecord = service.RetrieveMultiple(query).Entities[0]; //Update the record with the assembly's binary assemblyRecord["content"] = Convert.ToBase64String(File.ReadAllBytes(ASSEMBLY_PATH_ON_DISK)); service.Update(assemblyRecord); }
Summary
It is possible to programmatically update the binary of a plugin/workflow activity assembly stored in the CRM database. This opens up opportunities in deployment automation, or perhaps development of custom tools.
Thanks for the article. I’ve had endless trouble with the Plugin Registration Tool and out of frustration, I just decided to register/update it through the SDK – Made my life much easier.