Development 101: CRM and Continuous integration – C# Helper class

Yesterday I asked for some advice regarding Continuous Integration. @RajYRaman tweeted me and provided a link to the xRMCIFramework on CodePlex. * Kudos *
Today I had the opportunity to look at the framework and I’m pretty impressed with it. I was discussing with a collegue whether we should embed the framework with the automated script runner he developed. In our case it turned out to be overkill.

We only need three functions for our scenario:

  • Get the version number of a solution in a given environment
  • Export a solution (managed / unmanaged) from a given environment
  • Import a solution in a given environment and publish it

Looking at the code of the framework, it was quite easy to extract the functions we needed. I wrote a small generic class for it.

Helper class:

using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace JourneyIntoCRM
{
public class CRMSolution
{

private OrganizationService _service=null;
private CrmConnection _crmConnection = null;

/// <summary>
/// Default ctor, use the connectionstring named 'Crm'
/// </summary>
public CRMSolution() : this("Crm") { }

/// <summary>
/// Specify the connection to be used
/// </summary>
/// <param name="connectionName">name of the connection string</param>
public CRMSolution(string connectionName)
{
_crmConnection = new CrmConnection(connectionName);
}

/// <summary>
/// Get the version of a Solution
/// </summary>
/// <param name="uniqueName">name of the solution</param>
/// <returns>version number</returns>
public string GetVersion(string uniqueName)
{
string version = "";

if (!string.IsNullOrEmpty(uniqueName))
{
using (_service = new OrganizationService(_crmConnection))
{
//Find the solution
QueryExpression query = new QueryExpression
{
EntityName = "solution",
ColumnSet = new ColumnSet("friendlyname", "uniquename", "version"),
Criteria = new FilterExpression()
{
Conditions =
{
new ConditionExpression("uniquename", ConditionOperator.Equal, uniqueName)
}
}
};

EntityCollection solutions = _service.RetrieveMultiple(query);

if (solutions.Entities != null)
{
foreach (Entity solution in solutions.Entities)
{
if (solution["version"] != null) version = solution["version"].ToString();
}
}
}
}
return version;
}

/// <summary>
/// Import a solution
/// </summary>
/// <param name="importFile">filename of the solution to be imported</param>
/// <param name="publish">if true, all Xml changes are published</param>
/// <returns>xml containing import log</returns>
public string ImportSolution(string importFile, bool publish)
{
string data = "";

using (_service = new OrganizationService(_crmConnection))
{
Guid jobId = Guid.NewGuid();
try
{

byte[] fileBytes = File.ReadAllBytes(importFile);

ImportSolutionRequest req = new ImportSolutionRequest()
{
CustomizationFile = fileBytes,
ImportJobId = jobId,
OverwriteUnmanagedCustomizations = true
};
ImportSolutionResponse res = _service.Execute(req) as ImportSolutionResponse;

if (publish)
{
PublishAllXmlRequest xmlReq = new PublishAllXmlRequest();
_service.Execute(xmlReq);
}
}
catch (Exception) { }
Entity job = _service.Retrieve("importjob", jobId, new ColumnSet("solutionname", "data"));

if (job != null)
{
data = job["data"] as string;
}
}
return data;
}
/// <summary>
/// Export a solution
/// </summary>
/// <param name="uniqueName">Name of the solution</param>
/// <param name="fileName">filename to be saved</param>
/// <param name="managed">if true the solution will be exported as a managed solution</param>
public void ExportSolution(string uniqueName, string fileName, bool managed)
{
try
{
using (_service = new OrganizationService(_crmConnection))
{
ExportSolutionRequest req = new ExportSolutionRequest()
{
Managed = managed,
SolutionName = uniqueName,
};

ExportSolutionResponse res = _service.Execute(req) as ExportSolutionResponse;
File.WriteAllBytes(fileName, res.ExportSolutionFile);
}

}
catch (Exception e)
{
throw new Exception(string.Format("Error while exporting solution '{0}' to {1}: {2} ",uniqueName,fileName,e.Message));
}
}
}
}

In order to use the class the following calls will do the job:

// open the CRM environment specified in the connection string
CRMSolution cls = new CRMSolution("MyConnectionStringName");

// Import a solution and publish its XML
string resultXml = cls.ImportSolution(@"C:\Development\TestSolution.zip",true);

// Export a solution
cls.ExportSolution("MySolution", @"C:\Development\TestSolutionUnmanaged.zip", false);

// Get the version of one of my solutions
string version = cls.GetVersion("OneOfMySolutions");