locked
Incorrect Attribute Value RRS feed

  • Question

  • "2147220989 - Incorrect attribute value type System.Int32"

    Getting the error message above when running this section of code in a Post-Operation Plugin on the Update function. The Update function is linked to the form new_contractreview.

    The code is meant to reset the value of a custom OptionSet field (new_contractstatus). The code resets it from the value 100,000,001 (Sending) to 100,000,000 (Pending).

    // Get the GUID
    Entity CSVentity = new Entity("new_contractreview");
    Entity ent = (Entity)context.InputParameters["Target"];
    CSVentity.Id = ent.Id;
    
    // Set the value
    OptionSetValue myoptionset = new OptionSetValue();
    myoptionset.Value = 100000000;
    CSVentity.Attributes["new_contractstatus"] = myoptionset.Value;
    
    // Update the ContractReview Record
    service.Update(CSVentity);
    
    // Display error message
    throw new Exception("Error: Order charge file failed to write. The order charge file could not be exported.")
    • Edited by Kerl_J1310 Wednesday, July 22, 2015 10:00 AM
    Wednesday, July 22, 2015 9:59 AM

Answers

  • Hello,

    Try to change code line

    CSVentity.Attributes["new_contractstatus"] = myoptionset.Value;

    to line

    CSVentity.Attributes["new_contractstatus"] = myoptionset;


    Dynamics CRM MVP
    My blog

    • Proposed as answer by Guido PreiteMVP Wednesday, July 22, 2015 12:33 PM
    • Marked as answer by Kerl_J1310 Wednesday, July 22, 2015 2:29 PM
    Wednesday, July 22, 2015 10:59 AM
    Moderator

