CRM2011 Plugin InputParameter and OutputParameter Helper

Download: CRM 2011 Plugin Parameter Wrapper Generator (1.0.1.412)

Every time I am asked to write a plugin using one of the less common plugin messages, I silently wish that I didn’t have to trawl through the SDK and then access the InputParameters and OutputParameters collection through a DataCollection<string, object> collection. I usually end up deploying the plugin several times due to casting parameters to the wrong type or accessing parameters that just don’t exist. I know that there are several sources I could use to avoid this but lets face it – intelli-sense made us lazy.

So, the other day I’d had enough and created a tool that generates a helper file for plugin entity messages that gives me strongly typed access to all parameters in each plugin’s InputParameters and OutputParameters collection in C# or VB.Net.

The generated helper file includes a namespace for each plugin message and a class for each of the InputParameters and OutputParameters collection. Every parameter in the collection has a Contains<ParameterName> and a Get<ParameterName> method that both expect the Microsoft.Xrm.Sdk.IPluginExecutionContext passed to them. The Contains<ParameterName> method returns a boolean value indicating whether the parameter exists and the Get<ParameterName> method gets the strongly typed value of the parameter.

AccountPreCreate.cs (below) shows the use of the Xrm.Core.Helpers.Plugins.Create helper class. Because there is a namespace per message type, I can include the relevant namespace in the using statements in my plugin class and then simply call the Contains and Get methods on the InputParameters and OutputParameters classes.

namespace Client.Plugins
{
    using System;
    using Microsoft.Xrm.Sdk;
    using Xrm.Core.Helpers.Plugins.Create;

    /// <summary>
    /// AccountPreCreate Plugin.
    /// </summary>
    public class AccountPreCreate : Plugin
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="AccountPreCreate"/> class.
        /// </summary>
        public AccountPreCreate() : base(typeof(AccountPreCreate))
        {
            this.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(20, "Create", "account", new Action<LocalPluginContext>(this.ExecuteAccountPreCreate)));
        }

        /// <summary>
        /// Executes the plug-in.
        /// </summary>
        /// <param name="localContext">The <see cref="LocalPluginContext"/></param>
        protected void ExecuteAccountPreCreate(LocalPluginContext localContext)
        {
            IPluginExecutionContext context = localContext.PluginExecutionContext;
            if (InputParameters.ContainsTarget(context))
            {
                Entity target = InputParameters.GetTarget(context);
                //Do something with the target
            }
        }
    }
}

In order to generate the helper classes, I needed to get the list of plugin parameters for all messages. The SDK was not very helpful there and while I was able to find a complete list for CRM4 here, no such thing seems to exist for CRM2011. Eventually, I decided to generate my own list using the following SQL statements in the CRM database and used them in the generator to generate the helper classes.

SELECT DISTINCT REPLACE(mreq.Name, '{Entity.PrimaryEntityName}', ''), mrf.Name, mrf.ClrParser, ISNULL(mreq.PrimaryObjectTypeCode, 0)
FROM SdkMessageRequestField mrf
INNER JOIN SdkMessageRequest mreq ON mrf.SdkMessageRequestId = mreq.SdkMessageRequestId
WHERE NOT mrf.ClrParser LIKE '%Microsoft.Crm.Sdk%'
AND NOT mrf.ClrParser LIKE '%Microsoft.Crm.Sdk.Reserved%'
ORDER BY 1, 2, 4 DESC
SELECT DISTINCT REPLACE(mreq.Name, '{Entity.PrimaryEntityName}', ''), mrf.Value, mrf.ClrFormatter, ISNULL(mreq.PrimaryObjectTypeCode, 0)
FROM SdkMessageResponseField mrf
INNER JOIN SdkMessageResponse mres ON mrf.SdkMessageResponseId = mres.SdkMessageResponseId
INNER JOIN SdkMessageRequest mreq ON mres.SdkMessageRequestId = mreq.SdkMessageRequestId
WHERE NOT mrf.ClrFormatter LIKE '%Microsoft.Crm.Sdk%'
AND NOT mrf.ClrFormatter LIKE '%Microsoft.Crm.Sdk.Reserved%'
ORDER BY 1, 2, 4 DESC

Where the statements above select more than one instance of a message (one with a primary object type code and the other without), the tools assume that the one with the primary object type code is the correct one.

I have obviously not tested every single plugin message input/output parameter so please let me know if there is a message/parameter missing, an extra message/parameter or a parameter with the incorrect data type etc.

Advertisements

4 thoughts on “CRM2011 Plugin InputParameter and OutputParameter Helper

  1. More Accurate SQL to get the names:

    DECLARE @CoreMessage TABLE
    (
    SdkMessageIdName NVARCHAR(1000),
    SdkMessageId uniqueidentifier
    );

    INSERT INTO @CoreMessage
    SELECT DISTINCT
    SdkMessageIdName,
    SdkMessageId
    FROM sdkmessagefilter filter WITH(NOLOCK)
    WHERE iscustomprocessingstepallowed = 1
    AND isVisible = 1

    SELECT DISTINCT
    X.MessageName,
    X.ParamterDirection,
    X.ParameterName,
    X.TypeAndDll,
    ISNULL(E.Name,”) as PrimaryEntityName
    FROM (
    SELECT
    X.MessageName,
    ParamterDirection,
    ParameterName,
    TypeAndDll,
    MIN(TypeCode) as TypeCode
    FROM (
    SELECT DISTINCT
    filter.SdkMessageIdName as MessageName,
    ‘Input Parameter’ as ParamterDirection,
    mrf.Name as ParameterName,
    CASE
    WHEN mrf.Name = ‘Query’ THEN ‘Microsoft.Xrm.Sdk.Query.QueryBase,Microsoft.Xrm.Sdk’
    WHEN mrf.Name = ‘EntityMoniker’ THEN ‘Microsoft.Xrm.Sdk.EntityReference,Microsoft.Xrm.Sdk’
    WHEN mrf.Name = ‘state’ THEN ‘System.Int32’
    ELSE mrf.ClrParser
    END as TypeAndDll,
    ISNULL(mreq.PrimaryObjectTypeCode, 0) as TypeCode
    FROM @CoreMessage filter
    INNER JOIN [SdkMessagePairBase] pair WITH(NOLOCK) ON pair.SdkMessageId = filter.SdkMessageId
    INNER JOIN SdkMessageRequest mreq WITH(NOLOCK) ON pair.SdkMessagePairId = mreq.SdkMessagePairId
    LEFT OUTER JOIN SdkMessageRequestField mrf WITH(NOLOCK) ON mrf.SdkMessageRequestId = mreq.SdkMessageRequestId
    WHERE
    (
    (NOT mrf.ClrParser LIKE ‘%Microsoft.Crm.Sdk%’)
    AND
    (NOT mrf.ClrParser LIKE ‘%Microsoft.Crm.Sdk.Reserved%’)
    )
    OR ( mrf.ClrParser IS NULL
    AND mrf.Name NOT IN (‘Activity’, ‘Attachments’, ‘EntityId’, ‘EntityName’, ‘ExtraProperties’,
    ‘IncidentResolution’, ‘OpportunityClose’, ‘OrderClose’, ‘QuoteClose’, ‘Target’, ‘UpdateContent’))
    ) AS X
    GROUP BY
    X.MessageName,
    ParamterDirection,
    ParameterName,
    TypeAndDll
    UNION ALL
    SELECT
    X.MessageName,
    ParamterDirection,
    ParameterName,
    TypeAndDll,
    MIN(TypeCode) as TypeCode
    FROM (
    SELECT DISTINCT
    filter.SdkMessageIdName as MessageName,
    ‘Output Parameter’ as ParamterDirection,
    mrf.Name as ParameterName,
    CASE
    WHEN mrf.Name = ‘BusinessEntityCollection’ THEN ‘Microsoft.Xrm.Sdk.EntityCollection,Microsoft.Xrm.Sdk’
    WHEN mrf.Name = ‘BusinessEntity’ THEN ‘Microsoft.Xrm.Sdk.Entity,Microsoft.Xrm.Sdk’
    ELSE mrf.ClrFormatter
    END as TypeAndDll,
    ISNULL(mreq.PrimaryObjectTypeCode, 0) as TypeCode
    FROM @CoreMessage filter
    INNER JOIN [SdkMessagePairBase] pair WITH(NOLOCK) ON pair.SdkMessageId = filter.SdkMessageId
    INNER JOIN SdkMessageRequest mreq WITH(NOLOCK) ON pair.SdkMessagePairId = mreq.SdkMessagePairId
    INNER JOIN SdkMessageResponse mres WITH(NOLOCK) ON mres.SdkMessageRequestId = mreq.SdkMessageRequestId
    INNER JOIN SdkMessageResponseField mrf WITH(NOLOCK) ON mrf.SdkMessageResponseId = mres.SdkMessageResponseId
    WHERE
    (
    (NOT mrf.ClrFormatter LIKE ‘%Microsoft.Crm.Sdk%’)
    AND
    (NOT mrf.ClrFormatter LIKE ‘%Microsoft.Crm.Sdk.Reserved%’)
    )
    OR mrf.ClrFormatter IS NULL
    ) AS X
    WHERE X.ParameterName NOT IN (‘Entity’, ‘EntityCollection’)
    GROUP BY
    X.MessageName,
    ParamterDirection,
    ParameterName,
    TypeAndDll
    UNION ALL
    SELECT ‘PublishAll’,’none’, ”, ”, 0
    ) AS X
    LEFT OUTER JOIN [MetadataSchema].[Entity] E WITH(NOLOCK) ON E.[ObjectTypeCode] = X.TypeCode
    ORDER BY 1,2,3

  2. Small correction:

    (Please note this only pulls in messages you can actually write plugins against)
    DECLARE @CoreMessage TABLE
    (
    SdkMessageIdName NVARCHAR(1000),
    SdkMessageId uniqueidentifier
    );

    INSERT INTO @CoreMessage
    SELECT DISTINCT
    SdkMessageIdName,
    SdkMessageId
    FROM sdkmessagefilter filter WITH(NOLOCK)
    WHERE iscustomprocessingstepallowed = 1
    AND isVisible = 1

    SELECT DISTINCT
    X.MessageName,
    X.ParamterDirection,
    X.ParameterName,
    X.TypeAndDll,
    ISNULL(E.Name,”) as PrimaryEntityName
    FROM (
    SELECT
    X.MessageName,
    ParamterDirection,
    ParameterName,
    TypeAndDll,
    MIN(TypeCode) as TypeCode
    FROM (
    SELECT DISTINCT
    filter.SdkMessageIdName as MessageName,
    ‘Input Parameter’ as ParamterDirection,
    mrf.Name as ParameterName,
    CASE
    WHEN mrf.Name = ‘Query’ AND mrf.ClrParser IS NULL THEN ‘Microsoft.Xrm.Sdk.Query.QueryBase,Microsoft.Xrm.Sdk’
    WHEN mrf.Name = ‘EntityMoniker’ AND mrf.ClrParser IS NULL THEN ‘Microsoft.Xrm.Sdk.EntityReference,Microsoft.Xrm.Sdk’
    WHEN mrf.Name = ‘state’ AND mrf.ClrParser IS NULL THEN ‘System.Int32’
    ELSE mrf.ClrParser
    END as TypeAndDll,
    ISNULL(mreq.PrimaryObjectTypeCode, 0) as TypeCode
    FROM @CoreMessage filter
    INNER JOIN [SdkMessagePairBase] pair WITH(NOLOCK) ON pair.SdkMessageId = filter.SdkMessageId
    INNER JOIN SdkMessageRequest mreq WITH(NOLOCK) ON pair.SdkMessagePairId = mreq.SdkMessagePairId
    LEFT OUTER JOIN SdkMessageRequestField mrf WITH(NOLOCK) ON mrf.SdkMessageRequestId = mreq.SdkMessageRequestId
    WHERE
    (
    (NOT mrf.ClrParser LIKE ‘%Microsoft.Crm.Sdk%’)
    AND
    (NOT mrf.ClrParser LIKE ‘%Microsoft.Crm.Sdk.Reserved%’)
    )
    OR ( mrf.ClrParser IS NULL
    AND mrf.Name NOT IN (‘Activity’, ‘Attachments’, ‘EntityId’, ‘EntityName’, ‘ExtraProperties’,
    ‘IncidentResolution’, ‘OpportunityClose’, ‘OrderClose’, ‘QuoteClose’, ‘Target’, ‘UpdateContent’))
    ) AS X
    GROUP BY
    X.MessageName,
    ParamterDirection,
    ParameterName,
    TypeAndDll
    UNION ALL
    SELECT
    X.MessageName,
    ParamterDirection,
    ParameterName,
    TypeAndDll,
    MIN(TypeCode) as TypeCode
    FROM (
    SELECT DISTINCT
    filter.SdkMessageIdName as MessageName,
    ‘Output Parameter’ as ParamterDirection,
    mrf.Name as ParameterName,
    CASE
    WHEN mrf.Name = ‘BusinessEntityCollection’ THEN ‘Microsoft.Xrm.Sdk.EntityCollection,Microsoft.Xrm.Sdk’
    WHEN mrf.Name = ‘BusinessEntity’ THEN ‘Microsoft.Xrm.Sdk.Entity,Microsoft.Xrm.Sdk’
    ELSE mrf.ClrFormatter
    END as TypeAndDll,
    ISNULL(mreq.PrimaryObjectTypeCode, 0) as TypeCode
    FROM @CoreMessage filter
    INNER JOIN [SdkMessagePairBase] pair WITH(NOLOCK) ON pair.SdkMessageId = filter.SdkMessageId
    INNER JOIN SdkMessageRequest mreq WITH(NOLOCK) ON pair.SdkMessagePairId = mreq.SdkMessagePairId
    INNER JOIN SdkMessageResponse mres WITH(NOLOCK) ON mres.SdkMessageRequestId = mreq.SdkMessageRequestId
    INNER JOIN SdkMessageResponseField mrf WITH(NOLOCK) ON mrf.SdkMessageResponseId = mres.SdkMessageResponseId
    WHERE
    (
    (NOT mrf.ClrFormatter LIKE ‘%Microsoft.Crm.Sdk%’)
    AND
    (NOT mrf.ClrFormatter LIKE ‘%Microsoft.Crm.Sdk.Reserved%’)
    )
    OR mrf.ClrFormatter IS NULL
    ) AS X
    WHERE X.ParameterName NOT IN (‘Entity’, ‘EntityCollection’)
    GROUP BY
    X.MessageName,
    ParamterDirection,
    ParameterName,
    TypeAndDll
    UNION ALL
    SELECT ‘PublishAll’,’none’, ”, ”, 0
    ) AS X
    LEFT OUTER JOIN [MetadataSchema].[Entity] E WITH(NOLOCK) ON E.[ObjectTypeCode] = X.TypeCode
    ORDER BY 1,2,3

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s