【问题标题】:IReliableQueue Enqueue serialization errorIReliableQueue Enqueue 序列化错误
【发布时间】:2016-09-07 15:11:49
【问题描述】:

我在有状态服务结构应用程序中使用可靠队列。 当我试图将一个项目入队时,入队方法抛出异常

使用的代码是

 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 上,它正在抛出异常

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

堆栈跟踪

在 System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract、XmlWriterDelegator xmlWriter、对象 obj、布尔值 verifyKnownType,RuntimeTypeHandle 声明的TypeHandle,类型 声明类型)在 System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, 对象 obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator 作家,对象图,DataContractResolver dataContractResolver)在 System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator 作家,对象图,DataContractResolver dataContractResolver)在 System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator 作家,对象图,DataContractResolver dataContractResolver)在 System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter 作家,对象图)在 Microsoft.ServiceFabric.Replicator.DataContractStateSerializer1.Write(T value, BinaryWriter binaryWriter) at System.Fabric.Store.TStore5.GetValueBytes(TValue currentValue, TValue newValue) 在 System.Fabric.Store.TStore5.<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.DistributedQueue1.d__9.MoveNext() 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.GetResult()
在 TestService.TestService.d__2.MoveNext() 中 D:\Projects\Local\ReliableSerialization\Application1\TestService\TestService.cs:line 51 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.ServiceFabric.Services.Runtime.StatefulServiceReplicaAdapter.d__f.MoveNext()

当我将代码更改为使用具体类型时,它运行良好。

在我的情况下IReliableQueue&lt;CreateCommand&gt;

效果很好。

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

【问题讨论】:

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


【解决方案1】:

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

要利用数据协定中的多态性,您可以使用基类和 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; }
}

还请注意,已知类型属性支持传入一个函数来以编程方式发现子类型,但不要使用它,因为它会以奇怪且难以诊断的方式破坏可升级性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-10-13
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-30
    • 2012-01-01
    相关资源
    最近更新 更多