All replies

  • Hello,

    Try to change code line

    CSVentity.Attributes["new_contractstatus"] = myoptionset.Value;

    to line

    CSVentity.Attributes["new_contractstatus"] = myoptionset;


    Dynamics CRM MVP
    My blog

    • Proposed as answer by Guido PreiteMVP Wednesday, July 22, 2015 12:33 PM
    • Marked as answer by Kerl_J1310 Wednesday, July 22, 2015 2:29 PM
    Wednesday, July 22, 2015 10:59 AM
    Moderator
  • This fixed the error so thank you, but the field in the form isn't updating - any idea why this could be?
    Wednesday, July 22, 2015 11:05 AM
  • Hello,

    I would suggest to use Pre-Operation plugin and change your code to following:

    Entity ent = (Entity)context.InputParameters["Target"];
    
    OptionSetValue myoptionset = new OptionSetValue();
    myoptionset.Value = 100000000;
    ent["new_contractstatus"] = myoptionset;

    Why have you used Post plugin instead of Pre?


    Dynamics CRM MVP
    My blog

    Wednesday, July 22, 2015 11:29 AM
    Moderator
  • The plugin runs when a button is pressed on the form, submitting all the data from CRM to a file to be picked up by another program. I've only recently begun work on the plugin and CRM as a whole, with the plugin being mostly already implemented by my predecessor. This chunk of code and one or two other lines have been added by myself to extend the functionality a little further, so I've simply been told/given the plugin as a post-op. Don't know if it would still work correctly as a pre-op?
    Wednesday, July 22, 2015 11:59 AM
  • In this case you can create separated plugin that will do this trick and work on pre-operation.

    Dynamics CRM MVP
    My blog

    Wednesday, July 22, 2015 12:52 PM
    Moderator
  • How would this work? As the code above is only running if an error occurs during the writing of the file, then wouldn't the separate plugin that is pre-operation only run prior to the error occurring? Or are you able to call a plugin from within another plugin?
    Wednesday, July 22, 2015 1:16 PM
  • I mean then instead of enriching with additional logic your existing post plugin create another one plugin that will work on pre - update event. That's what I mean.

    Dynamics CRM MVP
    My blog

    Wednesday, July 22, 2015 1:23 PM
    Moderator
  • I understand that but how would this new plugin know when the error occurs, especially with the pre-operation occurring before the post-operation?
    Wednesday, July 22, 2015 1:28 PM
  • Ahh. At last I got your issue. So if some of validations are not passed for some reason you want to throw an error one one hand and update the status of record on another. In case your answer would be yes - unfortunately you will have to think on other way of doing it because when exception is thrown all changes are rolled back because since 2011 we have transactions in CRM. Fairly I'm not sure how to implement your scenario. Could you please describe the full scenario you're trying to implement?

    Dynamics CRM MVP
    My blog

    Wednesday, July 22, 2015 1:36 PM
    Moderator
  • Okay...

    The form is filled out by an employee, filling out various text boxes and choosing option sets etc. The form has a JS function attached to it that checks all the data has been entered correctly which then un-hides the Export button. Upon clicking this button, the status of the form changes from Pending (100,000,000) to Sending (100,000,001). When this changes to Sending, the plugin runs. The plugin then takes the data from the form and another form, writing it into two files - FM-SO and FM-SOCHG. These files, if written successfully, are then picked up by another program (Factory Master). However, should either of the files fail to be written, then the status of the form should return to Pending and a message outputted (At the moment this is implemented through an exception).

    Full Code Listings for the plugin:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Threading.Tasks;
    using System.Text.RegularExpressions;
    
    using Microsoft.Xrm.Sdk;
    using Microsoft.Crm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    using Microsoft.Xrm.Sdk.Messages;
    using Microsoft.Xrm.Sdk.Metadata;
    using Microsoft.Xrm.Sdk.Client;
    using Microsoft.Xrm.Sdk.Linq;
    
    using System.Web;
    using System.Web.UI;
    using Microsoft.Crm.Sdk.Messages;
    
    
    namespace SalesOrder
    {
        public class OrderPlugin : IPlugin
        {
            // Declare variables
            string callOffStatus;
            string CSVFile;
            string productid;
            string quantity;
            string amount;
            string date;
            string description;
    
            string chargeDescription;
            string chargeAmount;
            string CSVFile1;
    
            public void Execute(IServiceProvider serviceProvider)
            {
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
    
    
                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
    
                // The InputParameters collection contains all the data passed 
                // in the message request.
                if (context.InputParameters.Contains("Target") &&
                    context.InputParameters["Target"] is Entity)
                {
                    Entity entity = (Entity)context.InputParameters["Target"];
                    // Issue with plugin firing when not needed, new_quotecopyid is in the quote entity not sales order therefore resolves the issue
                    if (entity.Attributes.Contains("new_quotecopyid"))
                    {
                        return;
                    }
                    else
                    {
                        // Obtain the target entity from the Input Parameters.
                        Entity contractStatusImage = (Entity)context.PostEntityImages["ContractStatus"];
    
                        // Retrieve value from option set 
                        var ContractReviewStatus = ((Microsoft.Xrm.Sdk.OptionSetValue)(contractStatusImage.Attributes["new_contractstatus"])).Value.ToString();
    
                        // Only want the plugin to fire under certain condition, before hand when the 'Export To FM' button is pressed JS will change the option set value to 100000001. No other code will change the value of the option set therefore
                        // When a normal save executes the plugin will never be fired
    
                        // 100000001 = SENDING
                        if (ContractReviewStatus == "100000001")
                        {
                            // Retrieve the Images we stated in the plugin registration tool
                            Entity OrderNumberImage = (Entity)context.PostEntityImages["OrderNumberImage"];
    
                            // Use the above to retrieve the required data from the lookup
                            var orderNumber = ((Microsoft.Xrm.Sdk.EntityReference)(OrderNumberImage.Attributes["new_salesorderlookup"]));
                            // Retrieves the attributes from the entity the lookup corespondes too (enables us to select any attribute within the entity)
                            var orderNumberDetails = service.Retrieve(orderNumber.LogicalName, orderNumber.Id, new ColumnSet(true));
                            // Retrieve the customer order reference
                            var customerorderRef = orderNumberDetails["new_customerorderreference"].ToString();
                            // Retrieve the order number 
                            var actualOrderNumber = orderNumberDetails["new_neworderid"].ToString();
                            // Within the sales order we have a lookup to the customer's Account, we can access Account attributes through the following
                            var accountID = ((Microsoft.Xrm.Sdk.EntityReference)orderNumberDetails["customerid"]);
                            // Retrieve the attributes from the Account Entity
                            var accountNumberDetails = service.Retrieve(accountID.LogicalName, accountID.Id, new ColumnSet(true));
                            // Retrieve the account number 
                            var accountCode = accountNumberDetails["accountnumber"].ToString();
                            // Retrieve the date required from sales order
                            var dateDeliveryRequiredImage = orderNumberDetails["requestdeliveryby"];
                            // Retrieve the shippingcode from the sales order
                            var shippingCode = orderNumberDetails["new_addresscode"].ToString();
                            // Added by Kyle - Retrieve the call off status from the sales order
                            string callOff = ((Microsoft.Xrm.Sdk.OptionSetValue)(orderNumberDetails.Attributes["new_calloffstatus"])).Value.ToString();
    
                            if (callOff != null)
                            {
                                if (callOff == "100000000")
                                {
                                    callOffStatus = "Agreed";
                                }
                                else if (callOff == "100000001")
                                {
                                    callOffStatus = "Firm Urgent";
                                }
                                else if (callOff == "100000002")
                                {
                                    callOffStatus = "Firm";
                                }
                                else if (callOff == "100000003")
                                {
                                    callOffStatus = "Material";
                                }
                                else if (callOff == "100000004")
                                {
                                    callOffStatus = "Forecast";
                                }
                                else
                                {
                                    callOffStatus = "Error!";
                                }
                            }
                            else
                            {
                                throw new Exception("No Call Off Status selected for the current order.");
                            }
    
                            //var callOffStatus 
                            // Retrieve the GUID of the sales order number
                            Guid salesGUID = ((EntityReference)OrderNumberImage["new_salesorderlookup"]).Id;
    
                            // FetchXML Query will retrieve product details from different entities, Link-entity is where the different entites used are bought in
                            // Condition Attribute is used to only select the products that is in the Grid on the Order Form
                            string fetchxml = @"
                                <fetch distinct='false' mapping='logical' output-format='xml-platform' version='1.0'>
                                <entity name='salesorderdetail'>
                                    <attribute name='productid'/>
                                    <attribute name='productdescription'/>
                                    <attribute name='priceperunit'/>
                                    <attribute name='quantity'/>
                                    <attribute name='extendedamount'/>
                                    <attribute name='salesorderdetailid'/>
                                    <attribute name='description'/>
                                    <order descending='false' attribute='productid'/>
                                        <link-entity name='product' alias='af' to='productid' from='productid'>
                                            <attribute name='name'/>
                                            <attribute name='productnumber'/>
                                        </link-entity>
                                        <link-entity name='salesorder' alias='ac' to='salesorderid' from='salesorderid'> 
                                            <filter type='and'> 
                                                <condition attribute='salesorderid' operator='eq' value='" + salesGUID + @"'/> 
                                            </filter> 
                                        </link-entity>
                                </entity>
                                </fetch>";
    
                            // Results are stored in a entity collection
                            EntityCollection result = service.RetrieveMultiple(new FetchExpression(fetchxml));
                            {
                                if (result != null && result.Entities.Count > 0)
                                {
                                    //var count = result.Entities.Count;
                                    string todaysDate = DateTime.Now.ToString("dd/MM/yyyy"); //for date ordered
    
                                    // Code is for converting UTC format into local time, uses RetrieveLocalTimeFromUTCTime function that is on bottom of code
                                    if (dateDeliveryRequiredImage != null)
                                    {
                                        DateTime dateAndTime = (DateTime)dateDeliveryRequiredImage;
                                        var localDate = RetrieveLocalTimeFromUTCTime(dateAndTime, service);
                                        date = localDate.ToString("dd-MM-yyyy");
                                    }
                                    else
                                    {
                                        date = "";
                                    }
    
                                    foreach (Entity _entity in result.Entities) // Loop through every record
                                    {
                                        productid = ((AliasedValue)_entity.Attributes["af.productnumber"]).Value.ToString(); // Retrieve product number (ID)
                                        quantity = _entity.Attributes["quantity"].ToString();
                                        description = _entity.Attributes["description"].ToString();
                                        amount = ((Money)_entity.Attributes["extendedamount"]).Value.ToString();
    
    
                                        // CSV file calls itself so that with every loop no data is lost
                                        CSVFile = CSVFile +
                                            "FM-SSO" + "," +
                                            "" + "," + // Room for transaction user id
                                            accountCode + "," +
                                            "" + "," + // Room for ordered by address
                                            shippingCode + "," + // Room for deliver to address
                                            "" + "," + // Room for invoice to address
                                            customerorderRef + "," +
                                            todaysDate + "," +
                                            date + "," +
                                            productid + "," +
                                            quantity + "," +
                                            amount + "," + // Room for price
                                            description + "," +
                                            actualOrderNumber + "," +
                                            "" + "," + // Room for item number
                                            "Y" + "," + // Detailed order
                                            callOffStatus + "," + // Added by Kyle - room for call off status
                                            "@";
    
                                        CSVFile = CSVFile.Replace("@", System.Environment.NewLine); // @ Used as indication of new line as normal \n function didn't work
                                    }
    
                                    string AddressPath = "FM-SSO";
    
                                    // Save CSV file
                                    // Note: When adding products to record previous Products will appear in CSV file however no duplication of orders will appear in FM
                                    if (CSVFile != null)
                                    {
                                        AddressPath = "FM-SSO" + "_" + accountCode;
                                        string AddressSavePath = @"\\fm\CRMdata\maesteg\" + AddressPath + ".csv";
                                        System.IO.File.WriteAllText(AddressSavePath, CSVFile.ToString());
                                        CSVFile = "";
                                    }
                                    else
                                    {
                                        throw new Exception("Error: Order file failed to write. The order file could not be exported.");
                                    }
    
                                    // Retrieve Order Charges! This will retrieve any order charges associated with the sales order
                                    string fetchXML = @"
                                        <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
                                            <entity name='new_ordercharge'>
                                                <attribute name='createdon' />
                                                <attribute name='new_chargedescription' />
                                                <attribute name='new_amount' />
                                                <attribute name='new_orderchargeid' />
                                                <attribute name ='new_chargetext' />
                                                <order attribute='new_chargedescription' descending='false' />
                                                <link-entity name='salesorder' from='salesorderid' to='new_ordernumber' alias='ae'>
                                                <filter type='and'>
                                                    <condition attribute='salesorderid' operator='eq' value='" + salesGUID + @"'/>
                                                </filter>
                                            </link-entity>
                                            </entity>
                                        </fetch>";
    
                                    EntityCollection result1 = service.RetrieveMultiple(new FetchExpression(fetchXML));
                                    {
                                        if (result1 != null && result.Entities.Count > 0)
                                        {
                                            foreach (Entity _entity in result1.Entities) // Loop through every record
                                            {
                                                chargeDescription = _entity.Attributes["new_chargetext"].ToString();
                                                chargeAmount = _entity.Attributes["new_amount"].ToString();
    
                                                CSVFile1 = CSVFile1 +
                                                "FM-SOCHG" + "," +
                                                "" + "," + // Room for transaction user id
                                                actualOrderNumber + "," +
                                                chargeDescription + "," +
                                                chargeAmount + "," +
                                                "" + "," + // Room for VAT Code
                                                "" + "," + // Room for nominal code
                                                "" + "," + // Room for cost centre code
                                                "" + "," + // Room for department code
                                                "" + "," + // Room for onvoice per delivery
                                                "@";
                                                CSVFile1 = CSVFile1.Replace("@", System.Environment.NewLine); // @ Used as indication of new line as normal \n function didn't work
                                            }
    
                                            // Error:   CSVFile1 = null causing CRM form to crash at runtime.
                                            // Fix:     Added IF statement to prevent the code running if the value is null.
                                            if (CSVFile1 != null)
                                            {
                                                // Create a seperate CSV file
                                                string AddressPath1 = AddressPath + "FM-SOCHG" + "_" + accountCode;
                                                string AddressSavePath1 = @"\\fm\CRMdata\maesteg\" + AddressPath1 + ".csv";
                                                System.IO.File.WriteAllText(AddressSavePath1, CSVFile1.ToString());
                                                CSVFile1 = "";
                                            }
                                            else
                                            {
                                                //Check the spelling on the entity name, it is case sensitive
                                                Entity CSVentity = new Entity("new_contractreview");
                                                Entity ent = (Entity)context.InputParameters["Target"];
                                                CSVentity.Id = ent.Id;
    
                                                // Set the value of the 
                                                OptionSetValue myoptionset = new OptionSetValue();
                                                myoptionset.Value = 100000000;
                                                CSVentity.Attributes["new_contractstatus"] = myoptionset;
    
                                                // Update the ContractReview Record
                                                service.Update(CSVentity);
    
                                                throw new Exception("Error: Order charge file failed to write. The order charge file could not be exported.");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
    
            // Code taken from Microsoft Website for conveting Time into Local Time
            // Needed as without the date was always one day behind what was selected in CRM
            private DateTime RetrieveLocalTimeFromUTCTime(DateTime utcTime, IOrganizationService service)
            {
                int? timeZoneCode = RetrieveCurrentUsersSettings(service);
    
                if (!timeZoneCode.HasValue)
                    throw new Exception("Can't find time zone code");
    
                var request = new LocalTimeFromUtcTimeRequest
                {
                    TimeZoneCode = timeZoneCode.Value,
                    UtcTime = utcTime.ToUniversalTime()
                };
    
                var response = (LocalTimeFromUtcTimeResponse)service.Execute(request);
    
                return response.LocalTime;
            }
    
            private int? RetrieveCurrentUsersSettings(IOrganizationService service)
            {
                var currentUserSettings = service.RetrieveMultiple(
                new QueryExpression("usersettings")
                {
                    ColumnSet = new ColumnSet("localeid", "timezonecode"),
                    Criteria = new FilterExpression
                    {
                        Conditions =
                			{
                    			new ConditionExpression("systemuserid", ConditionOperator.EqualUserId)
                			}
                    }
                }).Entities[0].ToEntity<Entity>();
    
                return (int?)currentUserSettings.Attributes["timezonecode"];
            }
        }
    }
    // End of plugin
    Wednesday, July 22, 2015 1:48 PM
  • Ok. I have an idea how to make your solution work:

    I believe that you invoke an update of your record (to initiate a plugin) with simple settings of a field to value and forcing of record Save. So you will have to change the logic to following:

    1. User presses Export button -> you update record's status using Endpoint and handle an error.

    2. In case Error is thrown you can show message to a user and then again call an Update to set correct status.

    3. In case everything went fine just reload a form to see updated values.


    Dynamics CRM MVP
    My blog

    Wednesday, July 22, 2015 1:55 PM
    Moderator
  • Just fixed it and it now resets! Took out the exceptions and thought that the JavaScript may have been overwriting the reset (which it was).

    Is there any way of outputting a message to the user without using an exception?

    Wednesday, July 22, 2015 2:01 PM
  • I believe that an exception is the best one.

    But in case you want to avoid throwing exception you can go other way:

    1. Create a field that will contain a message.

    2. Update record status from a code with required status and new custom field with error message.

    3. After you've triggered an update read the resulting status and message and if status was not changed to processed - show user message with error message using standard alert.


    Dynamics CRM MVP
    My blog


    Wednesday, July 22, 2015 2:15 PM
    Moderator