Thursday, July 21, 2011

MSCRM 2011 early binding plugin

Checked on MSCRM 2011 on premise and online.

*** I think it's important to understand what is going behind the scenes, here's easier option for creating plugin with early binding. It's done using Dynamics CRM 2011 developer toolkit.
http://dynamicslollipops.blogspot.com/2012/02/mscrm-2011-using-early-binding-in.html

When i've tried to follow the sdk:

"Walkthrough: Build a Plug-in That Connects to Microsoft Dynamics CRM 2011 Using Developer Extensions"
I've ended up looking the web for a way to register plugin which refernced Microsoft.Xrm.Client.dll,
The plugin registration tool kept given me errors because it couldn't find Microsoft.Xrm.Client.dll
Could not load file or assembly 'Microsoft.Xrm.Client, Version=5.0.9688.1154, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.

All the solution in the web suggested to use ILMerge for merging the plugin assembly with the 


Microsoft.Xrm.Client.dll and many other not intuitive solutions.
WTF?!?! There most be easier why to enjoy the early binding with out all this mess.

It's possible, just follow these steps:

1) create the xrm class using CrmSvcUtil
Example:
CrmSvcUtil.exe /out:Xrm.cs /url:http://crm2011:5555/Basic/XRMServices/2011/Organization.svc /username:yyyyy /password:xxxxx /namespace:Xrm/serviceContextName:XrmServiceContext 
2) Add the created file to the project
3) Add reference to the project
microsoft.xrm.sdk.dll
microsoft.crm.sdk.proxy.dll
4) inherit IPlugin

This is it.

this is how you get the context:
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory =
                    (IOrganizationServiceFactory)serviceProvider.GetService(
                typeof(IOrganizationServiceFactory));
                IOrganizationService service =
                serviceFactory.CreateOrganizationService(context.UserId);

                XrmServiceContext xrm = new XrmServiceContext(service);
Example for the plugin:
public class SLAPlugin : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
            Entity entity;
            // Check if the input parameters property bag contains a target
            // of the create operation and that target is of type Entity.
            if (context.InputParameters.Contains("Target") &&
            context.InputParameters["Target"] is Entity)
            {
                // Obtain the target business entity from the input parameters.
                entity = (Entity)context.InputParameters["Target"];

                // Verify that the entity represents a contact.
                if (entity.LogicalName != Incident.EntityLogicalName) { return; }
            }
            else
            {
                return;
            }

            try
            {
                IOrganizationServiceFactory serviceFactory =
                    (IOrganizationServiceFactory)serviceProvider.GetService(
                typeof(IOrganizationServiceFactory));
                IOrganizationService service =
                serviceFactory.CreateOrganizationService(context.UserId);

                XrmServiceContext xrm = new XrmServiceContext(service);
                
                // Extract the tracing service.
                ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
                if (tracingService == null){
                    throw new InvalidPluginExecutionException("Failed to retrieve the tracing service.");
                }

                if(!context.PostEntityImages.Contains("MyImage")){
                    throw new InvalidPluginExecutionException("Failed to retrieve the Post Image.");
                }

                Entity postEntity = context.PostEntityImages["MyImage"];
                Incident caseTemp = postEntity.ToEntity<Incident>();

                if (caseTemp != null)
                {
                    //only if missing active conditionset start looking for one
                    if (caseTemp.new_ActiveCoditionSetId == null)
                    {
                        tracingService.Trace("Start looking for conditionset");
                        MSCRM2011SLAProcessWorker a = new MSCRM2011SLAProcessWorker();
                        a.GetConditionSetAndUpdateCase(xrm, tracingService,caseTemp);
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException(
                "An error occurred in the plug-in.", ex);
            }
        }
    }
Updating newly created entity that is not in the context
//create update case
Incident caseToUpdate = new Incident
{
 IncidentId = activeCase.IncidentId
};
//update the update case
xrm.Attach(caseToUpdate);
xrm.UpdateObject(caseToUpdate);
xrm.SaveChanges();
    
Hope it helps...

