Chris Dunaway

I have a custom activity with a replicator and listener and when the activity executes in the workflow, the following exception is thrown:


Workflow Terminated: ac237c1c-4a7e-44ec-b44c-169d7ecbc885 : Type 'Leggett.SAAF.BusinessObject.ApprovalItem' in Assembly 'Leggett.SAAF.BusinessObject, 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(Type objectType, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter)
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Type objectType, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArray(WriteObjectInfo objectInfo, NameInfo memberNameInfo, WriteObjectInfo memberObjectInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
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 System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService.SaveWorkflowInstanceState(Activity rootActivity, Boolean unlock)
at System.Workflow.Runtime.WorkflowExecutor.Persist(Activity dynamicActivity, Boolean unlock, Boolean needsCompensation)


The class in question, however, is not a public property or private field of the activity. Why is it trying to serialize an instance of this object. The Activity has a Dependency Property called RequestId which is an int. That property is used to load an instance of the ApprovalItem class from the database, but there is no reason this instance should be serialized.

What's going on here

Thanks,

Chris


Re: Windows Workflow Foundation Exception when executing custom activity

Saurabh Chechi - MSFT

Hi Chris,

If you are not referencing this class anywhere inside the workflow or custom activity, you should not get this exception. Can you send me the solution by mail (id is in my profile) or a small repro if this is a proprietary information. I will be interested in taking a look.

Thanks






Re: Windows Workflow Foundation Exception when executing custom activity

Chris Dunaway

Sorry about taking so long to respond.

As yet, I do not have a small app that can repro the problem. Sending the project is not an option as my company would probably object and it;s too large, and you would not be able to run it without the database. I will try to post portions of the code, but I'm not sure it will help.

The project is a web app. Once the workflow commences, we have an activity called ApproveRequestActivity. The code for this activity is as follows:


public partial class ApproveRequestActivity: SequenceActivity
{
private static DependencyProperty RequestIDProperty =
DependencyProperty.Register("RequestID", typeof(int), typeof(ApproveRequestActivity));
private static DependencyProperty RequestApprovalURLProperty =
DependencyProperty.Register("RequestApprovalURL", typeof(string), typeof(ApproveRequestActivity));

[NonSerialized]
private Request _request = null;

[NonSerialized]
private IFormDALService _dalService = null;

[NonSerialized]
private FormDAL _formDAL = null;

public int RequestID {
get { return (int)GetValue(RequestIDProperty); }
set { SetValue(RequestIDProperty, value); }
}

public string RequestApprovalURL {
get { return (string)GetValue(RequestApprovalURLProperty); }
set { SetValue(RequestApprovalURLProperty, value); }
}

public ApproveRequestActivity()
{
InitializeComponent();
}

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) {
_dalService = executionContext.GetService<FormDALService>();
_formDAL = _dalService.GetFormDAL(WorkflowInstanceId);
_request = _formDAL.GetRequest(this.RequestID);

return base.Execute(executionContext);
}

private void replicatorActivity1_ChildInitialized(object sender, ReplicatorChildEventArgs e) {
SendEmailActivity sendMail = e.Activity as SendEmailActivity;
if (sendMail != default(SendEmailActivity)) {
ApprovalItem approvalItem = e.InstanceData as ApprovalItem;
if (approvalItem == null) throw new ArgumentException("Could not find ApprovalItem");
sendMail.To = approvalItem.Approver.Email;
string accounts = string.Empty;
foreach (Request.AccountInformation accountInfo in _request.Users) {
if (accounts != string.Empty) accounts += ", ";
accounts += accountInfo.FirstName + " " + accountInfo.LastName;
}
sendMail.Body = string.Format(sendMail.Body, accounts, approvalItem.Name);
sendMail.Body += @"

Please follow this link to view and either approve or reject the request:
" + RequestApprovalURL + " requestid=" + RequestID + "&WFInstanceId=" + WorkflowInstanceId.ToString();
}
}

private void replicatorActivity1_Initialized(object sender, EventArgs e) {
if (_request != null)
replicatorActivity1.InitialChildData = _request.RequestedApprovalItems;
}
}



As you can see in the replicatorActivity1_ChildInitialized event, the ApprovalItem class is instantiated privately from the event args. Data from this instance is used to construct an e-mail in the SendEmailActivity which is sent out. The exception does not happen here, however. This activity completes fine and the emails all go out as expected.

The next activity in the workflow is a simple CodeActivity and in it's execute method it simply uses Debug.Writeline to write a message out. This was added just try to follow the execution of the workflow. This activity executes just fine as well.

The next activity is the ApprovalCompleteActivity. This is the activity that has the exception. The code for it is below:


public partial class ApprovalCompleteActivity : SequenceActivity {
private static DependencyProperty RequestIdProperty =
DependencyProperty.Register("RequestId", typeof(int), typeof(ApprovalCompleteActivity));

public int RequestId {
get { return (int)GetValue(RequestIdProperty); }
set { SetValue(RequestIdProperty, value); }
}

[NonSerialized]
private IFormDALService _dalService = null;

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) {

Debug.WriteLine("Executing ApprovalCompleteActivity...");

if (RequestId == -1) {
Debug.Write("RequestId is -1, closing...");
return ActivityExecutionStatus.Closed;
}

_dalService = executionContext.GetService<FormDALService>();

return base.Execute(executionContext);
}

public ApprovalCompleteActivity() {
InitializeComponent();
}

private void replicatorActivity1_ChildInitialized(object sender, ReplicatorChildEventArgs e) {
Debug.WriteLine("Initializing replicator child: " + (e.InstanceData));
}

private void replicatorActivity1_Initialized(object sender, EventArgs e) {
Debug.WriteLine("Replicator Initialized...");

FormDAL _formDAL = _dalService.GetFormDAL(WorkflowInstanceId);
Request _request = _formDAL.GetRequest(this.RequestId);

if (_request.RequestedApprovalItems != null)
replicatorActivity1.InitialChildData = _request.RequestedApprovalItems;
}

private void handleExternalEventActivity2_Invoked(object sender, ExternalDataEventArgs e) {
Debug.WriteLine("HandleExternalEventActivity2 Invoked.");
}
}



In the replicatorActivity1_Initialized event, we take the value of the RequestId dependency property which the activity gets from the previous activity, and use it to get our Request object from our db. The Request object has a RequestedApprovalItems collection which is a List<ApprovalItem> instance.


I had thought that this might be the source of the exception, so I commented this out and just used a locally created List<string> as the InitialChildData. I also commented it out in the previous activity, yet the exception still persists. By the way, this is the complete code for the activities minus the designer generated portion.

I don't know if this makes it any clearer, but this is a brick wall for me. I cannot proceed until I get this resolved. Since neither of the activities has an ApprovalItem instance as a field or property, I don't understand why the workflow is trying to serialize it when it persists!

Thanks again for looking at this.


Chris




Re: Windows Workflow Foundation Exception when executing custom activity

Saurabh Chechi - MSFT

Hi Chris,

You have your non serializable class as part of the event args which is making persistence service to try serialize the class.






Re: Windows Workflow Foundation Exception when executing custom activity

Chris Dunaway

I understand that but I still get the error if I comment that part out. I changed the replicator's InitialChildData to a simple List<string> so that the event args in the replicators ChildInitialized event is only working with strings, yet I still get the exception.

I'll take another look at the code and see if I overlooked something and report back.

Thanks,

Chris




Re: Windows Workflow Foundation Exception when executing custom activity

Chris Dunaway

I went back and commented out the items referring to the ApprovalItem class and this time it did not throw the exception. I must have missed something the first time.

Thanks for the help

Chris