I am having a 2 controller PayerController and BusinessController.
Both Controller constructors takes EntityManager as a parameter which is an abstract class.
I would like to resolve Each Manager class depending on the controller I am using.
For PayerController I would like to inject PayerManager class and for BusinessController I would like to inject BusinessManager.
Currentlly I am getting the last Object that has been resolved with EntityManager i.e BusinessManager.
I remember in Ninject we can do conditional injection pretty easily.
This is how current I am resolving the dependency But wont work.
Startup.cs
services.AddScoped(typeof(EntityManager), typeof(PayerManager));
services.AddScoped(typeof(EntityManager), typeof(BusinessManager));
Controllers
public class PayerController
{
private PayerManager Manager{get;}
public PayerController(EntityManager entityManager)
{
Manager = entityManager as PayerManager;
}
}
Manager Classes
public class PayerManager : EntityManager
{
public void MyPayer()
{
}
}
public class BusinessManager : EntityManager
{
public void MyBusiness()
{
}
}
public abstract class EntityManager
{
public string IAMCommon()
{
return "";
}
}
I don't understand why you think you need conditional dependency injection in this situation because the solution to make it work is very simple.
You can change your controllers to inject the correct type of dependency that they need.
public class PayerController
{
private PayerManager Manager { get; }
public PayerController(PayerManager manager)
{
Manager = manager;
}
}
public class BusinessController
{
private BusinessManager Manager { get; }
public BusinessController(BusinessManager manager)
{
Manager = manager;
}
}
Then make sure both types are registered in the service container.
services.AddScoped<PayerManager>();
services.AddScoped<BusinessManager>();
UPDATE
A better way is to use interfaces and possibly an abstract generic controller.
Define your interfaces:
public interface IEntityManager { }
public interface IPayerManager : IEntityManager { }
public interface IBusinessManager : IEntityManager { }
Update your classes to implement the interfaces:
public abstract class EntityManager : IEntityManager
{
protected EntityManager() { }
}
public class PayerManager : EntityManager, IPayerManager
{
public PayerManager() : base() { }
}
public class BusinessManager : EntityManager, IBusinessManager
{
public BusinessManager() : base() { }
}
Then create a base controller class:
public abstract class EntityController<T> : Controller where T : class, IEntityManager
{
protected(T manager)
{
Manager = manager
}
protected T Manager { get; }
}
Change your controllers to inherit from base controller:
public class PayerController : EntityController<IPayerManager>
{
public PayerController(IPayerManager manager) : base(manager) { }
}
public class BusinessController : EntityController<IBusinessManager>
{
public BusinessController(IBusinessManager manager) : base(manager) { }
}
And update the service register:
services.AddScoped<IPayerManager, PayerManager>();
services.AddScoped<IBusinessManager, BusinessManager>();
Make interface for each concrete class and Injecting interface in the controller
Startup.cs
services.AddScoped<IPayerManager, PayerManager>();
services.AddScoped<IBusinessManager, BusinessManager>();
Controllers
public class PayerController
{
private IPayerManager _entityManager{get;}
public PayerController(IPayerManager entityManager)
{
_entityManager= entityManager;
}
}
public class BusinessController
{
private IBusinessManager _entityManager{get;}
public BusinessController(IBusinessManager entityManager)
{
_entityManager= entityManager;
}
}
Manager Classes
public class PayerManager : EntityManager,IPayerManager
{
public void MyPayer()
{
}
}
public class BusinessManager : EntityManager,IBusinessManager
{
public void MyBusiness()
{
}
}
public abstract class EntityManager
{
public string IAMCommon()
{
return "";
}
}
Interfaces
public interface IPayerManager
{
void MyPayer();
}
public interface IBusinessManager
{
void MyBusiness();
}
#Maxspan, my suggestion:
Put all interfaces in Contracts folder and this folder inside your Models/Entities folder (Models/Entities folder - Contracts folder)
IEntityManager Interface
namespace WebApplication1.Entities.Contracts
{
public interface IEntityManager
{
//Method signature only
string IAMCommon();
}
}
IBusinessManager Interface
namespace WebApplication1.Entities.Contracts
{
public interface IBusinessManager : IEntityManager
{
//Method signature only
void MyBusiness();
}
}
IPayerManager Interface
namespace WebApplication1.Entities.Contracts
{
public interface IPayerManager : IEntityManager
{
//Method signature only
void MyPayer();
}
}
BusinessManager Concrete Class
using System;
using WebApplication1.Entities.Contracts;
namespace WebApplication1.Entities
{
public class BusinessManager : IBusinessManager
{
//Method signature in IEntityManager
public string IAMCommon() //Heritage in IBusinessManager (IBusinessManager : IEntityManager)
{
//Implement your code here.
throw new NotImplementedException();
}
//Method signature in IBusinessManager
public void MyBusiness()
{
//Implement your code here.
throw new NotImplementedException();
}
}
}
PayerManager Concrete Class
using System;
using WebApplication1.Entities.Contracts;
namespace WebApplication1.Entities
{
public class PayerManager : IPayerManager
{
//Method signature in IEntityManager
public string IAMCommon() //Heritage in IPayerManager (IPayerManager : IEntityManager)
{
//Implement your code here.
throw new NotImplementedException();
}
//Method signature in IPayerManager
public void MyPayer()
{
//Implement your code here.
throw new NotImplementedException();
}
}
}
Startup class
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using WebApplication1.Entities;
using WebApplication1.Entities.Contracts;
namespace WebApplication1
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IBusinessManager, BusinessManager>();
services.AddScoped<IPayerManager, PayerManager>();
}
}
}
BusinessController
using Microsoft.AspNetCore.Mvc;
using WebApplication1.Entities.Contracts;
namespace WebApplication1.Controllers
{
public class BusinessController : Controller
{
private readonly IBusinessManager _businessManager;
public BusinessController(IBusinessManager businessManager)
{
_businessManager = businessManager;
}
public IActionResult Index()
{
//Both methods in BusinessManager due to heritage (BusinessManager : IBusinessManager)
_businessManager.IAMCommon();
_businessManager.MyBusiness();
return View();
}
}
}
PayerController
using Microsoft.AspNetCore.Mvc;
using WebApplication1.Entities.Contracts;
namespace WebApplication1.Controllers
{
public class PayerController : Controller
{
private readonly IPayerManager _payerManager;
public PayerController(IPayerManager payerManager)
{
_payerManager = payerManager;
}
public IActionResult Index()
{
//Both methods in PayerManager due to heritage (PayerManager : IPayerManager)
_payerManager.IAMCommon();
_payerManager.MyPayer();
return View();
}
}
}
Related
I have 1 abstract class that is used by 2 other classes inheriting from it:
public abstract class FiltererBase
{
ColorsOrderer colorsOrderer;
public FiltererBase(ColorsOrderer colorsOrderer)
{
this.colorsOrderer = colorsOrderer;
}
protected string OrderColors(string colors)
{
return string.Join("", colors.ToCharArray().OrderBy(i => colorsOrderer.Order[i]));
}
}
public class Filterer1 : FiltererBase
{
public Filterer1(ColorsOrderer colorsOrderer)
: base(colorsOrderer) { }
}
public class Filterer2 : FiltererBase
{
public Filterer2(ColorsOrderer colorsOrderer)
: base(colorsOrderer) { }
}
As you can see, I am using dependency injection (DI) and passing the class instantiated from the child constructor to the parent constructor.
Is it really the best way to do DI with abstract (base) classes? Isn't the .NET Core framework providing a more automatic way to do that?
Unfortunately, it's not possible to inject parameters into a parent constructor.
You could use a composition approach instead of inheritance.
Refactoring your code to a composition approach, it would appear like this:
public class ColorFilter
{
ColorsOrderer colorsOrderer;
public ColorFilter(ColorsOrderer colorsOrderer)
{
this.colorsOrderer = colorsOrderer;
}
public string OrderColors(string colors)
{
return string.Join("", colors.ToCharArray().OrderBy(i => colorsOrderer.Order[i]));
}
}
public class Filterer1
{
ColorFilter colorFilter;
public Filterer1(ColorFilter colorFilter)
{
this.colorFilter = colorFilter;
}
public string OrderColors(string colors)
{
return this.colorFilter(colors);
}
}
public class Filterer2
{
ColorFilter colorFilter;
public Filterer2(ColorFilter colorFilter)
{
this.colorFilter = colorFilter;
}
public string OrderColors(string colors)
{
return this.colorFilter(colors);
}
}
I'd like to put in a base class a method in order not to repeat it in the inherited classes. There are interfaces for the base class and the inherited classes. Once I create a inherited class object I cannot use the base class method that I want to use. ¿What's wrong?
Thanks in advance.
public interface IRepository
{
string GetError(string LogNumber);
}
public class Repository : IRepository
{
public Repository()
{
}
public string GetError(string LogNumber)
{
return "The error is " + LogNumber;
}
}
public interface ICustomerRepository
{
// READ
List<Customer> ReadAll();
}
public class CustomerRepository : Repository, ICustomerRepository
{
public CustomerRepository() : base()
{
}
public List<Customer> ReadAll()
{
return fooFunction();
}
}
CustomerRepository myRepository = new CustomerRepository()
myRepository.
I think your code working fine. Please check below solution
public Form1()
{
InitializeComponent();
CustomerRepository myRepository = new CustomerRepository();
myRepository.GetError("string error");
}
public interface IRepository
{
string GetError(string LogNumber);
}
public class Repository : IRepository
{
public Repository()
{
}
public string GetError(string LogNumber)
{
return "The error is " + LogNumber;
}
}
public interface ICustomerRepository
{
// READ
List<Customer> ReadAll();
}
public class CustomerRepository : Repository, ICustomerRepository
{
public CustomerRepository() : base()
{
}
public List<Customer> ReadAll()
{
List<Customer> list;
return list = new List<Customer>();
}
}
public class Customer
{
}
Are you trying to put these statements outside the class? If yes, you should put them inside a method or preferably inside a main method.
Also, there is a semicolon missing at the end of the object initialization.
"CustomerRepository myRepository = new CustomerRepository();
myRepository."
Try correcting, you will be able to access the method from your base class.
I need to be able to serve additional methods in my generic controller if controller implements specific interface or has additional attribute or something like that. Here is what I have right now:
public abstract class AnimalController
{
[HttpPost]
public void Walk() { }
}
public class DogController : AnimalController
{
[HttpPost]
public void Bark() { }
}
public class CatController : AnimalController
{
[HttpPost]
public void Mew() { }
}
public class MutantController : DogController
{
[HttpPost]
public void Mew() { }
}
Mutant should have abilities of both Dog and Cat, but C# does not allow to do
public class MutantController : DogController, CatController
{
}
I was wondering what is the best way to solve this in context of WebAPI? Essentialy I need to add additional web methods depending on certain abilities. One solution is to do something like this:
public abstract class AnimalController
{
[HttpPost]
public void Walk() { }
}
public class DogController : AnimalController, ICanBark
{
[HttpPost]
public void Bark() { }
}
public class CatController : AnimalController, ICanMew
{
[HttpPost]
public void Mew() { }
}
public class MutantController : AnimalController, ICanMew, ICanBark
{
[HttpPost]
public void Bark() { }
[HttpPost]
public void Mew() { }
}
This will result in lots of additional code. I was thinking maybe SOMEHOW add methods dynamically so WebAPI knows to use additional controller when I place attributes on main one? Or processes via methods on attribute?
[CanMew]
[CanBark]
public class MutantController : AnimalController
{
}
Here is the Idea.
public interface IGeneralInterface { }
public interface IGenericInterface<T> : IGeneralInterface { }
public class GenericClass<T> : IGenericInterface<T> { }
public class SomeClient
{
Func<Type, IGeneralInterface> serviceFactory;
public SomeClient(Func<Type, IGeneralInterface> serviceFactory)
{
this.serviceFactory = serviceFactory;
}
public void DoSomething<T>()
{
var service = serviceFactory(typeof(T));
}
}
With Autofac, how can I inject this service factory into the client, so that the proper service can be resolved when client.DoSomething() is called?
I'm trying to import parts and include a custom MetadataAttribute, following the imperative model, using .NET 4.5
Below, I've included the simplest of example I can, which illustrates the problem.
When this code is executed, the Engine class constructor is called, and passed an empty Enumerator, rather than the two plugins which are clearly part of the project.
At the moment I'm suspecting the PluginMetadata attribute, but I don't see how to get Metadata into the catalog without it.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Registration;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var builder = new RegistrationBuilder();
builder.ForTypesDerivedFrom<IPlugIn>().Export<Lazy<IPlugIn, IPlugInMetadata>>();
builder.ForType<Engine>().Export();
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly(), builder);
var container = new CompositionContainer(catalog);
var engine = container.GetExport<Engine>();
engine.Value.Run();
}
}
internal class Engine
{
private IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> PlugIns { get; set; }
public Engine(IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> plugins)
{
PlugIns = plugins;
}
public void Run()
{
foreach (var plugIn in PlugIns)
{
Console.WriteLine("Starting {0}", plugIn.Metadata.Name);
plugIn.Value.Work();
}
}
}
interface IPlugIn
{
void Work();
}
interface IPlugInMetadata
{
string Name { get; }
}
[MetadataAttribute]
class PlugInMetadataAttribute : ExportAttribute, IPlugInMetadata
{
public PlugInMetadataAttribute(string name)
{
this.name = name;
}
private readonly string name;
public string Name { get { return name; } }
}
[PlugInMetadata("PlugIn1")]
class PlugIn1 : IPlugIn
{
public void Work()
{
Console.WriteLine("PlugIn 1 working");
}
}
[PlugInMetadata("PlugIn2")]
class PlugIn2 : IPlugIn
{
public void Work()
{
Console.WriteLine("PlugIn 2 working");
}
}
}
Metadata interfaces must not have any properties with setters. You should modify the IPlugInMetadata interface so its properties won't have any setters, otherwise the composition will fail:
interface IPlugInMetadata
{
string Name { get; }
}
Also, you should consider making your PlugInMetadataAttribute class inherit from ExportAttribute rather than Attribute. That will allow using this attribute as an export attribute and you won't have to use a RegistrationBuilder.
EDIT: I think I found your problem
When trying to use ImportMany in the constructor, you must specify so explicitly, so your constructor should look like this:
[ImportingConstructor]
public Engine([ImportMany] IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> plugins)
{
PlugIns = plugins;
}
Alternatively, you can choose to import it as a property:
[ImportMany]
private IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> PlugIns { get; set; }
As a side note, when deriving from ExportAttribute, you'd like to include constructors that automatically export your part as IPlugIn:
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
class PlugInMetadataAttribute : ExportAttribute, IPlugInMetadata
{
public PlugInMetadataAttribute()
: base(typeof(IPlugIn))
{
}
public PlugInMetadataAttribute(string contractName)
: base(contractName, typeof(IPlugIn))
{
}
public string Name { get; set; }
}