C# MongoDB驱动程序2.2的动态类型-如何不序列化类型鉴别器?
我有两个.Net(C#)应用程序通过Mongo传递“消息”。一个是作家,另一个是读者。\u t类型鉴别器导致我出现反序列化问题 这是他们用来与之通信的通用类的简化版本: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应用程序实际上是通过映射其
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一样灵活)