我有两个通过Mongo传递“消息”的.Net(C#)应用程序。一个是 Writer ,另一个是 Reader 。 _t 类型鉴别器导致我反序列化问题。
这是他们用来与之沟通的公共类的简化版本:
public class MyMessage {
public long Id {get; set;}
public string MessageText {get; set;}
public dynamic OriginalObject{get; set;}
}
Writer 应用实际上是通过映射来自 Reader 应用程序未知的其他类型的值来创建 MyMessage 的实例。它映射出已知的公共元素,然后将整个原始对象分配给动态 OriginalObject 属性。
public MyMessage CreateMessage(SomeOtherType originalMsg) {
return new MyMessage {
MessageText = originalMsg.SomeField,
OriginalObject = originalMsg
};
}
当.Net Mongo驱动程序序列化 MyMessage 时,它会将 _t 类型鉴别器添加到 OriginalObject 子文档中。
但是, Reader 应用程序没有引用 Writer 所做的所有类型。当 Reader 应用程序尝试反序列化 MyMessage 时,只要 OriginalObject 是它没有的类型,就会抛出Unknown discriminator value
错误。
我已经读过,只要实际类型与名义类型不匹配,就会添加 _t 类型鉴别器。这在真正的多态,强类型场景中是有意义的。但是现在C#有动态类型,我想用它。
此外,如果 MyMessage.OriginalMessage 的实例是纯粹的匿名类型,它可以完美地运行。没有写入 _t 类型鉴别器。 Reader 应用程序愉快地将其反序列化为动态(expando)对象,一切正常。只有当 OriginalMessage 的实例是某种强类型时才会出现此问题。
如何告诉Mongo Driver不要为动态类型添加_t类型鉴别器? 我也对其他解决方案/解决方案感兴趣,但只是排除 _t 将是我的首选方法。
.Net Framework 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"
}
答案 0 :(得分:0)
您可以使用Project
在提取时排除项目,如下所示:
return await this.GetCollection()
.Find(filter: new BsonDocument("_id", handle))
.Project(Builders<BsonDocument>.Projection.Exclude("_t"))
.FirstAsync();
答案 1 :(得分:0)
派对有点晚了,但这是一个禁止歧视者写作的惯例:
ConventionRegistry.Register("No discriminators for message types",
new ConventionPack { new NoDiscriminatorConvention() },
type => typeof(MyMessage).IsAssignableFrom(type));
您可以使用以下方式在应用启动时注册:
MyMessage
如果您已经映射了Id
类,例如要将_id
属性用作MongoDB的BsonClassMap.RegisterClassMap<MyMessage>(cm => {
cm.MapIdMember(m => m.Id).SetSerializer(new StringSerializer(BsonType.ObjectId));
cm.AutoMap();
cm.SetDiscriminatorIsRequired(false); });
元素,您可以在那里执行:
import React, { Component } from 'react'
import './Todo.css'
class Todo extends Component {
constructor (props) {
super(props)
this.state = { deleted: false }
}
clickFunction (event) {
this.setState({ deleted: true })
}
render () {
const classes = ['todo', this.props.className]
return (
{
!this.state.deleted
? <li>
{this.props.todoName}
<button
className={classes.join(' ')}
onClick={this.clickFunction.bind(this)}
value={this.props.value}
>delete</button>
</li>
: null
)
}
}
export default Todo
答案 2 :(得分:0)
在mongodriver 2.10中,mnibic的解决方案对我不起作用。
但是我能够使用 UndiscriminatedActualTypeSerializer 阻止添加_t和_v:
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);
}
}
}
}
程序开头的用法:
ConventionRegistry.Register("No discriminators",
new ConventionPack { new UndiscriminatedActualTypeConvention() },
type => true);