How-to series: Generate auto-numbers on custom entities (part 2)

In the first post of the series (see Part 1), I was dealing with the creation of a new entity which can be used to store the autonumbering parameters such as: which entity must get a number, which attribute must store the number, the number length, the prefix & suffix, etc.

In this second post, we will see how to generate the autonumber by using a plugin.

I’ll use Visual Studio 2010 with C# to create this plugin and then show how it work in real life.

  1. First step, open VS 2010 Sourire
  2. Next, create a new ‘Visual C# Windows Class Library’ project (you can choose either the .NET Framework 3.0 or 3.5)image
  3. Add a reference to the two following Microsoft assemblies given with the Microsoft CRM SDK (these DLLs are located under the CrmSdk\bin folder; make sure you choose the right version: 32-bits or 64-bits)
    • Microsoft.CRM.Sdk.dll
    • Microsoft.CRM.SdkTypeProxy.dll
  4. Next step, sign your assembly before doing anything else
    • Right-click on your project and select ‘Properties’
    • Select the ‘Signing’ menu
    • In the drop-down list, choose to create a new strong name key file by selecting the “<New…>” optionimage
    • Type in a key file name and choose a strong password
    • Visual Studio will then create a ‘.pfx’ file which will be attached to the assembly
  5. Rename the created C# class to whatever you like and put the code listed above (the code is self-explanatory):

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; using Microsoft.Crm.Sdk; using Microsoft.Crm.SdkTypeProxy; using Microsoft.Crm.Sdk.Query; namespace xRM.AutoNumberPlugin { /// <summary> /// Class that generates a random number for the Test Entity /// </summary> public class TestEntityAutoNumber : IPlugin { public void Execute(IPluginExecutionContext context) { DynamicEntity entity = null; // Verify we have an entity to work with if (context.InputParameters.Properties.Contains("Target") && context.InputParameters.Properties["Target"] is DynamicEntity && context.MessageName.Equals("Create")) { // Obtain the target business entity from the input parameters. entity = (DynamicEntity)context.InputParameters.Properties["Target"]; if (!context.OutputParameters.Properties.Contains("id")) { return; } // Verify that the entity represents a test entity if (entity.Name != "new_testentity") { return; } } else { return; } try { // Verify that the ID is returned upon creation of the test entity string entityId = context.OutputParameters.Properties["id"].ToString(); Key entityKey = new Key(); entityKey.Value = new Guid(entityId); // Get a new instance of the CRM service from the context ICrmService service = (ICrmService)context.CreateCrmService(true); // Create the query on the auto number entity QueryByAttribute query = new QueryByAttribute(); query.ColumnSet = new AllColumns(); query.EntityName = "xrm_automaticnumber"; query.Attributes = new string[] { "xrm_entityname" }; // The entity name you're looking for, selected from the drop-down list (see the how-to part 1) query.Values = new string[] { "new_testentity" }; // Create the request based on the above query RetrieveMultipleRequest request = new RetrieveMultipleRequest(); // Set the request properties request.Query = query; request.ReturnDynamicEntities = true; // Execute the request and get the response RetrieveMultipleResponse response = (RetrieveMultipleResponse)service.Execute(request); string prefix = null; string suffix = null; int length = 1; // Parse the response to get the values you want // (there should be only one record for the same entity) foreach (BusinessEntity be in response.BusinessEntityCollection.BusinessEntities) { if (((DynamicEntity)be).Properties.Contains("xrm_prefix")) prefix = ((string)((DynamicEntity)be)["xrm_prefix"]).ToString(); if (((DynamicEntity)be).Properties.Contains("xrm_suffix")) suffix = ((string)((DynamicEntity)be)["xrm_suffix"]).ToString(); if (((DynamicEntity)be).Properties.Contains("xrm_length")) length = ((CrmNumber)((DynamicEntity)be)["xrm_length"]).Value; } // Generating a random number based on the cryptographic library char[] chars = new char[10]; string a; a = "1234567890"; chars = a.ToCharArray(); byte[] data = new byte[1]; RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider(); crypto.GetNonZeroBytes(data); data = new byte[length]; crypto.GetNonZeroBytes(data); StringBuilder result = new StringBuilder(length); foreach (byte b in data) { result.Append(chars[b % (chars.Length - 1)]); } // Update the new entity's number attribute with the retrieved prefix & suffix and add the random number PropertyCollection properties = new PropertyCollection(); properties.Add(CrmTypes.CreateStringProperty("new_testentitynumber", prefix + "-" + result.ToString() + "-" + suffix)); properties.Add(CrmTypes.CreateKeyProperty("new_testentityid", entityKey)); entity.Properties = properties; // Creating a target update message to alter the newly created entity TargetUpdateDynamic updateEntity = new TargetUpdateDynamic(); updateEntity.Entity = entity; // Creating a request on the server UpdateRequest updateRequest = new UpdateRequest(); updateRequest.Target = updateEntity; // Updating the entity by using the created ICrmService UpdateResponse updated = (UpdateResponse)service.Execute(updateRequest); } catch (System.Web.Services.Protocols.SoapException ex) { throw new InvalidPluginExecutionException("An error occurred in the TestEntityAutoNumber plug-in.", ex); } } } }

  6. Compile your code and copy your assembly over to your server (I prefer this method)
  7. Launch the “Plugin Registration Tool” on the CRM server and connect to the desired organizationimage
    • Once connected to the correct organization, the right screen will display the list of already deployed plug-ins Untitled
    • Click on ‘Register’ and select the ‘Register New Assembly’ option from the toolbar, or use CTRL – A image
    • On the ‘Register New Plugin’ screen, select your assembly and select the class you want to register; I always choose to store my plug-ins in the database but this depends on your needs. Hit the “Register Selected Plugins” once you’re doneUntitled
    • If everything is OK, you should see this kind of message:image
    • The next step is the registration of a new ‘Step’ which is the event the plug-in will be attached to; to register a new step for the new plug-in, select your plug-in in the right screen and click on the ‘Register New Step’ in the toolbar (or hit CTRL – T)image
    • Now this is the fun part: you have to tell the server to which event the plug-in will be attached to (Create, Update, Delete, etc.). You also need to specify on which entity the plug-in will be run and the stage of execution (pre or post): these parameters are mandatory! (You can find more information on the execution pipeline here and on plug-in development & deployment here) Untitled
    • Hit ‘Register New Step’ to create the event handler
    • Last step is to create a pre or post XML image depending on your needs: in my case, I always create a post image if I’m dealing with a ‘Create’ messages (obviously, there is nothing in the database at that time so a pre image is irrelevant) and I always create pre & post images on ‘Update’ messages to get the data before and after update (think audit plug-in for example). To create a new image, select the step you just created in the right screen and select the ‘Register New Image’ from the toolbar or hit CTRL – Iimage[14]
    • In this last screen, you have to select the image type (pre or post) and give it a name: the name is really important if you want to use a code like the one below, which creates a new dynamic entity object from the post image:

      // Post image for the current entity

      DynamicEntity postImage = new DynamicEntity(); postImage = (DynamicEntity)context.PostEntityImages.Properties["postEntityImageXml"];

      Untitled

    • Hit the ‘Register Image’ button to create the new image
  8. Everything is all set! Your plug-in is now deployed and ready to run Sourire And here is the example based on the code above (see step 5 on this blog post):image

Links:

10 thoughts on “How-to series: Generate auto-numbers on custom entities (part 2)

    1. Hello,
      Well, I don’t think there is anything more to say… except, use the code as you like! I’m going to deal mostly with CRM 2011 but you can always ask me what you would like to see on my blog :-)

  1. Hi,

    thank you for that realy great walktrough! I am getting so far, that the plugin is retrieving all needed values form the custom autonumber entity. So my number is generated without any problems… Unfortunatly the system throws the good old CRM standard failure when I try to save the record: An failure acured …

    In the Eventlog of the server it generates the following errormessage:

    Web Service Plug-in failed in OrganizationId: 83597463-ae46-4924-b8b6-3286984773e6; SdkMessageProcessingStepId: d9c66093-8246-e011-9a62-0050568a1016; EntityName: campaignactivity; Stage: 50; MessageName: Create; AssemblyName: xRM.AutoNumberPlugin.TestEntityAutoNumber, Autonumber, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1dd1abacaed6ff77; ClassName: xRM.AutoNumberPlugin.TestEntityAutoNumber; Exception: Unhandled Exception: System.Web.Services.Protocols.SoapException: Server was unable to process request.
    Detail:
    0x80040216
    An unexpected error occurred.
    Platform

    at Microsoft.Crm.Extensibility.SdkTypeProxyCrmServiceWrapper.InternalInvoke(MethodInfo methodInfo, Object[] parameters)
    at xRM.AutoNumberPlugin.TestEntityAutoNumber.Execute(IPluginExecutionContext context)
    at Microsoft.Crm.Extensibility.PluginStep.Execute(PipelineExecutionContext context)
    .

    One more question:

    Key entityKey = new Key();
    entityKey.Value = new Guid(entityId);

    properties.Add(CrmTypes.CreateKeyProperty(“new_testentityid”, entityKey));

    Why is this needed? dont I have key allready? (I try to make it work for the campaignactivity

    Greetings and thanks in advance!

    Florian

    1. Hello Florian,
      I suppose that you have use the special method (or message) called ‘AddItemCampaignActivity’?
      You can find more info here: http://msdn.microsoft.com/en-us/library/bb959365.aspx
      If you can’t find what’s wrong, you can always send me the code and I’ll check it out.

      For your second question, you need in fact to create a new ID since the underlying database does not do it for you automatically, hence the 2 following lines:
      Key entityKey = new Key();
      entityKey.Value = new Guid(entityId);

      Also, the correct code for the campaign activity ID is:
      properties.Add(CrmTypes.CreateKeyProperty(“activityid”, entityKey));

      Hth,
      Oliver

  2. can you explain the c# code please? im new to crm and plugins, and i dont know c# too well either. thnx.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>