apollo7
asked on
CRM 2011 Opportunity Bug
I am working on a CRM 2011 environment that has been highly customized by different developers and I am trying to troubleshoot errors that happen sporadically. The error that I am working on now happens when I try to change the owner on an Opportunity.
It doesn't happen all the time but when it does the Opportunity form "freezes" after the Owner is changed (not on Save, the Save button becomes disabled as soon as the owner is changed)
After a few minutes, a Business Process error pops up, If I download the Error Log it seems to indicate a plug-in problem, however, there are only two plug-ins Apollo.Crm.Plugin and Apollo.Crm.Workflow.
Can someone give an idea where to start with this?
Thanks
If I click Download Error Log, I get the following:
It doesn't happen all the time but when it does the Opportunity form "freezes" after the Owner is changed (not on Save, the Save button becomes disabled as soon as the owner is changed)
After a few minutes, a Business Process error pops up, If I download the Error Log it seems to indicate a plug-in problem, however, there are only two plug-ins Apollo.Crm.Plugin and Apollo.Crm.Workflow.
Can someone give an idea where to start with this?
Thanks
If I click Download Error Log, I get the following:
Unhandled Exception: System.ServiceModel.FaultException`1
[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=5.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: Method not found: 'Boolean
Apollo.Crm.DataLayer.SalesOrder.get_IsAutomatedNetOff()'.Detail:
<OrganizationServiceFault xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
<ErrorCode>-2147220891</ErrorCode>
<ErrorDetails
xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<KeyValuePairOfstringanyType>
<d2p1:key>OperationStatus</d2p1:key>
<d2p1:value xmlns:d4p1="http://www.w3.org/2001/XMLSchema"
i:type="d4p1:string">0</d2p1:value>
</KeyValuePairOfstringanyType>
</ErrorDetails>
<Message>Method not found: 'Boolean Apollo.Crm.DataLayer.SalesOrder.get_IsAutomatedNetOff
()'.</Message>
<Timestamp>2016-02-08T20:03:23.7576248Z</Timestamp>
<InnerFault i:nil="true" />
<TraceText>
[Apollo.Crm.Plugin: Apollo.Crm.Plugin.Security.GranularSecurity]
[406435b9-ca5c-e311-ad79-463500000031: Apollo.Crm.Plugin.Security.GranularSecurity: Assign of opportunity]
[Apollo.Crm.Plugin: Apollo.Crm.Plugin.OrderLineAllocation]
[97b86809-4016-e311-a85d-463500000031: Apollo.Crm.Plugin.OrderLineAllocation: Update of salesorder]
</TraceText>
</OrganizationServiceFault>
ASKER
Yes, there are the two plugins, as well as Workflows and Sdk Message Processing Steps,
so there is plugin Apollo.Crm.Plugin and also Apollo.Crm.Plug.Approve.Fu nc under Sdk Message Processing Steps
so there is plugin Apollo.Crm.Plugin and also Apollo.Crm.Plug.Approve.Fu
I suspect one of these plugins is responsible for the problem, are you able to discuss this with any of the customizers of your system?
Although, I'm not especially familiar with coding for CRM the error message suggests that one of the plug-ins that is run when the opportunity owner is changed is referring to some code that is not present. Perhaps some other customizations have been removed that contained the relevant code.
I think this is going to be difficult to unpick without you discovering what was done to your system.
Although, I'm not especially familiar with coding for CRM the error message suggests that one of the plug-ins that is run when the opportunity owner is changed is referring to some code that is not present. Perhaps some other customizations have been removed that contained the relevant code.
I think this is going to be difficult to unpick without you discovering what was done to your system.
Hi,
As I see the message,
Method not found: 'Boolean Apollo.Crm.DataLayer.Sales Order.get_ IsAutomate dNetOff()'
I believe you are missing something and the code should be written this way:
Boolean automated = Apollo.Crm.DataLayer.Sales Order.get_ IsAutomate dNetOff();
or
bool automated = Apollo.Crm.DataLayer.Sales Order.get_ IsAutomate dNetOff();
This is a wild guess as get_IsAutomatedNetOff() method might return a true/false value.
As I see the message,
Method not found: 'Boolean Apollo.Crm.DataLayer.Sales
I believe you are missing something and the code should be written this way:
Boolean automated = Apollo.Crm.DataLayer.Sales
or
bool automated = Apollo.Crm.DataLayer.Sales
This is a wild guess as get_IsAutomatedNetOff() method might return a true/false value.
ASKER
So, would my next move be to connect to the plug-in using the PlugInRegistrationTool and look for methods that are disabled or otherwise not working? Or is it best to open the plug-in in Visual Studio, attach to the process and run debug while changing the owner of an opportunity?
Thanks
Thanks
Hi,
If you can post the plugin code here, I can suggest you what should be your next move. However, I strongly feel some keywords are missing from the code and plugin is deployed.
You can open plugin code to the VS and change the code with the above mentioned code and redeploy the plugin.
If you can post the plugin code here, I can suggest you what should be your next move. However, I strongly feel some keywords are missing from the code and plugin is deployed.
You can open plugin code to the VS and change the code with the above mentioned code and redeploy the plugin.
I think you need to fully document your system and get an understanding of what plugins you have in your CRM system and then try and establish what they are for. Then you can consider whether they are still needed and if not remove them.
ASKER
Thanks feridun and rikin, I am working on getting the code in this thread to have your help understanding and also correcting my immediate problem. It is one of many plugins with the source in TFS.
I will get something up here today.
Thanks
I will get something up here today.
Thanks
ASKER
Hi
I attached code from the plug-in that if referenced in the error posted earlier. Let me know if this helps clarify what is happening when I try to change an owner in an Opportunity and the entire screen freeze and business process error log is displayed. The error log specifically shows '[Apollo.Crm.Plugin: Apollo.Crm.Plugin.Security .GranularS ecurity]'
Thanks
I attached code from the plug-in that if referenced in the error posted earlier. Let me know if this helps clarify what is happening when I try to change an owner in an Opportunity and the entire screen freeze and business process error log is displayed. The error log specifically shows '[Apollo.Crm.Plugin: Apollo.Crm.Plugin.Security
Thanks
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using app.Crm;
using apollo.Crm.Security;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;
namespace apollo.Crm.Plugin.Security
{
/// <summary>
/// Applies the default share state to an entity record. Relies on the following configuration settings:
/// - DefaultShare - Global, BusinessUnitHierarchy, BusinessUnit,
/// <settings>
/// <setting name="DefaultShare">
/// <value>BusinessUnitHierarchy</value>
/// </setting>
/// </settings>
/// This plugin should be registered with a PostImage called Target.
/// </summary>
public class GranularSecurity
: IPlugin
{
#region ---------------------------------------- Constructor ------------------------------------------------
public GranularSecurity(string config, string secureConfig)
{
this.Configuration = new app.Crm.Configuration.Plugin(config);
this.SecureConfiguration = new app.Crm.Configuration.Plugin(secureConfig);
}
#endregion
#region ---------------------------------------- Properties -------------------------------------------------
public app.Crm.Configuration.Plugin Configuration
{ get; set; }
public app.Crm.Configuration.Plugin SecureConfiguration
{ get; set; }
#endregion
#region ---------------------------------------- Methods ----------------------------------------------------
public void Execute(IServiceProvider serviceProvider)
{
try
{
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Get a reference to the Organization service.
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
EntityReference entity = new EntityReference(context.PrimaryEntityName, context.PrimaryEntityId);
if ((context.MessageName.Equals("Create") || context.MessageName.Equals("Update") || context.MessageName.Equals("Assign")) && !context.SharedVariables.Contains("GranularSecurity"))
{
app.Crm.Configuration.AppSettings.GetInstance().Context.ApplyNew();
// Used to determine if the plugin has been called within the current execution context
context.SharedVariables.Add("GranularSecurity", true);
Common.LogTrace(string.Format("Executing GranularSecurity plugin for {2} of {0} entity id {1}.", context.PrimaryEntityName, context.PrimaryEntityId, context.MessageName));
// Get Input Parameters
Entity input = null;
if (context.MessageName != "Assign") input = (Entity)context.InputParameters["Target"];
// Get Post Image
Entity postImage = (Entity)context.PostEntityImages["Target"];
// Get Pre Image if available
Entity preImage = null;
if (context.MessageName.Equals("Assign") || context.MessageName.Equals("Update")) preImage = (Entity)context.PreEntityImages["Target"];
if (context.PrimaryEntityName == "opportunity")
{
applyGranularSecurity(service, entity, input, preImage, postImage, context.MessageName);
}
else //if ((context.MessageName.Equals("Create") || context.MessageName.Equals("Assign")) && (context.PrimaryEntityName == "quote" || context.PrimaryEntityName == "salesorder"))
{
applyParentalSecurity(service, entity, postImage);
}
}
}
catch (Exception ex)
{
Common.LogException(ex);
throw;
}
}
/// <summary>
/// Applies granular security to a record based on secure record attributes and plugin configuration.
/// See opportunity for an example.
/// </summary>
/// <param name="service"></param>
/// <param name="entity"></param>
/// <param name="input"></param>
/// <param name="preImage"></param>
/// <param name="postImage"></param>
private void applyGranularSecurity(IOrganizationService service, EntityReference entity, Entity input, Entity preImage, Entity postImage, string messageName)
{
// Get the record owner
DataLayer.SystemUser owner = new DataLayer.SystemUser(service, postImage.GetAttributeValue<EntityReference>("ownerid").Id);
// Has the record security status changed?
// NB. Even if the attribute has not changed it is being included in the input attributes
// --> pre image hack is to work around this.
if (secureStatusHasChanged(input, preImage))
{
// Apply Security Settings
if (input.GetAttributeValue<bool>("app_securityfirewalled") != true)
{
SecurityUtility.ApplyCascadeDefaultShares(service, Configuration, entity, owner);
}
else
{
SecurityUtility.RemoveCascadeAllShares(service, entity, owner);
// Now ensure that the record is still visible to management
if (postImage.GetAttributeValue<bool>("app_securityvisibletomanagement") == true)
{
SecurityUtility.ApplyCascadeManagementShare(service, entity, owner);
}
}
}
else if (visibleToManagementStatusHasChanged(input, preImage))
{
// The visible to managment status has changed but only apply management
// shares though if the record is secure.
if (postImage.GetAttributeValue<bool>("app_securityfirewalled") == true)
{
if (input.GetAttributeValue<bool>("app_securityvisibletomanagement") == true)
{
SecurityUtility.ApplyCascadeManagementShare(service, entity, owner);
}
else
{
SecurityUtility.RemoveCascadeManagementShare(service, entity, owner);
}
}
}
else if (messageName.Equals("Assign"))
{
// cascade re-assign to quotes, orders
SecurityUtility.CascadeAssign(service, entity, owner);
// remove all current shares
SecurityUtility.RemoveCascadeAllShares(service, entity, owner);
// apply shares
if (postImage.GetAttributeValue<bool>("app_securityfirewalled") == true)
{
if (postImage.GetAttributeValue<bool>("app_securityfirewalled") == true)
{
// apply management share if required
SecurityUtility.ApplyCascadeManagementShare(service, entity, owner);
}
}
else
{
// apply default shares
SecurityUtility.ApplyCascadeDefaultShares(service, Configuration, entity, owner);
}
}
}
private void applyParentalSecurity(IOrganizationService service, EntityReference entity, Entity postImage)
{
if (postImage.GetAttributeValue<EntityReference>("opportunityid") != null)
{
// Cascade parental shares where the record has an opportunity id
DataLayer.Opportunity opportunity = new DataLayer.Opportunity(service, postImage.GetAttributeValue<EntityReference>("opportunityid").Id);
if (!opportunity.IsSecureRecord)
{
SecurityUtility.ApplyDefaultShares(service, Configuration, entity, opportunity.Owner);
}
else if (opportunity.IsSecureRecord && opportunity.IsVisibleToManagement)
{
SecurityUtility.ApplyManagementShare(service, entity, opportunity.Owner);
}
}
else
{
// If the record is owned by a user -> Apply Default Shares
if (postImage.GetAttributeValue<int>("owneridtype") == 8)
{
DataLayer.SystemUser owner = new DataLayer.SystemUser(service, postImage.GetAttributeValue<Guid>("ownerid"));
SecurityUtility.ApplyDefaultShares(service, Configuration, entity, owner);
}
}
}
/// <summary>
/// Compares the input parameters to the pre image to determine if the value has changed.
/// This should not be necessary but is required as Opportunity is including parameters
/// that have not changed in the inputparameters.
/// <param name="opportunityInput"></param>
/// <param name="opportunityPreImage"></param>
/// <returns></returns>
private bool secureStatusHasChanged(Entity opportunityInput, Entity opportunityPreImage)
{
bool retVal = false;
if (opportunityInput != null)
{
if (opportunityInput.Attributes.Contains("app_securityfirewalled"))
{
if (opportunityPreImage == null)
{
retVal = true;
}
else
{
if (opportunityPreImage.GetAttributeValue<bool>("app_securityfirewalled") != opportunityInput.GetAttributeValue<bool>("app_securityfirewalled"))
{
retVal = true;
}
}
}
}
return retVal;
}
/// <summary>
/// Compares the input parameters to the pre image to determine if the value has changed.
/// This should not be necessary but is required as Opportunity is including parameters
/// that have not changed in the inputparameters. #DodgyJavascript
/// </summary>
/// <param name="opportunityInput"></param>
/// <param name="opportunityPreImage"></param>
/// <returns></returns>
private bool visibleToManagementStatusHasChanged(Entity opportunityInput, Entity opportunityPreImage)
{
bool retVal = false;
if (opportunityInput != null)
{
if (opportunityInput.Attributes.Contains("app_securityvisibletomanagement"))
{
if (opportunityPreImage == null)
{
retVal = true;
}
else
{
if (opportunityPreImage.GetAttributeValue<bool>("app_securityvisibletomanagement") != opportunityInput.GetAttributeValue<bool>("app_securityvisibletomanagement"))
{
retVal = true;
}
}
}
}
return retVal;
}
#endregion
}
}
ASKER
Any ideas on my next move? Let me know if you need more detail. I am looking at workflows that appear to kicked off by the plug-in. When the error does not occur, the workflow(s) succeed.
When I get the error, the workflows go into a waiting stage.
When I get the error, the workflows go into a waiting stage.
Sorry, I can't help here, coding is not part of my skillset. :(
Hi,
The above class is just calling the method from other class. Do you have the code for "Apollo.Crm.DataLayer.Sale sOrder" class? The error says a method in the class is missing. Can you check it?
Since you have code, are you able to debug the plugin?
The above class is just calling the method from other class. Do you have the code for "Apollo.Crm.DataLayer.Sale
Since you have code, are you able to debug the plugin?
ASKER
I ran a debug on the plugin and received 1 error:
Error 6 'Apollo.Crm.DataLayer.Sale sOrder' does not contain a definition for 'IsAutomatedNetOff' and no extension method 'IsAutomatedNetOff' accepting a first argument of type 'Apollo.Crm.DataLayer.Sale sOrder' could be found (are you missing a using directive or an assembly reference?) E:\TFS_DT\Apollo\TrunkWiPr o\Apollo.C rm.Plugin\ Apollo.Crm .Plugin\Or derLineAll ocation.cs 75 39 Apollo.Crm.Plugin
Error 6 'Apollo.Crm.DataLayer.Sale
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
ASKER
Rikin
Yes, it is an assembly deployed to the GAC but I am just using "View" when I open the the plug-in in TFS.
I am new to this project and just got the permission today to check-in/check-out so it is very possible that I am not seeing the most recent version (for one thing, there are pending changes)
Yes, it is an assembly deployed to the GAC but I am just using "View" when I open the the plug-in in TFS.
I am new to this project and just got the permission today to check-in/check-out so it is very possible that I am not seeing the most recent version (for one thing, there are pending changes)
ASKER
So would the next step to "get the latest version" and deploy to the GAC?
You need to figure it out first, is the code for the assembly available in the same project? Or is it an assembly added as a reference?
Check in GAC if the assembly is deployed over there or not.
And yes, get the latest version of the code/assembly or both.
Check in GAC if the assembly is deployed over there or not.
And yes, get the latest version of the code/assembly or both.
ASKER
This is the correct answer, we were looking at the wrong source code.
The plug-in registration tool described here, https://msdn.microsoft.com/en-us/library/hh237515(v=crm.6).aspx might give you more information.