ProtoContract 打破了 XmlMediaTypeFormatter 的行为

ProtoContract breaks XmlMediaTypeFormatter behavior

我有一个 ASP.NET 网络应用程序需要以 JSON、XML 和 ProtoBuf 的形式接收请求。为了让 ProtoBuf 工作,我需要用 [ProtoContract] 注释 DTO,但是一旦我这样做,XML 就会停止工作。

我可以将问题归结为 [ProtoContract]。我做了这个小测试应用程序:

class Program
{
    static void Main(string[] args)
    {
        var ser = new XmlMediaTypeFormatter();
        ser.UseXmlSerializer = true;
        Console.WriteLine($"With ProtoContract: {ser.CanReadType(typeof(Foo))}");
        Console.WriteLine($"Without ProtoContract: {ser.CanReadType(typeof(Foo1))}");
    }
}

[ProtoContract]
public class Foo
{
    [ProtoMember(0)]
    public string Bar { get; set; }
}

public class Foo1
{
    public string Bar1 { get; set; }
}

输出为:

With ProtoContract: False
Without ProtoContract: True

观察很清楚,一旦添加了属性,XmlSerializer 就无法再读取对象。有人经历过类似的行为吗?关于如何解决这个问题的任何想法?

这很有趣 - 我不知道它是怎么做到的,但今晚我会在反射器中查看!

但是,在这种情况下修复很简单:

[ProtoMember(1)]
public string Bar { get; set; }

奇怪的是,我知道要检查这个的原因是 0 在 protobuf 中从来不是合法的标签,但我很感兴趣 XmlMediaTypeFormattercare.

更新:原因是因为XmlSerializer如何访问对象上的属性,但是吞下异常意味着"nope, can't do that"。它成为您实际问题的牺牲品;尝试:

new XmlSerializer(typeof(Foo));

你应该看到:

Unhandled Exception: System.InvalidOperationException: There was an error reflecting type 'Foo'. ---> System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: tag
   at ProtoBuf.ProtoMemberAttribute..ctor(Int32 tag) in c:\Dev\protobuf-net\protobuf-net\ProtoMemberAttribute.cs:line 47
   at System.Reflection.CustomAttribute._CreateCaObject(RuntimeModule pModule, IRuntimeMethodInfo pCtor, Byte** ppBlob, Byte* pEndBlob, Int32* pcNamedArgs)
   at System.Reflection.CustomAttribute.CreateCaObject(RuntimeModule module, IRuntimeMethodInfo ctor, IntPtr& blob, IntPtr blobEnd, Int32& namedArgs)
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType, Boolean mustBeInheritable, IList derivedAttributes, Boolean isDecoratedTargetSecurityTransparent)

等等,这只是ProtoMembmerAttribute抱怨非法标签。