Importing and Exporting Dynamics CRM Solutions with code

It’s much more efficient to use the SDK to import and export Dynamics CRM solutions than to use the front end. Here is all the code you will need to do that.

Here are the usings you need:

using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.IO;

Publishing Customisations

You will need to do this before exporting a solution to ensure all customisations are included. It’s very easy:

public static void PublishAllCustomisations(IOrganizationService orgService)
{
    orgService.Execute(new PublishAllXmlRequest());
}

Exporting a Solution

This method exports a solution as either managed or unmanaged to the folder path supplied. The file it creates will be called solutionname_[un]managed.zip. It will automatically set the version of the solution to a value constructed from the date, plus an incremental number (e.g. 2014.02.14.03 for the third export of the 14th February 2014). This is my preferred versioning format for CRM solutions, but of course you might change this to suit your own needs. You can choose not to increment the version, by setting the incrementVersion parameter to false. You would do this for example if you were exporting unmanaged and managed one immediately after the other (true on the first, false on the second):

public static void ExportSolution(IOrganizationService orgService, ExportSolutionRequest exportRequest, string folderPath, bool incrementVersion = true)
{
    if (incrementVersion)
    {
        QueryExpression solutionQuery = new QueryExpression("solution") { ColumnSet = new ColumnSet("version") };
        solutionQuery.Criteria.AddCondition("uniquename", ConditionOperator.Equal, exportRequest.SolutionName);
        Entity solution = RetrieveSingleEntity(orgService, solutionQuery);

        string version = solution.GetAttributeValue("version");
        string newVersionPrefix = DateTime.Today.ToString("yyyy.MM.dd");
        if (version.StartsWith(newVersionPrefix))
        {
            int lastDot = version.LastIndexOf('.');
            int previousBuild = 0;
            int.TryParse(version.Substring(lastDot + 1), out previousBuild);
            solution["version"] = string.Format("{0}.{1}", newVersionPrefix, previousBuild + 1);
        }
        else
        {
            solution["version"] = string.Format("{0}.1", newVersionPrefix);
        }
        orgService.Update(solution);
    }

    string fileName = string.Format("{0}_{1}.zip", exportRequest.SolutionName, exportRequest.Managed ? "managed" : "unmanaged");
    File.WriteAllBytes(Path.Combine(folderPath, fileName), ((ExportSolutionResponse)orgService.Execute(exportRequest)).ExportSolutionFile);
}

private static Entity RetrieveSingleEntity(IOrganizationService orgService, QueryExpression query)
{
    query.PageInfo = new PagingInfo { Count = 1, PageNumber = 1 };
    EntityCollection results = orgService.RetrieveMultiple(query);
    return (results.Entities == null || results.Entities.Count < 1) ? null : results.Entities[0];
}

The ExportSolutionRequest includes numerous options around what is or is not included in the export, but in most cases it’s fine to accept the defaults and only set the SolutionName and Managed flag. This wrapper method does just that:

public static void ExportSolution(IOrganizationService orgService, string name, bool managed, string folderPath, bool incrementVersion = true)
{
    ExportSolution(orgService, new ExportSolutionRequest { SolutionName = name, Managed = managed }, folderPath, incrementVersion);
}

Importing a Solution

This is quite straightforward, just requiring the path to a zip file either generated by the ExportSolution method, or from the front end.

public static void ImportSolution(IOrganizationService orgService, string path)
{
    orgService.Execute(new ImportSolutionRequest
    {
        CustomizationFile = File.ReadAllBytes(path),
        OverwriteUnmanagedCustomizations = true,
        PublishWorkflows = true
    });
}

Hint: Using Visual Studio Unit Tests to Import/Export

Although it’s not really a Unit Test, it can be very handy to run combinations of the above methods from Visual Studio’s Test Explorer, saving a lot of front-end operations.

In a scenario where we have two development CRM Organisations (“DevOrgA” and “DevOrgB”) and a Test Organisation, we want A’s solution imported as managed into B, and both A and B imported as managed into Test. Here’s the code to do that (assuming you have a similar GetOrgService method to retrieve an Organisation Service connection):

[TestMethod]
public void ExportAllSolutions()
{
    using (OrganizationServiceProxy orgService = GetOrgService("DevOrgA"))
    {
        PublishAllCustomisations(orgService);
        ExportSolution(orgService, "SolutionA", false, FOLDER);
        ExportSolution(orgService, "SolutionA", true, FOLDER, false);
    }
    using (OrganizationServiceProxy orgService = GetOrgService("DevOrgB"))
    {
        PublishAllCustomisations(orgService);
        ExportSolution(orgService, "SolutionB", false, FOLDER);
        ExportSolution(orgService, "SolutionB", true, FOLDER, false);
    }
}

[TestMethod]
public void ImportAllSolutions()
{
    using (OrganizationServiceProxy orgService = GetOrgService("DevOrgB"))
    {
        ImportSolution(orgService, Path.Combine(FOLDER, "SolutionA_managed.zip"));
        ImportSolution(orgService, Path.Combine(FOLDER, "SolutionB_unmanaged.zip"));
        PublishAllCustomisations(orgService);
    }
    using (OrganizationServiceProxy orgService = GetOrgService("Test"))
    {
        ImportSolution(orgService, Path.Combine(FOLDER, "SolutionA_managed.zip"));
        ImportSolution(orgService, Path.Combine(FOLDER, "SolutionB_managed.zip"));
    }
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *