I just ran into a problem with a message handler that also implements other interfaces than IHandleMessages. In my case this is a generic interface IHandleInterval. Whenever a message arrives on the endpoint, it throws an error that no handlers are registered for the specified message although there is one. When removing my own generic interface from the class definition or moving the IHandleMessages to another class everything works fine.
I’m using the nuget package 7.0.0-beta0008 (on net core). Is this a known issue or is there any workaround for now?
it does work in this simple constellation. What I didn’t mention in the first place is that I use Autofac as DI Container instead of the buildin one. When I wire that up I receive an exception that the handler could not be found. When I remove the IHandleInterval interface from the handler it gets fired correctly. One workaround I found is to manually add the handler to the services collection - then it works.
Yes, you have to use a .net core web application. I reduced the code to the bare minimum, see below.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Create NServiceBus configuration
// todo: exchange with proper factory for configured transport, persistence and databus mechanisms
var exchangeFolder = "D:\\dummyfolder\\";
var epc = new EndpointConfiguration("GenericInterfaceEndpoint");
epc.UsePersistence<LearningPersistence>();
epc.UseSerialization<NewtonsoftSerializer>();
// Create transport
var transport = epc.UseTransport<LearningTransport>();
transport.NoPayloadSizeRestriction();
transport.StorageDirectory($"{exchangeFolder}MessageBus");
// Create data bus
var dataBus = epc.UseDataBus<FileShareDataBus>();
dataBus.BasePath($"{exchangeFolder}DataBus");
// Hook up the license data (Base64-Encoded Xml License)
epc.License("");
// COMMENT THIS LINE TO INVOKE EXCEPTION
services.AddTransient<HandlerImplementingUnrelatedGenericInterface>();
// COMMENT THIS LINE TO INVOKE EXCEPTION
services.AddSingleton<IHandleInterval<UserTaskInterval>, HandlerImplementingUnrelatedGenericInterface>();
services.AddSingleton<EndpointConfiguration>(epc);
services.AddSingleton<IMessageSession>(serviceProvider =>
Endpoint.Start(serviceProvider.GetService<EndpointConfiguration>()).Result);
var builder = new ContainerBuilder();
builder.Populate(services);
var container = builder.Build();
epc.UseContainer<AutofacBuilder>(
customizations: customizations =>
{
customizations.ExistingLifetimeScope(container);
});
return new AutofacServiceProvider(container);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
app.ApplicationServices.GetService(typeof(IMessageSession));
}
}
public interface IInterval
{
int IntervalMs { get; }
}
public interface IHandleInterval
{
}
public interface IHandleInterval<in TInterval> : IHandleInterval
where TInterval : IInterval
{
Task HandleInterval(TInterval interval);
}
public class UserTaskInterval : IInterval
{
public int IntervalMs { get; } = 1000;
}
public class HandlerImplementingUnrelatedGenericInterface
: IHandleMessages<MyMessage>
, IHandleInterval<UserTaskInterval>
{
public Task HandleInterval(UserTaskInterval interval)
{
Console.Out.WriteLine("Got the interval");
return Task.CompletedTask;
}
public Task Handle(MyMessage message, IMessageHandlerContext context)
{
Console.Out.WriteLine("Got the message");
return Task.CompletedTask;
}
}
public class MyMessage : ICommand
{
}
That line seems to cause NServiceBus to believe that the handler is already registered but when we try to resolve it using IHandleMessages<MyMessage> it can’t be found.
Since NServiceBus registers all interfaces on the handlers you should not need that registration, can you see if that works?
In the mean time I’ll digg a bit deeper into how autofac treats conflicting registrations like this.
I need this line for my internal interval handling, so I cannot remove it. Adding the specific handlers to the DI resolves this issue, too. For me this workaround is acceptable since I will not be having countless handlers anyway and can do this by reflection.