MVC 5 / UnityConfig - Same Interface - Multiple Implementations - c#

So I have this basic Interface:
public interface ISearchable
{
List<AutocompleteResult> Search(string term);
}
And two classes which implement this interface:
First Class:
public class LandlordReader :ISearchable
{
public List<AutocompleteResult> Search(string term)
{
....
}
}
Second Class:
public class CityReader : ISearchable
{
public List<AutocompleteResult> Search(string term)
{
....
}
}
From this point on, I'm in the dark...
In UnityConfig.cs I tried to register them by giving them a name:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<ISearchable, CityReader>("City");
container.RegisterType<ISearchable, LandlordReader>("Landlord");
}
In the MVC Controller I have no idea on what to specify (IN THE CONSTRUCTOR) - to tell it that I want one or another:
public LandlordController(ISearchable searcher)
{
// I want the LandlordReader here, but in the CityController, I want the CityReader....
this.searcher = searcher;
}
I'm quite a noob, regarding DI and UnityInjector, so a full working example would be good. I got lots of advices up to this point (use generic interface, use unity factory) - but trying them myself, none worked.
I know in ASP.NET Core there's an attribute you can directly specify in the constructor's parameter list, but I am currently working in MVC5.
Thanks. Finished a long post. Phew.

You can try one of these options if suitable in your scenario.
1
Using Named Serivce Injection
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<ISearchable, CityReader>("City");
container.RegisterType<ISearchable, LandlordReader>("Landlord");
}
public LandlordController([Dependency("Landlord")]ISearchable searcher)
{
this.searcher = searcher;
}
2
public interface ISearchable<T> where T : class
{
//..............
}
public class LandlordReader : ISearchable<LandlordReader>
{
public List<AutocompleteResult> Search(string term)
{
....
}
}
public class CityReader : ISearchable<CityReader>
{
public List<AutocompleteResult> Search(string term)
{
....
}
}
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<ISearchable, CityReader>("City");
container.RegisterType<ISearchable, LandlordReader>("Landlord");
}
and then when using in the constructor do this
private readonly ISearchable<CityReader> _cityReadersearcher;
private readonly ISearchable<LandlordReader> _landLordsearcher;
public LandlordController(ISearchable<CityReader> cityReadersearcher,
ISearchable<LandlordReader> landLordsearcher)
{
_cityReadersearcher= _cityReadersearcher;
_landLordsearcher = landLordsearcher;
}

Related

Log4net get correct class and method name in logfile using Ninject

I'm converting an application to use Ninject as IoC and one of the things I need to convert is the existing Log4net implementation. The problem that I'm facing is that in the logfile (I use the XmlLayoutSchemaLog4j pattern) the class and method name seems to be of the calling parent instead of the actual caller.
I checked the types that are given to the new Log4NetLogger() and they seem to be of the exact same type as you specify using the LogManager.GetLogger(Methodbase.GetCurrentMethod.DeclaringType);
I made a small program that uses the old and the new implementation to check the differences but I can't seem to find them.
the outcome of the program is this:
Every level is a specific log entry in the code and the first entry of that level is done via Ninject and the second is via de LogManager.
As you can see the logger is the same, but the class and method differs.
the code from the project is:
internal class Program
{
private static IDoSomething _something;
static void Main()
{
log4net.Config.XmlConfigurator.Configure();
Init();
_something.StartSomething();
}
private static void Init()
{
var kernel = new StandardKernel(new NinjectSettings { LoadExtensions = false });
kernel.Load(Assembly.GetExecutingAssembly());
_something = kernel.Get<IDoSomething>();
}
}
public class Bindings : NinjectModule
{
public override void Load()
{
Bind<ILogger>().ToMethod(x => new Log4NetLogger(x.Request.Target.Member.DeclaringType)).InTransientScope();
Bind<IDoSomething>().To<DoSomething>();
Bind<IDoSomethingElse>().To<DoSomethingElse>();
}
}
the dosomething:
public interface IDoSomething
{
void StartSomething();
}
public class DoSomething : IDoSomething
{
[Inject]
public ILogger Logger { get; set; }
public static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
[Inject]
public IDoSomethingElse DoSomethingElse { get; set; }
public void StartSomething()
{
Logger.Debug("Start StartSomething");
Log.Debug("Start StartSomething");
DoSomethingElse.StartSomethingElse();
Logger.Fatal("End StartSomething");
Log.Fatal("End StartSomething");
}
}
And the DoSomethingElse
public interface IDoSomethingElse
{
void StartSomethingElse();
}
public class DoSomethingElse : IDoSomethingElse
{
[Inject]
public ILogger Logger { get; set; }
public static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public void StartSomethingElse()
{
Logger.Info("Start Do Something Else");
Log.Info("Start Do Something Else");
StartSomethingLocal();
Logger.Error("End Do Something Else");
Log.Error("End Do Something Else");
}
private void StartSomethingLocal()
{
Logger.Warn("Start Do Something Local");
Log.Warn("Start Do Something Local");
Logger.Warn("End Do Something Local");
Log.Warn("End Do Something Local");
}
}
I tried several solutions for the type resolving in the new Log4NetLogger in the Load method but no luck.

