Thursday, 17 September 2015

Scripting on Business Process Flow in CRM 2015


With the introduction of MS CRM 2015, came many new features. The one we are going to discuss here is advancement of Business Process Flow and especially the Scripting part, which came as boon.
Before CRM 2015, the Business Process Flow exist, but no API availability made it impossible for the developers to interact with the BPF via programming.
CRM 2015 gave it a new look, while creating a Business Process Flow, we have the option of creating Branched stages, which in simple terms is we can conditionally decide which stage to be shown after the current stage. The branching decisions can be made on the basis of the value of any step used for the current stage.
Previously we were not allowed to visit an entity more than once before, now we can visit an entity more than once.
Above are the few highlights of features added for BPF, let`s delve into the Programmability enhancement.
The most important part is, How to hook to the Stage change or Stage Select events of BPF? This is indeed the simplest part.
Example:
If you want to hook to the Stage change event, you can do this by writing the below code. And, you have the freedom to place this code either onLoad or onSave of the form or else on change of any field.
//Register a function on change of the stage
Xrm.Page.data.process.addOnStageChange(stageChange);

stageChange – It is the function to be called when the stage is changed.

Similarly, you can hook onto the Stage select event.
//Register a function on select of a stage
Xrm.Page.data.process.addOnStageSelected(stageSelected);

stageSelected – It is the function to be called when the stage is selected.

We have the options to unhook the events as well.
//Unbind a function on change of the stage
Xrm.Page.data.process.removeOnStageChange(stageChange);
//Unbind a function on select of a stage
Xrm.Page.data.process.removeOnStageSelected(stageSelected);
By hooking onto either stage change or stage select events, we have plethora of options to use.
Like we mentioned above, that we can Branch the entities conditionally. We can leverage this functionality by showing different fields for an entity depending on the value selected for the step on the previous stage.
Let us explain you few of the available methods in this part of the Blog, and the rest in this.
  • Collapse or Expand the Business Process Flow:
We have the option to collapse the Business Process Flow by default, on load of the form.
Snippet:
Xrm.Page.ui.process.setDisplayState(string)
string: “expanded”  or “collapsed” are the two variables that can be passed.

  • Show/Hide the Business Process Flow:
We can show or hide the business flow. It can be useful when we don`t need few of the Security Roles to see the BPF.
Snippet:
Xrm.Page.ui.process.setVisible(bool)
bool: “true” to show and “false” to hide.

  • Active Process:
We can get the Current Active Process and we can set the Current Active Process. This is useful if you want different security profiles to see different processes.
  • getActiveProcess
This will give you the object of the current Active Process. Object will have,
Process Name, Process Id(GUID), Render State(Visible/Hidden) & Collection of Stage Objects.
Snippet:
var procObj = Xrm.Page.data.process.getActiveProcess();
  • setActiveProcess
This will allow you to set the Active Process.
Snippet:
Xrm.Page.data.process.setActiveProcess(procGUID, callbackFunction);
procGUID: Id of the process to be set.
callbackFunction: Function that will be called in order we have any necessary actions to be performed on setting the process.

  • Active Stage:
We can get the Current Active Stage and we can also set the Current Active Stage. This is useful if you want a user to move back to previous stage, when he selects “x” value for a step on current Active stage.
  • getActiveStage
This  will give you the object of current Active Stage. Object will have, Stage Name, Stage ID(GUID), Base Entity, Stage Status(active/inactive) & Collection of Step objects.
            Snippet:
var actStg = Xrm.Page.data.process.getActiveStage();
  • setActiveStage
This will allow you to set an Active Stage.
Note: Only completed stage for the current entity can be set using this method.
            Snippet:
Xrm.Page.data.process.setActiveStage(stgGUID, callbackFunction);
stgGUID: ID of the stage to be set.
callbackFunction: If in case any actions are to be performed after setting the Active Stage.

  • Get the Active Path
We can get the Active Path i.e., serves the exact seq. of stages that got the user to where he is now, the stage he is on and the predicted set of future stages on the basis of Branching rules.
Snippet:
var stgColl = Xrm.Page.data.process.getActivePath()
  • Get the Enabled Processes
We can get the list of enabled processes for a particular entity which user can use to switch.
Snippet:
Xrm.Page.data.process.getEnabledProcess(callbackFunction(enabledProcesses))
callbackFunction(enabledProcesses) :  This callback function will accept a parameter. The parameter will be an object having the list of enabled processes.
  • Navigate Previous or Next
What if you want to move the user next or prev depending on the value of a step on the current stage, to make that happen, we have 2 functions:
  • moveNext:
