Showing posts with label Custom Workflow Activity. Show all posts
Showing posts with label Custom Workflow Activity. Show all posts

Friday, 21 April 2017

How to read configuration data from an xml web resource via a Plug-in or Custom workflow activity?

URLs) in a single location without repeating them in all Java Scripts or plugins so that all your form scripts and plug-ins can access them.

This way you need to change those variables in only one location when you go from one environment to the other (i.e. Dev to Test and UAT etc.)

In an earlier post I discussed how to access these configurations in Java Scripts. So here I am going to write how to do it in plugins or custom workflow activity.

Let’s say you have created an XML web resource named new_ApiConfiguration.xml.
And assume your web resource looks like this:

<SacConsultingApi>
<CreateApiUrl>https://webapi.sacconsulting.com.au/crmdev/api/record?id=</CreateApiUrl>
<UpdateApiUrl>https://webapi.sacconsulting.com.au/crmdev/api/update?recId=</UpdateApiUrl>
<ExpireApiUrl>https://webapi.sacconsulting.com.au/crmdev/api/expire?recId=</ExpireApiUrl>
</SacConsultingApi>

And you can access these configurations inside you custom plugins or workflow activities by using the below method.

Declare the variables on top.

string CreateApiUrl;
string UpdateApiUrl;
string ExpireApiUrl;


private void ReadWebResourceAndGetData()
{           
   QueryExpression query = new QueryExpression
   {
     EntityName = "webresource",
         ColumnSet = new ColumnSet("name""content"),
         Criteria = new FilterExpression
         {
             Conditions =   {
                       new ConditionExpression
                       {
                            AttributeName = "name",
                            Operator = ConditionOperator.Equal,
                            Values = { "new_ApiConfiguration.xml"}
                       }
                  }
            }
          };    
          EntityCollection ec = service.RetrieveMultiple(query);
          if (ec.Entities[0].Attributes.Count > 0)
          {
              WebResource webResource = null;
              string webResourceContent = string.Empty;
              webResource = (WebResource)ec.Entities[0];
              if (webResource.Attributes.Contains("content"))
              {
                 byte[] binary = Convert.FromBase64String(webResource.Attributes["content"].ToString());
                 webResourceContent = UnicodeEncoding.UTF8.GetString(binary);
              }
              if (!string.IsNullOrEmpty(webResourceContent))
              {
                 XmlDocument xml = new XmlDocument();
                 xml.LoadXml(webResourceContent);
                 XmlNodeList xnList = xml.SelectNodes("CreateApiUrl");
                 if (xnList.Count > 0)
                 {
                     CreateApiUrl = xnList[0].InnerText;                       
                 }
                 xnList = xml.SelectNodes("UpdateApiUrl");
                 if (xnList.Count > 0)
                 {
                     UpdateApiUrl = xnList[0].InnerText;
                 }
                 xnList = xml.SelectNodes("ExpireApiUrl");
                 if (xnList.Count > 0)
                 {
                     ExpireApiUrl = xnList[0].InnerText;
                 }
      }
   }
}

Remember to change the name of the web resource to your web resource name.

This way when you deploy solutions from one environment to the other you don’t need to go and change your configurations in hundred places.

Friday, 24 March 2017

How to update CRM records correctly in C#?

Today I am going to write about a common mistake that CRM developers do very often. If you don’t correct this right now you will face some serious issues with your CRM system and some unpredictable behaviours even in Production systems which will be very hard to troubleshoot.
What is it?
Most of the time you will need to update a CRM record in your plugins or custom workflow activities or some of your console applications which you might write for various requirements.

I will take a plugin for example; Look at this basic plugin which updates the Do Not Email field of a contact record.

public class UpdateContact:IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));           
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.InitiatingUserId);

            using (XrmServiceContext serviceContext = new XrmServiceContext(service))
            {
                if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
                {
                    Entity entity = (Entity)context.InputParameters["Target"];
                    if (entity.LogicalName == Contact.EntityLogicalName)
                    {
                        var contactRecord = serviceContext.ContactSet.FirstOrDefault(c => c.Id == entity.Id);

                        //wrong way! This will update all the fields of the record.
                        contactRecord.DoNotEMail = false;
                        service.Update(contactRecord);


                        //Correct way to update. This will update only the specified field(s)
                        Contact contactRecordToUpdate = new Contact();
                        contactRecordToUpdate.Id = contactRecord.Id;
                        contactRecordToUpdate.DoNotEMail = false;
                        service.Update(contactRecordToUpdate);
                    }
                }
            }
        }
    }

Once you have taken the ID of the entity from the input parameters then you retrieve the Contact record. Now you are setting the field values you need to update on that object. This is the big mistake. If you do so and call update CRM will update all the fields of the entity which will cause to run many other plugins, workflows, business rules, JavaScripts etc.

Correct way is get the ID of the entity from the input parameters; then create a new instance of the entity and set the ID and the field values. Then pass that instance when you call the update method. 

How to tackle Concurrent Business Process flows

Dynamics 365 has introduced the new feature of Concurrent Business Process Flows. Here is a couple of good articles on that: http://dev...