Dependency Injection outside of Controller

Good day. I have a problem of understanding the Dependency Injection.
So what exactly do I need is to have access from child objects to parent objects.
For example, I have my MainProgram object. This object creates another object, another object create 3-d objects and so on. Let's stop on child object #5
This child needs to have a reference to object #1.
I don't understand how to do this in a better way. But then I started to search and find something called Dependency Injection.
I really hope that this thing is the right answer for my issue (If not, please tell).
So here in my problem and example.
I'm trying to create a WEB API for one of my services. Using ASP .NET Core 6
First, I created a simple class that will be MainProgram, when Server will receive POST request with needed data, it will launch some working in multi-threading.
public class MainProgram
{
public int MaxThreads { get; set; }
public int OrderCounter { get; set; }
public AdjustableSemaphore Semaphore { get; set; }
public MainProgram(int maxThreads)
{
MaxThreads = maxThreads;
Semaphore = new AdjustableSemaphore(MaxThreads);
}
public async Task StartOperation(IApiOperation operation)
{
try
{
operation.Prepare();
operation.Start();
while (!operation.IsReady())
{
await Task.Delay(500);
}
operation.Finish();
}
catch (Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(e.Message);
Console.ResetColor();
}
}
public string OperationStatus(IApiOperation operation)
{
return operation.ShowDetails();
}
}
Then I added this class to Program.cs for Dependency.
builder.Services.AddSingleton(program => new MainProgram(1000));
I made a Constructor for my Controller as it was in the example I read and all worked great.
Controller create instance of MainProgram by its own.
[ApiController]
[Route("/")]
public class ApiController : ControllerBase
{
private MainProgram _mainProgram;
public ApiController(MainProgram mainProgram)
{
_mainProgram = mainProgram;
}
[HttpPost]
[Route("test")]
public string Get()
{
TestOperation to = new TestOperation(_mainProgram);
new Thread(() =>
{
var project = _mainProgram.StartOperation(to);
}).Start();
return $"Started task #{to.Id}";
}
}
The problems that I have are in this line
TestOperation to = new TestOperation(_mainProgram);
This TestOperation also has a Dependency from MainProgram. I understand that I can pass my private _mainProgram in it.
But let's pretend that TestOperation also has a child, and this child also has a child, and only the third one needs a link to MainProgram.
I thought that's where Dependency Injection helps.
Main Question is
How can I create objects that have a constructor with dependency for MainProgram,
If I cannot write new TestOperation(WITHOUT ATTRIBUTE)? It will be a syntax error.
I think you'd avoid the cycle of dependency;
If you couldn't avoid it ,you could try to inject the IServiceProvider into your services,and get the target service with provider.GetService() method,and you could try to create a Parameterservice or Static class to hold the parameter you need,
I tried as below :
Services:
interface IA {int methodA();}
interface IB { int methodB(); }
interface IC { int methodC(); }
interface IParameterService { }
public class ParameterService: IParameterService
{
public int APara;
public int BPara;
public ParameterService(int para)
{
APara = para+1;
}
}
public class A : IA
{
private readonly IServiceProvider _provider;
private readonly int Id;
public A(IServiceProvider provider)
{
_provider = provider;
Id = (provider.GetService(typeof(IParameterService)) as ParameterService).APara;
}
public int methodA()
{
return Id+1;
}
}
public class B : IB
{
private readonly IServiceProvider _provider;
public B(IServiceProvider provider)
{
_provider = provider;
}
public int methodB()
{
return (_provider.GetService(typeof(IA)) as A).methodA();
}
}
public class C : IC
{
private readonly IServiceProvider _provider;
public C(IServiceProvider provider)
{
_provider = provider;
}
public int methodC()
{
return (_provider.GetService(typeof(IB)) as B).methodB();
}
}
In startup:
services.AddTransient<IParameterService>(x => new ParameterService(1));
services.AddTransient<IA,A>();
services.AddTransient<IB,B>();
services.AddTransient<IC, C>();
in controller:
private readonly A _A;
private readonly C _C;
public SomeController(IServiceProvider provider)
{
_A = (A)provider.GetService(typeof(IA));
_C=(C)provider.GetService(typeof(IC));
}
Result:

