Showing posts with label Plugin. Show all posts
Showing posts with label Plugin. Show all posts

Friday, 27 April 2018

Plugins in the sandbox, and why you don't get System.Security.Permissions.SecurityPermission

A relatively common error with plugins is "Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed". This is the general message that you get when you have a plugin registered in the sandbox, and it is trying to do something that is not permitted. You may get variations on this error, depending on exactly what the code is trying to do, for example:
  • FileIOPermission - access the file system
  • InteropPermission - mostly likely using an external assembly (either directly, or having ILMerged into your plugin assembly)
  • System.Net.WebPermission - some for on network access, e.g. trying to access a network resource by IP address (the sandbox only allows by DNS name)
  • SqlClientPermission - accessing SQL Server
The list can go on, and on. Rather than trying to list everything you can't do, it's a lot simpler to list what you can, which is broadly:
  • Execute code that doesn't try to access any local resources (file system, event log, threading etc)
  • Call the CRM IOrganizationService using the context passed to the plugin
  • Access remote web resources as long as you:
    • Use http or https
    • Use a domain name, not an IP address
    • Do not use the .Net classes for authentication
All of which is pretty restrictive, but is understandable given the sandbox is designed to protect the CRM server. To me, the most annoying one is the last, which makes it pretty much impossible to call other Microsoft web services directly, such as SharePoint or Reporting Services.

So, what to do about it. If you have CRM OnPremise, the simple and only solution is to register the assembly outside the sandbox, so that it can run in FullTrust - i.e. do whatever it wants (though still subject to the permissions of the CRM service account or asynchronous service account that it runs under).

And if you've got CRM Online, then the normal solution is to offload the processing to an environment that you have more control over. The most common option is to offload the processing to Azure, using the Azure Service Bus or Azure Event Hub . The alternative, new to CRM 9, is to send the data to a WebHook, which can be hosted wherever you like. 

Friday, 27 June 2014

Plugin pre-stages - some subtleties

The CRM SDK describes the main differences in plug stages here. However, there are some additional differences between the pre-validation and pre-operation stages that are not documented.

Compound Operations
The CRM SDK includes some compound operations that affect more than one entity. One example is the QualifyLead message, which can update (or create) the lead, contact, account and opportunity entities. With compound operations, the pre-validation event fires only once, on the original message (QualifyLead in this case) whereas the pre-operation event fires for each operation.
You do not get the pre-validation event for the individual operations. A key consequence of this is that if, for example, you register a plugin on pre-validation of Create for the account entity, it will not fire if an account is created via QualifyLead. However, a plugin on the pre-operation of Create for the account entity will fire if an account is created via QualifyLead.

Activities and Activity Parties
I've posted about this before, however it's worth including it in this context. When you create an activity, there will be an operation for the main activity entity, and separate operations to create activityparty records for any attribute of type partylist (e.g. the sender or recipient). The data for the activityparty appears to be evaluated within the overall validation - i.e. before the pre-operation stage. The key consequence is that any changes made to the Target InputParameter that would affect an activityparty will only be picked up if made in the pre-validation stage for the activity entity.

Monday, 7 April 2014

Controlling Duplicate Detection

The CRM SDK messages CreateRequest and UpdateRequest support a configuration parameter "SuppressDuplicateDetection" that provides control over whether duplicate detection rules will be applied - see http://msdn.microsoft.com/en-us/library/hh210213(v=crm.6).aspx. However, this parameter is not available through over programmatic means (such as the REST endpoint) to create or update records.

To workaround this, I created a plugin that sets the "SuppressDuplicateDetection" parameter based on the value of a boolean attribute that can included in the Entity instance that is created or updated.

I've posted the source code to the MSDN Code Gallery here

I created this because I had a need to apply duplicate detection rules to entities created via the REST endpoint in CRM 2011.

It may be that this plugin could also be used as a way to revert the CRM 2013 behaviour back to that of CRM 2011, to allow duplicate detection rules to fire on CRM forms. However, I've yet to test this fully; if anybody wants to test it, feel free to do so and make comments on this post. Otherwise, I'll probably update this post if I find anything useful with the CRM 2013 interface.

Wednesday, 13 July 2011

PartyList attributes and the plugin event pipeline

