Write a Custom Azure-Aware Plug-In

[Applies to: Microsoft Dynamics CRM 2011]

Writing a plug-in that works with Windows Azure is similar to writing any other Microsoft Dynamics CRM plug-in. However, in addition to invoking any desired web service methods, the plug-in must include code to initiate posting the execution context to the Windows Azure Service Bus.

noteNote
Support for synchronous registered plug-ins that can post the execution context to the Windows Azure Service Bus is new for Microsoft Dynamics CRM 2011 Update Rollup 12 and Microsoft Dynamics CRM December 2012 Service Update.

In this Section

Plug-in Design Considerations

For a plug-in that executes synchronously, the recommended design is for the plug-in to send a message to Windows Azure for the purpose of retrieving information from a listener application or other external service. Use of a two-way or REST contract on the Windows Azure Service Bus endpoint allows a data string to be returned to the plug-in.

It is not recommended that a synchronous plug-in use the Windows Azure Service Bus to update data with an external service. Problems can arise if the external service becomes unavailable or if there is a lot of data to update. Synchronous plug-ins should execute fast and not hold up all logged in users of an organization while a lengthy operation is performed. In addition, if a rollback of the current core operation that invoked the plug-in occurs, any data changes made by the plug-in are undone. This could leave Microsoft Dynamics CRM and an external service in an unsynchronized state.

Writing the Plug-in Code

In the following sample plug-in, code has been added to obtain the Windows Azure service provider and initiate posting the execution context to the service bus by calling Execute. Tracing code has been added to facilitate debugging of the plug-in because the plug-in must run in the sandbox.


using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.Serialization;

using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;

using Microsoft.Xrm.Sdk;

namespace Microsoft.Crm.Sdk.Samples
{
	/// <summary>
	/// A custom plug-in that can post the execution context of the current message to the Windows
    /// Azure Service Bus. The plug-in also demonstrates tracing which assist with
    /// debugging for plug-ins that are registered in the sandbox.
	/// </summary>
    /// <remarks>This sample requires that a service endpoint be created first, and its ID passed
    /// to the plug-in constructor through the unsecure configuration parameter when the plug-in
    /// step is registered.</remarks>
	public sealed class SandboxPlugin : IPlugin
	{
		private Guid serviceEndpointId; 

		/// <summary>
		/// Constructor.
		/// </summary>
		public SandboxPlugin(string config)
		{
			if (String.IsNullOrEmpty(config) || !Guid.TryParse(config, out serviceEndpointId))
			{
				throw new InvalidPluginExecutionException("Service endpoint ID should be passed as config.");
			}
		}

		public void Execute(IServiceProvider serviceProvider)
		{
			// Retrieve the execution context.
			IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

			// Extract the tracing service.
			ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
			if (tracingService == null)
				throw new InvalidPluginExecutionException("Failed to retrieve the tracing service.");

			IServiceEndpointNotificationService cloudService = (IServiceEndpointNotificationService)serviceProvider.GetService(typeof(IServiceEndpointNotificationService));
			if (cloudService == null)
				throw new InvalidPluginExecutionException("Failed to retrieve the service bus service.");

			try
			{
				tracingService.Trace("Posting the execution context.");
				string response = cloudService.Execute(new EntityReference("serviceendpoint", serviceEndpointId), context);
				if (!String.IsNullOrEmpty(response))
				{
					tracingService.Trace("Response = {0}", response);
				}
				tracingService.Trace("Done.");
			}
			catch (Exception e)
			{
				tracingService.Trace("Exception: {0}", e.ToString());
				throw;
			}
		}
	}
}

In your plug-in code, you can update the writeable data in the context before initiating the post. For example, you can add a key/value pair to the shared variables in the context.

Plug-in Registration

There are a few restrictions when you register a Windows Azure aware custom plug-in. The plug-in must be registered to execute in the sandbox. Because of this, the plug-in is limited to calling Microsoft Dynamics CRM SDK methods, Windows Azure solution methods, or accessing a network using a web client. No other external access, such as access to a local file system, is allowed.

For a plug-in registered to execute in asynchronous mode, this also means that the order of plug-in execution compared to other asynchronous plug-ins is not guaranteed. In addition, asynchronous plug-ins always execute after the Microsoft Dynamics CRM core operation.

Dealing with a Failed Service Bus Post

The expected behavior from a failed service bus post is dependent on whether the plug-in was registered for synchronous or asynchronous execution. For asynchronous plug-ins, the system job that actually posts the execution context to the service bus will retry the post. For a synchronous registered plug-in, an exception is returned. For more information, see Management and Notification of Run-time Errors.

ImportantImportant
For asynchronous registered plug-ins only, when the asynchronous job that posts to the Windows Azure Service Bus is retried after a post failure, the entire plug-in logic is executed again. Because of this, do not add any other logic to the custom Windows Azure aware plug-in other than just modifying the context and posting to the service bus.

For a plug-in registered to execute asynchronously, the RemoteExecutionContext contained in the body of the message that is sent over the service bus includes a OperationId property and a OperationCreatedOn property. These properties contain the same data as the AsyncOperationId and CreatedOn attributes of the related System Job (AsyncOperation) record. These additional properties facilitate sequencing and duplicate detection if the Windows Azure Service Bus post must be retried.

See Also

Microsoft Dynamics CRM 2011
Send comments about this topic to Microsoft.
© 2013 Microsoft Corporation. All rights reserved.

Community Additions

ADD
Show: