WebAPI Custom Model binding of complex abstract object

后端 未结 2 1545
野性不改
野性不改 2020-12-15 11:43

This is a tough one. I have an issue with binding a model from JSON. I am attempting to resolve polymorphic-ally the record supplied with the type of record that it will res

2条回答
  •  忘掉有多难
    2020-12-15 12:26

    After some research I discovered that metadata providers don't exist within WebAPI and in order to bind to complex abstract objects you have to write your own.

    I started by writing a new model binding method, with the use of a custom type name JSon serializer and finally I updated my endpoint to use the custom binder. It's worth noting the following will only work with requests in the body, you will have to write something else for requests in the header. I would suggest a read of chapter 16 of Adam Freeman's Expert ASP.NET Web API 2 for MVC Developers and complex object binding.

    I was able to serialize my object from the body of the request using the following code.

    WebAPI configuration

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Services.Insert(typeof(ModelBinderProvider), 0,
                new SimpleModelBinderProvider(typeof(RecordCollection), new JsonBodyModelBinder()));
        }
    }
    

    Custom model binder

    public class JsonBodyModelBinder : IModelBinder
    {
        public bool BindModel(HttpActionContext actionContext,
            ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(T))
            {
                return false;
            }
    
            try
            {
                var json = ExtractRequestJson(actionContext);
    
                bindingContext.Model = DeserializeObjectFromJson(json);
    
                return true;
            }
            catch (JsonException exception)
            {
                bindingContext.ModelState.AddModelError("JsonDeserializationException", exception);
    
                return false;
            }
    
    
            return false;
        }
    
        private static T DeserializeObjectFromJson(string json)
        {
            var binder = new TypeNameSerializationBinder("");
    
            var obj = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.Auto,
                Binder = binder
            });
            return obj;
        }
    
        private static string ExtractRequestJson(HttpActionContext actionContext)
        {
            var content = actionContext.Request.Content;
            string json = content.ReadAsStringAsync().Result;
            return json;
        }
    }
    

    Custom Serialization binding

    public class TypeNameSerializationBinder : SerializationBinder
    {
        public string TypeFormat { get; private set; }
    
        public TypeNameSerializationBinder(string typeFormat)
        {
            TypeFormat = typeFormat;
        }
    
        public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
        {
            assemblyName = null;
            typeName = serializedType.Name;
        }
    
        public override Type BindToType(string assemblyName, string typeName)
        {
            string resolvedTypeName = string.Format(TypeFormat, typeName);
    
            return Type.GetType(resolvedTypeName, true);
        }
    }
    

    End point definition

        [HttpPost]
        public void Post([ModelBinder(BinderType = typeof(JsonBodyModelBinder))]RecordCollection recordCollection)
        {
        }
    

提交回复
热议问题