2016-05-17 147 views
3

这是一个棘手的问题。我有一个从JSON绑定模型的问题。我试图解决多态的记录提供了它将解决的记录类型(我希望能够在将来添加多种记录类型)。我试图在调用端点时使用following example来解析我的模型,但是此示例仅适用于MVC而不适用于Web API应用程序。复杂抽象对象的WebAPI自定义模型绑定

我试图用IModelBinder和BindModel(HttpActionContext actionContext,ModelBindingContext bindingContext)编写它。但是我无法在System.Web.Http命名空间中找到等效的ModelMetadataProviders。

欣赏任何人都可以给的帮助。

我有一个Web API 2应用程序,它具有以下对象结构。

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结构

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

的[网页API模型绑定和多态传承]可能的复制(http://stackoverflow.com/questions/17277578/web-api-model-binding-and-polymorphic-inheritence ) – Kamo

+2

这是我在我的问题中使用的示例。为这个问题提供的答案是MVC模型绑定,我需要Web API模型绑定。 – garyamorris

回答

10

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

我开始写一个新的模型绑定方法,使用自定义类型名称JSon序列化程序,最后我更新了我的端点以使用自定义绑定器。值得注意的是,以下内容仅适用于正文中的请求,您必须在标题中为请求写入其他内容。我会建议阅读Adam Freeman的Expert ASP.NET Web API 2 for MVC Developers的第16章和复杂的对象绑定。

我能够使用下面的代码从请求的主体序列化我的对象。

的WebAPI配置

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

自定义模型粘合剂

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

自定义序列结合

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

终点定义

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

不是'BindModel'实现不可达代码中的最后一个'return false;'语句吗? – bump