Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Friday, 21 April 2017

How to read configuration data in plugins using secure configurations?


Recently, we deployed some custom SharePoint integration with Dynamics CRM which required some custom coding. As usual, we wanted to connect to different Dynamics CRM environments (DEV, TEST, UAT, PROD, etc.). Every time we deployed, we didn’t want to change the code so that it can connect to the correct SharePoint site.

To achieve this there are few options available and we used the Secure Configuration feature available with Plugin Registration tool. There you provide all the configurations like site URLs, usernames, passwords, etc., in XML format and you can access them within the constructor of your plugin.

Your plugin registration will look like this; inside secure configurations box you enter your configurations in xml format.
















Your configurations XML would look like this:

<Settings>
  <setting name="siteURL">
    <value>https://xxxx.sharepoint.com/sites/CRM-DEV/Cases/</value>
  </setting>
  <setting name="DocumentLibName">
    <value>CaseDocumentLibrary</value>
  </setting>
  <setting name="SPOUserName">
    <value>SPCRMIntegrationUser@xxxxx.com.au</value>
  </setting>
  <setting name="SPOpassword">
    <value>xxxxx</value>
  </setting>
  <setting name="Case_DocLibPath">
    <value>/sites/CRM-DEV/Cases/CaseDocumentLibrary</value>
  </setting>
  <setting name="Case_Type_Hidden_StaticName">
    <value>g5dc149027cf444eae73dfec7bd07885</value>
  </setting>
  <setting name="ContentTypeId">
    <value>0x012000E8517D690891E149A88FC509298C39B300BA883DF9E383BA47AD69DC71A7712B76</value>
  </setting>
</Settings>

Here in the constructor of the plugin, you can read the settings you set in the Secure Configuration XML.

public OnUpdateOfCase(string unsecureConfig, string secureConfig)
{
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(secureConfig);
            siteURL = SecureConfigHelper.GetConfigDataString(doc, "siteURL");
            DocumentLibName = SecureConfigHelper.GetConfigDataString(doc, "DocumentLibName");
            SPOUserName = SecureConfigHelper.GetConfigDataString(doc, "SPOUserName");
            SPOpassword = SecureConfigHelper.GetConfigDataString(doc, "SPOpassword");
            Case_DocLibPath = SecureConfigHelper.GetConfigDataString(doc, "Case_DocLibPath");
            Case_Type_Hidden_StaticName = SecureConfigHelper.GetConfigDataString(doc, "Case_Type_Hidden_StaticName");
            ContentTypeId = SecureConfigHelper.GetConfigDataString(doc, "ContentTypeId");

}

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. 

Monday, 20 March 2017

Connect to CRM via a console application


Connect to CRM via a console application.

If you are writing some complicated business logic inside your custom workflow activity or a plugin there is a high chance of your code throwing exception once you have registered them and started testing.

What I do is I create a simple Visual Studio C# console application and connect to CRM. Then debug the business logic in the console application first and make sure everything is working well before I insert the code into the plugin or workflow activity skeleton. This saves lot of time as debugging plugins and custom workflow activities is not very straight forward.

Creating a Console application is very easy and once created you can use it for multiple projects as you need to change only few variables.

Step 1:
Open visual studio and create a new project of type Console Application as below:

 


Step 2:
Under solution explorer right click on the project created and click properties. Then under the Application tab change the Target Framework to .Net Framework 4.5.2
If you don’t have this version of .net installed in your computer download it from Microsoft site and install.


















Step 3:
Refer the following assemblies. CRM dlls can be found under the bin folder in CRM SDK. You can download the SDK from Microsoft site.

























Update your Program.cs class like below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
using System.ServiceModel.Description;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Xrm.Sdk.Query;

namespace CRM2016ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        { 
            #region credentials
            string SoapOrgServiceUri = "https://CRMUrl/OrganizationName/XRMServices/2011/Organization.svc";
            ClientCredentials credentials = new ClientCredentials();
            credentials.UserName.UserName = "username";
            credentials.UserName.Password = "password";
            #endregion                     

            Uri serviceUri = new Uri(SoapOrgServiceUri);
            OrganizationServiceProxy proxy = new OrganizationServiceProxy(serviceUri, null, credentials, null);
            proxy.EnableProxyTypes();
            IOrganizationService orgService = (IOrganizationService)proxy;
            XrmServiceContext serviceContext = new XrmServiceContext(orgService);

        }
    }
}

Update username, password and crm url.




Now you have OrganizationService instance and if you have built your early bound classes then you have access to the ServiceContext too. In this example they are orgService and serviceContext respectively.

Now you can build your CRM queries with hard coded GUIDs to test your business logic. Once all tested and good to go move them to your plugins. J

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...