This will move the user to the next stage.
Snippet:
Xrm.Page.data.process.moveNext(callbackFunction)
callbackFunction: The callback function can be used to perform any actions that needs to be done after moving the user to the next stage.
  • movePrevious:
This will move the user to the previous stage.
Snippet:
Xrm.Page.data.process.movePrevious(callbackFunction)
callbackFunction: The callback function can be used to perform any actions that needs to be done after moving the user to the previous stage.
  • Process Methods
In the first part of the blog, we discussed how to retrieve Active Process. Now, let`s see how to retrieve the properties from the returned object.
var procObj = Xrm.Page.data.process.getActiveProcess();
  • Get the Id:
procObj.getId();
Returns a string.
  • Get the Name:
procObj.getName();
Returns a string.
  • Get the Stage Collection:
procObj.getStages();
Returns the collection of stages
  • Check whether the process is rendered or not:
procObj.isRendered();
Returns a bool.

  • Stage Methods
In the first part of the blog, we discussed how to retrieve Active Stage. Now, let`s see how to retrieve the properties from the returned object.
var actStg = Xrm.Page.data.process.getActiveStage();
  • Get the Category:
actStg. getCategory().getValue();
Returns an integer value of the Business Process Flow category.
  • Get the Entity Name:
actStg.getEntityName();
Returns the logical name of the entity.
  • Get the Id:
actStg.getId();
Returns a string.
  • Get the Stage Name:
actStg.getName();
Returns a string.
  • Get the Status:
actStg.getStatus();
Returns “active” or  “inactive”.
  • Get the Steps:
var stpColl = actStg.getSteps();
Returns collection of steps.
  • Step Methods:
