自定义类包含另一个自定义类时,DataContractResolver / KnownType问题

时间:2011-07-08 09:56:10

标签: c# .net fluent-nhibernate datacontractserializer known-types

我正在尝试使用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; }
}

正如你可以看到Joke模型包含一个Joke Category对象,如果我删除了Joke Category并且只是有一个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(这是从哪里来的?!)

有什么建议吗?

1 个答案:

答案 0 :(得分:6)

nHibernate假定除非另有说明,否则所有属性都是延迟加载的 这意味着,在您的情况下,每当您拉出JokeCategory对象时,都不会从数据库中提取Joke;相反,动态生成'代理' 第一次访问该属性时,nHibernate知道从数据库中取出它。 (这就是nHib的延迟加载方式)

所以基本上这里发生的是你希望你的JokeCategory属于JokeCategory类型,但由于它没有真正初始化 - 它的类型为Proxy...

(这只是一个简短的解释;谷歌更多关于nHib及其如何工作以了解更多信息。您还可以查看summer of nhibernate以获得对此ORM的精彩介绍)

而且,对于你的问题:你有几个选择:

  1. 将Category属性配置为非惰性,这会强制nHibernate使用正确的对象类型初始化它

  2. (在我看来更为可取)不要序列化您的模型实体;相反 - 构建某种DTO,它将保存您的表示层所需的任何信息 这样,您的演示文稿不会受到域模型更改的影响,反之亦然 此外,您可以在DTO中保存所有必要信息,即使它与多个模型实体相关。

  3. 例如:

      public class JokeDTO
        {
           public int JokeId;
           /*more Joke properties*/
           public int JokeCategoryId;
           public string JokeCategoryName;
           /*etc, etc..*/
        }
    
相关问题