IReliableQueue Enqueue序列化错误

时间:2016-09-06 07:36:23

标签: c# serialization azure-service-fabric service-fabric-stateful

我在Stateful服务结构应用程序中使用Reliable Queue。 当我试图将一个项目排队时,Enqueue方法抛出异常

使用的代码是

 protected override async Task RunAsync(CancellationToken cancellationToken)
        {
            ICommand myItem = new CreateCommand()
            {
                Data = "Sample Data",
                Id = Guid.NewGuid(),
                TenentName = "SampleTenant"
            };
            var myQueue = await this.StateManager.GetOrAddAsync<IReliableQueue<ICommand>>("CommandQueue");
            using (var tx = StateManager.CreateTransaction())
            {
                await myQueue.EnqueueAsync(tx, myItem, TimeSpan.FromSeconds(4), cancellationToken);
                await tx.CommitAsync();
            }
            using (var tx = StateManager.CreateTransaction())
            {
                var dq = await myQueue.TryDequeueAsync(tx);
                await tx.CommitAsync();
            }
        }
    }

    public interface ICommand
    {
        Guid Id { get; set; }
        string TenentName { get; set; }
    }


    public class CreateCommand : ICommand
    {
        public Guid Id { get; set; }
        public string TenentName { get; set; }
        public string Data { get; set; }
    }

在myQueue.EnqueueAsync上,它正在抛出异常

  

键入&#39; TestService.CreateCommand&#39;与数据合同名称   &#39; CreateCommand:http://schemas.datacontract.org/2004/07/TestService&#39;是   没想到。如果您正在使用,请考虑使用DataContractResolver   DataContractSerializer或添加静态未知的任何类型   已知类型的列表 - 例如,通过使用KnownTypeAttribute   属性或将它们添加到传递给的已知类型列表中   串行器。

堆栈跟踪

  

在   System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract   dataContract,XmlWriterDelegator xmlWriter,Object obj,Boolean   verifyKnownType,RuntimeTypeHandle declaredTypeHandle,Type   declaredType)at   System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract   dataContract,XmlWriterDelegator xmlWriter,Object obj,   RuntimeTypeHandle originalDeclaredTypeHandle,Type graphType)at   System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator   writer,Object graph,DataContractResolver dataContractResolver)at   System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator   writer,Object graph,DataContractResolver dataContractResolver)at   System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator   writer,Object graph,DataContractResolver dataContractResolver)at   System.Runtime.Serialization.XmlObjectSerializer.WriteObject(的XmlDictionaryWriter   作家,对象图)   Microsoft.ServiceFabric.Replicator.DataContractStateSerializer 1.Write(T value, BinaryWriter binaryWriter) at System.Fabric.Store.TStore 5.GetValueBytes(TValue currentValue,TValue   System.Fabric.Store.TStore 5.<AddAsync>d__4.MoveNext() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.ServiceFabric.Data.Collections.DistributedQueue 1.d__9.MoveNext()中的newValue)   在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)在System.Runtime.CompilerServices.TaskAwaiter.GetResult()
  在TestService.TestService.d__2.MoveNext()中   d:\项目\本地\ ReliableSerialization \应用1 \ TestService的\ TestService.cs:行   51点   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)   Microsoft.ServiceFabric.Services.Runtime.StatefulServiceReplicaAdapter.d__f.MoveNext()

当我更改代码以使用Concrete类型时它工作正常。

在我的案例中IReliableQueue<CreateCommand>

工作得很好。

我的代码参考:https://github.com/Azure-Samples/service-fabric-dotnet-iot/blob/master/src/gateway/IoTProcessorManagement.Common/WorkManagement/WorkManager.cs

1 个答案:

答案 0 :(得分:3)

您在类型上缺少DataContract和DataMember属性,并且由于数据协定序列化的工作方式的实现,您无法将DataContract属性放在接口上。缺少数据协定属性可能导致难以追踪错误,因为Service Fabric将在内部存储对象的引用并在您出队时返回该引用,但在对象在提交时将其发送到辅助节点时序列化该对象。当你忘记所述属性时,你会看到的是它有时似乎会起作用,但是要么投入提交事务,要么在服务重新启动之前你会拥有看似很好的填充对象(对于升级,如果该节点发生故障或其他原因)将为空(缺少属性的字段将为null / default)。

要利用数据协定中的多态性,您可以使用基类和KnownType属性。这是使用添加的删除命令的示例。

[DataContract]
[KnownType(typeof(CreateCommand))]
[KnownType(typeof(DeleteCommand))]
public class BaseCommand
{
    [DataMember]
    public Guid Id { get; set; }

    [DataMember]
    public string TenentName { get; set; }
}

[DataContract]
public class CreateCommand : BaseCommand
{
    [DataMember]
    public string Data { get; set; }
}

[DataContract]
public class DeleteCommand : BaseCommand
{
    [DataMember]
    public string SomeOtherData { get; set; }
}

另请注意,已知类型属性支持传递函数以编程方式发现子类型,但请勿使用它,因为它会破坏奇怪和难以诊断方式的可升级性。