JsonConverter:将c#对象序列化为json对象

时间:2012-10-08 14:22:42

标签: asp.net-mvc json.net ravendb

当使用Json.NET将MVC视图模型序列化为json时,我的视图模型(public object Result { get; set;})上有一个泛型对象属性,它被序列化为键值对而不是实际的json对象。是否有可以使用的转换器强制它被正确序列化?

这是Json.NET目前正在输出的内容:

"result": [
    {
      "key": "AssetId",
      "value": "b8d8fb71-2553-485b-91bf-14c6c563d78b"
    },
    {
      "key": "SearchResultType",
      "value": "Assets"
    },
    {
      "key": "Name",
      "value": "abstract-q-c-1920-1920-8"
    }
  ]

相反,我希望它输出:

"result": {
    "AssetId": "b8d8fb71-2553-485b-91bf-14c6c563d78b",
    "SearchResultType": "Assets",
    "Name": "abstract-q-c-1920-1920-8"
  }

修改: 要回答关于如何填充该属性的问题,它是通过RavenDB索引:

public class SiteSearchIndexTask : AbstractMultiMapIndexCreationTask<SiteSearchResult>
{
    public class Result
    {
        public object[] Content { get; set; }
    }

    public override string IndexName
    {
        get
        {
            return "SiteSearch/All";
        }
    }
    public SiteSearchIndexTask()
    {
        AddMap<Asset>(items => from item in items
                                where item.IsDeleted == false
                               select new 
                                          {
                                              Id = item.Id.ToString(),
                                              ObjectId = item.Id,
                                              ResultType = SearchResultType.Assets,
                                              Title = item.Name.Boost(3),
                                              Tags = item.Tags.Select(x => x.Name).Boost(2),
                                              Result = (object)item,
                                              Query = string.Join(" ", item.Description)
                                          });
        AddMap<User>(items => from item in items
                              where item.IsDeleted == false
                              select new 
                                         {
                                             Id = item.Id,
                                             ObjectId = item.UserId,
                                             ResultType = SearchResultType.Users,
                                             Title = item.Username.Boost(3),
                                             Tags = (BoostedValue) null,
                                             Result = (object)item,
                                             Query = string.Join(" ", item.FullName, item.Email)
                                         });
        Store(x => x.ObjectId, FieldStorage.Yes);
        Store(x => x.ResultType, FieldStorage.Yes);
        Store(x => x.Title, FieldStorage.Yes);
        Store(x => x.Tags, FieldStorage.Yes);
        Store(x => x.Result, FieldStorage.Yes);
        Store(x => x.Query, FieldStorage.Yes);
    }
}

编辑2 以下是资产和用户模型(为简洁而截断,因为它们只是一堆自动属性)

public class Asset : IHasId
{
    public string Id { get; set; }
    public Guid AssetId
    {
        get
        {
            Guid assetId;
            Guid.TryParse((Id ?? string.Empty).Replace("assets/", ""), out assetId);
            return assetId;
        }
        set { Id = "assets/" + value; }
    }

    public string Name { get; set; }
    public string Description { get; set; }
}

public class User : IHasId
{
    public User()
    {
        Status = UserStatus.Active;
    }

    public string Id { get; set; }
    public int UserId
    {
        get
        {
            int userId;
            int.TryParse((Id ?? string.Empty).Replace("users/", ""), out userId);
            return userId;
        }
        set { Id = "users/" + value; }
    }

    public string Username { get; set; }
    public string Password { get; set; }
    public string Email { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public UserStatus Status { get; set; }
}

编辑3 事实证明,当我单步执行代码时,该对象实际上是Raven.Abstractions.Linq.DynamicJsonObject类型,它包含一组键值对。所以我猜这个问题可能与Raven比Json.NET更相关。除非有一个转换器从键值对转到json对象。

1 个答案:

答案 0 :(得分:1)

查看您的查询结果会有所帮助,但您应该查看RavenDB网站上的the example on querying unlike documents with a multimap index

当我查看您的索引时,您似乎在尝试在字段存储和结果封装方面做得太多。它有时很难掌握,但索引中的映射不是定义结果的返回方式,而是定义索引的构建方式。除非您正在执行Reduce或TransformResults步骤,否则您仍将返回原始文档。

因此将文档封装为Result = (object)item是过度的。所以有一个ResultType枚举。如果您需要知道匹配的文档类型,只需在对象上使用.GetType(),您就可以快速查看它是用户还是资产。

以下是我定义搜索索引的方法。请注意,存在一些差异,因为您在索引中显示的属性不在您提供的模型中。 (我假设后端有一个独立的实体,而不是前端的模型,但需要根据需要进行调整。)

public class SearchIndex : AbstractMultiMapIndexCreationTask<SearchIndex.Result>
{
  public class Result
  {
      public object[] Content { get; set; }
      public string ResultType { get; set; }
  }

  public SearchIndex()
  {
      AddMap<Asset>(items => from item in items
                             select new Result
                             {
                               Content = new object[] {item.Name, item.Description},
                               ResultType = MetadataFor(item)["Raven-Entity-Name"].ToString()
                             });

      AddMap<User>(items => from item in items
                            select new Result
                            {
                              Content = new object[] { item.Username, item.FirstName, item.LastName, item.Email },
                              ResultType = MetadataFor(item)["Raven-Entity-Name"].ToString()
                            });

      Index(x => x.Content, FieldIndexing.Analyzed);
    }
}

然后我会这样查询:

var results = session.Advanced
                     .LuceneQuery<object, SearchIndex>()
                     .Where("ResultType:" + resultTypeName)
                     .AndAlso()
                     .Search("Content", searchTerm);

然后,您可以简单地检查结果并发现在转换为object时,您确实可以执行result.GetType()并查看该对象的构造方式。如果需要,您还可以在实体上放置一个公共接口来强制转换为对象,例如Raven示例中显示的IAmSearchable

当你最终通过MVC传回结果时,它应该被正确序列化,因为它将来自真实对象而不是乌鸦DynamicJsonObject。