Autofac: добавление декоратора к регистрации делегата, который принимает параметры
Я пытаюсь управлять регистрацией моих клиентов WCF с помощью autofac.
Мне нужно решить Func<MachineEndpoint, IFooService>
, поэтому я зарегистрировал сервис, используя:
builder.Register((c, p) => FooService(c, p.TypedAs<MachineEndpoint>())).UseWcfSafeRelease()
Где FooService-это:
private IJobService FooService(IComponentContext c, MachineEndpoint endpoint) {...}
Это работает нормально, но я хочу добавить к этому декоратор для обработки некоторых ошибок безопасности, поэтому я попробовал следующее:
builder.Register((c, p) => FooService(c, p.TypedAs<MachineEndpoint>())).UseWcfSafeRelease().Named<IFooService>("simple foo service");
builder.RegisterDecorator<IFooService>((c, p, inner) => Wrap(inner, p.TypedAs<MachineEndpoint>(), c.Resolve<CertificateLookupCache>()), "simple foo service");
Но я получаю DependecyResolutionException:
Autofac.Core.DependencyResolutionException: An exception was thrown while executing a resolve operation. See the InnerException for details. ---> System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at MyModule.<Load>b__4(IComponentContext c, IEnumerable`1 p) in MyModule.cs:line 30 (the first line above)
at Autofac.Builder.RegistrationBuilder.<>c__DisplayClass1`1.<ForDelegate>b__0(IComponentContext c, IEnumerable`1 p)
at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
at Autofac.Core.Resolving.InstanceLookup.Execute()
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Features.LightweightAdapters.LightweightAdapterRegistrationSource.<>c__DisplayClass3.<RegistrationsFor>b__1(IComponentContext c, IEnumerable`1 p)
at Autofac.Builder.RegistrationBuilder.<>c__DisplayClass1`1.<ForDelegate>b__0(IComponentContext c, IEnumerable`1 p)
at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
at Autofac.Core.Resolving.InstanceLookup.Execute()
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
--- End of inner exception stack trace ---
Server stack trace:
at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
at lambda_method(Closure , MachineEndpoint )
Как я могу зарегистрировать эти функции, чтобы получить параметр MachinEndpoint, передаваемый обоим объект клиента WCF и декоратор?
1 ответ:
Проблема вызвана вашим использованием параметров:
p.TypedAs<MachineEndpoint>()
, потому что в настоящее время существует ограничение в Autofac, а именно, чтоRegisterDecorator
не проходит через параметры при созданииinner
оформленного объекта.Поэтому, когда он пытается создать
В принципе, вы можете сделать две вещи:inner
с(c, p) => FooService(c, p.TypedAs<MachineEndpoint>())
,(IEnumerable<Parameter> p)
будет пустым, поэтому вы получите исключение.Вы можете попытаться реорганизовать свой код таким образом, чтобы он больше не использовал
p.TypedAs<MachineEndpoint>()
.Или
Потому что ваш
IFooService
в любом случае сервис WCF, который не имеет нескольких реализаций, вы можете зарегистрировать своего декоратора "вручную":builder.Register((c, p) => FooService(c, p.TypedAs<MachineEndpoint>())) .UseWcfSafeRelease() .Named<IFooService>("simple foo service"); builder.Register<IFooService>((c, p) => Wrap(c.ResolveNamed<IFooService>("simple foo service", TypedParameter.From(p.TypedAs<MachineEndpoint>())), p.TypedAs<MachineEndpoint>(), c.Resolve<CertificateLookupCache>()));