Tuesday 19 December 2017

Welcome in Dynamics World: Part-5 Custom Workflow

In my previous blog, I had explained about Plugin. Part 4
In this blog, I will try to focus on Custom workflow.
I am assuming you have some basic idea of C#.

Microsoft Dynamics 365 (online & on-premises) supports the registration and execution of custom workflow activities in addition to the out-of-box activities provided by Windows Workflow Foundation. Windows Workflow Foundation includes an activity library that provides activities for control flow, sending and receiving messages, doing work in parallel, and more. You can write custom workflow activities in Microsoft Visual C# or Microsoft Visual Basic .NET code by creating an assembly that contains one or more classes derived from the Windows Workflow FoundationCodeActivity class.

Prerequisites
Install Visual studio with .net framework 4.5.2
Install CRMSDKTemplates (SDK-Templates)
Demo
Open visual studio and select new project.

Select “CRM Developer Extensions” from template and 4.5.2 framework then select “CRM Workflow Project”.

Than select target SDK version. And click Create Project.












Add new class in your solution.





Add namespaces
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;
using System.Activities;
using System.Runtime.Serialization;

Add access modifier “Public” before class and Inherit class “CodeActivity
public class Calculator:CodeActivity
Implement abstract class.
public class Calculator:CodeActivity
    {

        protected override void Execute(CodeActivityContext context)
        {
            throw new NotImplementedException();
        }

    }

Now you need to create object of Trace and service interface.
public class Calculator:CodeActivity
    {
       protected override void Execute(CodeActivityContext executionContext)
        {
            try
            {
                //Create the tracing service
                ITracingService tracingService = executionContext.GetExtension<ITracingService>();
                //Create the context
                IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
                //Create the service object
                IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
//Do your work
            }
           catch(Exception ex)
            {
                throw new InvalidPluginExecutionException(ex.Message);
            }

        }
    }

These are the basic code needs in most of custom workflow.
In //Do your work section you can use your custom logic like update, assign validation etc.
Use trace.Trace(“your message”); to add message like console.write(“”) in console application. It will help you to get information when your plugin throw exception.
There is no Pre or Post image in custom workflow.

Add input parameters

While specifying the input parameter in your workflow class, you can also specify a default value for the parameter. The following sample shows the definition of an input parameter.
[Input("DateTime input")]
[Default("2004-07-09T02:54:00Z")]
public InArgument<DateTime> Date { get; set; }
Add output parameters
Output parameters are added in the same manner as the input parameters. The following sample shows the definition of an output parameter.
[Output("Money output only")]
[Default("23.3")]
public OutArgument<Money> MoneyOutput { get; set; }
Add input and output attributes for the same parameter
You can use the input and output attributes for the same parameter. In the following code example, IntParameter is the input as well as the output parameter.
[Input("Int input")]
[Output("Int output")]
[Default("2322")]
public InOutArgument<int> IntParameter { get; set; }
Additional attributes
Some types, such as EntityReference and OptionSetValue, require additional attributes apart from the InputOutput, and Default attributes. The additional attributes are: ReferenceTarget and AttributeTarget. The following sample shows the definition of a parameter of the EntityReferencetype.
[Input("EntityReference input")]
[Output("EntityReference output")]
[ReferenceTarget("account")]
[Default("3B036E3E-94F9-DE11-B508-00155DBA2902", "account")]
public InOutArgument<EntityReference> AccountReference { get; set; }

In my Example I have used below simple Input and output arguments
public class Calculator:CodeActivity
    {
       [Input("Input Data")]
       [RequiredArgument]
       public InArgument<string> InputData { get; set; }

       [Output("Output Data")]
       public OutArgument< double > OutputData { get; set; }
  protected override void Execute(CodeActivityContext executionContext)
       {
  }
    }
Complete sample: -
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;
using System.Activities;
using System.Runtime.Serialization;
using System.Data;
using System.Text.RegularExpressions;
using System.IO;
using System.Xml.XPath;
namespace DemoWorkflow
{
   public class Calculator:CodeActivity
    {
       [Input("Input Data")]
       [RequiredArgument]
       public InArgument<string> InputData { get; set; }

       [Output("Output Data")]
       public OutArgument<double> OutputData { get; set; }

       protected override void Execute(CodeActivityContext executionContext)
       {
           try
           {
             
               //Create the tracing service
               ITracingService tracingService = executionContext.GetExtension<ITracingService>();
               //Create the context
               IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
               //Create the service object
               IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
               IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
               if(InputData.Get(executionContext)!=null)
               {
                   OutputData.Set(executionContext, Evaluate(InputData.Get(executionContext)));
               }

           }
           catch (Exception ex)
           {
               throw new InvalidPluginExecutionException(ex.Message);
           }

       }
       public static double Evaluate(string expression)
       {
           var xsltExpression =
               string.Format("({0})",
                   new Regex(@"([\+\-\*])").Replace(expression, " ${1} ")
                                           .Replace("/", " div ")
                                           .Replace("%", " mod "));
           // ReSharper disable PossibleNullReferenceException
           return (double)new XPathDocument
               (new StringReader("<r/>"))
                   .CreateNavigator()
                   .Evaluate(xsltExpression);
           // ReSharper restore PossibleNullReferenceException
       }
    }
}

Impersonation in plug-ins

Impersonation is used to execute business logic (custom code) on behalf of a Microsoft Dynamics 365 system user to provide a desired feature or service for that user. Any business logic executed within a plug-in, including Web service method calls and data access, is governed by the security privileges of the impersonated user.

To impersonate plugin via code in Custom Workflow.
   IOrganizationService service = serviceFactory.CreateOrganizationService(new Guid(“impersonated user Guid”));

Register and Deploy Custom Workflow

 Make sure your plugin should have Private or Public key.










After you have done with your code. Now time to deploy your assembly in Dynamics CRM.
So, build your visual studio solution(Ctrl+Shift+b).
Now go to your project->bin->debug folder and check your assembly is created or not. There should have your assembly(dll).

Now open plugin registration tool and select “Register new Assembly”.














Now select your assembly and click on “Register Selected plugin”.





















You do not need to Register New Step to run your custom workflow.

Using Custom Workflow

Now you can use your custom workflow in any out of box workflow or action.

Go to Setting->process-> Create new workflow or Action
















Now when you click on “Add step” you will find your assembly here and select your class.

Specify input value, I have taken “Account Number” for input value and rename this field to “Enter value” on account form. Convert this workflow as real-time workflow so we can check result in real time.


In next step I am storing result in Account.











Activate your workflow. And got to account and enter any calculation value. You will see result in Result field.






















This is the beginning now you can build new custom workflow as per your requirement.
In next blog, I am sharing interview Question Answers.Click Here

Share your feedback!!

Field Security Profile - Based on Owner

 Recently received requirement related to Field security profile. Expectation : - 1.       Set to users need access of secure attributes. 2....

Test