I use the Command Handler pattern and bind to ninject.extensions.Conventions, which works fine when my actual implementation of the IQueryHandler <,> interface matches one particular type. Here is what I use:
kernel.Bind(x => x .FromThisAssembly() .SelectAllClasses() .InheritedFrom(typeof(IQueryHandler<,>)) .BindSingleInterface() .Configure(b => b.WhenInjectedInto(typeof(ValidationHandlerDecorator<,>)).InRequestScope())); kernel.Bind(typeof(IQueryHandler<,>)).To(typeof(PerformanceHandlerDecorator<,>)).InRequestScope();
But I came across a scenario where I need to override a specific default type at runtime based on a custom route value. The following works without problems:
kernel.Bind<IQueryHandler<query1, result1>>().ToMethod( context => HttpContext.Current.Request.RequestContext.RouteData.Values["type"].ToString().ToLower() == "api" ? (IQueryHandler<query1, result1>)new apiHandler() : (IQueryHandler<query1, result1>)new defaultHandler() )
The problem with the above is that I will need to write this code for each of my IQueryHandler <,> generic types. In addition, for each decorator that I would like to apply around the world (for example, in the upper sample), I would have to change each binding and add it, double or triple the code.
What I hope to do is use something like the following. I have implemented a class / interface to return the value of user route data. This is executed, but it throws an exception, because at run time, HttpContext.Current is null. I think because it does not allow the request at runtime.
kernel.Bind<IMyContext>().To<MyContext>().InRequestScope(); kernel.Bind(x => x .FromThisAssembly() .SelectAllClasses() .InheritedFrom(typeof(IQueryHandler<,>)) .StartingWith(kernel.Get<IMyContext>().customRouteValue)
Is it possible to use "ToMethod" or the Factory / Provider mechanism to move the logic to match a specific runtime value and return a specific type based on a naming convention? Or any other ideas for this?
UPDATE I use the following template to access the database: https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92
So, I have an implementation of IQueryHandler <,> for each type of query in my DB.
IQueryHandler<GetDocInfo, DocInfo> IQueryHandler<GetFileInfo, FileInfo> IQueryHandler<GetOrderInfo, OrderInfo> IQueryHandler<GetMessageInfo, MessageInfo>
My specific problem is that I have different schemas for specific tables between clients, so I have to redefine the implementation for specific clients based on Route Config in the url.
public class defaultschemaGetMessageQueryHandler : IQueryHandler<GetMessageInfo, MessageInfo> public class client1schemaGetMessageQueryHandler : IQueryHandler<GetMessageInfo, MessageInfo> public class client2schemaGetMessageQueryHandler : IQueryHandler<GetMessageInfo, MessageInfo>
Another place I'm interested in using it would be to override a particular query implementation to retrieve from another data store: API or NoSQL.
UPDATE 2 Final update. So I took the code below and changed it to go from an attribute-based naming scheme, because I don't want every IQueryable to be called "QueryHandler" for every other type by default.
Modified by:
string route = serviceType.Name.Substring(0, indexOfSuffix);
For this:
string route = System.ComponentModel.TypeDescriptor .GetAttributes(serviceType) .OfType<QueryImplementation>() .Single() .Id;
And added the following attribute that I use to decorate my IQueryHandlers
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct) ] public class QueryImplementation : System.Attribute { public string Id { get { return id; } } private string id; public QueryImplementation(string id) { this.id = id; } }
Used as follows:
[QueryImplementation("Custom")] public class CustomDocQueryHandler : IQueryHandler<GetDocInfo, DocInfo>
Then just had to do the same for my "default" to get the attribute instead of the name.