30 November 2010

CRM 2011 plugins

Yesterday I tried to write simple plugin against Dynamics CRM 2011. This plugin should update some property of contact in case if some activity is completed. In particular we have to set property new_lastcontacteddate if phone call is completed. In previous CRM version such plugin was arduous since we was able use only DynamicEntity. WSDL generated classes were not suitable in plugins since Microsoft.Crm.Sdk.ICrmService didn't support those generated classes. In order to use strongly typed classes in plugin in CRM 4.0 you could create new CrmService object in the plugin, but it is not good idea
, because we should use CreateCrmService of IPluginExecutionContext. Now crmsvcutil generates classes derived from Microsoft.Xrm.Sdk.Entity and we can use them in plugins.
Entity class has useful method ToEntity<>. It converts Entity to strongly typed class and back. But you should remember that not every conversion is permitted. In case if Entity is instance of different class that you want to convert to, you will receive runtime error like "Cannot convert entity phonecall to activitypointer".
So, if we register our plugin as post stage plugin for PhoneCall entity on SetStateDynamic message, we can receive our phone call as

PhoneCall call = context.PostEntityImages[IMAGE_NAME].ToEntity<PhoneCall>();

In case if state of phone call is completed we have to iterate through activity parties in call.To property:

if (call.StateCode == PhoneCallState.Completed)
{
    ProcessParties(service, call.To);
}

PhoneCall usually has only one recipient. But PhoneCall, Fax, Appointment, Letter and some other entities in CRM are Activities. They both have key named ActivityId and placed in related tables in the CRM database. As appointment could have more than one attendee, as emails could have more then one address in To, phone calls and faxes classes support more that one Activity Party in To property.

crmsvcutil utility generates property To as IEnumerable<ActivityParty>.


/// <summary>
/// Person that is being called.
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("to")]
public System.Collections.Generic.IEnumerable<DataModel.ActivityParty> To
{
  get
  {
    return System.Linq.Enumerable.Cast<YourDataModel.ActivityParty>(this.GetAttributeValue<Microsoft.Xrm.Sdk.EntityCollection>("to").Entities);
  }
  set
  {
    this.OnPropertyChanging("To");
    this.SetAttributeValue("to", new Microsoft.Xrm.Sdk.EntityCollection(new System.Collections.Generic.List<Microsoft.Xrm.Sdk.Entity>(value)));
    this.OnPropertyChanged("To");
  }
}

But here I have received first issue with beta version of CRM 2011 SDK. If you want to iterate through To items like 

foreach (var party in call.To)
{
  ProcessActivityParty(service, party);
}

you will receive error "Unable to cast object of type 'Microsoft.Xrm.Sdk.Entity' to type 'YourDataModel.ActivityParty'". I suppose it is error inside beta version and I hope it will be fixed in production. But for now I had to find solution which allow me to iterate through Activity Parties. And I found them.
I didn't cast context.PostEntityImages[IMAGE_NAME].ToEntity<PhoneCall>() but used late binding to access to "To" property.

Entity activity = context.PostEntityImages[IMAGE_NAME];

foreach (var party in ((EntityCollection)activity.Attributes[CustomEntities.Fax.To]).Entities)
{
  ProcessActivityParty(service, party);
}

Actually Attributes[CustomEntities.Fax.To] returns item of EntityCollection class and we are able to use this class to retrieve all activity parties.

At the end function ProcessActivityParty:

private void ProcessActivityParty(IOrganizationService service, Entity party1)
{
     ActivityParty party = party1.ToEntity<ActivityParty>();
     if (party.PartyId.LogicalName == Contact.EntityLogicalName)
     {
         Contact theContact = new Contact();
         theContact.ContactId = party.PartyId.Id;
         theContact.New_LastContact = DateTime.Now;
         service.Update(theContact.ToEntity<Entity>());
     }
}

And do not forget that CustomEntities.Fax.To class property is generated by tool presented in previous post

4 comments:

  1. Hi,

    This is a great article, but i get stuck at the first hurdle :-( my context has no PostEntityImages. I have registerd the plugin to the SetStateDynamicEntity message on the phonecall entity in the post operation, but I still get nothing :-(

    Also, how do you get access to the PhoneCallState enumeration. I had to create my own

    Cheers

    ReplyDelete
  2. Chris, I think, you have also register image. It's not enough just add step. You should add image in PluginRegistration tool.

    ReplyDelete
  3. [System.Runtime.Serialization.DataContractAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("CrmSvcUtil", "5.0.9688.42")]
    public enum PhoneCallState
    {

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Open = 0,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Completed = 1,

    [System.Runtime.Serialization.EnumMemberAttribute()]
    Canceled = 2,
    }

    this is PhoneCallState. It was generated with crmsvcutil.

    ReplyDelete
  4. Almost five years later and I still ran into this exact issue with the latest CRM 2015 sdk. Why Microsoft, why?

    ReplyDelete