How to decorate interfaces bound to more than one concrete type with Ninject - ninject

So, I have a message bus that instantiates message handlers through Ninject. I'd like to decorate my handlers with cross cutting concerns such as logging, transaction management, etc.
I setup my bindings like so:
kernel.Bind<IMessageHandler<int>>().To<IntHandlerOne>()
.WhenInjectedInto(typeof(HandlerDecorator<>));
kernel.Bind(typeof(IMessageHandler<>)).To(typeof(HandlerDecorator<>));
Which works fantastically whenever I have a single handler of a specific message type. However, when I have more than one handler defined:
kernel.Bind<IMessageHandler<int>>().To<IntHandlerOne>()
.WhenInjectedInto(typeof(HandlerDecorator<>));
kernel.Bind<IMessageHandler<int>>().To<IntHandlerTwo>()
.WhenInjectedInto(typeof(HandlerDecorator<>));
kernel.Bind(typeof(IMessageHandler<>)).To(typeof(HandlerDecorator<>));
Ninject will find and inject the decorator to the message bus, and then attempt unsuccessfully to inject both handlers into the decorator constructor.
public HandlerDecorator(IMessageHandler<T> handler)
You may be thinking, why don't I just modify my decorator to accept the list of handlers? I thought about this, but that defeats the purpose of the handler. I want to be able to easily chain multiple decorators together transparently. Each instance of IMessageHandler<T> should get an entirely new chain of handlers.
I've published an example test library on GitHub that should illustrate what I'm talking about here.
Is there any way to do this in Ninject?

Use
kernel.Bind<IMessageHandler<int>>().To<IntHandlerOne>().WhenParentNamed("One");
kernel.Bind<IMessageHandler<int>>().To<IntHandlerTwo>().WhenParentNamed("Two");
kernel.Bind(typeof(IMessageHandler<>)).To(typeof(HandlerDecorator<>)).Named("One");
kernel.Bind(typeof(IMessageHandler<>)).To(typeof(HandlerDecorator<>)).Named("Two");
Also be aware that most of the Bus Frameworks have some way to do decorations for message handlers. May have a look there first.

You should wrap those handlers in a composite:
public class CompositeMessageHandler<T> : IMessageHandler<T>
{
private readonly IEnumerable<IMessageHandler<T>> handlers;
CompositeMessageHandler(IEnumerable<IMessageHandler<T>> handlers)
{
this.handlers = handlers;
}
public void Handle(T message)
{
foreach (var handler in this.handlers)
{
handler.Handle(message);
}
}
}
This composite can again be injected into your decorator. Or perhaps you should do it the other way around: Wrap each handler with a decorator and wrap those into the composite.
I'm not sure how to register this with Ninject though.

Related

Does MediatR walk all classes in the project looking for matches?

