的WebAPI定制型号复杂的抽象对象绑定 [英] WebAPI Custom Model binding of complex abstract object

查看:190
本文介绍了的WebAPI定制型号复杂的抽象对象绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个艰难的一个。我有从JSON结合的模式的问题。我试图解决的多态性,盟友,它会解析(我希望能够在未来添加许多记录类型)记录的类型提供的记录。我试图使用following例如的调用端点但这个例子仅适用于MVC和非Web API的应用程序时要解决我的模型。

我试图用IModelBinder和BindModel(HttpActionContext ActionContext中,ModelBindingContext的BindingContext)写。但是我无法找到ModelMetadataProviders在System.Web.Http命名空间中的等价物。

鸭preciate任何帮助,任何人都可以给。

我有具有以下对象结构的Web API 2应用程序。

 公共抽象类ResourceRecord
{
    公共抽象的字符串类型{搞定; }
}公共类的arecord:ResourceRecord
{
    公共重写字符串类型
    {
        {返回A; }
    }    公共字符串AVAL {搞定;组; }}公共类b立法:ResourceRecord
{
    公共重写字符串类型
    {
        {返回B; }
    }    公共字符串BVAL {搞定;组; }
}公共类RecordCollection
{
    公共字符串ID {搞定;组; }    公共字符串名称{;组; }    公开名单< ResourceRecord>记录{搞定; }    公共RecordCollection()
    {
        记录=新的List< ResourceRecord>();
    }
}

JSON结构

  {
  ID:1
  名称:MYNAME
  记录: [
    {
      类型:A,
      安勤:AVAL
    },
    {
      类型:B
      BValue:BVAL
    }
  ]
}


解决方案

经过一番研究,我发现,元数据提供者没有在存在的WebAPI,为了绑定到你必须写自己的复杂的抽象对象。

我开始写一个新的模型结合的方法,通过使用自定义的类型名称JSON序列化,最后我更新了我的端点使用自定义粘合剂。值得注意的是下面将只在身体的要求工作,你必须写在标题中要求别的东西。我建议rel=\"nofollow\">专家的ASP.NET Web API 2亚当·弗里曼的和复杂的对象结合。

我能够使用以下code中的请求的主体序列化我的对象。

的WebAPI配置

 公共静态类WebApiConfig
{
    公共静态无效的注册(HttpConfiguration配置)
    {
        config.Services.Insert(typeof运算(ModelBinderProvider),0,
            新SimpleModelBinderProvider(typeof运算(RecordCollection),新JsonBodyModelBinder< RecordCollection>()));
    }
}

自定义模型绑定

 公共类JsonBodyModelBinder< T> :IModelBinder
{
    公共BOOL BindModel(HttpActionContext ActionContext中,
        ModelBindingContext的BindingContext)
    {
        如果(bindingContext.ModelType!= typeof运算(T))
        {
            返回false;
        }        尝试
        {
            VAR JSON = ExtractRequestJson(ActionContext中);            bindingContext.Model = DeserializeObjectFromJson(JSON);            返回true;
        }
        赶上(JsonException除外)
        {
            bindingContext.ModelState.AddModelError(JsonDeserializationException除外);            返回false;
        }
        返回false;
    }    私有静态ŧDeserializeObjectFromJson(JSON字符串)
    {
        变种粘合剂=新TypeNameSerializationBinder();        VAR OBJ = JsonConvert.DeserializeObject< T>(JSON,新JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.Auto,
            活页夹=粘结剂
        });
        返回OBJ;
    }    私人静态字符串ExtractRequestJson(HttpActionContext ActionContext中)
    {
        VAR内容= actionContext.Request.Content;
        JSON字符串= content.ReadAsStringAsync()结果。
        返回JSON;
    }
}

自定义序列结合

 公共类TypeNameSerializationBinder:SerializationBinder
{
    公共字符串TypeFormat {搞定;私人集; }    公共TypeNameSerializationBinder(字符串typeFormat)
    {
        TypeFormat = typeFormat;
    }    公共覆盖无效BindToName(类型serializedType,出字符串的AssemblyName,字符串出来的typeName)
    {
        的AssemblyName = NULL;
        的typeName = serializedType.Name;
    }    公众覆盖类型BindToType(字符串的AssemblyName,字符串的typeName)
    {
        字符串resolvedTypeName =的String.Format(TypeFormat,typeName的);        返回Type.GetType(resolvedTypeName,真);
    }
}

终点定义

  [HttpPost]
    公共无效后([ModelBinder的(BinderType = typeof运算(JsonBodyModelBinder< RecordCollection>))] RecordCollection recordCollection)
    {
    }

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 resolve to (I want to be able to add many record types in the future). I have attempted to use the following example to resolve my model when calling the endpoint however this example only works for MVC and not Web API applications.

I have attempted to write it using IModelBinder and BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext). However I can't find the equivalent of ModelMetadataProviders in the System.Web.Http namespace.

Appreciate any help anyone can give.

I have a Web API 2 application which has the following object structure.

public abstract class ResourceRecord
{
    public abstract string Type { get; }
}

public class ARecord : ResourceRecord
{
    public override string Type
    {
        get { return "A"; }
    }

    public string AVal { get; set; }

}

public class BRecord : ResourceRecord
{
    public override string Type
    {
        get { return "B"; }
    }

    public string BVal { get; set; }
}

public class RecordCollection
{
    public string Id { get; set; }

    public string Name { get; set; }

    public List<ResourceRecord> Records { get; }

    public RecordCollection()
    {
        Records = new List<ResourceRecord>();
    }
}

JSON Structure

{
  "Id": "1",
  "Name": "myName",
  "Records": [
    {
      "Type": "A",
      "AValue": "AVal"
    },
    {
      "Type": "B",
      "BValue": "BVal"
    }
  ]
}

解决方案

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<RecordCollection>()));
    }
}

Custom model binder

public class JsonBodyModelBinder<T> : 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<T>(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 recordCollection)
    {
    }

这篇关于的WebAPI定制型号复杂的抽象对象绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