自定义类包含另一个自定义类时的 DataContractResolver / KnownType 问题
我正在尝试使用 DataContractJsonSerializer 类将对象列表输出为 json 格式,但是我不断遇到以下错误。
Type 'Castle.Proxies.JokeCategoryProxy' with data contract name
'JokeCategoryProxy:http://schemas.datacontract.org/2004/07/Castle.Proxies'
is not expected. Consider using a DataContractResolver or add any types not
known statically to the list of known types - for example, by using the
KnownTypeAttribute attribute or by adding them to the list of known
types passed to DataContractSerializer.
我知道这个问题之前已经得到了回答,但似乎只有当我的对象中有一个属性是另一个自定义对象时才会发生。
[DataContract]
[KnownType(typeof(ModelBase<int>))]
public class Joke : ModelBase<int>
{
[DataMember]
public virtual string JokeText { get; set; }
[DataMember]
public virtual JokeCategory JokeCategory { get; set; }
}
[DataContract]
[KnownType(typeof(ModelBase<int>))]
public class JokeCategory : ModelBase<int>
{
[DataMember]
public virtual string Name { get; set; }
}
正如您所看到的,笑话模型包含一个笑话类别对象,如果我删除笑话类别并仅具有一个 int (JokeCategoryId),则错误就会消失,尽管这是一种解决方案,但不是理想的解决方案,因为我希望在不具有可用类别的情况下提供类别再次查询。
下面是我用来生成 json 的代码
public static ContentResult JsonResponse<TReturnType>(this Controller controller, TReturnType data)
{
using (var oStream = new System.IO.MemoryStream())
{
new DataContractJsonSerializer(typeof(TReturnType)).WriteObject(oStream, data);
return new ContentResult
{
ContentType = "application/json",
Content = Encoding.UTF8.GetString(oStream.ToArray()),
ContentEncoding = Encoding.UTF8
};
}
}
最让我困惑的是错误引用了 Castle.Proxies.JokeCategoryProxy (这是从哪里来的?!)
有什么建议吗?
I'm trying to output a list of objects to a json format using the DataContractJsonSerializer class however I keep running into the following error.
Type 'Castle.Proxies.JokeCategoryProxy' with data contract name
'JokeCategoryProxy:http://schemas.datacontract.org/2004/07/Castle.Proxies'
is not expected. Consider using a DataContractResolver or add any types not
known statically to the list of known types - for example, by using the
KnownTypeAttribute attribute or by adding them to the list of known
types passed to DataContractSerializer.
I know this has been answered before but it only seems to happen when in my object a have a property which is another custom object.
[DataContract]
[KnownType(typeof(ModelBase<int>))]
public class Joke : ModelBase<int>
{
[DataMember]
public virtual string JokeText { get; set; }
[DataMember]
public virtual JokeCategory JokeCategory { get; set; }
}
[DataContract]
[KnownType(typeof(ModelBase<int>))]
public class JokeCategory : ModelBase<int>
{
[DataMember]
public virtual string Name { get; set; }
}
As you can see the Joke model contains a Joke Category object, if I remove the Joke Category and simply have an int (JokeCategoryId) the error disappears, although a solution, not an ideal one as I would like to have the Category available without having to query again.
Below is the code I'm using to generate the json
public static ContentResult JsonResponse<TReturnType>(this Controller controller, TReturnType data)
{
using (var oStream = new System.IO.MemoryStream())
{
new DataContractJsonSerializer(typeof(TReturnType)).WriteObject(oStream, data);
return new ContentResult
{
ContentType = "application/json",
Content = Encoding.UTF8.GetString(oStream.ToArray()),
ContentEncoding = Encoding.UTF8
};
}
}
What confuses me the most is that the error references Castle.Proxies.JokeCategoryProxy (where did this come from?!)
Any suggestions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
nHibernate 假定您的所有属性(除非另有指定)都是延迟加载的。
这意味着,在您的情况下,每当您提取
Joke
对象时,都不会从数据库中提取JokeCategory
;相反,“代理”是动态生成的。第一次访问该属性时,nHibernate 知道从数据库中提取它。 (这就是 nHib 延迟加载的工作原理)
所以基本上这里发生的事情是您希望您的
JokeCategory
是JokeCategory
类型,但因为它没有真正初始化- 它的类型为Proxy...
。(这只是一个简短的解释;谷歌更多有关 nHib 及其工作原理的信息,以了解更多信息。您还可以查看 nhibernate 之夏对这个 ORM 的一个很好的介绍)
并且,对于你的问题:你在这里有几个选项:
将你的 Category 属性配置为非惰性的,这将强制 nHibernate 使用正确的对象类型初始化它
初始化它(在我看来更可取)不要序列化您的模型实体;相反,构建某种 DTO 来保存表示层所需的任何信息。
这样您的演示文稿就不会受到域模型更改的影响,反之亦然。
此外,您可以在 DTO 中保存所有必要的信息,即使它与多个模型实体相关。
例如:
nHibernate assumes that all your properties, unless specified otherwise, are lazy-loaded.
What that means is that, in your case, the
JokeCategory
isn't pulled from the DB whenever you pull yourJoke
object; instead, a 'proxy' is generated dynamically.The first time you access that property nHibernate knows to pull it from the DB. (this is how nHib's lazy-loading works)
So basically what's going on here is that you expect your
JokeCategory
to be of typeJokeCategory
, but since it isn't really initialized- it's of typeProxy...
.(this is just a brief explanation; google some more on nHib and how it works to find out more. you can also check out summer of nhibernate for a great introduction to this ORM)
And, to your question: you have a couple of options here:
configure you Category property as non-lazy, which will force nHibernate to initialize it with the proper object type
(much more preferable, in my opinion) do not serialize your Model entities; instead- build some sort of DTO that will hold whatever information your presentation layer needs.
This way your presentation needn't be affected by changes to the domain model and vice versa.
also, you can hold all the necessary information in your DTO, even if it's related to more than one Model entity.
For example: