Tuesday 13 May 2014

CRM 2011 / 2013 Mastering Plugin Registration Filtering Attributes

In plugin, we also can filter our logic to do or not to do something. Moreover, for Plugin onUpdate, for example : to prevent user to update AccountCode or Quote Type, or whatever, sometimes our logic only work, for example if Quote type has been changed, then you have to prompt user to say, you cannot change the Quote Type. But, if you only change the Address in Quote, you by default will also hit the plugin, so that you have to filter, like this :

if(entity.Attributes.Contains("tfp_quotetype"))
{
throw new InvalidPluginExecutionException("Hi you cannot change Quote Type");
}

But, again your plugin also will be executed.


Let’s say in your plugin, you update this entity using this plugin, this also can cause infinite looping for updating.


In this post, I would like to know to filter Attribute that you don’t want to fire the Plugin.


By default, your plugin, after registered will not filter any attributes, meaning that, once your entity updated, no matter which attribute it is updated, it will trigger your plugin.


image


In my code, I did not do any filter :


image


Meaning that, any changes on every field, the plugin will be triggered


We try this



image


Let’s we do filter, I don’t want to trigger this if Ship Method field changed,


image


then I try to uncheck this attribute :


image


Then, I try to update the Shipping Method :


Will it work? Meaning that if I update the Shipping Method, this plugin will not be triggered?


Let me try!


I update the value from null to Airbone,


But, why I still get this plugin executed?


image


Then, you debug, yes it hits your plugin :


image


If you thought like that, it is wrong, and you’re still confused about Plugin Filtering


Actually plugin filtering attributes is used to trigger plugin or execute plugin once the field is changed, then which fields you want to trigger the plugin, you have make it as checked.


When you uncheck, it doesn’t mean that if you change the shippingmethodcode value (only this field you change in UI) so that your plugin will not be executed, since there are many other attributes that your checked before that has changed, it can be CRM system field that is hidden.


Those fields, for example :


ModifiedOn


image


And you realize that ModifiedOn field is in the checked list.







image


So, even though you are only update the Shipping Method, it also affect to other field, even though your target entity as input parameter does not contain shippingmethodcode, your plugin will still be executed.


Then, you try to not include the ModifiedOn and its friends


image


Then you try again, your plugin is still being hit


image


Then, what you do?


Okey, let’s understand this filtering, let’s change your mind to not focus to what you don’t want, but let’s focus to what you want.


You will fill difficult to uncheck every attribute that you don’t want.


For example, you don’t want to execute plugin after you change your shippingmethod only.


Now, let’s think that actually you want to execute your Plugin, IF QUOTE TYPE is changed.


Okay, what will do is :


1. Deselect all your attributes


2. Then check the ‘Quote Type’


image


Until your plugin step will be look like this.


image


Then stay tune in your plugin and trigger your quote, keep your breakpoint, then let’s you see if your plugin is triggered or not.


Wow, your plugin is not executed after you change the shipping method :


image


So, let’s you have very long code for calculation, it is better to filter attribute do you want to trigger and execute your plugin rather than you let any minor change in your field then run your long lines code of plugin.


Remember that QuoteId (uniqueidentifier) will be always be the InputParameter


image


Hope it helps and change your mind!

CRM 2013 Custom Action as Next Action

As we know that Custom Action gives you a special capability to extend xRM Platform and it gives a great future.

At My Previous Post I was talking about Custom Action as Validation Gate and many of my posts are related to Custom Action.

Now, I would like to show you about Custom Action that not only as validation, but also can give you a new idea to do next action.

Now, start with my previous custom action, but I will not only use that for giving this Business Error :

image

I would like to put 5600 to fill one of my field value in Quote :

image

Because actually, I already did pass the Quote entity to my Custom Action, remember this snipped :

image

Actually, there are two possibility ways to do :

1. Getting an Output, still getting an output from the custom action then in my plugin I set my Revenue field value based on the output from my custom action, rather than I just throwing an error, which is I get that 5600.0

2. I use my custom action to update my Revenue field.

This is what I did is using the number 2, because I want my plugin is only calling my custom action and all of the logic will be done by my custom action, my plugin no need to do anything anymore since this custom action will be called by anywhere, for example if I have an calculator apps in my web or my agent desktop app, etc.

Then, I modify my code in Action Code :

public class Action_SimpleCalculation : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
#region must to have

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

IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

// Create service with context of current user
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

//create linq context
KonicaBaseContext baseContext = new KonicaBaseContext(service);

//create tracing service
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

#endregion

//To get access to the image of the Quote record
EntityReference entityRef = context.InputParameters["Target"] as EntityReference;

//To read the input parameter
Money money1 = context.InputParameters["Money1"] as Money;
Money money2 = context.InputParameters["Money2"] as Money;

