How do I auto-register/resolve services by their interface? - asp.net-core

I'm developing a MVC .NET Core 3/Angular/Entity Framework application. My application will likely have a lot of repositories in it. To support this I would like to resolve the service (repository) by its default interface (i.e. I request IRepository and the DI resolver gives me Repository). I know I can manually wire up the dependencies, but all of my DI frameworks in the past have had a means of auto-registering/resolving based on patterns or the like.
For example, with Castle Winsdor I could wire it up like this:
container.Register(Classes
.FromAssemblyNamed("MyLibary.Repository")
.InNamespace("MyLibrary.Repository")
.WithService.DefaultInterfaces()
.LifestyleTransient()
);
This would register all classes in the MyLibrary.Repository namespace to be resolved by their default interfaces they implement. How can this be done in .NET Core 3? If this isn't built-in, I'm assuming I will have to use reflection to query all the classes in the assembly, iterate through each class and register it by its interface it implements.

I would recommend AutoRegisterDI lib to not reinvent a bicycle. It's fast, simple and based on Microsoft Dependency Injection. This benchmark will show you the speed difference.
And this is the article about how to use it

Install this package:
NetCore.AutoRegisterDi
Add this code to your program.cs:
builder.Services.RegisterAssemblyPublicNonGenericClasses()
.Where(c => c.Name.EndsWith("Service"))
.AsPublicImplementedInterfaces(ServiceLifetime.Scoped); // default is Transient
If you have a Singleton service , add [RegisterAsSingleton] on top of your service class.
If you want to ignore injection of an particular interface add this line after .Where() :
.IgnoreThisInterface<IMyInterface>()

you can do this with reflection in c#.first create an extension method like this :
public static void AddScopedServices(this IServiceCollection serviceCollection)
{
}
and use it in startup.cs ,ConfigureServices method : services.AddScopedServices();
now to implement this method like this:
var allProviderTypes = System.Reflection.Assembly.GetAssembly(typeof(ICartRepository))
.GetTypes().Where(t => t.Namespace != null).ToList();
foreach (var intfc in allProviderTypes.Where(t => t.IsInterface))
{
var impl = allProviderTypes.FirstOrDefault(c => c.IsClass && intfc.Name.Substring(1) == c.Name);
if (impl != null) serviceCollection.AddScoped(intfc, impl);
}
you just need to put all your interfaces in a namespace and introduce one of them in this method ,in my case I used ICartRepository ,so it takes all interfaces and search for classes which inherit from that interface.
one point you need to consider is that class names must be like interfacenames without 'I' in the beginning ,like 'CartRepository'

I recently got tired of writing the same old
services.AddTransient<IInterface,IImplementation>
so I created a simple library to help me auto-register services.
You can check it out here.
Register the library in Startup.cs
There are 3 interface -> ITransient, IScoped, ISingleton generic and non-generic versions.
Let's say you want to register service "TestService" as transient.
TestService: ITransient<ITestService>, ITestService
Inherit ITransient interface and its done.
For more detailed information please refer to the Readme section.
Currently it lacks registering services with implementation factory, but it's something I'm willing to do in the near future.

Related

Configure DI using Json config

