Контекстная привязка Autofac не работает в ASP.Core 2.0 - PullRequest
0 голосов
/ 14 мая 2018

Недавно мне пришлось воспользоваться контекстным связыванием, которое поддерживает Autofac, но каким-то образом в ASP.NET Core 2.0 это просто не работает. Я следовал примеру (варианты 2 и 3) на Как выбрать реализацию службы по контексту? Страница часто задаваемых вопросов, однако мне удалось заставить ее работать только в ASP.NET MVC 5 и ASP.NET WEB API 2 проекта. Пример:

public interface ISender
{
  void Send(Destination dest, Content content);
}

// We can implement the interface for different
// "sending strategies":
public class PostalServiceSender : ISender { ... }
public class EmailNotifier : ISender { ... }

public class ShippingProcessor
{
  public ShippingProcessor(ISender shippingStrategy) { ... }
}

public class CustomerNotifier
{
  public CustomerNotifier(ISender notificationStrategy) { ... }
}

Следующая конфигурация привязки не удалось работать:

var builder = new ContainerBuilder();

builder.RegisterType<PostalServiceSender>()
       .As<ISender>()
       .AsSelf();
builder.RegisterType<EmailNotifier>()
       .As<ISender>()
       .AsSelf()
       .InstancePerLifetimeScope();

builder.RegisterType<DefaultSender>()
           .As<ISender>()
           .InstancePerLifetimeScope();

builder.RegisterType<ShippingController>()
       .WithParameter(
         new ResolvedParameter(
           (pi, ctx) => pi.ParameterType == typeof(ISender),
           (pi, ctx) => ctx.Resolve<PostalServiceSender>()))
           .InstancePerLifetimeScope();
builder.RegisterType<CustomersController>();
       .WithParameter(
         new ResolvedParameter(
           (pi, ctx) => pi.ParameterType == typeof(ISender),
           (pi, ctx) => ctx.Resolve<EmailNotifier>()))
           .InstancePerLifetimeScope();
var container = builder.Build();

От вышеуказанных конфигураций связывания ожидается, что класс DefaultSender будет реализацией ISender по умолчанию. Только PostalServiceSender и CustomerNotifier настроены для получения другой реализации ISender. К сожалению, реализация DefaultSender передается везде, где запрашивается ISender. Кто-нибудь сталкивался с таким поведением в .NET Core 2.0?

1 Ответ

0 голосов
/ 14 мая 2018

Ваша конфигурация отличная, и все должно работать нормально, кроме основного контроллера ASP.net.

Контроллеры в ядре ASP.net создаются не Autofac, а byb ASP.net core:

По умолчанию ASP.NET Core разрешает параметры контроллера из контейнерано на самом деле не разрешает контроллер из контейнера.Обычно это не проблема, но это означает:

жизненный цикл контроллера обрабатывается платформой, а не время жизни запроса. Жизненный цикл параметров конструктора контроллера обрабатывается временем жизни запроса. Специальная проводка, которую вы могли выполнить при регистрации контроллера (например, настройка ввода свойств), не будет работать.Вы можете изменить это, указав AddControllersAsServices() при регистрации MVC в коллекции сервисов.Это автоматически зарегистрирует типы контроллеров в IServiceCollection при вызове builder.Populate(services).>> http://autofac.readthedocs.io/en/latest/integration/aspnetcore.html#controllers-as-services

Все, что вам нужно сделать, это позвонить AddControllersAsServices

// Add controllers as services so they'll be resolved.
services.AddMvc().AddControllersAsServices();

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

builder.RegisterType<PostalServiceSender>()
       .Keyed<ISender>("postal");
builder.RegisterType<EmailNotifier>()
       .Keyed<ISender>("email")
       .InstancePerLifetimeScope();
builder.RegisterType<DefaultSender>()
       .As<ISender>()
       .InstancePerLifetimeScope();       

и ваш контроллер вот так:

builder.RegisterType<ShippingController>()
       .WithParameter(
         new ResolvedParameter(
           (pi, ctx) => pi.ParameterType == typeof(ISender),
           (pi, ctx) => ctx.ResolveNamed<ISender>("postal")))
       .InstancePerLifetimeScope();
builder.RegisterType<CustomersController>()
       .WithParameter(
         new ResolvedParameter(
           (pi, ctx) => pi.ParameterType == typeof(ISender),
           (pi, ctx) => ctx.ResolveNamed<ISender>("email")))
       .InstancePerLifetimeScope();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...