//Capture Discount Rate
decimal discount = 0;
discount = (decimal) context.InputParameters["Discount"];

//Now, I am talking about Custom Action as Validation Gate
if(discount >= 100)
{
throw new InvalidPluginExecutionException("Hi, are you crazy to give such discount? We will not gain any profit, do you realize that?!");
}

else{
//This is how the calculation works and custom action as a Calculation Formula
Money sum = new Money(money1.Value + money2.Value);
Money sumafterDiscount = new Money();
sumafterDiscount = new Money(sum.Value - ((sum.Value) * (discount / 100)));

//using this as a response output
context.OutputParameters["MoneySum"] = sumafterDiscount;

//rather than only giving me an output, I would like to call next action, that is update the revenue field in my quot
//I already have my quote Id

Quote myQuote = new Quote();
myQuote.Id = entityRef.Id;
myQuote.tfp_Revenue = sumafterDiscount;
service.Update(myQuote);
           }
}
}

Then in my Plugin I just call my Action

//create target entity as early bound
Quote TargetEntity = entity.ToEntity<Quote>();

//call Business Layer
QuoteBL quoteBL = new QuoteBL();

//Money moneySum = quoteBL.ExecuteCustomAction_SimpleCalculation(service, new Money(2000), new Money(5000), TargetEntity.Id) ;
//throw new InvalidPluginExecutionException("Hi, your total Amount will be = " + moneySum.Value.ToString());

//this one to prevent infinite loop, because custom action will update the revenue
if (TargetEntity.tfp_Revenue != null)
{
return;
}

//just call my custom action
quoteBL.ExecuteCustomAction_SimpleCalculation(service, new Money(2000), new Money(5000), TargetEntity.Id);

I don’t call the “throw new InvalidPluginExecutionException” anymore, but I call my Custom Action, instead.


After you saved to trigger plugin and custom action, you can test it and here is your expected result :


image


Hope it helps!

CRM 2013 Custom Action as Validation Gate

In My Previous Post I was talking about Custom Action in Microsoft Dynamics CRM 2013 as Custom Message and also I give example about utilizing Custom Action as Calculation Formula.

Now, I will still using the same Custom Action as Example, but I will add some logic to make it as Validation Gate.

Imagine that you have several application that need connect to your CRM and do the same calculation, then you have to copy paste your custom code to all of the apps and do the validation.

Let’s go to the example with still using same custom action but adding some sauce : Discount

image

Then, I amend my code to give some validation :

public class Action_SimpleCalculation : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
#region must to have

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

IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

// Create service with context of current user
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

//create linq context
KonicaBaseContext baseContext = new KonicaBaseContext(service);

//create tracing service
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

#endregion

//To get access to the image of the Quote record
EntityReference entityRef = context.InputParameters["Target"] as EntityReference;

//To read the input parameter
Money money1 = context.InputParameters["Money1"] as Money;
Money money2 = context.InputParameters["Money2"] as Money;

//Capture Discount Rate
decimal discount = 0;
discount = (decimal) context.InputParameters["Discount"];

//Now, I am talking about Custom Action as Validation Gate
if(discount >= 100)
{
throw new InvalidPluginExecutionException("Hi, are you crazy to give such discount? We will not gain any profit, do you realize that?!");
}

else{
//This is how the calculation works and custom action as a Calculation Formula
Money sum = new Money(money1.Value + money2.Value);
Money sumafterDiscount = new Money();
sumafterDiscount = new Money(sum.Value - ((sum.Value) * (discount / 100)));

//using this as a response output
context.OutputParameters["MoneySum"] = sumafterDiscount;
}
}
}

Then, I also add parameter to call this action :

#region custom action execution

//EARLY BOUND
public Money ExecuteCustomAction_SimpleCalculation(IOrganizationService service, Money money1Param, Money money2Param, Guid quoteId)
{
tfp_Action_SimpleCalculationRequest request = new tfp_Action_SimpleCalculationRequest()
{
Money1 = money1Param,
Money2 = money2Param,
Target = new EntityReference("quote", quoteId),
//new parameter
Discount = 120
};

tfp_Action_SimpleCalculationResponse response = service.Execute(request) as tfp_Action_SimpleCalculationResponse;
//Processing of response
return response.MoneySum;
}
#endregion

 


Update your Plugin Assembly then see the result.


And yeah, this is the result


image


Now, change the discount again to less than 100.


image





Then Update your plugin.


Here is the result :


image

CRM 2013 Register Custom Action as an Advance Custom Message

Action in CRM 2013 is a great feature.

In my previous posts, I have talked about Action :

All about Custom Action