Is it possible to set up configurable DI using the new JSON config?
I.e. I have two classes that implement the same interface, can I use the JSON config to specify which class to inject.
For example:
Given two classes
public class RealService: IService {...}
public class FakeService: IService {...}
and appsettings.json:
"ServiceImplementation": "FakeService"
and in Startup.cs
void ConfigureServices(IServiceCollection services){
var serviceNameToInject = Configuration["ServiceImplementation"];
IService serviceToInject = Type.GetType(serviceNameToInject )
service.AddTransient<IService, serviceToInject >
....
I assume something like this would work but it doesn't feel right, so is there a better way to achieve Json configurable DI using the new ASP.NET Core MVC framework?
Thanks in advance,
Michael McD.
Whilst the out of Service container doesn't support JSON/XML Configuration. ASP.net core allows you to replace the default container with an IOC container of your choice: some of which support JSON and XML configuration such as Autofac.
You can read more about JSON and XML config of Autofac here: http://docs.autofac.org/en/latest/configuration/xml.html#configuring-with-microsoft-configuration
And how to configure Autofac in Asp.net Core Over here: https://docs.asp.net/en/latest/fundamentals/dependency-injection.html?highlight=addtransient#replacing-the-default-services-container
No out-of-the-box support yet.
You may use reflection to do that work yourself while adding sections in your appSettings.json. However, please be aware that your code might not be compilable under .NET Native.
Another question that you may ask yourself at that moment is... when are you are swapping implementations. Are you doing redeploying your whole application at the same time? If yes, why not have it in code and gain the benefits of static typing?
At that point, it's an architectural consideration and positive and negative must be weighted in.

IAuthenticationFilter equivalent in MVC6

I'm moving a Web Api 2 project to MVC 6, since Microsoft is merging the two APIs in ASP.NET 5. In my WebApi project I had a custom Attribute Filter class that would authenticate, authorize and prevent transaction replays using a combination of public key, private key and HMAC authentication (basically, doing this with some tweaks to fit into my project).
Now in MVC6, as far as I understand I must stop using anything in the Microsoft.Web.Http namespace and instead use Microsoft.AspNet.Mvc. So I have done that, but the Microsoft.AspNet.Mvc.Filters doesn't seem to have any equivalent of Web Api 2's IAuthenticationFilter.
This is a problem for me because my customer AuthenticationFilter implemented all of IAuthenticationFilter, with all the logic in there. More importantly, it was using the Context to temporarily store the public key of the account, so my controller could access it to load up the account in turn.
So my question is, what is the proper way to filter requests in MVC6, using an Authentication Filter-like class to intercept the requests and return the appropriate status codes? I can't find any article that goes specifically in these details (they all tend to cover MVC5).
I know it's an older question, but hopefully someone (maybe even yourself) might find value in the answer.
MVC6 does in fact have an alternative. You have an
public abstract class AuthorizationFilterAttribute :
Attribute, IAsyncAuthorizationFilter, IAuthorizationFilter, IOrderedFilter
which basically tells you, that you can create your custom class, derive it from this (namespace of all of these interfaces, btw, is Microsoft.AspNet.Mvc.Filters and that should be it. You can either decorate the action with it, or you can do this in Startup.cs, to apply to all actions:
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container.
services.AddMvc(options =>
{
// add an instance of the filter, like we used to do it
options.Filters.Add(new MySpecialFilter());
});
services.AddTransient<LogFilter>();
}
If you want to use a bit more logic in the filter (e.g. my LogFilter above) which is instantiated through DI, you need to use either Service Filters or Type Filters.
You can now decorate the actions with [ServiceFilter(typeof(LogFilter))] or use o.Filters.Add(new ServiceFilterAttribute(typeof(LogFilter))); in the Startup.cs file. But keep in mind, to do this you need to register the type with the DI container, like I did above with the .AddTransient<>() call.
IAuthenticationFilter is no more and IAuthorizationFilter simply does not replace it in MVC 6
Reason: authentication is NOT EQUAL to authorization.
Therefore IMO the authentication filter should stay available!

Lost scope using DependencyResolver in another class library, using Castle Windsor and FluentNhibernate and NHibernate

In my WCF project I register my interface using Castle Windsor in the global.asax:
Component.For<IStrategy>()
.ImplementedBy<MyStrategy>()
.LifestylePerWcfOperation(),
Then later on in the same file I configure NHibernate using FluentNhibernate using a provider:
FluentConfiguration configuration = Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008.ConnectionString(myConnString)
.Provider<ConnectionProvider>())
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<TenantMap>()) etc etc
However this ConnectionProvider is hosted in a common shared dll library as there are other WCF services that need to use it. I want to register this dependency as below but it doesn't work which means I have to manually new up a instance.
public ConnectionProvider()
{
// doesnt work
using (IDependencyScope scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope())
{
_myStrategy = scope.GetService<IStrategy>();
}
}
Is there anyway to make this work? Its like its lost scope as its in another assembly now. In the same assembly the DependencyScope works fine and creates an instance, but I want to keep it in a shared dll.
EDIT: The error I get is "System.Web.Http.Dependencies.EmptyResolver" on a watch on this bit of code: GlobalConfiguration.Configuration.DependencyResolver
I can see several problems with the code above:
1) You are registering IStrategy,MyStrategy with a per WcfOperation lifestyle. This means that windsor will create a strategy for each WcfOperation. On the otherhand you are trying to manually set the lifestyle of the component by using scope.GetService. For scope.GetService to work you will need a lifestyle scoped.
2) Assuming that the code for ConnectionProvider above is the constructor, it seems that the constructor is trying to get something from the container. This is in general a bad idea, and even worse when using an Ioc container like windsor. Instead pass the IStrategy to the constructor (inject it).
3) Seeing that you are calling the container a constructor here, probably means that you are not adhering to the principle that there should be only 3 calls to the container, 1 to register component, 1 to retrieve a top level component, and 1 to release the container.
I suggest you read a bit more about depedency injection and Ioc containers in general to fully understand how to work with this container.