How to use Automapper IMappingAction with asp.net bolierplate?

Dears,
I used Automapper IMappingAction to encapsulate Before and After Map Actions into small reusable classes but i can't make my class work with ASPNET Bolierplate Ioc Castle Windsor
configuration.CreateMap<CustomerDto, Customer>()
.AfterMap<CustomerAction>().ReverseMap();
public class CustomerAction : IMappingAction<CustomerDto, Customer>
{
private readonly IObjectMapper _objectMapper;
public CustomerAction(IObjectMapper objectMapper)
{
_objectMapper = objectMapper;
}
public void Process(CustomerDto customerDto, Customer customer)
{
}
}
when my code get execute, i got exception that my class doesn't have parameterless constructor
https://github.com/aspnetzero/aspnet-zero-core/issues/1587#issuecomment-415617774
Do you try this?
cfg.CreateMap<CustomerDto, Customer>().AfterMap((source, destination) =>
{
var action = IocManager.IocContainer.Resolve<CustomerAction>();
action.Process(source, destination);
}).ReverseMap();
public class CustomerAction : IMappingAction<CustomerDto, Customer>, ITransientDependency
{
private readonly IObjectMapper _objectMapper;
public CustomerAction(IObjectMapper objectMapper)
{
_objectMapper = objectMapper;
}
public void Process(CustomerDto customerDto, Customer customer)
{
}
}

How can I pass a runtime parameter as part of the dependency resolution?

