【问题标题】:How to resolve the dependencies of a WebAPI Controller with DryIoc如何使用 DryIoc 解决 WebAPI 控制器的依赖关系
【发布时间】:2017-08-16 19:54:25
【问题描述】:

我一直在阅读文档,但对于如何实现这一点有点困惑。我有一个名为 NewsController 的 WebAPI 控制器,我将在下面列出。它有一个构造函数,当前需要三个依赖项。我为 DryIoc 创建了一个静态类,因此我可以在整个项目中全局使用它,并且它在启动时被初始化。

我想做的是在我的 DryIoc 类中注册控制器及其依赖项,然后以某种方式在 NewsController 控制器中解决它。我想这样做的原因是,当我开始测试时,我可以简单地让测试项目更改注册控制器的范围并使用存根或模拟实现。

注册依赖项

public static class RegisterDependencies
    {
        public static Container container;

    public static void Initialize()
    {
        container = new Container(rules => rules
        .WithDefaultReuseInsteadOfTransient(Reuse.InWebRequest)
        .WithoutThrowOnRegisteringDisposableTransient()
        .WithoutImplicitCheckForReuseMatchingScope());

        container.Register<INewsManager, NewsManager>();
        container.Register<IGetNews, NewsManager>();
        container.Register<IAddNews, NewsManager>();

        container.Register<ILoggingService, Logger>();

        container.Register<NewsController>(made: Made.Of(() => new NewsController
            (Arg.Of<ILoggingService>(), Arg.Of<IGetNews>(), Arg.Of<IAddNews>(),
            Arg.Of<INewsManager>())));
    }
}

NewsController(它的一部分)

public class NewsController : ApiController
    {
        private INewsManager _nm;
        private IGetNews _getNews;
        private IAddNews _addNews;
        private ILoggingService _log;

    public NewsController(ILoggingService logger, IGetNews getNews,
        IAddNews addNews, INewsManager newsManager)
    {
        _getNews = getNews;
        _addNews = addNews;
        _log = logger;
        _nm = newsManager;
    }

    [HttpGet]
    public IHttpActionResult GetNews()
    {

        var newsItems = _getNews.GetNews();

        if (newsItems == null || newsItems.Count() <= 0)
        {
            _log.Error("News Items couldn't be loaded.");

            return NotFound();
        }



        return Ok(Mapper.Map<List<NewsDto>>(newsItems));
    }

更新:

到目前为止,我通过 WebApiConfig 进行了“自动”依赖解析,但我不确定如何从测试项目中访问它,因此我可以用我的存根替换真正的实现。

WebApiConfig

public static void Register(HttpConfiguration config)
        {
        // Web API configuration and services
        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        RegisterDependencies.controllerContainer = new Container(rules => rules.With(FactoryMethod.ConstructorWithResolvableArguments)).WithWebApi(
            config, throwIfUnresolved: type => type.IsController());
        RegisterDependencies.InitializeControllerContainer(RegisterDependencies.controllerContainer);

      }

注册依赖项

public static class RegisterDependencies
    {
        public static IContainer controllerContainer;

        public static void InitializeControllerContainer(IContainer ControllerContainer)
        {

            ControllerContainer.RegisterMany<ILoggingService, Logger>(setup: Setup.With(allowDisposableTransient: true));
            ControllerContainer.RegisterMany<INews, NewsManager>(setup: Setup.With(allowDisposableTransient: true));
        }

新闻控制器

public class NewsController : ApiController
    {
        private INews _news;
        private ILoggingService _log;

        public NewsController(INews news, ILoggingService logger)
        {
            _news = news;
            _log = logger;
        }

【问题讨论】:

    标签: c# unit-testing asp.net-web-api inversion-of-control dryioc


    【解决方案1】:

    好吧,这就是我想出的。

    在上述UPDATE: 下的问题中,您将看到使用WebAPIConfig 自动注册和解析依赖项的代码。您需要使用来自 NuGet 的 DryIoc.WebAPI 包以及 DryIoc。

    为了能够交换测试实现,您需要为您的测试/模拟依赖项创建一个类。您可以只使用上面的 RegisterDependencies,但注册您的存根或模拟,而不是生产实现。

    然后你的测试类(我正在使用 xUnit)将看起来像这样,但不要担心构造函数中的 AutoMapper 部分:

    public class NewsControllerTests
        {
            private IContainer _testContainer;
            private NewsController _controller;
    
            public NewsControllerTests()
            {
                Mapper.Initialize(config =>
                {
                    config.CreateMap<News, NewsDto>();
                    config.CreateMap<NewsDto, News>();
                });
    
                _testContainer = RegisterTestDependencies.testContainer = new Container(rules => rules.With(FactoryMethod.ConstructorWithResolvableArguments)).WithWebApi(
                    new HttpConfiguration(), throwIfUnresolved: type => type.IsController());
    
                RegisterTestDependencies.InitializeTestContainer(_testContainer);
    
            }
    
           [Fact]
            void GetNews_WithoutId_ReturnsAllNewsItems()
            {
                //Arrange
    
            using (var scope = _testContainer.OpenScope(Reuse.WebRequestScopeName))
            {
                _controller = scope.Resolve<NewsController>();
    
                //Act
    
                var getNewsResult = _controller.GetNews() as OkNegotiatedContentResult<List<NewsDto>>;
    
                //Assert
    
                getNewsResult.Content.Should().AllBeOfType<NewsDto>();
    
            }
    
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-28
      • 2015-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-27
      • 1970-01-01
      相关资源
      最近更新 更多