Tuesday, January 31, 2012

Step by step plugin tutorial using Developer's Toolkit Part 3

This blog is an extension of my last blog Step by step plugin tutorial using Developer's Toolkit Part 2. We used “Create Wrapper” method to generate strongly typed classes. In this blog, we will use OrganizationServiceContext to create “Task” entity instead of using service.Create() method. To use OrganizationServiceContext in the plugin, we need to add reference to Microsoft.Xrm.Sdk.Client at the top of the class.
using Microsoft.Xrm.Sdk.Client;
Now create an instance of OrganizationServiceContext by passing the OrganizationService as shown below
// TODO: Implement your custom Plug-in business logic.
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
//ITracingService tracingService = localContext.TracingService;
//create a service context
var ServiceContext = new OrganizationServiceContext(service);
Now replace the
service.Create(task);
with
ServiceContext.AddObject(task);
ServiceContext.SaveChanges();
Deploy the plugin and test it.

Advantages of using OrganizationServiceContext

The biggest advantage of using OrganizationServiceContext is that we can track multiple entities/operations and save all the changes with ServiceContext.SaveChanges(); statement. Have a look at this article on MSDN. 

3 comments:

  1. Hey! Thank you for some great posts, I really enjoy reading them!

    I am new to CRM development and hence have a question:

    I am developing a simple plugin, which adds a (right now) hard coded signature to the emails being sent. It should be the same for the entire organization.

    I've hooked up on the Create message and made a method, which is shown below:

    private static void AddSignatureToEmail(IOrganizationService service, Guid id)
    {
    using (var crm = new OrganizationServiceContext(service))
    {

    var email = crm.EmailSet.Where(e => e.Id == id).First();

    string signature = "CUSTOM, HARDCODED SIGNATURE";

    string orgDescr = email.Description;
    string[] splittedDesr = orgDescr.Split('<', '>');
    string newDescr = "<" + splittedDesr[1] + ">" + splittedDesr[2] + signature + "<" + splittedDesr[3] + ">";

    email.Description = newDescr;

    crm.UpdateObject(email);
    crm.SaveChanges();
    }
    }


    Whenever I save the email (to invoke the Create), I get a Microsoft.Xrm.Sdk.SaveChangesException when the UpdateObject(email) is called. But if I try to see the content of the Description after the changes I get the message perfectly formatted with the signature.
    I have tried a few different things, but it dosent seem to work out for me. Got any advice?

    Sincerly,

    Mads


    Ps. The email.Description contains some XML for formatting the body of the email, which is why I split the body string (I haven't started to calculate with formatted emails yet) - do you have a nicer way to do it?
    Btw, if I remove the append of the signature, e.g. only get the email and try to reinsert it into CRM I still get an error

    ReplyDelete
    Replies
    1. Thanks for the feedback.

      I need to see the whole code and I also need an exact error message. In these kind of scenarios,generally the problem is context does not understand if it is tracking an object.

      try clearing the context and attach the object before updating it.
      //Add this line after linq query
      crm.ClearChanges();

      //add this line before update object
      crm.Attach(email);

      I hope this helps.

      Delete
    2. Hi again.
      (Sorry for the somehow late reply, but I only work part time, so I haven't had a chance to look at your suggestion before now).

      My code looks like this:

      using System;
      using System.Diagnostics;
      using System.Linq;
      using System.ServiceModel;
      using Microsoft.Xrm.Sdk;
      using Xrm;

      public class Fixer : IPlugin
      {
      public void Execute(IServiceProvider serviceProvider)
      {
      ITracingService trace = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

      IPluginExecutionContext context = (IPluginExecutionContext)
      serviceProvider.GetService(typeof(IPluginExecutionContext));

      Entity entity;

      if (context.InputParameters.Contains("Target") &&
      context.InputParameters["Target"] is Entity)
      {
      entity = (Entity)context.InputParameters["Target"];
      if (entity.LogicalName != "email") { return; }
      }
      else
      {
      return;
      }

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

      var id = (Guid)context.OutputParameters["id"];

      AddSignatureToEmail(service, id);
      }
      catch (FaultException ex)
      {
      throw new InvalidPluginExecutionException("An error occurred in the plug-in.", ex);
      }
      catch (SaveChangesException ex)
      {
      throw new InvalidPluginExecutionException("An error occurred in the plug-in.", ex);
      }
      }

      private static void AddSignatureToEmail(IOrganizationService service, Guid id)
      {
      using (var crm = new OrganizationServiceContext(service))
      {
      var email = crm.EmailSet.Where(e => e.Id == id).First();
      crm.ClearChanges();

      string signature = "This is my custom signature";

      string orgDescr = email.Description;
      string[] splittedDesr = orgDescr.Split('<', '>');
      string newDescr = "<" + splittedDesr[1] + ">" + splittedDesr[2] + signature + "<" + splittedDesr[3] + ">";

      email.Description = newDescr;

      crm.Attach(email);
      crm.UpdateObject(email);
      crm.SaveChanges();

      }
      }
      }

      The error message I get is:

      Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, An error occurred in the plug-in.

      [E-mailFooterFixer: Fixer]
      [Fixer: Create of email]

      Message: An error occured while processing this request.
      Results: Microsoft.Xrm.Sdk.SaveChangesResultCollection
      StackTrace: at Microsoft.Xrm.Sdk.Client.OrganizationServiceContext.SaveChanges(SaveChangesOptions options)
      at Fixer.AddSignatureToEmail(IOrganizationService service, Guid id)
      at Fixer.Execute(IServiceProvider serviceProvider)

      So it looks like I cant use the SaveChanges() call - Google tells me I'ts because I use LINQ (according to this blogpost: http://social.microsoft.com/Forums/en-US/crmdevelopment/thread/682a7be2-1c07-497e-8f58-cea55c298062/ ), do you have any input?

      The step is set up to be post-operation, synchronous with the create message and email as primary entity..

      Furthermore, the ClearChanges() and Attach() dosent seem to make a difference - atleast I get the same error if I exclude the lines.

      /Mads

      Delete