There are two parts to this question. First I am going to explain what I think is happening? And then second, in that explanation, I want to verify how it is finding a class it needs.
This is from Nick Chapsas' program Write cleaner APIs in .NET 7 with MediatR.
This code handles a request using MediatR as follows.
n program.cs it has:
app.MediateGet<ExampleRequest>("example/{name}");
which is called via the extension function:
public static WebApplication MediateGet<TRequest>(
this WebApplication app,
string template) where TRequest : IHttpRequest
{
app.MapGet(template, async (IMediator mediator,
[AsParameters] TRequest request) => await mediator.Send(request));
return app;
}
where IHttpRequest is defined as:
public interface IHttpRequest : IRequest<IResult>
{
}
So what has occurred from all this is me have an app.MapGet() call for the url "example/{name}" and it will be handles by MediatR.
ExampleRequest.cs is a POCO containing the URL parameters, etc.
The handler must implement the interface IRequestHandler<ExampleRequest, IResult>. When that url is requested, it will instantiate the appropiate class and call its Handle() method passing in the ExampleRequest and getting a Task returned.
Question 1: Is that correct?
There is the following class in the program that is a handler that implements the require interface. And it is called by MediatR.
public class ExampleHandler : IRequestHandler<ExampleRequest, IResult>
{
private readonly GuidService _guidService;
public ExampleHandler(GuidService guidService)
{
_guidService = guidService;
}
public async Task<IResult> Handle(
ExampleRequest request, CancellationToken cancellationToken)
{
await Task.Delay(10, cancellationToken);
return Results.Ok(new
{
message = $"The age was: {request.Age} and the name was: {request.Name}",
requestGuid = request.GuidService.Id,
ctorGuid = _guidService.Id
});
}
}
Question 2a: How does MediatR find this class? It is not passed to anything or registered with anything. Does MediatR scan all classes looking for a match?
Question 2b: And if so, what if there are two matches?
Question 2c: Also if so, is there a way to register handler classes to speed up finding them and avoid duplicate matches?
1. Effectively, yes. The idea is that you're tying individual endpoint operations to a responsible request/response handler, for which a concrete implementation class may implement one or several; the endpoint is abstracted from that responsibility and just needs to know about it's own required input and output pair, resolution is handled by MediatR.
2a. Reflection and assembly scanning. The registration process asks for assemblies to scan, and the MediatR library will locate and attempt to register classes that fulfill its interfaces
https://github.com/jbogard/MediatR/blob/master/src/MediatR/Registration/ServiceRegistrar.cs
MediatR supports Microsoft.Extensions.DependencyInjection.Abstractions
directly. To register various MediatR services and handlers:
services.AddMediatR(cfg =>
cfg.RegisterServicesFromAssemblyContaining()); or with an
assembly:
services.AddMediatR(cfg =>
cfg.RegisterServicesFromAssembly(typeof(Startup).Assembly));
This registers:
IMediator as transient
ISender as transient
IPublisher as transient
IRequestHandler<,> concrete implementations as transient
IRequestHandler<> concrete implementations as transient
INotificationHandler<> concrete implementations as transient
IStreamRequestHandler<> concrete implementations as transient
IRequestPreProcessor<> concrete implementations as transient
IRequestPostProcessor<,> concrete implementations as transient
IRequestExceptionHandler<,,> concrete implementations as transient
IRequestExceptionAction<,>) concrete implementations as transient
This also registers open generic implementations for:
INotificationHandler<>
IRequestPreProcessor<>
IRequestPostProcessor<,>
IRequestExceptionHandler<,,>
IRequestExceptionAction<,>
2b. Which takes precedence depends on how you register them, but MediatR will only resolve one IRequestHandler for a given type. The assembly scanner will register the first located handler and will skip any additional ones it finds. If you manually register multiple, it will use the last registered.
2c. Yes. You do not have to use the automated assembly scanning via the registration extensions to register MediatR; you can manually register the implementations of IMediator, ISender, and IPublisher yourself, and then selectively register all of your various handlers manually into the IoC container.

How to receive IHubContext out of Dependency Injected classes?

I want to send message from Service A using SignalR when some event occures (for example, message from Service B received).
So hub method needs to be called from some sort of handler, that not constructed using Dependency Injection. How I can do this?
So far, I tried and read about the following things:
I can inject context into Controller and lead it to my handler. I probably can do that, but passing hub context from the top (controller class) to the bottom (handler class) is not the best approach, which adds a lot of dependencies to the classes that should not be aware of this context, so I would like to avoid that.
I can inject my IHubContext in "any" class, but then, the thing is, how to get an instance of that class on my handler?
Add Static method to class with injected context!? Well, that works until you have 1 client because with new client static property is going to be overwritten.
So I cannot imagine, how handler can use dependency injected IHubContext.
Probably, someone did that before and have an example of how to truly inject context into any class.
Thank you in advance and any additional information will be provided, if necessary.
Answer 1
Here is one possible solution. Implement a factory pattern. Create a factory that knows how to create your handler. Inject the IHubContext in the factory. You can use a few approaches that way:
Construct the Handler by passing in the IHubContext
Create a public property in the Handler and set the IHubContext
Create a method in the Handler and pass the IHubContext as a parameter
You can decide whichever approach suits you. Inject that factory in the controller via DI, and get the handler using the factory method. That way you are not exposing the IHubContext. Please see the code below
public interface IHandlerFactory
{
Handler CreateHandler();
}
public class HandlerFactory : IHandlerFactory
{
private IHubContext _hubContext;
public HandlerFactory(IHubContext context)
{
_hubContext = context;
}
public Handler CreateHandler()
{
return new Handler(param1, param2, _context);
}
}
Then in the entry point, controller/service, inject the factory via DI
public class MyController : Controller
{
private Handler _handler;
public MyController(IHandlerFactory factory)
{
_handler = factory.CreateHandler();
}
}
Then you can use that _handler in the other methods. I hope this helps.
Answer 2
Another possible solution is to use IHostedService if it's possible at all for you. Please see a solution to a GitHub issue, provided by David Fowler here, that I think somewhat relevant to your scenario.

