Autofac: разрешение зависимостей для ApiControllers - PullRequest
0 голосов
/ 15 октября 2019

Я новичок в Inversion of Control & Autofac. Изучая документацию, я понял, что существует множество концепций ASP.NET Web Api, которые я не совсем понимаю или не имею опыта, что затрудняет определение того, чего не хватает в моей реализации.

Я хочу применить Autofacв существующий проект ASP.NET Web Api, который имеет несколько ApiControllers. Все эти контроллеры имеют общий родительский абстрактный класс. Этот абстрактный класс имеет метод, который отвечает за возврат экземпляра службы. Я надеялся заменить этот метод на внедрение зависимостей Autofac.

Родительский абстрактный класс, от которого наследуется каждый ApiController, очень прост.

public abstract class BaseApiController
{
    public IMyService serviceClient { get; set; }

    public BaseApiController() {}

    public BaseApiController(IMyService serviceClient)
    {
        this.serviceClient = serviceClient;
    }
}

Каждый контроллер наследует от вышеуказанного класса, в то время как некоторыеиспользует метод Get по умолчанию, большинство из них имеют несколько маршрутов. Ни один контроллер не указывает конструктор:

public class MyController : BaseApiController
{
    public MyController() : base() {}
    public MyController(IMyService serviceClient) : base(serviceClient) {}

    [HttpGet]
    [Route("api/foo/bar")]
    [ActionName("FooBar")]
    public string FooBar()
    {
        using (serviceClient)
        {
            return serviceClient.GetFooBar() as string;
        }
    }
}

Autofac интегрирован в метод Application_Start приложений Glabal.asax.cs, регистрируя ServerClientProvider, который должен быть поставщиком, к которому следует обращаться при зависимостик IMyService встречается:

public class Global : System.Web.HttpApplication, IContainerProviderAccessor
{
    #region AutoFac
    private static IContainerProvider _containerProvider;

    public IContainerProvider ContainerProvider => _containerProvider;
    #endregion AutoFac

    protected void Application_Start(object sender, EventArgs e)
    {

        var builder = new ContainerBuilder();

        builder.Register(x => ServiceClientProvider.GetServiceClient())
            .As<IMyService>()
            .InstancePerRequest();

        builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
        builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();

        var container = builder.Build();

        GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
        GlobalHost.DependencyResolver = new AutofacDependencyResolver(container);

        _containerProvider = new ContainerProvider(container);

    }
}

Я настроил приложение ASP.NET, в файле web.config:

<configuration>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web" preCondition="managedHandler" />
      <add name="PropertyInjection" type="Autofac.Integration.Web.Forms.PropertyInjectionModule, Autofac.Integration.Web" preCondition="managedHandler" />
    </modules>
  </system.webServer>
<configuration>

Насколько я понимаю, Autofac должен автоматически разрешить поставщикапри обнаружении контроллера с открытым свойством, которое соответствует зарегистрированному типу (Property Injection), или если существует конструктор с параметром, который соответствует любой зарегистрированной зависимости.

Однако я не получаю никаких ошибок, связанных с моимКонфигурация Autofac. Я получаю исключение NullReferenceException, когда MyController пытается вызвать метод IMyService.FooBar.

Чего мне не хватает?

Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 24 октября 2019

После нескольких попыток отладки кода я понял, что в проекте существует еще одна начальная реализация. Используется OWIN, и начальная реализация, с которой я пытался интегрировать Autofac, создается, но никогда не используется. Таким образом, следуя инструкциям на https://autofac.readthedocs.io/en/latest/integration/owin.html,, мы получили результаты, которые я искал.

Вот как должна выглядеть реализация запуска:

[assembly: OwinStartup(typeof(MyWebApp.Api.StartUp))]

namespace MyWebApp.Api
{
    public class StartUp
    {

        public void Configuration(IAppBuilder app)
        {
            // In OWIN you create your own HttpConfiguration rather than
            // re-using the GlobalConfiguration.
            HttpConfiguration httpconfig = new HttpConfiguration();

            httpconfig.Routes.MapHttpRoute(
                name: "ApiRouteWithAction",
                routeTemplate: "api/{controller}/{action}");

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

            // Autofac SignalR integration
            var builder = new ContainerBuilder();

            // Register Web API controller in executing assembly.
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

            // Register SignalR hubs.
            builder.RegisterHubs(Assembly.GetExecutingAssembly());

            // Registering Deletegates
            builder.Register(x => ServiceClientProvider.GetServiceClient())
                .As<IMyService>()
                .InstancePerRequest();

            // Set the dependency resolver to be Autofac.
            var container = builder.Build();
            httpconfig.DependencyResolver = new AutofacWebApiDependencyResolver(container);

            app.UseWebApi(httpconfig);

            // Register the Autofac middleware FIRST, then the custom middleware if any.
            app.UseAutofacMiddleware(container);
        }
    }
}

Контроллер и аннотацияКласс, унаследованный от него, был откорректирован, удалив конструкторы без параметров.

public abstract class BaseApiController
{
    public IMyService serviceClient { get; set; }

    public BaseApiController(IMyService serviceClient)
    {
        this.serviceClient = serviceClient;
    }
}

Каждый контроллер наследует от вышеуказанного класса, в то время как некоторые используют метод Get по умолчанию, большинство имеют несколько маршрутов. Ни один контроллер не указывает конструктор:

public class MyController : BaseApiController
{
    public MyController(IMyService serviceClient) : base(serviceClient) {}

    [HttpGet]
    [Route("api/foo/bar")]
    [ActionName("FooBar")]
    public string FooBar()
    {
        using (serviceClient)
        {
            return serviceClient.GetFooBar() as string;
        }
    }
}

Спасибо за интерес, надеюсь, моя ошибка новичка поможет другому новичку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...