Резервный контроллер DryIOC WebAPI

Я использую DryIOC.WebAPI для разрешения моих контроллеров API.

Таким образом, конфигурация WebAPI:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));


        config.EnableCors();
        config.MapHttpAttributeRoutes();

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

        Startup.IocContainer.WithWebApi(config);
        Startup.IocContainer.RegisterWebApiControllers(config);
    }
}

Он отлично работает, пока я не забуду создать сопоставление в контейнере IOC. В этом случае преобразователь зависимостей не может создать экземпляр APIController с помощью DryIOC.

Когда это происходит, он возвращается к распознавателю WebAPI по умолчанию, который затем выдает ошибку «Нет конструктора по умолчанию».

Это нежелательное поведение для меня. Если разрешение DryIOC не удается, я хочу, чтобы на этом все остановилось — не было возврата к реализации по умолчанию и не было неточного сообщения об отсутствии конструктора по умолчанию. Я хочу знать, какие типы DryIOC не может разрешить, чтобы я мог это исправить.

Как я могу этого добиться?


person reach4thelasers    schedule 23.03.2016    source источник
comment
вы можете самостоятельно переопределить преобразователь по умолчанию, прежде чем передавать его в DryIOC и остановить его там   -  person Nkosi    schedule 23.03.2016
comment
Я сделал запрос на вытягивание DryIOC здесь: bitbucket.org/dadhi/dryioc/pull-requests/15/   -  person reach4thelasers    schedule 23.03.2016
comment
внесение этого изменения в структуру DryIOC довольно экстремально. Вы должны воспользоваться расширяемостью, которую позволяет веб-API. Посмотрев, как источник DryIOC заменяет преобразователь по умолчанию, а не обертывает его, я отредактирую свой ответ, чтобы показать, как вы можете обернуть DryIOCResover и выдать нужную ошибку.   -  person Nkosi    schedule 23.03.2016
comment
Я прокомментировал предложенный PR bitbucket .org/dadhi/dryioc/pull-requests/15/   -  person dadhi    schedule 23.03.2016
comment
@reach4thelasers обнаружил некоторую документацию по теме: IDependencyResolver, которая может противоречить вашим требованиям.   -  person Nkosi    schedule 24.03.2016


Ответы (2)


Согласно документации Microsoft:

Внедрение зависимостей в ASP.NET Web API 2

Если метод GetService не может разрешить тип, он должен возвращать значение null. Если метод GetServices не может разрешить тип, он должен вернуть пустой объект коллекции.

Не создавать исключения для неизвестных типов.

Реализации этого интерфейса должны делегировать базовому контейнеру внедрения зависимостей предоставление зарегистрированной службы для запрошенного типа. Когда нет зарегистрированных служб запрошенного типа, платформа ASP.NET MVC ожидает, что реализации этого интерфейса вернут null из GetService и вернут пустую коллекцию из Получить службы.

Когда веб-API создает экземпляр контроллера, он сначала вызывает IDependencyResolver.GetService, передавая тип контроллера. Вы можете использовать этот хук расширяемости для создания контроллера, разрешающего любые зависимости. Если GetService возвращает значение null, веб-API ищет конструктор без параметров в классе контроллера.

Вы можете переопределить преобразователь по умолчанию самостоятельно

public static class ResolverHelper {
    public static void OverrideResolver(this HttpConfiguration httpConfiguration) {
        var innerResolver = httpConfiguration.DependencyResolver;
        var resolver = new MyDryIocDependencyResolver(innerResolver);
        httpConfiguration.DependencyResolver = resolver;
    }
}

и в вашем пользовательском преобразователе произойдет сбой, как вы хотите.

Фрагмент из MyDryIocDependencyResolver

public class MyDryIocDependencyResolver : IDependencyResolver { 
    IDependencyResolver innerResolver;

    public MyCustomDependencyResolver(IDependencyResolver innerResolver) {
        this.innerResolver = innerResolver;
    }

    public IDependencyScope BeginScope() {
        return this;
    }

    public object GetService(Type serviceType) {
        try {
            return innerResolver.Getservice(serviceType);
        } catch (Exception ex) {
            //TODO: Log resolution error
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType) {
        try {
            return innerResolver.GetServices(serviceType);
        } catch (Exception ex) {
           //TODO: Log resolution error
           return new List<object>();
        }
    }

    public void Dispose() {
      // NO-OP 
    }
}

В вашей регистрации вы можете переопределить его

//...other code
Startup.IocContainer.WithWebApi(config);
Startup.IocContainer.RegisterWebApiControllers(config);
config.OverrideResolver();
//...other code

Таким образом, если/когда DryIocDependencyResolver не сможет разрешить тип службы, вы все равно будете знать, что не было разрешено, поймаете это и вернете значения по умолчанию, как указано в предлагаемых рекомендациях. Лучшее обоих миров.

надеюсь, это поможет

person Nkosi    schedule 23.03.2016
comment
Это действительно рекомендация MS. Однако проблема в том, что мы теряем подробное исключение из интегрированной библиотеки IoC. DryIoc и другие IoC предоставляют много информации о том, что, почему не разрешено и в каком состоянии находится контейнер. Так вы сможете выявить проблему гораздо быстрее. - person dadhi; 24.03.2016

Еще один способ проверить проблемы с разрешениями контроллера со всей возможной информацией — использовать метод IContainer.VerifyResolutions.

Например:

var container = new Container().WithWebApi(config);
var errors = container.VerifyResolutions();
Debug.Assert(errors.Length == 0);

Дополнительные сведения см. в вики.

Примечание. Единственная загвоздка с контроллерами в том, что текущий DryIoc.WebApi регистрирует реализацию контроллера с конкретным типом контроллера и всеми его реализованными типами в качестве типов служб. Таким образом, для одного неразрешенного метода class MyController: ApiController {} метод VerifyResolutions вернет 3 одинаковые ошибки:

  • один для MyController
  • один для ApiController
  • и один для IHttpController

Вы можете сгруппировать результаты проверки errors по Factory.FactoryID, чтобы получить более компактный вывод.

person dadhi    schedule 24.03.2016