The error message I'm getting is
2016-09-14 18:55:12,276 INFO
NServiceBus.Unicast.Transport.TransportReceiver - Failed to process
message Autofac.Core.DependencyResolutionException: None of the
constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'ProjectServices.EsbHandlers.NewProcessMessageHandler' can be invoked
with the available services and parameters: Cannot resolve parameter
'ProjectServices.Cache.ICachedNotificationsStorage
cachedNotificationsStorage' of constructor 'Void
.ctor(Project.Model.IRepository,
Project.Model.Services.ICaseDelegationService,
Priject.Model.Services.IDocumentDelegationService,
ETeismasServices.Cache.ICachedNotificationsStorage)'.
The dependency is registered in Autofac :
builder.RegisterType<CachedNotificationsStorage>().As<ICachedNotificationsStorage>();
And this is the CachedNotificationStorage constructor
public class CachedNotificationsStorage : ICachedNotificationsStorage
{
private readonly int itemsExpireMinutes;
private const string NotificationsCacheKey = "Notifications";
private readonly ObjectCache cache;
public CachedNotificationsStorage()
{
itemsExpireMinutes = int.Parse(ConfigurationManager.AppSettings["notificationsListItemsCahceExpirationInMinutes"]);
cache = MemoryCache.Default;
cache.Add(NotificationsCacheKey, new List<CachedNotificationsListItem>(), new CacheItemPolicy());
}
//.... logic etc
}
So Autofac is trying to create a NewProcessMessageHandler
For that, Autofac needs to resolve an implementation of ICachedNotificationStorage.
There is a concrete implementation of ICachedNotificationStorage registered as ICachedNotificationStorage.
Why can't Autofac resolve it?
There is no magic in that constructor, it just adds an initial empty list to the cache.
NewProcessMessageHandler class :
public class NewProcessMessageHandler : BaseHandler<NewProcessMessage>
{
public NewProcessMessageHandler(IRepository repository, ICaseDelegationService caseDelegationService,
IDocumentDelegationService documentDelegationService, ICachedNotificationsStorage cachedNotificationsStorage)
: base(repository, caseDelegationService, documentDelegationService, cachedNotificationsStorage)
{
}
}
And its base
public abstract class BaseHandler<T>: IHandleMessages<T>
{
...
protected BaseHandler(IRepository repository, ICaseDelegationService caseDelegationService,
IDocumentDelegationService documentDelegationService, ICachedNotificationsStorage cachedNotificationsStorage)
{
this.repository = repository;
this.caseDelegationService = caseDelegationService;
this.documentDelegationService = documentDelegationService;
this.cachedNotificationsStorage = cachedNotificationsStorage;
}
...
}
Full code which performs the registration
private void StartNserviceBus()
{
SetLoggingLibrary.Log4Net(() => log4net.Config.XmlConfigurator.Configure());
Configure.Transactions.Enable();
Configure.Serialization.Xml();
var builder = Behaviors.IoCServiceBehavior.CreateContainerBuilder();
builder.RegisterType<Repository>().As<IRepository>()
.WithResolvedParameter((c, p) => new Lazy<ISession>(() => SessionFactory.Get().OpenSession()));
builder.RegisterType<CaseDelegationService>().As<ICaseDelegationService>();
builder.RegisterType<DocumentDelegationService>().As<IDocumentDelegationService>();
builder.RegisterType<ChargesServiceStub>().As<IProjectChargesService>();
builder.RegisterType<CachedNotificationsStorage>().As<ICachedNotificationsStorage>();
builder.RegisterType<MeowDataOutputServiceClient>().As<IMeowDataOutputService>().AsWcfProxy();
RegisterESBMessageHandlers(builder);
container = builder.Build();
Configure.With(AllAssemblies.Matching("ExternalServices.Contracts.ESB.").And("ProjectService"))
.DefineEndpointName("project_inbound")
.AutofacBuilder(container)
.UseTransport<Msmq>()
.MsmqSubscriptionStorage()
.DisableTimeoutManager()
.PurgeOnStartup(false)
.UnicastBus()
.ImpersonateSender(false)
.LoadMessageHandlers()
.DisableTimeoutManager()
#if DEBUG
.Log4Net()
#endif
.DefiningEventsAs(t => t.Namespace != null && t.Namespace.StartsWith("ExternalServices.Contracts.ESB"))
.CreateBus()
.Start(
() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install()
);
}
RegisterESBMEssageHanlders() : the method registers 40+ message handlers
private void RegisterESBMessageHandlers(ContainerBuilder builder)
{
...40 of them handlers
builder.RegisterType<EsbHandlers.NewPartyDocumentMessageHandler>().AsSelf();
builder.RegisterType<EsbHandlers.NewProcessMessageHandler>().AsSelf();
}
Related
My .Net 7 application has the following issue:
Autofac.Core.DependencyResolutionException: An exception was thrown while activating MyApp.Modules.MyModule.Application.MyModule.UpdateCommand.UpdateCommandHandler.
---> Autofac.Core.DependencyResolutionException: None of the constructors found with 'MyApp.Modules.MyModule.Infrastructure.Configuration.AllConstructorFinder' on type 'MyApp.Modules.MyModule.Application.MyModule.UpdateCommand.UpdateCommandHandler' can be invoked with the available services and parameters:
Cannot resolve parameter 'MyApp.Modules.MyModule.Application.Contracts.IMyModule myModule' of constructor 'Void .ctor(Serilog.ILogger, MyApp.Modules.MyModule.Application.Contracts.IMyModule)'.
UpdateCommandHandler.cs (where the issue is occurring)
public class UpdateCommandHandler: ICommandHandler<UpdateCommand>
{
private readonly IMyModule _myModule;
private readonly ILogger _logger;
public UpdateCommandHandler(ILogger logger, IMyModule myModule)
{
_myModule = myModule;
_logger = logger;
}
public async Task<Unit> Handle(UpdateCommand request, CancellationToken cancellationToken)
{
var foo = await _myModule.ExecuteQueryAsync(new SampleQuery());
return Unit.Value;
}
}
Program.cs
...
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(b => b.RegisterModule(new AutofacModules()));
...
I looked at similar issues before posting, such as this, but I do believe I appropriately registered IMyModule in Autofac as MyModule in the following.
AutofacModules.cs
public class AutofacModules: Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<MyModule>().As<IMyModule>().InstancePerLifetimeScope();
}
}
IMyModule.cs
public interface IMyModule
{
Task ExecuteCommandAsync(ICommand command);
Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query);
}
MyModule.cs
public class MyModule: IMyModule
{
public async Task ExecuteCommandAsync(ICommand command)
{
await CommandsExecutor.Execute(command);
}
public Task<TResult> ExecuteQueryAsync<TResult>(IQuery<TResult> query)
{
var scope = MyCompositionRoot.BeginLifetimeScope();
var mediator = scope.Resolve<IMediator>();
return mediator.Send(query);
}
}
AllConstructorFinder.cs
internal class AllConstructorFinder : IConstructorFinder
{
private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> Cache = new();
public ConstructorInfo[] FindConstructors(Type targetType)
{
var result = Cache.GetOrAdd(targetType, t => t.GetTypeInfo().DeclaredConstructors.ToArray());
return result.Length > 0 ? result : throw new NoConstructorsFoundException(targetType);
}
}
In my Program.cs, I had registered MyModule, but, as I have multiple modules with their own containers, I didn't register it in the module's own composition root. By adding the following line, I'm able to include MyModule as a constructor parameter.
MyModuleStartup.cs
...
var containerBuilder = new ContainerBuilder();
...
/* NEW LINE */
containerBuilder.RegisterType<CventModule>().As<ICventModule>().InstancePerLifetimeScope();
...
So lesson here is make sure the component you are using is registered to Autofac root container your module is running directly in. Thanks to #Travis Illig for the troubleshooting link which helped me immensely.
I'm attempting to register all open generic components I tag with a custom attribute. The query finds the class correctly but the interface is not registered properly. I'm able to register and resolve the component fine using RegisterGeneric
**Working: **
/// <inheritdoc />
[GenericTransient]
public sealed class RetryPolicyService<TResult> : IRetryPolicyService<TResult>
{...
}
builder.RegisterGeneric(typeof(RetryPolicyService<>))
.As(typeof(IRetryPolicyService<>))
.InstancePerDependency();
Not Working:
builder.RegisterAssemblyOpenGenericTypes(Assembly.GetExecutingAssembly())
.Where(t =>
t.GetCustomAttribute<GenericTransientAttribute>() != null)
.As(t => t.GetInterfaces()[0]);
Not Working:
builder.RegisterAssemblyOpenGenericTypes(Assembly.GetExecutingAssembly())
.Where(t =>
t.GetCustomAttribute<GenericTransientAttribute>() != null)
.AsImplementedInterfaces();
Break Point
The expectation is to be able to inject IRetryPolicyService into objects. Again its working as expected when I register the type specifically.
private readonly IHttpClientService _httpClient;
private readonly IRetryPolicyService<HttpResponseMessage> _retryPolicy;
public ServiceController(
IHttpClientService httpClient,
IRetryPolicyService<HttpResponseMessage> retryPolicy)
{
_httpClient = httpClient;
_retryPolicy = retryPolicy;
_retryPolicy.CreatePolicy(5, times => TimeSpan.FromMilliseconds(times * 1000));
}
The following simplified example works fine. If you uncomment GenericTransient attribute on the second service then controller will get its instance (last registration wins). And the retryPolicies variable will get 2 instances.
The first variant (with GetInterfaces()) also worked after adding .GetGenericTypeDefinition().
using Autofac;
using System.Reflection;
namespace Console.Core6
{
internal class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyOpenGenericTypes(Assembly.GetExecutingAssembly())
.Where(t => t.GetCustomAttribute<GenericTransientAttribute>() != null)
.AsImplementedInterfaces();
builder.RegisterAssemblyOpenGenericTypes(Assembly.GetExecutingAssembly())
.Where(t => t.GetCustomAttribute<GenericTransientAttribute>() != null)
.As(t => t.GetInterfaces()[0].GetGenericTypeDefinition());
builder.RegisterType<ServiceController>().InstancePerDependency();
var container = builder.Build();
var controller = container.Resolve<ServiceController>();
var retryPolicies = container.Resolve<IEnumerable<IRetryPolicyService<HttpResponseMessage>>>();
}
}
internal class GenericTransientAttribute : Attribute
{ }
public interface IRetryPolicyService<TResult>
{ }
[GenericTransient]
public sealed class RetryPolicyService<TResult> : IRetryPolicyService<TResult>
{}
//[GenericTransient]
public sealed class RetryPolicyService2<TResult> : IRetryPolicyService<TResult>
{}
public class ServiceController
{
private readonly IRetryPolicyService<HttpResponseMessage> _retryPolicy;
public ServiceController(IRetryPolicyService<HttpResponseMessage> retryPolicy)
{
_retryPolicy = retryPolicy;
}
}
}
IN a Winforms project, I have set up Autofac and Factory Pattern and it looks like it's working as expected. However, I'm still not sure whether the following is best practice.
The factory class is:
public static class Client
{
public static readonly IRequestFactory RequestFactory = new RequestFactory();
}
public class Configuration
{
public IContainer Container { get; private set; }
public Configuration()
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.Where(t => t.Name.EndsWith("Request"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
Container = builder.Build();
}
}
public class RequestFactory : IRequestFactory, IDisposable
{
private ILifetimeScope scope;
public RequestFactory()
{
scope = Client.Configuration.Container.BeginLifetimeScope();
}
public T Get<T>()
{
return scope.Resolve<T>();
}
public void Dispose()
{
if (scope != null)
{
scope.Dispose();
}
}
}
Then, classes in separate assemblies have the IRequestFactory as a ctor parameter.
Is the above the correct way to implement factor pattern with Autofac or is there a better way?
I have an Asp.NET MVC5 application in which I registre my types using Autofac in Startup class in this way:
public class Startup
{
public void Configuration(IAppBuilder app)
{
IContainer container = null;
var builder = new ContainerBuilder();
// Register Services
builder.RegisterType<SalesRepository>().As<ISalesRepository>().InstancePerRequest();
builder.RegisterType<SalesService>().As<ISalesService>().InstancePerRequest();
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.AsClosedTypesOf(typeof(IHandle<>))
.AsImplementedInterfaces()
.InstancePerRequest();
builder.Register<IAppEvents>(_ => new AppEvents(container)).InstancePerRequest();
// Register MVC Controllers
builder.RegisterControllers(Assembly.GetExecutingAssembly());
container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
}
These are my services (this is a simplified scenario, only for demonstration).
The SalesService class receives a ISalesRepository interface as dependency . In addition I have an AppEvents class where I want to resolve IHandle types:
public interface ISalesRepository { }
public class SalesRepository : ISalesRepository
{
public SalesRepository() { }
}
public interface ISalesService { }
public class SalesService : ISalesService
{
ISalesRepository _repo;
public SalesService(ISalesRepository repo)
{
_repo = repo;
}
}
public interface IHandle<T>
{
void Handle();
}
public class SalesActionHandle : IHandle<string>
{
ISalesRepository _repo;
public SalesActionHandle(ISalesRepository repo)
{
_repo = repo;
}
public void Handle() { }
}
public interface IAppEvents
{
void Raise<T>();
}
public class AppEvents : IAppEvents
{
private readonly IContainer _container;
public AppEvents(IContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
public void Raise<T>()
{
var handlers = _container.Resolve<IEnumerable<IHandle<T>>>(); // Runtime error here
foreach (var handler in handlers)
handler.Handle();
}
}
And this is my only (simplified) controller:
public class HomeController : Controller
{
ISalesService _service;
IAppEvents _events;
public HomeController(ISalesService service, IAppEvents events)
{
_service = service;
_events= events;
}
public ActionResult Index()
{
_events.Raise<string>();
return View();
}
}
The problem I have is that I get an error at this line when it is executed:
var handlers = _container.Resolve<IEnumerable<IHandle<T>>>();
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I resolve it by doing this:
public void Raise<T>()
{
using (var scope = _container.BeginLifetimeScope("AutofacWebRequest"))
{
var handlers = scope.Resolve<IEnumerable<IHandle<T>>>();
foreach (var handler in handlers)
handler.Handle();
}
}
But in this case, when IHandle is resolved (with SalesActionHandle instance), a new instance of SalesRepository is passed as parameter in SalesActionHandle constructor. What I want is to "reuse" the same instance that SalesService is using (it was created when ISalesService was resolved. I want the same SalesRepository instance for the request)
Is there any way to achieve this behaviour?
The sample code is avaible in Github: https://github.com/josmonver/AutofacTest
You may want to use
AutofacDependencyResolver.Current.RequestLifetimeScope
to match your current request scope, but not to create a new request scope.
I am using in my project MediatR. This is what I have in my service class:
public class WebShopServices : IWebShopServices
{
private readonly IMediator _mediator;
public WebShopServices(IMediator mediator)
{
_mediator = mediator;
}
public void UpdateCustomerAddress(UpdateAddressInformationCommand updateAddressInformation)
{
_mediator.Send(updateAddressInformation);
}
}
This is my handler
public class UpdateCustomerAddressHandler : RequestHandler<UpdateAddressInformationCommand>
{
private readonly OnlineSalesService _client;
private readonly IDataContractsFactory _factory;
private readonly IParameterValidator _validator;
public UpdateCustomerAddressHandler(OnlineSalesService client,
IDataContractsFactory factory, IParameterValidator validator)
{
_client = client;
_factory = factory;
_validator = validator;
}
protected override void HandleCore(
UpdateAddressInformationCommand updateAddressInformation)
{
_validator.Validate(updateAddressInformation);
var updateAddressCommand =
_factory.CreateCustomerDefaultAddressCommand(updateAddressInformation);
try
{
_client.SetCustomerDefaultAddress(updateAddressCommand);
}
catch (Exception ex)
{
throw new CustomerException("Something happened with the service.", ex);
}
}
}
This is my model class:
public class UpdateAddressInformationCommand : IRequest
{
public string CustomerNumber { get; set; }
public AddressInformation AddressInformation { get; set; }
}
And this is what I wrote in dependency injection config:
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof (IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof (Ping).Assembly).AsImplementedInterfaces();
builder.RegisterInstance(Console.Out).As<TextWriter>();
builder.Register<SingleInstanceFactory>(ctx => {
var c = ctx.Resolve<IComponentContext>();
return t => c.Resolve(t);
});
builder.Register<MultiInstanceFactory>(ctx => {
var c = ctx.Resolve<IComponentContext>();
return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
});
builder.RegisterType<GetCustomerDetailsResultHandler>()
.As<IRequestHandler<GetCustomerDetailsQuery,GetCustomerDetailsResult>>();
builder.RegisterType<UpdateCustomerAddressHandler>()
.As<RequestHandler<UpdateAddressInformationCommand>>();
And it keeps giving me this exception:
{"The requested service
'MediatR.IRequestHandler`2[[Service.DataContracts.UpdateAddressInformationCommand,
Service, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null],[MediatR.Unit, MediatR, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=null]]' has not been registered. To
avoid this exception, either register a component to provide the
service, check for service registration using IsRegistered(), or use
the ResolveOptional() method to resolve an optional dependency."}
Does anyone know how to fix this problem?
Try this to registering IRequestHandler via:
builder.RegisterAssemblyTypes(assembly).As(t => t.GetInterfaces()
.Where(i => i.IsClosedTypeOf(typeof(IRequestHandler<,>)))
.Select(i => new KeyedService(HandlerKey, i)));
To make it easier to use mediatr and Autofac try the MediatR.Extensions https://github.com/bernos/MediatR.Extensions
I solved the problem by creating an empty class UpdateAddressInformationResult, and in UpdateCustomerAddressHandler I implemented interface IRequestHandler.
I really don't know how to solve the RequestHandler issue. Thanks all.