In the previous point, we got the step collection. Now, let`s see how to retrieve the properties from the returned object.
  • Get the Logical Name:
stpColl.getAttribute();
Returns the logical name of the step.
  • Get the Name of the step:
stpColl.getName();
Returns the step name.
  • Get the Required Level:
stpColl.isRequired();
Returns a bool.
All these are new addition in the CRM 2015 box and those are the most asked and helpful additions. We can achieve many things by hooking onto stage change and stage select events.

Thursday, 10 September 2015

Dynamics CRM Plugin Impersonation

Plug-ins execute under the security account that is specified on the Identity tab of the CRMAppPool Properties dialog box. By default, CRMAppPool uses the Network Service account identity.
The two methods that can be employed to impersonate a user:
  1. During Plugin registration:
   One method to impersonate a system user within a plug-in is by specifying the impersonated user during plug-in registration. When registering a plug-in programmatically, if the SdkMessageProcessingStep.ImpersonatingUserId attribute is set to a specific Microsoft Dynamics CRM system user, Web service calls made by the plug-in execute on behalf of the impersonated user. If ImpersonatingUserId is set to a value of null or Guid.Empty during plug-in registration, the calling/logged on user or the standard "system" user is the impersonated user.

  1. During Plugin Execution:
Impersonation that was defined during plug-in registration can be altered in a plug-in at run time. Even if impersonation was not defined at plug-in registration, plug-in code can still use impersonation. The following discussion identifies the key properties and methods that play a role in impersonation when making Web service method calls in a plug-in.
The platform passes the impersonated user ID to a plug-in at run time through the UserId property. This property can have one of three different values as described below:

Condition>> 
if(The SdkMessageProcessingStep.ImpersonatingUserId attribute is set to null or Guid.Empty at plug-in registration.)
      Then User Id Value will be>> Initiating user or "system" user

If(The ImpersonatingUserId property is set to a valid system user ID at plug-in registration.)
     Then User Id Value will be>> Impersonated user.

If(The current pipeline was executed by the platform, not in direct response to a service method call.
     Then User Id Value will be>> "system" user

If you specify an impersonated user during plug-in registration, you should set up the service proxy in the plug-in by passing a value of true to the CreateOrganizationService method. a value of true indicates to use the ID in the IPluginExecutionContext.UserId property as the impersonated user. The following code example shows how to do this.

Example
[C#]  IOrganizationService service = factory.CreateOrganizationService (true);
This is equivalent to the following code:
Example
[C#] IOrganizationService service = factory.CreateOrganizationService(context.UserId);
To ignore any impersonating user set during plug-in registration, use the following code.
 Example
[C#] IOrganizationService service = factory.CreateOrganizationService(false);
When a value of false is passed the platform uses the built-in "system" account to execute Web service method calls made by your plug-in code.

The InitiatingUserId property of the execution context contains the ID of the system user that called the service method that ultimately caused the plug-in to execute.

IOrganizationService service = factory.CreateOrganizationService(context. InitiatingUserId );

Wednesday, 2 September 2015

Understanding Plugin sandbox mode

Plugins

Plugins in CRM are great ways to run powerful .NET code and our one of the CRM Developers most powerful tools in his toolbox.
There are lots of steps you need to go through when creating a plugin and there are lots of things which can error.
The knowledge you need is usually built up with a bit of theoretical knowledge and then a lot of practical trying.  The amount of knowledge you need to write a plugin is one of the reasons Why .NET developers struggle with CRM Development
If you are starting out writing plugins, I would recommend my youtube plugin playlist
I would recommend reading my blog post on common plugin errors, which you will certainly experience at some point CRM 2011/2013 – Common Plugin Errors and Isolation Mode
The common errors talks about the  post discusses a deployment common error you might experience, which is you cannot deploy plugins with isolation mode = none if you are not a deployment administrator.
If the isolation mode = “Sandbox” then any CRM Developer who has the security role of Administrator can deploy plugins into a sandboxed environment.

Where can you see the Isolation mode of a plugin

When you create a plugin you can choose two different types of isolation mode
  • Sandbox
  • None
You may have seen these when you are deploying plugins in the CRM Developer toolkit, it’s in the RegisterFile.crmregister file, you can see each assembly has
IsolationMode= “Sandbox”
You can also see what isolation mode of a plugin if you open the Plugin Registration Tool.
  1. open the Plugin Registration tool
  2. connect to CRM instance
  3. Right click on an Assembly and choose update
  4. Now see the Isolation mode
isolation mode

When developers talk, naming and terms used can add confusion and slow down people’s understanding.
A plugin assembly has a setting called Isolation mode and this can be set to None or Sandboxed, but you will rarely hear any CRM developers use the term isolation mode.
Instead they will say things like these
  • A plugin is sandboxed
  • CRM online plugins must run in the sandbox
  • it’s a normal plugin
When a CRM Developer mention Sandbox/Sandboxed and plugin they mean the plugin has an isolation mode which equal “Sandbox”
CRM online plugins can only run with an isolation mode = sandboxed
A normal plugin is a plugin which has an isolation mode =  “none”

Often used but not really understood

CRM isolation mode is used all the time by all CRM developers who create plugins but often most CRM developers only have a vague idea of what Isolation mode means.
Most CRM Developers will have heard about Isolation mode with regards to CRM online.  The reason for this is CRM Plugins created for CRM Online organisations must have Isolation mode = “Sandboxed”

What is the Isolation mode?

The first (and best) place to start with understanding Isolation mode and Sandboxed plugins is with this great MSDN article which can be found in the CRM SDK (which should be the first place you look for documentation)
You will notice the isolation mode of a plugin is at the assembly level and not the individual plugin level.
This is why when you create a new plugin there is no setting for isolation mode because it’s at a DLL\project level and you can have many plugins inside one project (or inside one dll).

Isolation Environment

Plugins with an isolation level of “Sandbox” run in an isolated environment and as you can imagine this environment is more secure.  Key point
The sandbox is more secure and some actions are restricted
The restrictions are a bit of mystery, in the sense there is not one all encompassing list of code which will cause an error in a sandboxed plugin.  This can be very frustrating when you deploy a plugin in the sandbox and it throws an error, finding the cause of this can be difficult and frustrating.
The Plug-in isolation, trusts, and statistics article states
isolated environment, also known as a sandbox, a plug-in or custom activity can make use of the full power of the Microsoft Dynamics CRM SDK to access the organization web service. Access to the file system, system event log, certain network protocols, registry, and more is prevented in the sandbox.

The article gives a good description of what this means by saying Plugins deployed in the sandbox are partially trusted (e.g. you only partially trust the plugin and are limiting it’s powers) and plugins which are not in the sandboxed are fully trusted (by you the developer) and you are happy to let them interact with the file system, registry, call other dll’s and web services etc.

Sandboxed and non sandboxed plugins

I recently had some experience with sandboxed plugins because a project I was working on moved all the plugins out of the sandbox.  The first result was I couldn’t not update or publish any plugins because I wasn’t a Deployment admin
The second side effect is I remember the sandbox has its own service.  If you have ever installed CRM you notice there are Sandbox CRM Service and standard CRM Service.  Most CRM Developers know of the services when they do one of the many IISRESETS + Service restart, which usually happens if you have DLL’s in the GAC.  The sandbox service runs all the sandbox plugins.
The sandbox service runs all the sandbox plugins.
I was remote debugging, so instead of attaching the remote debugging to the
  • w3wp.exe – standard plugin
  • CRMASyncService.exe – if the plugin is asynchronous
  • Microsoft.Crm.Sandbox.WorkerProcess.exe – for sandbox plugins
One reason I personally don’t like remote debugging is if someone is debugging a standard plugin, then by debugging the w3wp they stop the whole server whilst and everyone else who is using it.  I have seen some scenarios where other developers and testers have had to stop whilst the one developer debugged his plugin (poor show).
To get around this you can change the plugin to sandboxed and then when you debug you only stop the sandbox service

Sandbox limitations

I have stated previously it’s difficult to know what the limitations are but here some of the limitations taken from the msdn article
  • Access to the file system (C Drive)
  • system event log
  • certain network protocols
  • registry
  • You cannot access any other DLL’s
  • You cannot call any webservices from within a sandboxed plugin
  • IP addresses cannot be used
  •  Only the HTTP and HTTPS protocols are allowed.
  • In isolated mode you cannot call any external DLL’s\DLL’s in the GAC
This blog had some good restrictions in a bit more detail
  • Attempting to use the AppDomain.CurrentDomain.AssemblyResolve event
  • IO.Path.GetTempPath() [System.Security.Permissions.EnvironmentPermissionException]
  • Any filesystem access code [System.Security.Permissions.FileIOPermissionException]
  • Attempting to use the EventLog [System.Diagnostics.EventLogPermissionException]
  • Attempting to use IsolatedStorage [System.Security.Permissions.IsolatedStoragePermissionException]
  • Any references to Thread.CurrentThread caused a security failure.

I believe CRM online sandboxed plugins cannot use LINQ queries, which throws an error due to another transaction being created in the LINQ query.
Custom workflows cannot be used in the CRM online sandbox
I came across an error which prompted me to write this blog post.  I was trying to searilze some fields and pass them between plugins using shared variables
This forum post below is the same error
Unhandled Exception:
System.MethodAccessException: Attempt by security transparent method ‘TestingSeam.CrmTesting.Execute(System.IServiceProvider)’ to access security critical method ‘System.Web.Script.Serialization.JavaScriptSerializer..ctor(
This error was unusual because it was complaining about access to a critical method.  I wondered why serialization was critical method but thinking about it, serialization must involve writing the data to disk and sandboxed plugins are not allowed to do this.
A Gotcha also occurred when someone changed the plugin to sandbox mode, it stopped the plugin working, so I had to leave a comment in the code to say, this plugin won’t work if the plugin is sandboxed.

Why put plugins in the sandbox

So the question is why would people choose to put plugins in the sandbox.
The most common reason is they are using CRM online and you have no choice because all plugins have to be
Runtime statistics are created  PluginTypeStatistic entity records. These records are populated within 30 minutes to one hour after the sandboxed custom code executes
This url has an interesting benefit
  1. If the sandbox worker process that hosts this custom code exceeds threshold CPU, memory, or handle limits or is otherwise unresponsive, that process will be killed by the platform. At that point any currently executing plug-in or custom workflow activity in that worker process will fail with exceptions. However, the next time that the plug-in or custom workflow activity is executed it will run normally. There is one worker process per organization so failures in one organization will not affect another organization.

Why haven’t you listed all errors

Some readers maybe dissapointed I haven’t listed all the methods and exact lines of code which will cause sandbox plugins to throw security errors.
Whilst writing this blog post I realised the reason Microsoft have listed all the causes of security errors in sandboxed plugins because there are potentially lots of them and if they tried to list them all, they would miss some. In fact I would say it’s impossible to list them all, so there is no benefit to trying.
The way to think about the sandbox is it’s a bit like a sandpit and the code is a child.  As soon as any code/child tries to get out of the sandpit we throw an error and a parent comes along, tells the child off and throws them back in the sandpit.
This is why sandboxed code is safer because it can’t get onto your server and cause havoc.

Summary

The limitations of sandboxed plugins can be a significant influencing factor for many CRM solutions to be on premise.
The limitation of not being able to call webservices and DLL’s in the GAC can be quite restrictive.
There is a solution using ILMERGE, which is a method of merging a number of different DLL’s into one DLL, which will allow you to use the plugin in a sandboxed environment.  I would be cautious about this approach because if you ask anyone who has done it, they will tell you it wasn’t easy and debugging a merged DLL can be impossible.
Here is a good article on ILMerge issues