This should be a quick post about a subtlety with the plugin event pipeline. I recently wrote a plugin that could modify the data that's submitted when updating an activity record. This should have been a straightforward plugin on the Pre event that modified the Target InputParameter, and it all worked fine, except for partylist fields (such as the resources field on the serviceappointment entity, or optionalattendees on the appointment entity). Essentially, any changes I made to these fields in the plugin were ignored.

Fortunately, there is a solution, and it depends on the stage that you register the plugin on. If you register on stage=20 (i.e. within the transaction), your changes are ignored. However, change the registration to stage=10 (before the transaction), then it does work. There's no documentation on this, but I expect it is due to how the partylist data is saved. This data is written to the activityparty table in the database, and I expect that the SQL for this is already fixed at the start of the transaction, and hence is unaffected by changes in the plugin code.

Friday, 11 February 2011

Plugin Deployment Options

The CRM 4 SDK gives some information about the storage options when registering plugins but there are a few more considerations. I got prompted to elaborate on this in a forum post, and I think it's worth documenting this here as well:

The 3 storage options are: Database, Disk and GAC. The main differences between these are:

  • Database: The assembly dll is stored in the database, rather than the file system. The major advantages are that the assembly need only be deployed once if you have multiple CRM servers, and that no additional action is required to restore / redeploy the assembly either during disaster recovery, or if redeploying to an alternate server. This is the preferred option in a production environment
  • Disk: The assembly dll is placed in the \server\bin\assembly directory on each server. You have to ensure the dll is placed in the correct place on all CRM servers, so the deployment overhead is a little greater. I normally use this option in development environments as you can redeploy newer versions solely by file transfer, rather than reregistering. Also, if debugging, the assembly .pdb file needs to be placed in the same location; with this option it's easy to ensure the dll and pdb are from the same build
  • GAC: The assembly is placed in the Global Assembly Cache on each CRM server, and again you will have to do this. The GAC does allow multiple versions of an assembly, but CRM doesn't, so you don't really gain anything by using the GAC. I don't think I've ever used this option

There is one further consideration. If your plugin assembly has other dependent assemblies, then you can place this dependent assembly in the GAC whichever of the above options you take. However, if you use the Disk option, then the dependent assemblies can also be deployed into the \server\bin\assembly directory

Wednesday, 22 October 2008

Deploying Custom Workflow Activities - Add authorizedType

This is the first of an intended two posts about registering custom workflow activities, and regards the initial deployment; a subsequent post will address updates and versioning issues.

The CRM 4.0 SDK gives a reasonable overview of registering a custom workflow activity, covering the following steps:
  1. Building / Deploying a plugin registration tool
  2. Registering the assembly
  3. Adding referenced assemblies to the GAC
  4. Stopping and restarting the CRM Async Service

However, one important point is omitted - adding your activity classes as an authorizedType within the web.config file. Workflow in CRM 4.0 uses the Windows Workflow Foundation (WWF) which, as a relatively new .Net technology, includes a reasonable security model to reduce the risk of malicious code being deployed within it.

The security model in WWF will only allow a permitted list of classes to be called as custom activities. In CRM 4.0 this list is stored in the web.config file in the root of the CRM website, and looks like this:

<System.Workflow.ComponentModel.WorkflowCompiler>
<authorizedTypes>
<authorizedType Assembly="System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Workflow.Activities" TypeName="IfElseActivity" Authorized="True"/>
<authorizedType Assembly="System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Workflow.Activities" TypeName="IfElseBranchActivity" Authorized="True"/>
</authorizedTypes>
</System.Workflow.ComponentModel.WorkflowCompiler>

For your custom activity to be permitted, you have to add an entry as an element; for example:

<authorizedType Assembly="MyAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken="7766554433221100" Namespace="MyActivities" TypeName="*" Authorized="True"/>

Note that I've used an asterisk (*) to indicate all classes in the given namespace and assembly are permitted; you could reference an individual class if you prefer. Also note that the assembly is referenced by the strong name, as the assembly has been digitally signed when it was compiled.

This raises the question 'what happens if you don't do this step?' If you don't, you can deploy the workflow plugin, and use it in a workflow rule, but you get an error when you try to publish the workflow rule. Unfortunately the message you get is unhelpful; it's a variation of 'An unexpected error has occurred'. If you dig deeper, and enable tracing on the server, you do get a useful message in the w3wp log, such as the following:

Workflow compilation failed:WF363: Type MyActivities.Demo, MyAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken="7766554433221100 is not marked as authorized in the application configuration file.

