Showing posts with label Workflow error. Show all posts
Showing posts with label Workflow error. Show all posts

Thursday, February 3, 2011

Issue with Pulishing Workflow that use Custom Workflow Assembly

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.

Tuesday, November 30, 2010

Workflows - Behind the scene

We were recently working on designing a tool that deletes workflow job. We thought it would be easy to just filter out all job that related to a workflow by the workflow id and then delete that’s it.

But like always we were in for a surprise. Just thought putting it down would help others in resolving this mystery.

Each Workflow has a unique id just like any other entity. But if you search for workflow jobs using this id to look for all jobs related to this workflow, you would be in for a surprise. It would not return all of the jobs that you are expecting. The reason being each time you revise a workflow i.e unpublish and publish the workflow once again, it creates a new workflow entry in the tables. If you want to look for the workflow jobs related to a particular workflow then you need to look for the workflow id assigned to each of its versions.

For workflow, you would find the following definitions available in the tables.


There will be only 1 definition record in CRM for a workflow no matter how many times you revise it.


But each time you publish a workflow it will create a new activation record.


The activation workflow record will have its parent workflowid set to the workflow definition id.

The workflow definition record will store the id of the currently active version of the workflow.

If you unpublish a worklfow and publish it again, it will add another row to the table and the status would now be as follows:


Note the activeworkflowid of the Definition record now refers the Guid of the latest version of the workflow that is published.

Now if you want to look for system jobs for this workflow, you will need to search for jobs that have their workflowactivationid set to any of the workflowid listed above in the table.

Hope this helps you find your way through the maze of workflows!!!

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.