none
CRM 2011: Case plugin to update allotment used value

    Vraag

  • Hi all,

    Trying to develop a plugin to decrement allotment used value on contract line when deleting a related case.

    So I have created the below plugin using crm devlopment toolkit to get the contractline id using pre image then updating the contract line record, as shown below:

    // <copyright file="PostCaseDelete.cs" company="">
    // Copyright (c) 2011 All Rights Reserved
    // </copyright>
    // <author></author>
    // <date>12/25/2011 11:51:31 AM</date>
    // <summary>Implements the PostCaseDelete Plugin.</summary>
    // <auto-generated>
    //     This code was generated by a tool.
    //     Runtime Version:4.0.30319.1
    // </auto-generated>
    namespace UpdateAllotmentUsedField.PostCaseDelete
    {
        using System;
        using System.ServiceModel;
        using Microsoft.Xrm.Sdk;
    
        /// <summary>
        /// PostCaseDelete Plugin.
        /// </summary>    
        public class PostCaseDelete: Plugin
        {
            /// <summary>
            /// Alias of the image registered for the snapshot of the 
            /// primary entity's attributes before the core platform operation executes.
            /// The image contains the following attributes:
            /// No Attributes
            /// </summary>
            private readonly string preImageAlias = "PreCaseImage";
    
            /// <summary>
            /// Initializes a new instance of the <see cref="PostCaseDelete"/> class.
            /// </summary>
            public PostCaseDelete()
                : base(typeof(PostCaseDelete))
            {
                base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(40, "Delete", "incident", new Action<LocalPluginContext>(ExecutePostCaseDelete)));
    
                // Note : you can register for more events here if this plugin is not specific to an individual entity and message combination.
                // You may also need to update your RegisterFile.crmregister plug-in registration file to reflect any change.
            }
    
            /// <summary>
            /// Executes the plug-in.
            /// </summary>
            /// <param name="localContext">The <see cref="LocalPluginContext"/> which contains the
            /// <see cref="IPluginExecutionContext"/>,
            /// <see cref="IOrganizationService"/>
            /// and <see cref="ITracingService"/>
            /// </param>
            /// <remarks>
            /// For improved performance, Microsoft Dynamics CRM caches plug-in instances.
            /// The plug-in's Execute method should be written to be stateless as the constructor
            /// is not called for every invocation of the plug-in. Also, multiple system threads
            /// could execute the plug-in at the same time. All per invocation state information
            /// is stored in the context. This means that you should not use global variables in plug-ins.
            /// </remarks>
            protected void ExecutePostCaseDelete( LocalPluginContext localContext )
            {
                if ( localContext == null )
                {
                    throw new ArgumentNullException("localContext");
                }
    
                IPluginExecutionContext context = localContext.PluginExecutionContext;
    
                Entity preImageEntity = (context.PreEntityImages != null && context.PreEntityImages.Contains(this.preImageAlias)) ? context.PreEntityImages[this.preImageAlias] : null;
    
                EntityReference contractDetailId = (EntityReference)preImageEntity.Attributes [ "contractdetailid" ];
                string contractLineId = contractDetailId.Id.ToString( );
    
                //throw new InvalidPluginExecutionException(contractLineId);
    
                //start update opportunity product exist///////////////////////////////////////////////////////////////////////////////////
                Entity ContractDetail = new Entity("contractline");
    
                ////Create a KeyProperty to hold the guid of the record to be updated
                Guid ContractDetailId = new Guid(contractLineId);
                /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                int x = int.Parse(ContractDetail [ "allotmentused" ].ToString( ));
                ContractDetail [ "allotmentused" ] = x - 1;
                //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            }
        }
    }
    
    

    But I need help to execute the update message

    Best regards...

    zondag 25 december 2011 11:19