Once you find it, this message is pretty useful, as it tells you most of the problem, and also references the assembly in exactly the same way as you need to in web.config

Sunday, 31 August 2008

Hiding System Views in CRM 4.0

In CRM 3.0 it was relatively easy to hide one of the built-in system views - all you had to do was share the view with an empty team, which converted the view to a userquery entity. However, CRM 4.0 does not support this.


There is an alternative route, but it required plug-in coding. Rather than have to write code for each deployment, I created a standard plug-in that can be used to hide any views, based on some XML configuration. The source code and compiled code is available on the MSDN Code Gallery, along with a sample configuration file.

Friday, 29 August 2008

Plug-ins - differences between Target and Image Entity

In a plug-in there are potentially several ways to access entity data relevant to the plug-in action. For example, on the create message you can access the data on the new entity instance in one of the following ways:
  1. Via the Target InputParameter
  2. Via an Image Entity registered on the step
  3. Via a Retrieve request in the plug-in code

These do not always work in the same way, as follows:

Availability of the data by stage

The general rules are:

  1. InputParameter is available in all stages. It can be modified in the pre-stage, but changing it in the post-stage will have no effect
  2. A PostImage Entity is available in the post-stage, and a PreImage Entity in the pre-stage only
  3. If using a Retrieve in the plug-in, then the data returned depends on the stage. In the pre-stage, you will see the data before the modification, whereas in the post-stage you see the data after the modification
  4. Some Image Entities are not relevant for some messages - e.g. there is no PreImage for a Create message, and no PostImage for a Delete message

Data in the Name attribute

If the message is updating CRM (e.g. a Create or Update message) then the InputParameter only contains the minimum information that needs to be saved to CRM. A consequence of this is that the name attribute of any of the following data types is null:

  • Lookup
  • Owner
  • Customer
  • Picklist
  • Boolean

So, if your code needs to access the name, then you cannot rely on the InputParameter, and have to use either the Image Entity or a Retrieve to get the data.

My preference is to use an Image Entity, mostly as this reduces the code I have to write. The CRM SDK also suggests that this is more efficient, though I've not done any thorough performance testing on this to determine if this is relevant.

Thursday, 31 July 2008

"Invalid Domain Name" error when registering plug-ins

On a couple of occasions recently I've had an error "Invalid domain name. Domain name is either invalid or unreachable" when registering a plug-in with the RegisterSolutionRequest.

It looks to me like this is a spurious message, possibly caused by a timeout. My reasons for thinking this are:
- I get the message on a VPC image which is the CRM server, SQL server and domain controller. If the domain was really unreachable, that would mean AD or DNS were not working and I'd expect other problems.
- The message does not always occur. Registering exactly the same solution and steps normally works fine. It's not a persistent error.
- It only occurs for me when registering a large number of steps, which again is consistent with it being a timeout issue.

So, my general recommendation if getting this error is to try again, possibly registering fewer steps at a time. If I find out any moe on this, I'll post it here.

Update - 4 Aug 08
It seems an alternative reason for this error is if the RegisterSolutionRequest (or similar request) is submitted by code that is running as one of the built-in accounts - e.g. NetworkService. I could image how this occurs, as these accounts are identified as e.g. NT AUTHORITY\NetworkService, and the platform code may be looking for a domain called 'NT AUTHORITY'.

Only members of the Deployment Administrators role can register plug-ins, and it appears that CRM only allows user accounts to be added to this role (the dialog for adding users does give the option to add built-in security principals). Therefore it looks like it's not possible to register plug-ins via one of the built-in accounts - an example of this would be via code that itself is running in a plug-in

Friday, 20 June 2008

Plugin Parameters

Although the CRM 4.0 SDK is generally pretty comprehensive, I find it doesn't contain as much information as I'd like about the information passed to plugins for each of the messages.

The following table lists the main parameters passed to plugins on the most common messages. If the message you want isn't listed here, post a comment and I'll update the table.

