While there can be many other reasons for this, recently we came across a situation where a simple workflow assembly designed by us could not be used in a Workflow. If we added the reference to this workflow assembly in the Workflow, it wouldn’t publish. We would receive the following message "An error occured when the workflow was being created. Try to save the worflow again". Refer to the image below.
There was no further information to be found in the event log for this.
Upon further review of the code, it was noticed that the Namespace and Class name was the same.
Upon changing the namespace to something other than TestWorkflow the workflow designer accepted the workflow assembly and published it too.
Just wondering if this were an issue, it should not have allowed us to register the assembly in the first place. It would have been a better indicator of something being wrong with the class declarations.
For anyone else who face the same problem… it might help to check the class name.
Inogic is a hub of like minded professionals who believe in innovativeness and are committed to putting our time and efforts to R & D on Dynamics CRM.We endeavor to share some of our work on this blog by introducing Tips, Tricks and products from our labs.
Showing posts with label Work flow issue. Show all posts
Showing posts with label Work flow issue. Show all posts
Thursday, February 3, 2011
Friday, October 22, 2010
Issues with class level declaration in CRM 4 Plugins and Workflows
It is important that you avoid class level declaration and initialization of variables in Plugins and Workflows.
Let us discuss the issues that one can face with Plugins. Plugins as you know is executed synchronously. But if there happen to be multiple calls made to the same plugin assembly and class, a new object for the Plugin is not always created. Instead the same object is reused. So if you have initialized a class level variable at the start and not in the Execute method, it will be initialized only once at the start and there after for subsequent calls the plugin will reuse the last value stored in the variables much like the static variables.
An example of this would be
public class MyPlugIn : IPlugin
{
ICrmService _service = null;
Bool _myBool = false;
public void Execute(IPluginExecutionContext context)
{
//Check if particular field contains data then set the _myBool as true
{
_myBool = true;
}
//Update record with _myBool Field.
}
}
_mybool is initialized to be false only once at the start. If for some execution the condition succeeds and the value is set to true. The next call to this plugin would use the _mybool value as true by default not initialize it to false.
This behavior can be replicated using the Bulk Edit feature of Dynamics CRM. If you have a plugin registered for the Update method and you use the Bulk Edit feature to update multiple records at one go, the plugin would fire for each of the records modified but the _mybool variable will only be initialized once.
It would be advisable to ensure that class level variables are initialized in the Execute method each time.
Workflow Issues:
If you happen to declare the ICrmService variable at class level in a workflow assembly and make a call to that assembly in step 1 of the workflow and have step 2 that performs another action in the same workflow, the workflow would go into Waiting and not close with a completed or failed status.
The Workflow error message will display the following error for the Workflow job.
Workflow paused due to error: Unhandled Exception: System.Workflow.Runtime.Hosting.PersistenceException: Type 'Inogic' in Assembly 'Inogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. at System.Workflow.Runtime.WorkflowExecutor.Persist(Activity dynamicActivity, Boolean unlock, Boolean needsCompensation) at System.Workflow.Runtime.WorkflowExecutor.System.Workflow.ComponentModel.IWorkflowCoreRuntime.PersistInstanceState(Activity activity) at System.Workflow.ComponentModel.Activity.MarkClosed() at System.Workflow.ComponentModel.Activity.MarkCompleted() at System.Workflow.ComponentModel.ActivityExecutionContext.CloseActivity() at System.Workflow.ComponentModel.ActivityExecutorOperation.Run(IWorkflowCoreRuntime workflowCoreRuntime) at System.Workflow.Runtime.Scheduler.Run() Inner Exception: System.Runtime.Serialization.SerializationException: Type 'Inogic' in Assembly 'Inogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph) at System.Workflow.ComponentModel.Activity.Save(Stream stream, IFormatter formatter) at System.Workflow.ComponentModel.Activity.Save(Stream stream) at System.Workflow.Runtime.Hosting.WorkflowPersistenceService.GetDefaultSerializedForm(Activity activity) at Microsoft.Crm.Workflow.CrmWorkflowPersistenceService.SaveWorkflowInstanceState(Activity rootActivity, Boolean unlock) at System.Workflow.Runtime.WorkflowExecutor.Persist(Activity dynamicActivity, Boolean unlock, Boolean needsCompensation)
This is again because of the declaration of the CRM service object at the class level. The variable is not released after the completion of job if the variable is defined at class level and hence conflicts with the steps that follow in the same workflow job.
[CrmWorkflowActivity("Customer Search")]
Public partial class CustomerSearch: Activity
{
public static ICrmService crmservice = null; // or make it as function level reference
…… Execute(…….) { }
………..
}
Moving the ICrmService object declaration from Class level to the Execute method ensure that the object is released upon the completion of the job.
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
ICrmService crmservice = null;
Processing…..
}
hopefully this solution will help you to avoid custom WF error. Any feedback on this blog is commendable.
Let us discuss the issues that one can face with Plugins. Plugins as you know is executed synchronously. But if there happen to be multiple calls made to the same plugin assembly and class, a new object for the Plugin is not always created. Instead the same object is reused. So if you have initialized a class level variable at the start and not in the Execute method, it will be initialized only once at the start and there after for subsequent calls the plugin will reuse the last value stored in the variables much like the static variables.
An example of this would be
public class MyPlugIn : IPlugin
{
ICrmService _service = null;
Bool _myBool = false;
public void Execute(IPluginExecutionContext context)
{
//Check if particular field contains data then set the _myBool as true
{
_myBool = true;
}
//Update record with _myBool Field.
}
}
_mybool is initialized to be false only once at the start. If for some execution the condition succeeds and the value is set to true. The next call to this plugin would use the _mybool value as true by default not initialize it to false.
This behavior can be replicated using the Bulk Edit feature of Dynamics CRM. If you have a plugin registered for the Update method and you use the Bulk Edit feature to update multiple records at one go, the plugin would fire for each of the records modified but the _mybool variable will only be initialized once.
It would be advisable to ensure that class level variables are initialized in the Execute method each time.
Workflow Issues:
If you happen to declare the ICrmService variable at class level in a workflow assembly and make a call to that assembly in step 1 of the workflow and have step 2 that performs another action in the same workflow, the workflow would go into Waiting and not close with a completed or failed status.
The Workflow error message will display the following error for the Workflow job.
Workflow paused due to error: Unhandled Exception: System.Workflow.Runtime.Hosting.PersistenceException: Type 'Inogic' in Assembly 'Inogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. at System.Workflow.Runtime.WorkflowExecutor.Persist(Activity dynamicActivity, Boolean unlock, Boolean needsCompensation) at System.Workflow.Runtime.WorkflowExecutor.System.Workflow.ComponentModel.IWorkflowCoreRuntime.PersistInstanceState(Activity activity) at System.Workflow.ComponentModel.Activity.MarkClosed() at System.Workflow.ComponentModel.Activity.MarkCompleted() at System.Workflow.ComponentModel.ActivityExecutionContext.CloseActivity() at System.Workflow.ComponentModel.ActivityExecutorOperation.Run(IWorkflowCoreRuntime workflowCoreRuntime) at System.Workflow.Runtime.Scheduler.Run() Inner Exception: System.Runtime.Serialization.SerializationException: Type 'Inogic' in Assembly 'Inogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph) at System.Workflow.ComponentModel.Activity.Save(Stream stream, IFormatter formatter) at System.Workflow.ComponentModel.Activity.Save(Stream stream) at System.Workflow.Runtime.Hosting.WorkflowPersistenceService.GetDefaultSerializedForm(Activity activity) at Microsoft.Crm.Workflow.CrmWorkflowPersistenceService.SaveWorkflowInstanceState(Activity rootActivity, Boolean unlock) at System.Workflow.Runtime.WorkflowExecutor.Persist(Activity dynamicActivity, Boolean unlock, Boolean needsCompensation)
This is again because of the declaration of the CRM service object at the class level. The variable is not released after the completion of job if the variable is defined at class level and hence conflicts with the steps that follow in the same workflow job.
[CrmWorkflowActivity("Customer Search")]
Public partial class CustomerSearch: Activity
{
public static ICrmService crmservice = null; // or make it as function level reference
…… Execute(…….) { }
………..
}
Moving the ICrmService object declaration from Class level to the Execute method ensure that the object is released upon the completion of the job.
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
ICrmService crmservice = null;
Processing…..
}
hopefully this solution will help you to avoid custom WF error. Any feedback on this blog is commendable.
Subscribe to:
Posts (Atom)