Friday, 6 September 2013

Executing stand alone C# code within CRM

A question that I was asked recently, and have pondered for quite some time, is providing an ability to execute some independent/standalone C# code within a CRM instance. There are quite a few ways to do this, but I'll describe my preferred pattern here. The solution I put forward is an attempt to provide complex code solutions that do not require the use of another server or external application. And it should also work both Online and OnPremise.

Firstly, to support our "C#" calls we need a new entity that will trigger it. Let's call it "Custom Method". In it's most basic form it would be a very simple object with just 3 main attributes, the method name, parameters and result:



Next, what we would do is attach a C# plugin on the PreCreate of this that will allow us to run some C# code in the background. Using the developer tools a very basic plugin skeleton that has 1 custom method (contained within the plugin class for simplicity) will look something like this:

public class ExecuteCustomMethod: Plugin
{
    private readonly IDictionary<string, Func<string,string>> methods = 
     new Dictionary<string, Func<string,string>>();

    public ExecuteCustomMethod()
        : base(typeof(ExecuteCustomMethod))
    {
        methods.Add("Add2Numbers", Add2Numbers);
        RegisteredEvents.Add(new Tuple<int, string, string, 
            Action<LocalPluginContext>>
                (20, 
                 "Create", 
                 "xrm_custommethod", 
                 Execute));
    }

    protected void Execute(LocalPluginContext localContext)
    {
        if (localContext == null)
        {
            throw new ArgumentNullException("localContext");
        }
        
        var target = (Entity)localContext
                         .PluginExecutionContext
                         .InputParameters["Target"];

        try
        {
            var name = (string) target["xrm_name"];
            var parameters = (target.Contains("xrm_parameters") ? 
                              (string) target["xrm_parameters"] : 
                              string.Empty);
            target["xrm_result"] = methods[name].Invoke(parameters);
        }
        catch (Exception ex)
        {
            target["xrm_result"] = ex.ToString();
        }
    }

    private string Add2Numbers(string numbers)
    {
        var numberArray = numbers.Split('|');

        return (decimal.Parse(numberArray[0]) + 
                decimal.Parse(numberArray[1])).ToString();
    }
}

You could easily extend the parameters and/or result to use XML and serialize/de-serialize the results to provide a more robust/complete solution. For simplicity purposes I presume the parameter will be provided in a pipe delimited format. Now, you simply execute and retrieve the results as follows:



Effectively this may offer an easy solution to execute some complex stand alone C# for whatever reason required.



No comments:

Post a Comment