MessageParameterDirectionTypeComments
AssignAssigneeInputSecurityPrincipal
AssignTargetInputMoniker
CancelSalesOrderOrderCloseInputDynamicEntity
Close*ActivityCloseInputDynamicEntity
CloseStatusInputInt32
CreateidOutputGuidOnly available on the Post Stage
CreateTargetInputDynamicEntity
DeleteTargetInputMoniker
ExecuteFetchXmlInputString
ExecuteFetchXmlResultOutputString
GrantAccessPrincipalAccessInputPrincipalAccess
GrantAccessTargetInputMoniker
HandleSourceQueueIdInputGuid
HandleTargetInputDynamicEntity
Lose*ActivityCloseInputDynamicEntity
LoseStatusInputInt32
RetrieveBusinessEntityOutputDynamicEntity
RetrieveColumnSetInputColumnSetBase
RetrieveTargetInputMoniker
RetrieveExchangeRateExchangeRateOutputDecimal
RetrieveExchangeRateTransactionCurrencyIdInputGuid
RetrieveMultipleBusinessEntityCollectionOutputBusinessEntityCollection
RetrieveMultipleQueryInputQueryExpression
RetrieveMultipleReturnDynamicEntitiesInputBoolean
RetrievePrincipalAccessAccessRightsOutputAccessRights
RetrievePrincipalAccessPrincipalInputSecurityPrincipal
RetrievePrincipalAccessTargetInputMoniker
RevokeAccessRevokeeInputPrincipalAccess
RevokeAccessTargetInputMoniker
RouteEndpointIdInputGuid
RouteRouteTypeInputRouteType
RouteSourceQueueIdInputGuid
RouteTargetInputMoniker
SendEmailIdInputGuid
SendIssueSendInputBoolean
SendSubjectOutputStringThis is the subject after the tracking token has been added
SendTrackingTokenInputString
SetStateDynamicEntityEntityMonikerInputMoniker
SetStateDynamicEntityStateInputString
SetStateDynamicEntityStatusInputInt32
UpdateTargetInputDynamicEntityTo get the Primary Key, find the KeyProperty within the DynamicEntity
Win*ActivityCloseInputDynamicEntity
WinQuoteCloseInputDynamicEntity
WinStatusInputInt32


Notes:
*ActivityClose. For the Win, Lose and Close messages, one of the parameters is an activity type whose name depends on the primary entity - e.g. the Win message could have a QuoteClose or OpportunityClose entity passed to it

To gather this information I used the plugin tools described on the MSCRM Team blog. The source code for these tools can be found here:
Bulk Registration Tool
Plugin Logger

Other Links:
Plugin Development
Plugin Messages

Tuesday, 3 June 2008

Differences between Workflow and Plugins in CRM 4.0

A common question I get is ‘what is the difference between workflow and plugins, and when should I use one or the other ?’. This article is intended to be a comprehensive answer to these 2 questions.

First of all, I want to clarify the distinction between what I consider 3 distinct categories of workflow – the terminology is my own:
  • Simple workflow. This is one or more workflow rules created within the MSCRM interface, and which do not include custom workflow activities.
  • Workflow with custom workflow activities. I’ll explain more about custom workflow activities later in this article; for now the key point is that a custom workflow activity is .Net code that is written to perform functions not possible in simple workflow, and this code can be called from a workflow rule
  • Workflows created with the Workflow Designer in Windows Workflow Foundation. It is possible to build workflows outside of the CRM user interface, but I’m not going to include them in this article.
Simple workflows
The main characteristics of simple workflows are:
  • * Creating a simple workflow involves no code
  • Workflows run only on the CRM server – workflow processing is not available within a client that is offline
  • Workflows run asynchronously – any data changes made within a workflow rule will not show up immediately within the CRM user interface
  • Workflows can be run manually or automatically. The automatic running of workflows is based on several data modification events
  • Workflow rules are entity specific
  • The state and stage of a workflow instance can be viewed within the CRM user interface by any CRM user with appropriate permissions

Some limitations of workflows are:

  • Workflow rules cannot be created for all entities
  • Although workflow rules can be triggered by the most common data modification events, there are some events that don’t trigger workflow rules
  • * Simple workflows offering limited capability to perform calculations

Characteristics and limitations marked with an asterix (*) do not apply if using custom workflow activities; the others do still apply.

Custom workflow activities
Custom workflow activities allow you to extend the capabilities of workflow rules. Three common uses are to perform calculations on CRM data, to access CRM functionality that is not available in the out-of-the-box workflow activities, and to access external data.

Custom workflow activities are written as .Net assemblies which have to be registered on the CRM server. These assemblies can include information about parameters that can be passed into or out of the activity.

Plugins
A plugin is .Net code that is registered on the CRM server. A plugin assembly can be registered for one or more steps – these steps correspond to the combination of the message (event), entity and stage. An example of a step would be the Create message for the account entity on the pre-event stage. Registration of the assembly and steps is part of the plugin deployment process, and there is no direct user interaction with plugins