12 comments:

  1. Hello

    Did you already try to Linq To Crm (early binding)?

    I always get the message "Unable to cast object of type 'Microsoft.Xrm.Sdk.Entity' to type '....'."

    In some forums I found that I have to call the "OrganizationServiceProxy.EnableProxyTypes()" method. But this class/method is located in the client sdk.

    Does Early binding (with linq) from a plugin really work?? :/

    ReplyDelete
  2. Yes it works.
    If you want you could send me sample of your code and i will try to find the problem.

    Anyway here is some LINQ i have in my code

    var conditionsSets = xrm.new_conditionsetSet.Where(cs => cs.statecode.Value == new_conditionsetState.Active).OrderBy(o => o.new_Order);

    ReplyDelete
  3. Hello. My second post didn't arrived. I managed it. The OrganizationServiceProxy IS on the server available.
    I created a instance of this class and called the EnableProxyTypes and now it works.

    THanks

    ReplyDelete
  4. Dear all,
    anyone met the error below before ? please kindly advise !

    unexpected exceoption from plug-in (excecute): PluginWalkThrough.Plugin: System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Xrm.Client, Version=5.0.9688.1154, Culture=neutral, Pub LicKeyToken=31bf3856ab364e35' or one of its dependencies. The system can't find the file specified.

    Many thanks,
    rith

    ReplyDelete
  5. Plesae remove the reference to Microsoft.Xrm.Client assebmly from your plugin project and follow the blog.
    I think it will help you to solve the problem.

    ReplyDelete
  6. Dear yairrose,
    In the plugin also contain the xrm.cs that require the Microsoft.Xrm.Client assembly together.
    if i remove the error will occur with xrm.cs

    Many thanks,
    rith

    ReplyDelete
  7. If you'll create the xrm.cs this why (Without the codegeneration)
    CrmSvcUtil.exe /out:Xrm.cs /url:http://crm2011:5555/Basic/XRMServices/2011/Organization.svc /username:yyyyy /password:xxxxx /namespace:Xrm/serviceContextName:XrmServiceContext
    you won't need the Microsoft.Xrm.Client.

    The other option for you is to use the ILMerge (Just google it and you'll find out how to do it)

    ReplyDelete
  8. So what you have demonstrated is that we need to use a very specific namespace for the generated entities in order to get the plugin registration tool to use them without a bunch of extra trouble.

    Thank you for this info!

    ReplyDelete
    Replies
    1. That's not quit right, The namespace is not importent here and can be changed.
      The importent thing is not to use the "codegeneretion" dll when using CrmSvcUtil.

      Thank you for your comment.

      Delete
  9. Hello,

    I recently got stung by this Microsoft.Xrm.Client.dll error and I was able to resolve it by removing Microsoft.Xrm.Client.CodeGeneration from the CrmSvcUtil parameter list and then removing the reference to Microsoft.Xrm.Client from the Visual Studio project.

    What I've learned from this experience is that for CRM Online I can't use the Microsoft.Xrm.Client.CodeGeneration CrmSvcUtil parameter. This immediately causes me to ask:

    What benefits/features does using Microsoft.Xrm.Client.CodeGeneration parameter give?

    What I am losing by not using the Microsoft.Xrm.Client.CodeGeneration parameter?

    Can anyone help with these questions?

    ReplyDelete
    Replies
    1. Hi,
      You can find it here in Microsoft Dynamics CRM 2011 SDK:
      http://msdn.microsoft.com/en-us/library/gg695792.aspx

      You can find more differences between with and without CodeGeneration in
      http://kelvinshen.blogspot.co.il/2012/01/generate-code-with-crmsvcutilexe.html

      The main difference is that the service context using CodeGeneration is derived from CrmOrganizationServiceContext while when not using the CodeGeneration is derived from OrganizationServiceContext

      Delete
  10. Hello,

    you squeezed the space between '/namespace:Xrm' and '/serviceContextName:XrmServiceContext'.

    Caused me quite some troubles because it still executes but then causes 1000 errors when integrated in the project.

    Please fix in the article :).

    ReplyDelete