How to properly construct dependent objects manually?

I'm using Ninject.Web.Common and I really like Ninject so far. I'm not used to dependency injection yet so I've got a pretty lame question I can't however google and answer to so far.
Suppose I have a Message Handler which depends on my IUnitOfWork implementation. I need to construct an instance of my handler to add it to Web API config. I've managed to achieve this using the following code:
var resolver = GlobalConfiguration.Configuration.DependencyResolver;
config.MessageHandlers.Add((myproject.Filters.ApiAuthHandler)resolver.GetService(typeof(myproject.Filters.ApiAuthHandler)));
I really dislike typing this kind of stuff so I'm wondering if I'm doing it right. What's the common way of constructing dependent objects manually?
Well I use dependency injection in real world projects only half a year ago, so I'm a pretty new to this stuff. I would really recommend the Dependency Injection in .NET book, where all the concepts are described pretty well and I learned a lot from it.
So far for me what worked the best is overwriting the default controller factory like this:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel _kernel;
public NinjectControllerFactory()
{
_kernel= new StandardKernel();
ConfigureBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext,
Type controllerType)
{
return controllerType == null
? null
: (IController)_kernel.Get(controllerType);
}
private void ConfigureBindings()
{
_kernel.Bind<IUnitOfWork>().To<MessageHandler>();
}
}
And in the Global.asax in the Application_Start function you just have to add this line:
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
This approach is called the composition root pattern and considered the "good" way for dependency injection.
What I would recommend as well that if you have multiple endpoints like services and other workers as well you should create an Application.CompositionRoot project and handle there the different binding configuration for the different endpoints for your application.

Web services and interface compatibility

Adding a service reference to a web service (this is all WCF) in Visual Studio produces some generated code including a client-side restatement of the interface being exposed.
I understand why this interface is generated: you might be consuming a 3rd party service and not have access to the actual interface.
But I do, and the two are not assignment compatible even though the transparent proxy does indeed exactly implement the interface to which I want to cast.
I can use reflection, but that's ugly. Is there some way to defeat this faux type safety and inject metadata to so I can use an interface with a class?
My specific problem departs from the norm in complicated ways that have to do with a single client that uses some derivatives of a base class directly and uses others remotely via service references. The base class for each server needs to keep references to subscribing clients in a collection for enumeration to notify events, and the problem was type varied due to the use of proxies.
None of these answers solves my specific problem, yet every single answer was instructive and helpful. I found my own solution (use a dual binding) but I would never have figured it out if you hadn't radically improved my understanding of the whole business.
Three excellent answers. How to choose just one? I choose the first, because it directly solves the problem I first thought I had.
If you already have the contract dll at the client, you don't even need a service reference (unless you are using it to write the setup code for you) - you can simply subclass ClientBase and expose the Channel, and use that directly - something like (no IDE handy...):
public class WcfClient<T> : ClientBase<T> where T : class
{
public new T Channel {get {return base.Channel;}}
}
Then you can just do things like:
using(var client = new WcfClient<IFoo>())
{
client.Channel.Bar(); // defined by IFoo
}
You still need the configuration settings in the config to determine the address, binding, etc - but less messy than proxy generation. Also, you might choose to re-implement IDipsoable to deal with the fact that WCF proxies can throw in Dispose() (which is bad):
public class WcfClient<T> : ClientBase<T>, IDisposable where T : class
{
public new T Channel {get {return base.Channel;}}
void IDisposable.Dispose() {
try {
switch(State) {
case CommunicationState.Open: Close(); break;
// etc
}
} catch {} // swallow it down (perhaps log it first)
}
}
When you add the service reference, go to "Advanced" and make sure "Reuse types in referenced assemblies" is selected and that the assembly containing your interface definition is selected. You can also do this with an existing service reference by right clicking on it and going to "Configure".
In order to return an interface from a service you need to use the KnownType attribute:
http://weblogs.asp.net/avnerk/archive/2006/07/31/WCF-Serialization-part-1_3A00_-Interfaces_2C00_-Base-classes-and-the-NetDataContractFormatSerializer.aspx
If you want to return a custom type from the service:
http://msdn.microsoft.com/en-us/library/bb628653.aspx
Does any of that help?