Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# MongoDB驱动程序2.2的动态类型-如何不序列化类型鉴别器?_C#_.net_Mongodb_Mongodb .net Driver - Fatal编程技术网

C# MongoDB驱动程序2.2的动态类型-如何不序列化类型鉴别器?

C# MongoDB驱动程序2.2的动态类型-如何不序列化类型鉴别器?,c#,.net,mongodb,mongodb-.net-driver,C#,.net,Mongodb,Mongodb .net Driver,我有两个.Net(C#)应用程序通过Mongo传递“消息”。一个是作家,另一个是读者。\u t类型鉴别器导致我出现反序列化问题 这是他们用来与之通信的通用类的简化版本: public class MyMessage { public long Id {get; set;} public string MessageText {get; set;} public dynamic OriginalObject{get; set;} } Writer应用程序实际上是通过映射其

我有两个.Net(C#)应用程序通过Mongo传递“消息”。一个是作家,另一个是读者。\u t类型鉴别器导致我出现反序列化问题

这是他们用来与之通信的通用类的简化版本:

public class MyMessage {
    public long Id {get; set;}
    public string MessageText {get; set;}
    public dynamic OriginalObject{get; set;}
}
Writer应用程序实际上是通过映射其他类型的值来创建MyMessage的实例,而Reader应用程序将不知道这些值。它映射出已知的公共元素,然后将整个原始对象指定给dynamic OriginalObject属性

public MyMessage CreateMessage(SomeOtherType originalMsg) {
    return new MyMessage {
        MessageText = originalMsg.SomeField,
        OriginalObject = originalMsg            
    };
}
当.Net Mongo驱动程序序列化MyMessage时,它会将类型鉴别器添加到原始对象子文档中

但是,Reader应用程序并没有引用Writer所引用的所有类型。当读卡器应用程序尝试反序列化MyMessage时,只要OriginalObject是它没有的类型,它就会抛出一个
未知鉴别器值
错误

我已经了解到,只要实际类型与标称类型不匹配,就会添加类型鉴别器。这在真正的多态、强类型场景中是有意义的。但是现在C#有了动态类型,我想使用它

另外,如果MyMessage.OriginalMessage的实例是纯匿名类型,那么它可以完美地工作。没有写入类型鉴别器。Reader应用程序愉快地将其反序列化为动态(expando)对象,一切正常。只有当OriginalMessage的实例是某种强类型时,我才有这个问题

如何告诉Mongo驱动程序不要为动态类型添加类型鉴别器? 我也对其他解决方案/解决方案感兴趣,但我更喜欢的方法是简单地排除\u t

.NETFramework 4.6.1,MongoDB.Driver 2.2.3

更多示例代码:

public void SaveMessages()
{
    var message1 = new MyMessage { 
        Id=1, 
        MessageText="Anonymous Message", 
        OriginalMessage=new{ Field1 = "f1", Field2 = "f2" }
    };
    _collection.InsertOne(message1);  // no _t since OriginalMessage is purely anonymous

    var message2 = new MyMessage { 
        Id=2, 
        MessageText="Strong Message", 
        OriginalMessage=new SomeOtherType{Prop1="p1", Prop2="p2"}
    };
    _collection.InsertOne(message2); // has _t since SomeOtherType is not "dynamic"
}

您可以使用
Project
在获取时排除项目,如下所示:

return await this.GetCollection()
            .Find(filter: new BsonDocument("_id", handle))
            .Project(Builders<BsonDocument>.Projection.Exclude("_t"))
            .FirstAsync();
return等待这个。GetCollection()
.Find(过滤器:新的BsonDocument(“\u id”,句柄))
.Project(Builders.Projection.Exclude(“\t”))
.FirstAsync();

您可以使用
Project
在获取时排除项目,如下所示:

return await this.GetCollection()
            .Find(filter: new BsonDocument("_id", handle))
            .Project(Builders<BsonDocument>.Projection.Exclude("_t"))
            .FirstAsync();
return等待这个。GetCollection()
.Find(过滤器:新的BsonDocument(“\u id”,句柄))
.Project(Builders.Projection.Exclude(“\t”))
.FirstAsync();

派对有点晚了,但这里有一个禁止写入鉴别器的约定:

internal class NoDiscriminatorConvention : ConventionBase, IClassMapConvention
{
    public void Apply(BsonClassMap classMap)
    {
        classMap.SetDiscriminatorIsRequired(false);
    }
}
您可以使用以下方法在应用程序启动时注册:

ConventionRegistry.Register("No discriminators for message types",
        new ConventionPack { new NoDiscriminatorConvention() },
        type => typeof(MyMessage).IsAssignableFrom(type));
如果您已经映射了
MyMessage
类,例如,为了将
Id
属性用作MongoDB的
\u Id
元素,您可以在此处进行映射:

BsonClassMap.RegisterClassMap<MyMessage>(cm => {
    cm.MapIdMember(m => m.Id).SetSerializer(new StringSerializer(BsonType.ObjectId));
    cm.AutoMap();
    cm.SetDiscriminatorIsRequired(false); });
BsonClassMap.RegisterClassMap(cm=>{
cm.MapIdMember(m=>m.Id).SetSerializer(新的StringSerializer(BsonType.ObjectId));
cm.AutoMap();
cm.需要设置鉴别器(假);});

派对有点晚了,但这里有一个禁止写入鉴别器的约定:

internal class NoDiscriminatorConvention : ConventionBase, IClassMapConvention
{
    public void Apply(BsonClassMap classMap)
    {
        classMap.SetDiscriminatorIsRequired(false);
    }
}
您可以使用以下方法在应用程序启动时注册:

ConventionRegistry.Register("No discriminators for message types",
        new ConventionPack { new NoDiscriminatorConvention() },
        type => typeof(MyMessage).IsAssignableFrom(type));
如果您已经映射了
MyMessage
类,例如,为了将
Id
属性用作MongoDB的
\u Id
元素,您可以在此处进行映射:

BsonClassMap.RegisterClassMap<MyMessage>(cm => {
    cm.MapIdMember(m => m.Id).SetSerializer(new StringSerializer(BsonType.ObjectId));
    cm.AutoMap();
    cm.SetDiscriminatorIsRequired(false); });
BsonClassMap.RegisterClassMap(cm=>{
cm.MapIdMember(m=>m.Id).SetSerializer(新的StringSerializer(BsonType.ObjectId));
cm.AutoMap();
cm.需要设置鉴别器(假);});
的解决方案在mongodriver 2.10中对我不起作用

但是我能够使用无差别的DacTualTypeSerializer来防止添加:

public class UndiscriminatedActualTypeConvention : ConventionBase, IClassMapConvention
{
    public void Apply(BsonClassMap cm)
    {
        Type type = cm.ClassType;
        if (type.IsClass
            && type != typeof(string)
            && type != typeof(object)
            && !type.IsAbstract)
        {
            foreach (var memberMap in cm.DeclaredMemberMaps)
            {
                var genericBase = typeof(UndiscriminatedActualTypeSerializer<>);
                var genericType = genericBase.MakeGenericType(new[] { memberMap.MemberType });
                var serializer = genericType
                    .GetProperty("Instance", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)
                    .GetValue(null, null) as IBsonSerializer;

                cm.MapMember(memberMap.MemberInfo).SetSerializer(serializer);
            }
        }
    }
}
mongodriver 2.10的解决方案不适用于我

但是我能够使用无差别的DacTualTypeSerializer来防止添加:

public class UndiscriminatedActualTypeConvention : ConventionBase, IClassMapConvention
{
    public void Apply(BsonClassMap cm)
    {
        Type type = cm.ClassType;
        if (type.IsClass
            && type != typeof(string)
            && type != typeof(object)
            && !type.IsAbstract)
        {
            foreach (var memberMap in cm.DeclaredMemberMaps)
            {
                var genericBase = typeof(UndiscriminatedActualTypeSerializer<>);
                var genericType = genericBase.MakeGenericType(new[] { memberMap.MemberType });
                var serializer = genericType
                    .GetProperty("Instance", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)
                    .GetValue(null, null) as IBsonSerializer;

                cm.MapMember(memberMap.MemberInfo).SetSerializer(serializer);
            }
        }
    }
}

您是否尝试了“BsonDocument”而不是“dynamic”?将MyMessage定义更改为使用强类型,如BsonDocument,效果很好。但我真的希望动态体验能够将其与特定类型(即使特定类型像Bson/Json/Dictionary一样灵活)分离。您是否尝试过“BsonDocument”而不是“dynamic”?将MyMessage定义更改为使用强类型,如BsonDocument,效果很好。但我真的希望这种动态体验能够将它与特定类型解耦(即使特定类型像Bson/Json/Dictionary一样灵活)