如何在DTO中使用ASP.NET Web API和Unity?

时间:2017-01-17 14:35:51

标签: c# asp.net-web-api dependency-injection unity-container

我目前正在使用Unity容器在现有的ASP.NET Web API项目中实现依赖项注入。

我已经设法通过配置依赖项解析器将我的服务类注入我的API控制器。

但是对于控制器功能,我必须使用数据传输对象(DTO) 在那个目标中,我无法找到如何使用我的模型合同。

以下是 Web API控制器方法

[HttpPost]
[Route("api/application/save")]
public IHttpActionResult SaveApplication(ApplicationUpdateDTO applicationUpdate)
{
    // Inner code calling service methods expecting IApplication and
    // collections of ITag as parameters.
}

这是 DTO定义

public class ApplicationUpdateDTO
{
    public IApplication Application { get; set; }
    public IEnumerable<int> DeletedTagIds { get; set; }
    public IEnumerable<ITag> AddedTags { get; set; }
    public IEnumerable<int> DeletedPlatformIds { get; set; }
    public IEnumerable<ITag> AddedPlatforms { get; set; }
}

因此,DTO本身已初始化,但不是全部null的属性。

我理解为什么不能设置属性:接口不能实例化,并且它没有任何线索可以使用哪些类。但是由于注册,我的Unity容器确实如此。

  • 是否可以使用此链接&#34;以某种方式初始化DTO属性?
  • 有更好的方法吗?
  

备注:

     
      
  • 如果我在DTO中使用我的界面实现,那么显然可以正常工作。
  •   
  • 控制器方法接收与我的DTO相同的JSON对象。
  •   

修改

我还参考this post尝试了ModelBinder的实施 但对于关于ValueProviderResult的行,我得到了null值。

为方便起见,以下是托德在另一个问题中的答复:

public class CreateSomethingModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        string key = bindingContext.ModelName;
        ValueProviderResult val = bindingContext.ValueProvider.GetValue(key);
        if (val != null)
        {
            string s = val.AttemptedValue as string;
            if (s != null)
            {
                return new CreateSomething(){Title = s; UserId = new Guid(ControllerContext.HttpContext.Request.Headers["userId"]);}
            }
        }
        return null;
    }
}

我从问题的回答中得到的微小差异是使用System.Web.Http.ModelBinding.IModelBinder而不是MVC。

根据要求,以下是我的界面的简要说明 IApplication接口

public interface IApplication
{
    /// <summary>
    /// Identifier of the application.
    /// </summary>
    int Id { get; set; }

    /// <summary>
    /// Name of the application.
    /// </summary>
    string Name { get; set; }

    /// <summary>
    /// Version of the application.
    /// </summary>
    string Version { get; set; }

    /// <summary>
    /// Tags associated to the application.
    /// </summary>
    ICollection<ITag> Tags { get; }
}

ITag界面

public interface ITag
{
    /// <summary>
    /// Identifier of the tag.
    /// </summary>
    int Id { get; set; }

    /// <summary>
    /// Identifier of the application to which the tag is linked.
    /// </summary>
    int ApplicationId { get; set; }

    /// <summary>
    /// Value of the tag.
    /// </summary>
    string Value { get; set; }
}

JSON

的示例
{
    "marketApplication": {
      "Id": 20,
      "Name": "MyApplication",
      "Version": "2.0"
    },
    "deletedTagIds": [],
    "addedTags": [
      {
        "Id": 0,
        "Value": "NewTag"
      }
    ],
    "deletedProgramIds": [],
    "addedPrograms": [
      {
        "Id": 0,
        "Name": "x86"
      }
    ]
}

1 个答案:

答案 0 :(得分:2)

依赖注入是组合松耦合组件图形的实践。组件是系统中包含行为的类。

依赖注入并不意味着构建仅包含数据的对象。使用依赖注入我们构建组件图。在构建了该图之后(使用构造函数注入),我们使用方法调用将运行时数据传递给该图。

每次尝试使用依赖注入或DI容器(如Unity)时,都会遇到麻烦。因此,尽管您的问题表明您希望使用Unity执行此操作,但Unity应该被排除在等式之外(针对此特定情况)。

正如其他人已经说过的那样,通过请求构建的数据传输对象(DTO)是Web API的Model Binder的工作。默认的模型绑定器不能为您反序列化接口,这是非常明显的;他们应该反序列化什么实现?

虽然您可以替换默认的模型绑定器,但您应该退后一步,仔细查看您要实现的目标。你正在抽象数据。隐藏抽象背后的DTO通常没什么意义,因为接口意味着抽象行为

因此,不是使用接口,而是使用具体类通常要好得多。

  

它可以节省来自&#34; sub-DTO&#34;手动具体的

更简单的方法是使用组合,而不是这样做。您可以使用较小的DTO组成DTO。这样可以避免完全复制。

  

使用我的Unity容器中注册的匹配类型。

这假设这些DTO应该在容器中注册,但同样,DI容器不应该保存任何运行时数据。这应该被禁止。或者如上所述here

  

在构建过程中不要将运行时数据注入应用程序组件中;它会导致歧义,使组合根变得更加复杂,并且使得验证DI配置的正确性变得非常困难。我的建议是让运行时数据流过构造对象图的方法调用。

<强>更新

组合的想法很简单,您可以从较小的类构建类;而不是使用继承或复制对象结构。在您的情况下,这看起来如何显然取决于您的需求,但我想您希望将ITag数据复制到另一个具有更多属性的类:

public class SomeObject
{
    // Members:
    public string Name { get; set; }
    public string Description { get; set; }

    // Members to copy from ITag
    public int Id { get; set; }
    public int ApplicationId { get; set; }
    public string Value { get; set; }

    // more members
}

相反,您可以从具体的SomeObject DTO中撰写 Tag

public class SomeObject
{
    // Members:
    public string Name { get; set; }
    public string Description { get; set; }

    public Tag Tag { get; set; }

    // more members
}

这样您就不必复制Tag个成员;您只需要设置Tag属性,并引用反序列化的Tag DTO。