【问题标题】:web api model binding to an interfaceweb api模型绑定到接口
【发布时间】:2013-08-21 20:32:45
【问题描述】:

我正在尝试将控制器操作绑定到接口,但仍保持默认绑定行为。

public class CoolClass : ISomeInterface
{
    public DoSomething {get;set;} // ISomeInterface
}

public class DosomethingController : ApiController
{
    public HttpResponseMessage Post(ISomeInterface model)
    {
        // do something with model which should be an instance of CoolClass
    }
} 

我的服务的消费者对 CoolClass 一无所知,所以让他们在传递的 Json 中添加“$type”在我看来是一种黑客行为。我希望能够在服务中处理它。如果我将 CoolClass 指定为操作参数,它就可以正常工作。

编辑:所以我在这里找到了我的问题的部分解决方案Dependency injection for ASP.NET Web API action method parameters,但有一个后续问题。该解决方案不解析接口属性。请参阅下面的示例。

IConcreteClass 将被解析,但 ISubtype 不会。

public class SubConcreteClass : ISubtype
{
    // properties
}

public class ConcreteClass : IConcreteClass
{
    public ISubtype Subtype {get;set;}
}

一旦媒体格式化程序发现它可以解析 IConcreteClass 中的类型,它就会读取整个流。所以我猜没有机会解析接口成员。

【问题讨论】:

  • 另一种选择,请查看我对类似问题的回答here

标签: c# asp.net-mvc asp.net-web-api parameterbinding


【解决方案1】:

所以如果这可以帮助其他人,我会继续发布我想出的解决方案。

上面说过,action方法的接口参数可以用DI来解析。但是该对象的接口成员需要以不同的方式处理。

我创建了两种类型的 Json 转换器,一个实体类型和一个集合类型,来装饰接口属性。

这里有一个类需要解析为动作接口参数。

public class CreateEnvelopeModel : ICreateEnvelopeCommand
{
    [JsonConverter(typeof(EntityModelConverter<CreateEmailModel, ICreateEmailCommand>))]
    public ICreateEmailCommand Email { get; set; }
    [JsonConverter(typeof(CollectionEntityConverter<CreateFormModel, ICreateFormCommand>))]
    public IList<ICreateFormCommand> Forms { get; set; }
}

这是控制器操作方法

public HttpResponseMessage PostEnvelope(ICreateEnvelopeCommand model)
{
    // do stuff
}

这是 2 个 json 转换器

public class EntityModelConverter<T, Tt> : JsonConverter where T : Tt
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Tt));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize<T>(reader);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value, typeof(T));
    }
}

public class CollectionEntityConverter<T, Tt> : JsonConverter where T : Tt
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(IList<Tt>));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        IList<Tt> items = serializer.Deserialize<List<T>>(reader).Cast<Tt>().ToList();
        return items;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value, typeof(IList<T>));
    }
}

【讨论】:

  • 这是一个很好的解决方案。
  • 这非常简单有效。使用 this 与自定义模型绑定有什么缺点吗?关于如何在接口具有多个实现类(例如 IAuto、Car:IAuto、Truck:IAuto)的集合上使用类似的东西有什么想法吗?
【解决方案2】:

查看Model Binders 部分here。我认为这是你的情况。

【讨论】:

  • 谢谢亚历克斯。我看到了那个页面,但我真的希望这可以用我的 DI 容器解决。是不是不能用 DI 解析 API 动作接口参数?
  • 这个建议没有帮助,因为链接的内容不包括通用列表。
猜你喜欢
  • 2016-12-21
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
  • 1970-01-01
  • 2018-01-30
  • 1970-01-01
  • 2012-08-28
  • 1970-01-01
相关资源
最近更新 更多