如何让控制器从发布的JSON对象设置ObjectId

时间:2013-09-11 21:06:50

标签: c# asp.net-mvc-4 mongodb-.net-driver

我有一个控制器,用于添加或编辑作为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解析为User,以便在ObjectId存在时正确设置它?

2 个答案:

答案 0 :(得分:1)

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

您可以为User创建自定义模型绑定器并在其中反序列化该对象,也可以user SaveOrUpdateUser string Newtonsoft.Json.JsonConvert.DeserializeObject<User>(jsonString) JsonConverter {{1}}那里的反序列化。

在任何一种情况下,代码都是:

{{1}}

Newtonsoft的JSON反序列化非常复杂,我对其工作方式印象非常深刻,甚至将一些JSON反序列化为一个自定义对象,该对象具有另一个自定义类型的Dictionary作为其属性之一。话虽如此,如果无法通过默认配置弄清楚,您可以通过创建自定义{{1}}来帮助解决问题。我自己没有这样做,所以我必须先测试一个例子才能提供指导。

答案 1 :(得分: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(),然后应用{{1} } [JsonConverter(typeof(ObjectIdConverter))]

中的Id属性

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