DataContract model binding to JSON in ASP.NET MVC Action Method Arguments

╄→尐↘猪︶ㄣ 提交于 2019-12-04 04:59:01

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.

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

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);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!