Container.GetInstance(Type) when using WcfOperationLifestyle throws ActivationException

I have a WebAPI service using SimpleInjector. I have this set up using AsyncScopedLifestyle for my scoped dependencies, and one of these dependencies is my Entity Framework DataContext. Many things in my service depend on the DataContext, and it is generally injected in to my MediatR handlers using constructor injection - this works well. Separately I have a few areas where I need to create an instance of an object given its type (as a string), so I have created a custom activator class (ResolvingActivator) that is configured with a reference to Container.GetInstance(Type):
In my container bootstrap code:
ResolvingActivator.Configure(container.GetInstance);
I can then create objects by using methods such as:
ResolvingActivator.CreateInstance<T>(typeName)
When I'm using WebAPI, the above is working perfectly.
A further part of the project is a legacy API that uses WCF. I have implemented this as a translation layer, where I translate old message formats to new message formats and then dispatch the messages to the Mediator; I then translate the responses (in new format) back to old format and return those to the caller. Because I need access to the Mediator in my WCF services, I'm injecting this in their constructors, and using the SimpleInjector.Integration.Wcf package to let SimpleInjector's supplied SimpleInjectorServiceHostFactory build instances of the services. I've also created a hybrid lifestyle, so I can use the same container for my both my WebAPI and WCF services:
container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
new AsyncScopedLifestyle(),
new WcfOperationLifestyle());
This works well for some calls, but when a call ultimately calls my ResolvingActivator class, I get an ActivationException thrown, with the following message:
The DataContext is registered as 'Hybrid Async Scoped / WCF Operation' lifestyle, but the instance is requested outside the context of an active (Hybrid Async Scoped / WCF Operation) scope.
As I only receive this error when making WCF calls, I'm wondering if I have something wrong in my configuration. In a nutshell, this will work:
public class SomeClass
{
private readonly DataContext db;
public SomeClass(DataContext db)
{
this.db = db;
}
public bool SomeMethod() => this.db.Table.Any();
}
But this will not:
public class SomeClass
{
public bool SomeMethod()
{
// Code behind is calling container.GetInstance(typeof(DataContext))
var db = ResolvingActivator.CreateInstance<DataContext>();
return db.Table.Any();
}
}
Any ideas where I'm going wrong?
Edit: here is the stack trace from the ActivationException:
at SimpleInjector.Scope.GetScopelessInstance[TImplementation](ScopedRegistration`1 registration)
at SimpleInjector.Scope.GetInstance[TImplementation](ScopedRegistration`1 registration, Scope scope)
at SimpleInjector.Advanced.Internal.LazyScopedRegistration`1.GetInstance(Scope scope)
at lambda_method(Closure )
at SimpleInjector.InstanceProducer.GetInstance()
at SimpleInjector.Container.GetInstance(Type serviceType)
at Service.Core.ResolvingActivator.CreateInstance(Type type) in Service.Core\ResolvingActivator.cs:line 43
at Service.Core.ResolvingActivator.CreateInstance(String typeName) in Service.Core\ResolvingActivator.cs:line 35
at Service.Core.ResolvingActivator.CreateInstance[TService](String typeName) in Service.Core\ResolvingActivator.cs:line 69
With a full stack trace here: https://pastebin.com/0WkyHGKv
After close inspection of the stack trace, I can conclude what's going on: async.
The WcfOperationLifestyle under the covers depends on WCF's OperationContext.Current property, but this property has a thread-affinity and doesn't flow with async operations. This is something that has to be fixed in the integration library for Simple Injector; it simply doesn't support async at the moment.
Instead, wrap a decorator around your handlers that start and end a new async scope. This prevents you from having to use the WcfOperationLifestyle all together. Take a look at the ThreadScopedCommandHandlerProxy<T> implementation here to get an idea how to do this (but use AsyncScopedLifestyle instead).

Using Ninject as IoC for EasyNetQ

i'm using EasyNetQ library in my project and I would like to use Ninject as IoC Container for EasyNetQ components.
I created a custom logger in order to log anythong from EasyNetQ:
public class LogNothingLogger : IEasyNetQLogger
{
...
}
And then using the Ninject extension in my main function:
public class Program
{
static void Main(string[] args)
{
// Container creation and custom logger registration
IKernel cointainer = new StandardKernel();
cointainer.Bind<IEasyNetQLogger>().To<LogNothingLogger>();
// Register Ninject as IoC Container for EasyNetQ
cointainer.RegisterAsEasyNetQContainerFactory();
// Create bus
using (IBus bus = RabbitHutch.CreateBus("host=localhost"))
{
// Do something with bus...
}
}
}
But I get the following exception:
Ninject.ActivationException was unhandled
More than one matching bindings are available.
Matching bindings:
1) binding from IEasyNetQLogger to LogNothingLogger
2) binding from IEasyNetQLogger to method
Activation path:
2) Injection of dependency IEasyNetQLogger into parameter logger of constructor of type RabbitBus
1) Request for RabbitBus
Suggestions:
1) Ensure that you have defined a binding for IEasyNetQLogger only once.
[...]
Am I using this package in the wrong way? Is there any solution?
Thanks!
As the exception says, there are two bindings for IEasyNetQLogger.
I suppose that an ninject extension you are using is already binding an IEasyNetQLogger.
You could use Rebind (IBindingRoot.Rebind<IEasyNetQLogger>()) to override any existing binding for IEasyNetQLogger.
But i would also advise you to look into why the extension is already creating a binding and how it is supposed to be used.
What is the extension you are using?
Edit: i took a glance at https://github.com/mikehadlow/EasyNetQ/tree/master/Source/EasyNetQ.DI.Ninject
and i did not find any binding for IEasyNetQLogger. Are you sure you don't have defined an additional IBindingRoot.Bind<IEasyNetQLogger>().ToMethod(...) binding?
It could also be NinjectAdapter.Register<IEasyNetQLogger>(Func<IEasyNetQLogger> ...).
If you have not done so, then the EasyNetQ is already registering a logger by NinjectAdapter.Register<IEasyNetQLogger>(Func<IEasyNetQLogger> ...).
As before, you can use Rebind(..) to replace the binding (which must be done after the original binding was created!) or look into how it is supposed to work.
Of course you might also just want to skip the binding since you only created one for "log nothing logger"...

sharp architecture contrib transaction attribute in windows service

For some reason this:
[Transaction]
public void DoSomething()
{
...
}
does not work I still have to explicitly use the transaction like this:
public void DoSomething()
{
using (var tx = NHibernateSession.Current.BeginTransaction())
{
....
tx.Commit();
}
}
Any ideas why?
I am using something like this to bootstrap stuff:
_container = new WindsorContainer();
ComponentRegistrar.AddComponentsTo(_container);
...
ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(_container));
ComponentRegistrar.AddComponentsTo(_container, typeof(NHibernateTransactionManager));
NHibernateSession.Init(new ThreadSessionStorage(),
new[] { "Bla.Domain.dll" },
new AutoPersistenceModelGenerator().Generate(),
"NHibernate.config");
As Doan said the component that had the method is not proxied.
Since the method is not virtual, I am assuming that your class is implementing an interface. make sure that you have the dependency in the class calling DoSomething defined as the interface and not the implementing class.
if you debug the code, and check the run time type of the object, it should be a castle proxy
for more details check the trouble shooting section on Sharp Architecture contrib wiki
https://github.com/sharparchitecture/Sharp-Architecture-Contrib/wiki/Troubleshooting
Normally, this kind of problem is caused by the failure of invoking the dynamic proxy that provides the transaction management service. Two of the most common errors are:
The method cannot be proxied: most likely not implement any interface method, or the object was not proxied.
The method was called from the same class, which bypassed all proxies.
Edit:
I guess you use Castle Windsor as IoC container. The [Transaction] decoration requires the Automatic Transaction Management Facility in order to work. If you successfully configured the facility, i.e. you made [Transaction] work in one method, but not other, then the answer above applies. If all Transaction decoration failed to work, then you have to review the configuration of the facility first.