Steven Blom
Steven Blom

Reputation: 345

Task`1 cannot be serialized for Web Application referencing BCL.Async

We recently deployed a newly developed pre-compiled service to our test domain and received the following error:

Type 'System.Threading.Tasks.Task`1[Domain.Infrastructure.Contracts.Configuration.DomainServices]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.  If the type is a collection, consider marking it with the CollectionDataContractAttribute.  See the Microsoft .NET Framework documentation for other supported types. 

The server is Windows 2008R2 running .NET 4.0.

There has been a few Stack Overflow questions about this, but most seem to be referring to the CTP release of Async. Apparently you MUST have .NET 4.5 installed on the server in order to use this code.

Has this situation changed at all with the release of the BCL.Async NuGet package?

I was under the impression that code that was compiled with an Async compiler and includes the BCL libraries from NuGet had everything they needed to run in a .NET 4 environment.

Is it still the case that we have to upgrade the .NET runtime on the server to 4.5?

Edit: Stack Trace Provided:

[InvalidDataContractException: Type 'System.Threading.Tasks.Task`1[Domain.Infrastructure.Contracts.Configuration.DomainServices]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.  If the type is a collection, consider marking it with the CollectionDataContractAttribute.  See the Microsoft .NET Framework documentation for other supported types.]
System.Runtime.Serialization.DataContractCriticalHelper.ThrowInvalidDataContractException(String message, Type type) +1184850
System.Runtime.Serialization.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type) +787
System.Runtime.Serialization.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type) +117
System.Runtime.Serialization.XsdDataContractExporter.GetSchemaTypeName(Type type) +85
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.CreatePartInfo(MessagePartDescription part, OperationFormatStyle style, DataContractSerializerOperationBehavior serializerFactory) +48
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.CreateMessageInfo(DataContractFormatAttribute dataContractFormatAttribute, MessageDescription messageDescription, DataContractSerializerOperationBehavior serializerFactory) +708
System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter..ctor(OperationDescription description, DataContractFormatAttribute dataContractFormatAttribute, DataContractSerializerOperationBehavior serializerFactory) +570
System.ServiceModel.Description.DataContractSerializerOperationBehavior.GetFormatter(OperationDescription operation, Boolean& formatRequest, Boolean& formatReply, Boolean isProxy) +308
System.ServiceModel.Description.DataContractSerializerOperationBehavior.System.ServiceModel.Description.IOperationBehavior.ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch) +69
System.ServiceModel.Description.DispatcherBuilder.BindOperations(ContractDescription contract, ClientRuntime proxy, DispatchRuntime dispatch) +120
System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) +4250
System.ServiceModel.ServiceHostBase.InitializeRuntime() +82
System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) +64
System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +789
System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +255
System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +1172

[ServiceActivationException: The service '/Services/Binary/Endpoint.svc' cannot be activated due to an exception during compilation.  The exception message is: Type 'System.Threading.Tasks.Task`1[Domain.Infrastructure.Contracts.Configuration.DomainServices]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.  If the type is a collection, consider marking it with the CollectionDataContractAttribute.  See the Microsoft .NET Framework documentation for other supported types..]
System.Runtime.AsyncResult.End(IAsyncResult result) +901504
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +178638
System.Web.AsyncEventExecutionStep.OnAsyncEventCompletion(IAsyncResult ar) +107

Upvotes: 2

Views: 2615

Answers (1)

Adam Maras
Adam Maras

Reputation: 26853

Okay, I'm going to take a good guess here that you're trying to expose an asynchronous WCF operation that returns a Task<Domain.Infrastructure.Contracts.Configuration.DomainServices>. While Microsoft.Bcl.Async will allow you to compile code that uses tasks, it won't provide the .NET Framework 4.5 changes to WCF that allow you to use tasks in services.

That being said, you can still use the asynchronous programming model to expose the asynchronous method to WCF, while still writing the code using the TPL. To do so, you'll have to wrap the method with APM begin/end methods. Something like this:

[ServiceContractAttribute]
public interface ISampleService
{
    [OperationContractAttribute]
    string SampleMethod();

    [OperationContractAttribute(AsyncPattern = true)]
    IAsyncResult BeginSampleMethod(AsyncCallback callback, object asyncState);

    string EndSampleMethod(IAsyncResult result);
}

public class SampleService : ISampleService
{
    // the async method needs to be private so that WCF doesn't try to
    // understand its return type of Task<string>
    private async Task<string> SampleMethodAsync()
    {
        // perform your async operation here
    }

    public string SampleMethod()
    {
        return this.SampleMethodAsync().Result;
    }

    public IAsyncResult BeginSampleMethod(AsyncCallback callback, object asyncState)
    {
        var task = this.SampleMethodAsync();
        if (callback != null)
        {
            task.ContinueWith(_ => callback(task));
        }

        return task;
    }

    public string EndSampleMethod(IAsyncResult result)
    {
        return ((Task<string>)result).Result;
    }
}

Upvotes: 8

Related Questions