2

我有一个控制器,它添加或编辑一个作为 JSON 对象发送到控制器的实体。

这是控制器:

public JsonResult SaveOrUpdateUser(User user)
{
    Collection.Save(user);
    //Collection is MongoDB.Driver.MongoCollection<User>
    return Json(user);
}

如果用户是新用户,则一切正常。mongo 驱动程序按应有的方式设置 ID,并返回带有 ID 设置的新用户。但是,如果用户是现有用户,并且我正在更新某些内容,mongo 认为它是新用户,因为 MVC 似乎无法从我发送的 JSON 中自动设置 ObjectId。

现有用户的 JSON如下所示(为简洁而编辑)

{
    "Id": "5230d5c5eae61521585eda99",
    "Username": "someone@domain.com",
    "Password": "newpassword"
}

和 C# 用户类:

public class User
{
    public ObjectId Id {get; set;}
    public string Username {get; set;}
    public string Password {get; set;}
}

但是,user当被 MVC 解析时,看起来像这样:

ObjectId Id = ObjectId(000000000000000000000000);
string Username = "someone@domain.com";
string Password = "newpassword";

因此,就 mongo 驱动程序而言,这是一个新实体。那么,有没有办法控制 MVC 如何将 JSON 解析为 aUser以便正确设置 ObjectId(如果存在)?

4

2 回答 2

1

使用默认的 Model Binder 反序列化 JSON 时,我从来没有这么幸运过。尝试使用 Newtonsoft 的库,我相信它包含在 Visual Studio 2012 中的 MVC 4 项目中。如果没有,您应该能够在 Nuget 包管理器中找到它。

您可以创建自定义模型绑定User器并在那里反序列化对象,或者您可以将user参数设置为SaveOrUpdateUsera string,然后在那里进行反序列化。

无论哪种情况,代码都很简单:

Newtonsoft.Json.JsonConvert.DeserializeObject<User>(jsonString)

Newtonsoft 的 JSON 反序列化非常复杂,它的工作方式给我留下了深刻的印象,即使将一些 JSON 反序列化为自定义对象,该对象具有另一种自定义类型的 Dictionary 作为其属性之一。话虽如此,如果使用默认配置无法解决问题,您可以通过创建自定义JsonConverter. 我自己没有这样做,所以我必须先测试一个例子,然后才能提供指导。

于 2013-09-12T02:24:57.043 回答
0

经过一番搜索,我发现了如何处理这个问题。我想避免为每个请求手动反序列化 JSON 对象(即使我有一个通用的工厂方法),并且更希望该对象由控制器自动绑定。

答案是创建一个自定义模型绑定器来覆盖BindModel(). System.Web.Mvc由于这是我存储在 Mongo 中的任何实体的问题,而不仅仅是User类,我的自定义模型绑定器需要是通用的,这样我就不必为我拥有的每个实体创建一个很大程度上冗余的模型绑定器。

这是这个类的样子:

public class MongoEntityDataBinder<T> : DefaultModelBinder where T: IDataEntity
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        string body;
        using(var stream = controllerContext.HttpContext.Request.InputStream)
        {
            stream.Seek(0, SeekOrigin.Begin);
            using(var reader = new StreamReader(stream))
            {
                body = reader.ReadToEnd();
            }
        }

        if(string.IsNullOrEmpty(body)) return null;

        try
        {
            return JsonConvert.DeserializeObject<T>(body);
        }
        catch(Exception)
        {
            return null;
        }
    }
}

接下来,需要注册这个自定义模型绑定器,所以在 Global.asax 中:

ModelBinders.Binders.Add(typeof(MongoEntityDataBinder<IDataEntity>), new MongoEntityDataBinder<IDataEntity>());

最后,我的控制器现在看起来像这样:

public JsonResult SaveOrEditUser([ModelBinder(typeof(MongoEntityDataBinder<User>))] User user)
{
    //Function body
}

最后要注意的一件事是,Json.NET 本身也不知道如何序列化/反序列化 ObjectId,所以我还需要覆盖Newtonsoft.Json.JsonConverter.WriteJson()然后Newtonsoft.Json.JsonConverter.ReadJson()应用[JsonConverter(typeof(ObjectIdConverter))]到 Id 属性IDataEntity

这篇文章是一个很好的起点:ASP.NET Custom Model Binder

于 2013-09-12T14:36:16.507 回答