Как разрешить зависимости контроллера WebAPI с DryIoc

Я читал документацию, и я немного смущен тем, как мне этого добиться. У меня есть контроллер WebAPI под названием NewsController, который я перечислю ниже. У него есть один конструктор, который в настоящее время принимает три зависимости. Я создал статический класс для DryIoc, чтобы я мог использовать его глобально в течение всего проекта, и он инициализируется при запуске.

То, что я хотел бы сделать, это зарегистрировать контроллер с его зависимостями в моем классе DryIoc, а затем каким-то образом разрешить это в контроллере NewsController. Причина, по которой я хочу это сделать, заключается в том, что когда я начинаю тестирование, я могу просто сделать так, чтобы тестовый проект изменил область действия зарегистрированного контроллера и использовал заглушенные или смоделированные реализации.

RegisterDependencies

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

      }

RegisterDependencies

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

NewsController

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

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

1 ответ

Решение

Хорошо, вот что я придумал.

В приведенном выше вопросе в разделе ОБНОВЛЕНИЕ: вы увидите код, который будет автоматически регистрировать и разрешать зависимости с помощью WebAPIConfig. Вам нужно будет использовать пакет DryIoc.WebAPI от NuGet, а также DryIoc.

Чтобы иметь возможность менять реализации тестов, вам нужно создать класс для ваших зависимостей test/mock. Вы можете просто использовать 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>();

        }


    }
}
Другие вопросы по тегам