ASP.NET MVC 操作方法参数中 DataContract 模型绑定到 JSON

发布于 2024-10-30 23:55:11 字数 1049 浏览 4 评论 0原文

MVC3 带有 JsonValueProviderFactory(),它可以非常方便地将传入的 JSON 绑定到模型。不幸的是,我不知道如何设置名称与传入 JSON 不同的模型合约。例如:

[DataContract(Name = "session")]
public class FacebookSession
{
    [DataMember(Name = "access_token")]
    public string AccessToken { get; set; }

    [DataMember(Name = "expires")]
    public int? Expires { get; set; }

    [DataMember(Name = "secret")]
    public string Secret { get; set; }

    [DataMember(Name = "session_key")]
    public string Sessionkey { get; set; }

    [DataMember(Name = "sig")]
    public string Signature { get; set; }

    [DataMember(Name = "uid")]
    public string UserId { get; set; }
}

当传入表示 facebook 会话的 json 对象时,属性 Secret 和 expires 会正确绑定,但其余属性不会正确绑定,因为属性名称与 json 键名称不同。我希望数据契约序列化器会尝试绑定到属性中提供的名称,但情况似乎并非如此。有人有任何解决方法建议吗?

编辑

我将如何使用此模型的示例:

    public ActionResult Log(int? custId, FacebookSession response)
    {       
          ViewBag.Id = response.UserId;                         
          return View();
    }

MVC3 comes out of the box with JsonValueProviderFactory() which is very handy for binding incoming JSON to a model. Unfortunately, I can't figure out how to setup model contracts with names that differ from the incoming JSON. For example:

[DataContract(Name = "session")]
public class FacebookSession
{
    [DataMember(Name = "access_token")]
    public string AccessToken { get; set; }

    [DataMember(Name = "expires")]
    public int? Expires { get; set; }

    [DataMember(Name = "secret")]
    public string Secret { get; set; }

    [DataMember(Name = "session_key")]
    public string Sessionkey { get; set; }

    [DataMember(Name = "sig")]
    public string Signature { get; set; }

    [DataMember(Name = "uid")]
    public string UserId { get; set; }
}

when passing in a json object representing the facebook session, the properties secret and expires bind properly, but the rest do not because the property name is different than the json key name. I would expect that the datacontract serializer would try and bind to the name provided in the attribute, but that doesn't appear to be the case. Does anyone have any workaround suggestions?

Edit

