How to use NinjectModule with Ninject.MVC and multiple layers? - ninject

I have four layers in my application where the Service layer is the context root:
Presention
|
|
Services (Context Root)
|
|
Repository
|
|
Data
I am using Ninject MVC for the Presention layer specific items, and I have everything else registered in the services layer (context root).
However, My data layer has some data layer specific services that I would like registered in that layer. Currently my Services layer doesn't know about my Data layer and I see no real reason to make that a requirement. Is there a way using Ninject Modules to register all IOC containers that inherit from Ninject Module in one fell swoop?
On a side note I am using Telerik in the project so I cannot use reflection to get all of the objects that inherit from NinjectModule. Telerik's versions of NinjectModule are either sealed or unable to be accessed and re-registered.

the Ninject IKernel interface has a Load() method which takes as parameter a list of assemblies. It will search for any INinjectModule in those assemblies and load them.
otherwise, check out the Ninject Conventions project. I am using it to automatically bind any class that implements my own IDependency:
Kernel.Bind( scanner =>
{
scanner.From( assemblies )
.Select( t => t.Is<IDependency>() )
.BindAllInterfaces()
.ConfigureFor<ISingletonDependency>( config => config.InSingletonScope() )
.ConfigureFor<IRequestDependency>( config => config.InRequestScope() );
} );

Related

AutoMapper not detecting profiles in external assemblies

I am using ASP.Net core with latest Automapper. This is related to this and this. I think I am doing what needs to be done according to those questions, but still I get below error from Automapper.
AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping.
Mapping types:
ToDoDto -> CreateTodoCommand
Module.Todo.Domain.Dto.ToDoDto -> Module.Todo.Domain.Commands.CreateTodoCommand
at lambda_method19(Closure , ToDoDto , CreateTodoCommand , ResolutionContext )
I have an interface which will be implemented by classes that needs to participate in mappings.
public interface IMapFrom<T>
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}
But mapping classes can be in many assemblies since I have a plugin architecture. So, lot of stuff are being loaded dynamically by the host application. My Assembly locating method use below line to load Assembly in a loop until it finishes loading all modules.
AssemblyLoadContext.Default.LoadFromAssemblyPath(file.FullName); //file.FullName is full path to Dll like E:\Project\Modules\Module.Todo\bin\Module.Todo.dll
Once it's done I can see loaded assemblies in watch window
Above loading method gets called in ConfigureServices(). I know this should work because the same assembly collection is passed to MediatR services.AddMediatR(assemblies) as well as Automapper services.AddAutoMapper(assemblies);
MediatR scans and find all Commands etc. but Automapper fails to locate mappings from other assemblies. However Automapper loads profiles properly from directly linked assemblies via Assembly.GetExecutingAssembly().GetReferencedAssemblies()
What may be the problem?
I got my assemblies to load properly and setup the mappings to work by making my mappings by inheriting Profile class like
public class MyProfile:Profile
{
public MyProfile()
{
CreateMap<A,B>();
}
}
and not using
public interface IMapFrom<T>
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}

How do I auto-register/resolve services by their interface?

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.

How to keep DbContext and entities internal while injecting into services?

I am creating an ASP Core MVC application. Within my solution I have Web project (MVC) and a Core project (BLL/DAL).
I thought it would be a good idea to keep my persistence models and DbContext inside Core project as internal, since Web project should never need the persistence models or need to access context directly, it will get all it needs from services.
Core project has an IServiceCollection extension method which allows me to add the DbContext from service layer to the service container in MVC project without MVC needing direct access to it.
The issue comes when I need to use the DbContext inside my service classes in Core project. The service classes must be public for the view layer to access them, but I cannot inject DbContext into them via the constructor because it is internal.
If I want to make the DbContext public so it can be injected, I must also make all of my persistence models public since they are declared with DbSets in the context.
Do I really need to make all of my persistence models public or is there a way to resolve this?
First of all, you need to make Entity public, otherwise, you will not be able to access them in Service Layer. We should reference Entity from Data Access Layer instead of accessing ViewModel from Service Layer in Data Access Layer. And then, you could make DbContext public to be able accessed from Service Layer.
If you want to avoid accessing DbContext directly from Service Layer, you could consider implementing public Repository which will inject DbContext to handle CURD operations.

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.

Naming conventions for a project containg only WCF ServiceReferences?

Let's say we have a back-end that needs to talk to N external systems using some kind of Web Services.
What I do is: Create a separate project and generate there the proxy classes (using the service's WSDL in the WCF Service Reference dialog).
About the project name suffix:
I firstly though XxAdapter. But then, I started creating classes with additional logic like CircuitBreakers so I ended up with XxAgent (from ServiceAgent).
What should be the "correct" suffix for the name of such projects.
The most appropriate suffix is "Proxies" because of several reasons:
Your component contains all the web service proxy classes.
In case that you want to make calls to several service proxies transparent, you can create a new class named MyLocalProxy, and perform the action
public class MyServiceProxy
{
public void DoSomething()
{
var serviceProxy1 = new ServiceProxy1();
serviceProxy1.DoOneThing();
var serviceProxy2 = new ServiceProxy2();
serviceProxy2.DoAnotherThing();
}
}
The additional class helps you to not depend on concrete service proxies, so you can interchange them as you wish.
Cheers.