Then I also have many example to utilize Action to cater my idea extending xRM Platform.
Now, I am explaining Custom Action as Custom Message that enable for developer to Register as a Step in Plugin Registration Tool!
This is very useful when you want to do integration or calling a server side complex business logic, for example Calculation and Validation.

But, there is a doubt that in Steps, you can only do simple thing, nothing to do? Then, how?
These standard steps of CRM 2013 Action are very limited and nothing much different with other Workflow.

 

image

 

If you think that Available Steps in Action is not be able to accommodate what you want, then? Then, Customize it, do advance customization on it.

Now, first let me guide you. I give you example how to extend Custom Action as Custom Message, I don’t want to give a complex sample now, just give you a concept to understand.

I give you sample how to do calculation with Formula : Money1 + Money2 = MoneySum.

Two input arguments : Money 1 and Money 2

One outpur argument : Money Sum

 

1. Create an Action (You can refer to my above links, and also from that link you can see any links to talk about Action in CRM 2013)

Create your own Message : SimpleCalculation, for example (and give some prefix to indicate it)

(Remember, this is will be your custom message, a verb, a message, that you will use as your universal code contract to be registered to be used by any custom code, just make sure you give them a proper name).

Define your argument as well

 

image

 

2. Why no steps?

I want to let you know that you also can create your logic instead using those standard steps.

3. Activate it.

4. Generate an Early Bound Class to get your action in your class library

Please refer to this article :

 

Generate Custom Action as Early Bound

 

You also can use Early Bound and Late Bound, but for easier way, I use Early Bound as a sample.

5. Create a Plugin Class and put this code :

public class Action_SimpleCalculation : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
#region must to have

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

IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

// Create service with context of current user
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

//create linq context
KonicaBaseContext baseContext = new KonicaBaseContext(service);

//create tracing service
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

#endregion

//To get access to the image of the Quote record
EntityReference entityRef = context.InputParameters["Target"] as EntityReference;

//To read the input parameter
Money money1 = context.InputParameters["Money1"] as Money;
Money money2 = context.InputParameters["Money2"] as Money;

Money sum = new Money(money1.Value + money2.Value);

//using this as a response output
context.OutputParameters["MoneySum"] = sum;
}
}

6. Register Your Class as Plugin using Plugin Registration Tool


(You might have to refresh your Plugin Registration Tool until you can see your Action as Message)


image


Register your step :


image


7. Call your Action from your Code


image


8. Pass to your Execution Code your own parameter


image


For example : 2000 and 5000, and pass your Quote Id as Target Entity (if you have this specific entity when you create your Action)


Then, your Total Amount will be : 7000 from 2000 + 5000
Throw an error message for capturing your Total Amount.


Let’s test it, run your code!


9. Test your code by triggering your custom code (In this case I call my Action after my Quote updated)


Here is the result :


image


Here, I don’t put any logic in my Plugin, I just using one single point, that is Custom Action.


Next time, my logic has been changed, I don’t need to change my plugin logic or any custom code about my calculation, because I only implement my code in this Action.


Hope it is informative for you!

CRM 2013 Error : Workflow associated with this custom operation is not activated

When you are triggering a plugin that call a Custom Action, you might have this error :

“Workflow associated with this custom operation is not activated”

 

image

 

Resolution :

Go back to your Custom Action and Activate it.

CRM 2013 Utilize Custom Action as Dynamics Error Message

Many times during my project development and implementation, I have requirement to Alert user if they have to input some field, those some fields sometimes is not mandatory during the Form, but it is mandatory for our Logic.

For example, in the Account entity creation or update.

In Contact entity, City is not mandatory for some accounts type.

If Contact Role is an Influencer, then their address will be very important to you, including City, State, and Country to complete your Addresses.

If Contact Role is an Owner, then same as well, their complete address will be mandatory.

If Contact Roles is not an Influencer nor an Owner then, Address fields will be only Optional or Recommendation.

So, you cannot make the Address fields as Mandatory for all of Situation, yes, you can achieve this by using JS or Business Rules, but remember that if you Form script, then let’s say user do inserting using backend such as other application or using excel import wizard, then you are forced to use Plugin to validate. Lets say you have to implement this in Lead, Account, and Contact, then this is applied to Create and Update Messages, right.

So, what possible situation is by creating a plugin that calls this :

 

image

And I put them to all of my coding.

That’s fine, yes that’s Okay, and it worked.

Then what happened if my user said : Hi, I don’t want to use that messages.

Often, developer use their own way and words to spread an alert, that is not acceptable by some business users because this is till blur and unclear.

So, let’s say first you say : “Please input ‘blabla’ Value!!”, then user said, please change to : “‘blabla’ Value Cannot be Blank”, then change again to more polite command : “Hi Sir/Madam, Please don’t forget to fill the ‘blabla’ Value. Thanks”, then what will you do?