An example of how I would use this model:

    public ActionResult Log(int? custId, FacebookSession response)
    {       
          ViewBag.Id = response.UserId;                         
          return View();
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

哆兒滾 2024-11-06 23:55:12

我最终使用了 gt124 的链接 模型绑定器示例 以及 一个更好的模型绑定器来编写我自己的模型绑定逻辑。它最终看起来像这样:

public interface IFilteredModelBinder : IModelBinder
    {
        bool IsMatch(Type modelType);
    }

public class SmartModelBinder : DefaultModelBinder
{
    private readonly IFilteredModelBinder[] _filteredModelBinders;

    public SmartModelBinder(IFilteredModelBinder[] filteredModelBinders)
    {
        _filteredModelBinders = filteredModelBinders;
    }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        foreach (var filteredModelBinder in _filteredModelBinders)
        {
            if (filteredModelBinder.IsMatch(bindingContext.ModelType))
            {
                return filteredModelBinder.BindModel(controllerContext, bindingContext);
            }
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

public class NewtonsoftJsonModelBinder : IFilteredModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
        {
            // not JSON request
            return null;
        }

        var request = controllerContext.HttpContext.Request;
        request.InputStream.Position = 0;
        var incomingData = new StreamReader(request.InputStream).ReadToEnd();

        if (String.IsNullOrEmpty(incomingData))
        {
            // no JSON data
            return null;
        }
        object ret = JsonConvert.DeserializeObject(incomingData, bindingContext.ModelType); 
        return ret;
    }

    public bool IsMatch(Type modelType)
    {
        var ret = (typeof(JsonModel).IsAssignableFrom(modelType));
        return ret;
    }
}

然后我使用 JSON.net 属性映射到模型上的不同对象属性(而不是 DataContracts)。这些模型全部继承自空基类 JsonModel。

I ended up using gt124's link model binder example along with a better model binder to write my own model binding logic. It ended up looking like this:

public interface IFilteredModelBinder : IModelBinder
    {
        bool IsMatch(Type modelType);
    }

public class SmartModelBinder : DefaultModelBinder
{
    private readonly IFilteredModelBinder[] _filteredModelBinders;

    public SmartModelBinder(IFilteredModelBinder[] filteredModelBinders)
    {
        _filteredModelBinders = filteredModelBinders;
    }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        foreach (var filteredModelBinder in _filteredModelBinders)
        {
            if (filteredModelBinder.IsMatch(bindingContext.ModelType))
            {
                return filteredModelBinder.BindModel(controllerContext, bindingContext);
            }
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

public class NewtonsoftJsonModelBinder : IFilteredModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
        {
            // not JSON request
            return null;
        }

        var request = controllerContext.HttpContext.Request;
        request.InputStream.Position = 0;
        var incomingData = new StreamReader(request.InputStream).ReadToEnd();

        if (String.IsNullOrEmpty(incomingData))
        {
            // no JSON data
            return null;
        }
        object ret = JsonConvert.DeserializeObject(incomingData, bindingContext.ModelType); 
        return ret;
    }

    public bool IsMatch(Type modelType)
    {
        var ret = (typeof(JsonModel).IsAssignableFrom(modelType));
        return ret;
    }
}

I then used JSON.net attributes to map to the different object properties (instead of DataContracts) on the models. The models all inherited from an empty base class JsonModel.

心舞飞扬 2024-11-06 23:55:12

您可以将其作为字符串传入并手动调用 datacontractdeserializer,除非您编写自己的模型绑定程序。我相信默认的活页夹使用 javascriptserializer,而不是 datacontractjsserializer。

模型绑定器示例

You can pass it in as a string and manually call the datacontractdeserializer, unless you write your own modelbinder. I believe the default binder uses the javascriptserializer, not the datacontractjsserializer.

Model Binder Example

爱冒险 2024-11-06 23:55:12

您不需要替换默认的绑定器,只需编写一个属性,就像

public class DataContractJsonModelBinderAttribute : CustomModelBinderAttribute
{
    public override IModelBinder GetBinder()
    {
        return new DataContractJsonModelBinder();
    }
}

使用起来很简单

[DataContract(Name = "session")]
[DataContractJsonModelBinder]
public class FacebookSession
{
    [DataMember(Name = "access_token")]
    public string AccessToken { get; set; }

    [DataMember(Name = "expires")]
    public int? Expires { get; set; }

    [DataMember(Name = "secret")]
    public string Secret { get; set; }

    [DataMember(Name = "session_key")]
    public string Sessionkey { get; set; }

    [DataMember(Name = "sig")]
    public string Signature { get; set; }

    [DataMember(Name = "uid")]
    public string UserId { get; set; }
}

UPDATE 现在您可以简单地使用内置的 Json.NET 功能,如下所示:

[JsonObject]
public class FacebookSession
{
    [JsonProperty("access_token")]
    public string AccessToken { get; set; }
}

如果需要的话

var facebokSession = JsonConvert.DeserializeObject<FacebookSession>(facebookSessionJsonString);

You don't need to replace the default binder, just write an attribute like that

public class DataContractJsonModelBinderAttribute : CustomModelBinderAttribute
{
    public override IModelBinder GetBinder()
    {
        return new DataContractJsonModelBinder();
    }
}

the using is simple

[DataContract(Name = "session")]
[DataContractJsonModelBinder]
public class FacebookSession
{
    [DataMember(Name = "access_token")]
    public string AccessToken { get; set; }

    [DataMember(Name = "expires")]
    public int? Expires { get; set; }

    [DataMember(Name = "secret")]
    public string Secret { get; set; }

    [DataMember(Name = "session_key")]
    public string Sessionkey { get; set; }

    [DataMember(Name = "sig")]
    public string Signature { get; set; }

    [DataMember(Name = "uid")]
    public string UserId { get; set; }
}

UPDATE Now y can simply use built-in Json.NET functionality like that:

[JsonObject]
public class FacebookSession
{
    [JsonProperty("access_token")]
    public string AccessToken { get; set; }
}

and if necessary

var facebokSession = JsonConvert.DeserializeObject<FacebookSession>(facebookSessionJsonString);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文