I need to be able to pass a connection string into some of my service implementations. I am doing this in the constructor. The connection string is configurable by user will be added the ClaimsPrincipal as a Claim.
All fine so far.
Unfortunately, I also want to be able to use the dependency injection features in ASP.NET Core to the fullest and resolve the service implementation though DI.
I have a POC implmentation:
public interface IRootService
{
INestedService NestedService { get; set; }
void DoSomething();
}
public class RootService : IRootService
{
public INestedService NestedService { get; set; }
public RootService(INestedService nestedService)
{
NestedService = nestedService;
}
public void DoSomething()
{
// implement
}
}
public interface INestedService
{
string ConnectionString { get; set; }
void DoSomethingElse();
}
public class NestedService : INestedService
{
public string ConnectionString { get; set; }
public NestedService(string connectionString)
{
ConnectionString = connectionString;
}
public void DoSomethingElse()
{
// implement
}
}
These services have been registered during startup and INestedService has been added the constructor of a controller.
public HomeController(INestedService nestedService)
{
NestedService = nestedService;
}
As expected, I get the error Unable to resolve service for type 'System.String' while attempting to activate 'Test.Dependency.Services.NestedService'.
What are my options here?
To pass a runtime parameter not known at the start of the application, you have to use the factory pattern. You have two options here:
factory class (similar to how IHttpClientFactory is implemented)
public class RootService : IRootService
{
public RootService(INestedService nested, IOtherService other)
{
// ...
}
}
public class RootServiceFactory : IRootServiceFactory
{
// in case you need other dependencies, that can be resolved by DI
private readonly IServiceProvider services;
public RootServiceFactory(IServiceProvider services)
{
this.services = services;
}
public IRootService CreateInstance(string connectionString)
{
// instantiate service that needs runtime parameter
var nestedService = new NestedService(connectionString);
// note that in this example, RootService also has a dependency on
// IOtherService - ActivatorUtilities.CreateInstance will automagically
// resolve that dependency, and any others not explicitly provided, from
// the specified IServiceProvider
return ActivatorUtilities.CreateInstance<RootService>(services,
new object[] { nestedService, });
}
}
and inject IRootServiceFactory instead of your IRootService
IRootService rootService = rootServiceFactory.CreateInstance(connectionString);
factory method
services.AddTransient<Func<string,INestedService>>((provider) =>
{
return new Func<string,INestedService>(
(connectionString) => new NestedService(connectionString)
);
});
and inject the factory method into your service instead of INestedService
public class RootService : IRootService
{
public INestedService NestedService { get; set; }
public RootService(Func<string,INestedService> nestedServiceFactory)
{
NestedService = nestedServiceFactory("ConnectionStringHere");
}
public void DoSomething()
{
// implement
}
}
or resolve it per call
public class RootService : IRootService
{
public Func<string,INestedService> NestedServiceFactory { get; set; }
public RootService(Func<string,INestedService> nestedServiceFactory)
{
NestedServiceFactory = nestedServiceFactory;
}
public void DoSomething(string connectionString)
{
var nestedService = nestedServiceFactory(connectionString);
// implement
}
}
Simple configuration
public void ConfigureServices(IServiceCollection services)
{
// Choose Scope, Singleton or Transient method
services.AddSingleton<IRootService, RootService>();
services.AddSingleton<INestedService, NestedService>(serviceProvider=>
{
return new NestedService("someConnectionString");
});
}
With appSettings.json
If you decide to hide your connection string inside appSettings.json, e.g:
"Data": {
"ConnectionString": "someConnectionString"
}
Then provided that you've loaded your appSettings.json in the ConfigurationBuilder (usually located in the constructor of the Startup class), then your ConfigureServices would look like this:
public void ConfigureServices(IServiceCollection services)
{
// Choose Scope, Singleton or Transient method
services.AddSingleton<IRootService, RootService>();
services.AddSingleton<INestedService, NestedService>(serviceProvider=>
{
var connectionString = Configuration["Data:ConnectionString"];
return new NestedService(connectionString);
});
}
With extension methods
namespace Microsoft.Extensions.DependencyInjection
{
public static class RootServiceExtensions //you can pick a better name
{
//again pick a better name
public static IServiceCollection AddRootServices(this IServiceCollection services, string connectionString)
{
// Choose Scope, Singleton or Transient method
services.AddSingleton<IRootService, RootService>();
services.AddSingleton<INestedService, NestedService>(_ =>
new NestedService(connectionString));
}
}
}
Then your ConfigureServices method would look like this
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration["Data:ConnectionString"];
services.AddRootServices(connectionString);
}
With options builder
Should you need more parameters, you can go a step further and create an options class which you pass to RootService's constructor. If it becomes complex, you can use the Builder pattern.
I devised this little pattern to help me resolve objects that require runtime parameters ,but also have dependencies which the DI container is able to resolve - I implemented this using the MS DI Container for a WPF App.
I already had a Service Locator (yes I know its a code smell - but I attempt to resolve that by the end of the example) that I used in specific scenarios to get access to objects in the DIC:
public interface IServiceFactory
{
T Get<T>();
}
Its implementation takes a func<> in the constructor to decouple the fact it relies on MS DI.
public class ServiceFactory : IServiceFactory
{
private readonly Func<Type, object> factory;
public ServiceFactory(Func<Type, object> factory)
{
this.factory = factory;
}
// Get an object of type T where T is usually an interface
public T Get<T>()
{
return (T)factory(typeof(T));
}
}
This was created in the composition root like so:
services.AddSingleton<IServiceFactory>(provider => new ServiceFactory(provider.GetService));
This pattern was extended to not only 'Get' objects of type T, but 'Create' objects of type T with parameters P:
public interface IServiceFactory
{
T Get<T>();
T Create<T>(params object[] p);
}
The implementation took another func<> to decouple the creation mechanism:
public class ServiceFactory : IServiceFactory
{
private readonly Func<Type, object> factory;
private readonly Func<Type, object[], object> creator;
public ServiceFactory(Func<Type, object> factory, Func<Type, object[], object> creator)
{
this.factory = factory;
this.creator = creator;
}
// Get an object of type T where T is usually an interface
public T Get<T>()
{
return (T)factory(typeof(T));
}
// Create (an obviously transient) object of type T, with runtime parameters 'p'
public T Create<T>(params object[] p)
{
IService<T> lookup = Get<IService<T>>();
return (T)creator(lookup.Type(), p);
}
}
The creation mechanism for the MS DI container is in the ActivatorUtilities extensions, here's the updated composition root:
services.AddSingleton<IServiceFactory>(
provider => new ServiceFactory(
provider.GetService,
(T, P) => ActivatorUtilities.CreateInstance(provider, T, P)));
Now that we can create objects the problem becomes we have no way of determining the type of object we need without the DI container actually creating an object of that type, which is where the IService interface comes in:
public interface IService<I>
{
// Returns mapped type for this I
Type Type();
}
This is used to determine what type we are trying to create, without actually creating the type, its implementation is:
public class Service<I, T> : IService<I>
{
public Type Type()
{
return typeof(T);
}
}
So to pull it all together, in your composition root you can have objects that don't have runtime parameters which can be resolved by 'Get' and ones which do resolved by 'Create' e.g.:
services.AddSingleton<ICategorySelectionVM, CategorySelectionVM>();
services.AddSingleton<IService<ISubCategorySelectionVM>, Service<ISubCategorySelectionVM, SubCategorySelectionVM>>();
services.AddSingleton<ILogger, Logger>();
The CategorySelectionVM has only dependencies that can be resolved via the DIC:
public CategorySelectionVM(ILogger logger) // constructor
And this can be created by anyone with a dependency on the service factory like:
public MainWindowVM(IServiceFactory serviceFactory) // constructor
{
}
private void OnHomeEvent()
{
CurrentView = serviceFactory.Get<ICategorySelectionVM>();
}
Where as the SubCategorySelectionVM has both dependencies that the DIC can resolve, and dependencies only known at runtime:
public SubCategorySelectionVM(ILogger logger, Category c) // constructor
And these can be created like so:
private void OnCategorySelectedEvent(Category category)
{
CurrentView = serviceFactory.Create<ISubCategorySelectionVM>(category);
}
Update : I just wanted to add a little enhancement which avoided using the service factory like a service locator, so I created a generic service factory which could only resolve objects of type B:
public interface IServiceFactory<B>
{
T Get<T>() where T : B;
T Create<T>(params object[] p) where T : B;
}
The implementation of this depends on the original service factory which could resolve objects of any type:
public class ServiceFactory<B> : IServiceFactory<B>
{
private readonly IServiceFactory serviceFactory;
public ServiceFactory(IServiceFactory serviceFactory)
{
this.serviceFactory = serviceFactory;
}
public T Get<T>() where T : B
{
return serviceFactory.Get<T>();
}
public T Create<T>(params object[] p) where T : B
{
return serviceFactory.Create<T>(p);
}
}
The composition root adds the original service factory for all the generic typed factories to depend on, and any of the typed factories:
services.AddSingleton<IServiceFactory>(provider => new ServiceFactory(provider.GetService, (T, P) => ActivatorUtilities.CreateInstance(provider, T, P)));
services.AddSingleton<IServiceFactory<BaseVM>, ServiceFactory<BaseVM>>();
Now our main view model can be restricted to creating only objects that derive from BaseVM:
public MainWindowVM(IServiceFactory<BaseVM> viewModelFactory)
{
this.viewModelFactory = viewModelFactory;
}
private void OnCategorySelectedEvent(Category category)
{
CurrentView = viewModelFactory.Create<SubCategorySelectionVM>(category);
}
private void OnHomeEvent()
{
CurrentView = viewModelFactory.Get<CategorySelectionVM>();
}
I know this is a bit old but thought i'd give my input since there is a easier way to do this in my opinion. This doesn't cover all the cases as shown in other posts. But this is a easy way of doing it.
public class MySingleton {
public MySingleton(string s, int i, bool b){
...
}
}
No lets create a service extention class to add easier and keep it neet
public static class ServiceCollectionExtentions
{
public static IServiceCollection RegisterSingleton(this IServiceCollection services, string s, int i, bool b) =>
services.AddSingleton(new MySingleton(s, i, b));
}
Now to call it from startup
services.RegisterSingleton("s", 1, true);
IMHO, follow the options pattern. Define a strong type to hold your connection string, then an IConfigureOptions<T> to configure it from your user claim.
public class ConnectionString {
public string Value { get; set; }
}
public class ConfigureConnection : IConfigureOptions<ConnectionString> {
private readonly IHttpContextAccessor accessor;
public ConfigureConnection (IHttpContextAccessor accessor) {
this.accessor = accessor;
}
public void Configure(ConnectionString config) {
config.Value = accessor.HttpContext.User ...
}
}
public class NestedService {
...
public NestedService(IOptions<ConnectionString> connection) {
ConnectionString = connection.Value.Value;
}
...
}
Further to #Tseng's extremely helpful answer, I found I could also adapt it to use delegates:
public delegate INestedService CreateNestedService(string connectionString);
services.AddTransient((provider) => new CreateNestedService(
(connectionString) => new NestedService(connectionString)
));
Implemented in RootService in the same way #Tseng suggested:
public class RootService : IRootService
{
public INestedService NestedService { get; set; }
public RootService(CreateNestedService createNestedService)
{
NestedService = createNestedService("ConnectionStringHere");
}
public void DoSomething()
{
// implement
}
}
I prefer this approach for cases where I need an instance of a factory in a class, as it means I can have a property of type CreateNestedService rather than Func<string, INestedService>.