Okay, you have to change all of your Code, it is fine since you just copy paste, but you have various word for ‘blabla’ right? It can be City, State, Country, Fax, Mobile Phone, Membership ID, or whatever you have. So, yes, this is sometimes annoying.

Then, what I did in CRM 2011 is I create an entity, similar to Configuration entity to store my own Error Messages

Key Name

Key Value

Parameter Type

Description

CityBlank

Please input ‘City’ Value

Error Message

Error message if City Blank

StateBlank

Please input ‘State Value

Error Message

Error message if State Blank

CountryBlank

Please input ‘Country Value

Error Message

Error message if Country Blank

Imagine you have many fields, then you have to change all of the Key Value.

It is okay, maybe you can utilize the string.format Message to make the City, State, Country, etc as dynamic value.

But, do you know that in CRM 2013, you can utilize custom action to make your own Error Message more dynamic? This is the more elegant idea to work with Action to get some dynamic Error Message.

If you have known familiar with Action, please refer to this link :

http://aileengusni.blogspot.com/2014/05/crm-2013-let-me-introduce-nice-new_2810.html

http://aileengusni.blogspot.com/2014/05/crm-2013-custom-action-as-configuration.html

 

Here is the steps :

1. Create an Action

 

Create custom action1

 

2. Define your Arguments

Input : FieldName – String – Required – Input

Output : MessageOutput – String – Required – Output

 

Define Argument custom action 2

 

3. Define your Steps by Assigning the Value

 

Set Message Output 3

 

In this step, using your Input Argument you can create a Dynamic Output, using that FieldName input argument as dynamic value, based on what you pass as input.

 

4. After define your arguments and Activate your Custom Action

Activate CA 4

 

5. Using .NET in Plugin you can call your Custom Action

Early Bound

 

coding to call2

Late Bound

Call custom action late bound

Call that action in your Plugin

coding to call1

Here is the code
//EARLY BOUND
public string ExecuteCustomAction_PleaseInputValue(IOrganizationService service, string strFieldName)
{
tfp_Action_PleaseInputValueRequest request = new tfp_Action_PleaseInputValueRequest()
{
FieldName = strFieldName
};

tfp_Action_PleaseInputValueResponse response = service.Execute(request) as tfp_Action_PleaseInputValueResponse;
//Processing of response
return response.MessageOutput;
}

//LATE BOUND
public string ExecuteCustomAction_PleaseInputValue(IOrganizationService service, string strInputParameter, string strInputParameterValue, string strOutputParameter)
{
OrganizationRequest req = new OrganizationRequest("tfp_Action_PleaseInputValue");
req[strInputParameter] = strInputParameterValue;
//execute the request
OrganizationResponse response = service.Execute(req);
return response[strOutputParameter].ToString();
}
For Reference :

http://a33ik.blogspot.co.il/2013/10/custom-actions-walkthrough-for-net-and.html


To generate Action in Early Bound Class :


http://aileengusni.blogspot.com/2014/05/crm-2013-generate-custom-action-as.html


6. Here is your result


When City is Blank


Business Process output 5


7. Here if you want to change your Error Message, just change it :


- Go back to your Action


- Deactivate first


image


- Change the steps


image


8. Here is your result


image


Enjoy it!


For your information, for importing Action it can be a big deal in CRM 2013, at least until Rollup 2
Please refer to this :


http://aileengusni.blogspot.com/2014/05/crm-2011crm-2013-import-solution-error.html


Hope it helps!

CRM 2013 Generate Custom Action as Early Bound

I really love to use Custom Action, it opens my mind to extend xRM Platform capability and make my job for Integration and Dynamic job easier.
I can use Action for Integration Message make it as single verb and key integration single point, and also can utilize this to combine my logic and show error message.
Because of that, I think I have to include custom action to my custom development, and sometimes, Early Bound is making my life easier.
Here is the steps you to generate Custom Actions as your Early Bound class library.
1. Download CRM 2013 SDK
2. Using CrmSvcUtil.exe


Generate Early Bound Custom Action


3. Define your own Server URL and Output file (location and namespace).
Don’t forget to add this parameter :
/generateActions

4. Here is my complete commands as example :


CrmSvcUtil.exe /url:"http://aileengusnidev:5555/contoso/XRMServices/2011/Organization.svc" /out:"../Crosscutting/BaseContext.cs" /domain:mycrmdev /username:administrator /password:mypassword /serviceContextName:"BaseContext" /namespace:TFP.Xrm.Contoso /generateActions




Remember you can save this as .bat file, so every time you need it, just run it!

For smart way, you can refer to this link : http://aileengusni.blogspot.com/2014/05/crm-sdk-smart-way-to-use-crmsvcutilexe_13.html

Aileen Gusni

Aileen Gusni