The main characteristics of plugins are:

  • They have to be written as .Net code
  • Although they typically run on the CRM server, they can be deployed and configured to run on a CRM client that is offline
  • They can run either synchronously or asynchronously. If they run synchronously, any data changes made within the plugin will show up immediately within the CRM user interface
  • Synchronous plugins can run on either the pre-event or post-event stage. The pre-event stage happens before data is written to the CRM database, and a plugin registered on a pre-event step can cancel the data writing and provide an error message to the user.
  • More entities can have plugins registered for them than can have workflow rules
  • Plugins can run on more events than can workflow rules. An example is that plugins can run on data retrieval, not just modification events

The main limitations of plugins are:

  • Plugins cannot be run manually; they only run on the steps for which they are registered
  • There is no user interaction with plugins, other than error messages that might be throw by a synchronous plugin

Sample Scenarios
So, having covered the main characteristics and limitations of simple workflows, custom workflow activities and plugins, when should you choose one or another ? Here are some common scenarios:

What you want to achieve can be done with a simple workflow, and it is acceptable or desirable for this to happen asynchronously and on the server only
In this case I’d go with simple workflows; there’s no point writing code if you don’t have to.

What you want to achieve has to run synchronously
If so, workflow won’t do, so it would have to be a plugin. An alternative could be to use client script, but I don’t intend to complicate this article by including this in any more detail

You need to be able to cancel the data operation
A pre-event plugin is the only option covered here, though again client script should be considered

You want to give users the discretion to run the operation manually
Here you’ll need a workflow. Whether or not you need a custom workflow activity depends on the complexity of the operations. Again, there may be an option outside of the scope of this article – to write an ASP .Net application that is called from an ISV Config button

You need to write custom code, but you want users to decide whether this code should run, and under what circumstances
In this case I’d go with a custom workflow activity, as you could make this available for users to add to their own workflows

Further Information
There is more detail about how to write and deploy plugins and custom workflow assemblies within the CRM 4.0 SDK, though unfortunately there’s not a lot of information about when to choose one or the other.

The classroom training material ‘Extending Microsoft Dynamics CRM 4.0’, course number 8969, should have more information both about building plugins and custom workflow assemblies, and when to use them. This course will also cover other solution technologies such as client script and ASP .Net extensions.

One of the MS team, Humberto Lezama has also produced a useful matrix indicating the relative merits of workflow and plugins. This can be found here

Thursday, 22 May 2008

Posting on Microsoft Dynamics CRM Team Blog

I've been invited to post again on the Microsoft Dynamics CRM Team Blog. This time I've included information about plugin messages, and how a couple of tools can be used to record information about all plugin events on a CRM 4.0 deployment. The article is here: http://blogs.msdn.com/crm/archive/2008/05/21/plugins-which-message-and-which-pipeline.aspx

The two tools are both available on the MSDN Code Gallery:
http://code.msdn.microsoft.com/crm40pluginbulk
http://code.msdn.microsoft.com/crm40pluginlogger

Wednesday, 21 May 2008

Some Plugin Tools

I've posted 2 resources (.Net projects) to the MSDN Code Gallery to assist with writing and deploying plugins for CRM 4.0.

One tool is a logging tool This writes details about any plugin event to SQL tables. This records standard event data - date, message, primary entity, stage and pipeline - and also any data passed in property bags - InputParameter, OutputParameter, PreEntityImage, PostEntityImage and SharedVariable. I find this very useful when determining what information is passed for each message.

The other tool is a registration tool. This is a set of enhancements to the plugindeveloper that is included in the CRM 4.0.4 SDK. The main enhancement is to allow registration of a plugin against all messages or all entities. I use this in conjunction with the logging tool to allow me to quickly build an environment that captures all customisable plugin events on a CRM deployment. This tool makes use of the sdkmessagefilter class to determine which combinations of plugin event and message are available on a CRM deployment

Both resources on the Code Gallery contain the full source code, which is made available under the Microsoft Public License (Ms-PL), as well as installation instructions

More information about these tools, and an explanation of the code will shortly be posted on the Microsoft Dynamics CRM Team Blog. Rather than repeat the content here, I'll post a link when it's live.

Updated 21-05-08: The Team Blog link is http://blogs.msdn.com/crm/archive/2008/05/21/plugins-which-message-and-which-pipeline.aspx