FluentValidation as a service

I'm using FluentValidation 2 for validating some entities. I'd like to create an IValidationService that I can pass into other services to allow them to perform validation. I'd like to expose it like this:
public interface IValidationEngine
{
IEnumerable<ValidationError> Validate<T>(T entity);
}
Where ValidationError is a class that encapsulates my validation errors. Ideally, I'd like to not have to expose a specific validator to one of my services (such as OrderValidator). I'd like the validation service be capable of constructing/finding the correct validator. Does FV have anything built in for locating a validator for a specific type (and it internally caches)? Or, do I have to go the IValidatorFactory route and then wire each validator with my IoC container?
I've managed to solve this with the IValidatorFactory method. I'm using Ninject, so specific IoC details below would need to be changed.
public interface IValidationService
{
IEnumerable<ValidationError> Validate<T>(T entity)
where T : class;
}
public class FluentValidationService : IValidationService
{
private readonly IValidatorFactory validatorFactory;
public FluentValidationService(IValidatorFactory validatorFactory)
{
this.validatorFactory = validatorFactory;
}
public IEnumerable<ValidationError> Validate<T>(T entity)
where T : class
{
var validator = this.validatorFactory.GetValidator<T>();
var result = validator.Validate(entity);
return result.Errors.Select(e => new ValidationError(e.PropertyName, e.ErrorMessage));
}
}
// Then implement FV's IValidatorFactory:
public class NinjectValidatorFactory : ValidatorFactoryBase
{
private readonly IKernel kernel;
public NinjectValidatorFactory(IKernel kernel)
{
this.kernel = kernel;
}
public override IValidator CreateInstance(Type validatorType)
{
return kernel.TryGet(validatorType) as IValidator;
}
}
// I then wire both of these in a Ninject Module:
public class ValidationModule : NinjectModule
{
public override void Load()
{
this.Bind<IValidationService>().To<FluentValidationService>().InRequestScope(); // Specific to MVC.
this.Bind<IValidatorFactory>().To<NinjectValidatorFactory>().InRequestScope();
}
}
// Then I can use it inside a service:
public class FooService
{
private readonly IValidationService validationService;
public FooService(IValidationService validationService)
{
this.validationService = validationService;
}
public bool Add(Foo foo)
{
if(this.validationService.Validate(foo).Any())
{
// Handle validation errors..
}
// do other implementation details here.
}
}

Categories

Resources