【问题标题】:DataContract model binding to JSON in ASP.NET MVC Action Method ArgumentsDataContract 模型绑定到 ASP.NET MVC 操作方法参数中的 JSON
【发布时间】:2014-06-23 19:42:38
【问题描述】:

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 键名称不同。我希望 datacontract 序列化程序会尝试绑定到属性中提供的名称,但事实并非如此。有没有人有任何解决方法的建议?

编辑

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

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

【问题讨论】:

    标签: c# asp.net-mvc-3 datacontractserializer modelbinders model-binding


    【解决方案1】:

    我最终使用 gt124 的链接 model binder examplea better model binder 来编写我自己的模型绑定逻辑。它最终看起来像这样:

    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。

    【讨论】:

    • 确保替换默认的活页夹:在 Application_Start:ModelBinders.Binders.DefaultBinder = new SmartModelBinder(new [] {new NewtonsoftJsonModelBinder()});
    【解决方案2】:

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

    Model Binder Example

    【讨论】:

    • 这不起作用,响应为= null。我的意思是,我可能会在 js 调用中执行 JSON.Stringify(),但这会让我感到难过。
    • 上面的例子可能足以让你编写一个使用 datacontractjsonserializer 的模型绑定器...
    【解决方案3】:

    不用替换默认binder,写个属性就行了

    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; }
    }
    

    更新现在您可以像这样简单地使用内置的 Json.NET 功能:

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

    如果有必要

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      相关资源
      最近更新 更多