Antwoorden

  • Hii mostafa,

    i got the service

    localContext.OrganizationService.Update(entity)
    

    try this andlet me know.


    By Sanz If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    • Als antwoord voorgesteld door san Sanz maandag 26 december 2011 16:47
    • Als antwoord gemarkeerd door Mostafa Moatassem dinsdag 27 december 2011 10:19
    maandag 26 december 2011 16:47
  • yes there are 2 ways to handle Plugins, one is with the old way implementing the IPlugin interface and the other one is by usinfg the CRM Dev toolkit but they are similar. To use the dev toolkit you need to have a reference of the service as follows

     

     

                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)localContext.ServiceProvider.GetService(typeof(IOrganizationServiceFactory));
    
                IOrganizationService service = serviceFactory.CreateOrganizationService(localContext.PluginExecutionContext.UserId);
    
                /// put your code.
    
    
                service.Update(ContractDetail);
    


    Regards,
    Damian Sinay
    maandag 26 december 2011 16:49

Alle reacties

  • any suggestions ??
    zondag 25 december 2011 15:50
  • The context object you use from IPluginExecutionContext has the update method so you need to use

    context.Update(ContractDetail);

    That right after your line

    ContractDetail [ "allotmentused" ] = x - 1;

     


    Regards,
    Damian Sinay
    zondag 25 december 2011 21:50
  • not working, it gives me error:

    Error 1 'Microsoft.Xrm.Sdk.IPluginExecutionContext' does not contain a definition for 'Update' and no extension method 'Update' accepting a first argument of type 'Microsoft.Xrm.Sdk.IPluginExecutionContext' could be found (are you missing a using directive or an assembly reference?)

     

    Please advise..

    maandag 26 december 2011 10:32
  • Hii first you need to do

     

    create service from IPluginContext

     

       IPluginExecutionContext context = (IPluginExecutionContext)
                        serviceProvider.GetService(typeof(IPluginExecutionContext));
    
                    // Obtain the organization service reference.
                    IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
    
    
    

    service has update method .


    By Sanz If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    • Als antwoord voorgesteld door san Sanz maandag 26 december 2011 11:08
    • Voorstel als antwoord ongedaan gemaakt door Mostafa Moatassem maandag 26 december 2011 12:04
    maandag 26 december 2011 11:08
  • Hi,

    You can update the entity by using the IOrganizationService . Create a object for IOrganizationService and pass the context object as a parameter and then you can use the service object to update the 'ContractDetail ' as shown below.

    service.Update(ContractDetail);

    Please see the SDK or follow the below link

    Thanks,

    Deepak K

     


    Deepak Kumar
    maandag 26 december 2011 11:47
  • Dears,

    If you can take a minute looking on the source code above, you will see that there is no IServiceProvider object passed to the Execute so how can I create the IOrganizationService object ??

    maandag 26 december 2011 12:00
  • hey hi,

    You need to inherit IPLugin for crm 2011,it has ServiceProvider


    By Sanz If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    maandag 26 december 2011 12:41
  • Yes, you need to inherit IPLugin and you get the service context as follows
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
    
    

    serviceProvider is the parameter passed on the Execute method

    Regards,
    Damian Sinay
    maandag 26 december 2011 16:19
  • and how would I inherit IPlugin if I'm already inherited Plugin ??

     

    Best regards..

    maandag 26 december 2011 16:22
  • replace Plugin by IPLugin and implement the Execute method.
    Regards,
    Damian Sinay
    maandag 26 december 2011 16:25
  • Dear disnay,

    It looks like we are trying to override the autocreated code of the crm dev toolkit, is there any way to update it instead to re writing the whole plugin code ???

     

    Best regards..

    maandag 26 december 2011 16:33
  • Hii mostafa,

    i got the service

    localContext.OrganizationService.Update(entity)
    

    try this andlet me know.


    By Sanz If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    • Als antwoord voorgesteld door san Sanz maandag 26 december 2011 16:47
    • Als antwoord gemarkeerd door Mostafa Moatassem dinsdag 27 december 2011 10:19
    maandag 26 december 2011 16:47
  • yes there are 2 ways to handle Plugins, one is with the old way implementing the IPlugin interface and the other one is by usinfg the CRM Dev toolkit but they are similar. To use the dev toolkit you need to have a reference of the service as follows

     

     

                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)localContext.ServiceProvider.GetService(typeof(IOrganizationServiceFactory));
    
                IOrganizationService service = serviceFactory.CreateOrganizationService(localContext.PluginExecutionContext.UserId);
    
                /// put your code.
    
    
                service.Update(ContractDetail);
    


    Regards,
    Damian Sinay
    maandag 26 december 2011 16:49
  • Guys, thanks alot for your support, I tried it and it works :)

     

    But when trying to test the plugin it gives me error: "An error has ocurred........"

    Below is the error log file:

     

    Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: System.Web.HttpUnhandledException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #FAAED955Detail: 

    <OrganizationServiceFault xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">

      <ErrorCode>-2147220970</ErrorCode>

      <ErrorDetails xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />

      <Message>System.Web.HttpUnhandledException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #FAAED955</Message>

      <Timestamp>2011-12-27T10:22:17.0147222Z</Timestamp>

      <InnerFault>

        <ErrorCode>-2147220956</ErrorCode>

        <ErrorDetails xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />

        <Message>Unexpected exception from plug-in (Execute): UpdaeAllotmentUsedField.PostCaseDelete.PostCaseDelete: System.NullReferenceException: Object reference not set to an instance of an object.</Message>

        <Timestamp>2011-12-27T10:22:17.0147222Z</Timestamp>

        <InnerFault i:nil="true" />

        <TraceText>

     

    [UpdaeAllotmentUsedField.PostCaseDelete: UpdaeAllotmentUsedField.PostCaseDelete.PostCaseDelete]

    [da14f44f-7130-e111-865e-000c2932b3b7: PostCaseDelete]

     

    Entered UpdaeAllotmentUsedField.PostCaseDelete.PostCaseDelete.Execute(), Correlation Id: d5fdc7c2-e971-4426-9a94-b35ce039ba14, Initiating User: 79dc5e8c-2a60-e011-98e4-000c29786082

    UpdaeAllotmentUsedField.PostCaseDelete.PostCaseDelete is firing for Entity: incident, Message: Delete, Correlation Id: d5fdc7c2-e971-4426-9a94-b35ce039ba14, Initiating User: 79dc5e8c-2a60-e011-98e4-000c29786082

    Exiting UpdaeAllotmentUsedField.PostCaseDelete.PostCaseDelete.Execute(), Correlation Id: d5fdc7c2-e971-4426-9a94-b35ce039ba14, Initiating User: 79dc5e8c-2a60-e011-98e4-000c29786082

     

     

    </TraceText>

      </InnerFault>

      <TraceText i:nil="true" />

    </OrganizationServiceFault>

     

    Please advise..

    dinsdag 27 december 2011 10:24
  • hi please check before deleting ,might be service or any object is null?

     

    use try catch and throw exception with a proper message, so we can check

     

     


    By Sanz If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    • Bewerkt door san Sanz dinsdag 27 december 2011 10:37
    dinsdag 27 december 2011 10:36
  • I tried it, and it throws exception: Object reference not set to an instance of an object

    I have tried the below to create IOrganizationService object

    IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)localContext.ServiceProvider.GetService(typeof(IOrganizationServiceFactory));
    
                IOrganizationService service = serviceFactory.CreateOrganizationService(localContext.PluginExecutionContext.UserId);
    
    
    Best regards.

     

     

    dinsdag 27 december 2011 11:20
  • can you try with this

    localContext.OrganizationService

    By Sanz If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    dinsdag 27 december 2011 11:25
  • I tried it, now the error changed to: the given key was not present in the dictionary
    dinsdag 27 december 2011 12:08
  • it means ,service  is correct,check the update method,
    or else can you share your error code block

    By Sanz If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    dinsdag 27 december 2011 12:20
  • Below is the 
    Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: System.Web.HttpUnhandledException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #CCC8B0DFDetail: 
    <OrganizationServiceFault xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
      <ErrorCode>-2147220970</ErrorCode>
      <ErrorDetails xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
      <Message>System.Web.HttpUnhandledException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #CCC8B0DF</Message>
      <Timestamp>2011-12-27T12:27:07.8611321Z</Timestamp>
      <InnerFault>
        <ErrorCode>-2147220891</ErrorCode>
        <ErrorDetails xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
        <Message>The given key was not present in the dictionary.</Message>
        <Timestamp>2011-12-27T12:27:07.8611321Z</Timestamp>
        <InnerFault i:nil="true" />
        <TraceText>
    [UpdaeAllotmentUsedField.PostCaseDelete: UpdaeAllotmentUsedField.PostCaseDelete.PostCaseDelete]
    [da14f44f-7130-e111-865e-000c2932b3b7: PostCaseDelete]
    Entered UpdaeAllotmentUsedField.PostCaseDelete.PostCaseDelete.Execute(), Correlation Id: 94bf0ac2-aff5-4c20-b722-8e3207011ce1, Initiating User: 79dc5e8c-2a60-e011-98e4-000c29786082
    UpdaeAllotmentUsedField.PostCaseDelete.PostCaseDelete is firing for Entity: incident, Message: Delete, Correlation Id: 94bf0ac2-aff5-4c20-b722-8e3207011ce1, Initiating User: 79dc5e8c-2a60-e011-98e4-000c29786082
    Exiting UpdaeAllotmentUsedField.PostCaseDelete.PostCaseDelete.Execute(), Correlation Id: 94bf0ac2-aff5-4c20-b722-8e3207011ce1, Initiating User: 79dc5e8c-2a60-e011-98e4-000c29786082
    </TraceText>
      </InnerFault>
      <TraceText i:nil="true" />
    </OrganizationServiceFault>
    and the full plugin code:
    // <copyright file="PostCaseDelete.cs" company="">
    // Copyright (c) 2011 All Rights Reserved
    // </copyright>
    // <author></author>
    // <date>12/27/2011 11:55:30 AM</date>
    // <summary>Implements the PostCaseDelete Plugin.</summary>
    // <auto-generated>
    //     This code was generated by a tool.
    //     Runtime Version:4.0.30319.1
    // </auto-generated>
    namespace UpdaeAllotmentUsedField.PostCaseDelete
    {
        using System;
        using System.ServiceModel;
        using Microsoft.Xrm.Sdk;
    
        /// <summary>
        /// PostCaseDelete Plugin.
        /// </summary>    
        public class PostCaseDelete: Plugin
        {
            /// <summary>
            /// Alias of the image registered for the snapshot of the 
            /// primary entity's attributes before the core platform operation executes.
            /// The image contains the following attributes:
            /// No Attributes
            /// </summary>
            private readonly string preImageAlias = "PostCaseImage";
    
            /// <summary>
            /// Initializes a new instance of the <see cref="PostCaseDelete"/> class.
            /// </summary>
            public PostCaseDelete()
                : base(typeof(PostCaseDelete))
            {
                base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(40, "Delete", "incident", new Action<LocalPluginContext>(ExecutePostCaseDelete)));
    
                // Note : you can register for more events here if this plugin is not specific to an individual entity and message combination.
                // You may also need to update your RegisterFile.crmregister plug-in registration file to reflect any change.
            }
    
            /// <summary>
            /// Executes the plug-in.
            /// </summary>
            /// <param name="localContext">The <see cref="LocalPluginContext"/> which contains the
            /// <see cref="IPluginExecutionContext"/>,
            /// <see cref="IOrganizationService"/>
            /// and <see cref="ITracingService"/>
            /// </param>
            /// <remarks>
            /// For improved performance, Microsoft Dynamics CRM caches plug-in instances.
            /// The plug-in's Execute method should be written to be stateless as the constructor
            /// is not called for every invocation of the plug-in. Also, multiple system threads
            /// could execute the plug-in at the same time. All per invocation state information
            /// is stored in the context. This means that you should not use global variables in plug-ins.
            /// </remarks>
            protected void ExecutePostCaseDelete(LocalPluginContext localContext)
            {
                try
                {
                    if (localContext == null)
                    {
                        throw new ArgumentNullException("localContext");
                    }
    
                    <strong>IPluginExecutionContext context = localContext.PluginExecutionContext;
    
                    //IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)localContext.ServiceProvider.GetService(typeof(IOrganizationServiceFactory));
                    //IOrganizationService service = serviceFactory.CreateOrganizationService(localContext.PluginExecutionContext.UserId);
    
    
                    Entity preImageEntity = (context.PreEntityImages != null && context.PreEntityImages.Contains(this.preImageAlias)) ? context.PreEntityImages[this.preImageAlias] : null;
    
    
                    // TODO: Implement your custom Plug-in business logic.
    
                    EntityReference contractDetailId = (EntityReference)preImageEntity.Attributes [ "contractdetailid" ];
                    string ContractLineId = contractDetailId.Id.ToString( );
    
                    //throw new InvalidPluginExecutionException(ContractLineId);
    
                    Entity ContractDetail = new Entity("contractline");
    
                    ////Create a KeyProperty to hold the guid of the record to be updated
                    Guid ContractDetailId = new Guid(ContractLineId);
                    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                    int x = int.Parse(ContractDetail [ "allotmentused" ].ToString( ));
                    ContractDetail [ "allotmentused" ] = x - 1;
    
                    localContext.OrganizationService.Update(ContractDetail);</strong>
    
                    //service.Update(ContractDetail);
                }
                catch(Exception e)
                {
                    throw new InvalidPluginExecutionException( e.Message,e );
                }
            }
        }
    }
    
    

    Best regards..
    dinsdag 27 december 2011 12:28
  • Hi can you try this

     

        Entity ContractDetail = new Entity("contractline");

    ////Create a KeyProperty to hold the guid of the record to be updated
    Guid ContractDetailId = new Guid(ContractLineId);

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    if(ContractDetail.Attributes.ContainsKey("allotmentused"))
    {
    int x = int.Parse(ContractDetail [ "allotmentused" ].ToString( ));
    ContractDetail [ "allotmentused" ] = x - 1;

    localContext.OrganizationService.Update(ContractDetail);
    }
    else
    {
    throw new Exception("allotment is not found");
    }
    </strong>

    By Sanz If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    dinsdag 27 december 2011 12:32
  • I have found 2 spelling mistakes and I have fixed them:

    contractdetail instead of contractline

    allotmentsused instead of allotmentused

     

    However it throws the exception ("allotment is not found");

    also the related contract line is readonly, could this be the cause of the problem ??

     

    Thanks alot for your help

    dinsdag 27 december 2011 12:57
  • that means the value of allotment is null,

    what do you want to do if allotmentused is null?

    if it is null dont want do any thing

    just skip the else condition it will work for you,

    if(!ContractDetail.Attributes.ContainsKey("allotmentused"))
    {
    int x = int.Parse(ContractDetail [ "allotmentused" ].ToString( ));
    ContractDetail [ "allotmentused" ] = x - 1;

    localContext.OrganizationService.Update(ContractDetail);
    }


    By Sanz If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    • Bewerkt door san Sanz dinsdag 27 december 2011 13:01
    dinsdag 27 december 2011 13:01
  • the problem is that the allotments used is not null, it contains a value

    however I tried what you say and it gives me error: the given key was not present in the dictionary

     

     

    Best regards..


    dinsdag 27 december 2011 13:04
  • hi can you use this line

     

     

    throw new Exception(ContractLineId );

    By Sanz If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    dinsdag 27 december 2011 13:20
  • I have used it, and it display the GUID of the related contract line
    dinsdag 27 december 2011 13:23
  • any updates about my issue ??
    dinsdag 27 december 2011 16:47

  • Hi Mostafa, i think you can't update the contractline entity once it's activated.
    You could create a mirror entity (like "myContractLine") to store allotments used / remaining.
    I'm starting similar plugins to manage activities duration in the incident and contractlines entities. Can you share your code with me?

    Best regards,
    zondag 24 februari 2013 11:40