WebAPI controller. How to add dynamic methods? - c#

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
{
}

Related

MVC 5 / UnityConfig - Same Interface - Multiple Implementations

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;
}

Conditional Dependency Resolving in Asp.net core

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();
}
}
}

An abstract class which can be derived by database classes

This is my abstract class:
namespace MusicStoreApp.BLL.Master
{
public abstract class Master<T>
{
MusicStoreEntities db = new MusicStoreEntities();
public void Add(T item)
{
db.T.Add(item);
db.SaveChanges();
}
}
}
This is my target output in the other classes:
public class AlbumRepository : Master<Album>
{
public void Add(Album item)
{
db.Albums.Add(item);
db.SaveChanges();
}
}
public class ArtistRepository : Master<Artist>
{
public void Add(Artist item)
{
db.Artists.Add(item);
db.SaveChanges();
}
}
What i am tring to do here, that i should create a reusable interface-like class. So, i can just type the name of the T reference and it will create the rest of the codes for me.
The way your sample is setup can't work because T needs to point to two different classes (the specific instance and the DbSet that contains that class). Instead, try this:
namespace MusicStoreApp.BLL.Master
{
public abstract class Master<T>
{
MusicStoreEntities db = new MusicStoreEntities();
public void Add(T item)
{
db.Entry(item).State = System.Data.Entity.EntityState.Added;
db.SaveChanges();
}
}
}
You don't need this T anonymous type. Just do something like this:
public abstract class Master
{
public abstract void Add(Master item);
}
Then you can just inherit the Master like this:
public class Album : Master
public override void Add(Album item)
{
db.Albums.Add(item);
db.SaveChanges();
}
}
If you want to use a repository for the add just remove the add function from master and make interface and inherit from it:
public interface IMasterRepository
{
public void Add(Master item);
}
public class AlbumRepository : IMasterRepository
public override void Add(Album item)
{
db.Albums.Add(item);
db.SaveChanges();
}
}
But don't mix the entity classes with the repositories.
You are mixing abstract with generic class. The former contains something that requires to be implemented by the inheritors while the later provides common implementation that differs by some type(s) of the objects involved. From your explanation (and since your "abstract" class does not contain any abstract method), looks like you need a generic class. Something like this
public class Master<T>
{
MusicStoreEntities db = new MusicStoreEntities();
public void Add(T item)
{
db.Set<T>().Add(item);
db.SaveChanges();
}
}
public class AlbumRepository : Master<Album> { }
public class ArtistRepository : Master<Artist> { }
Note that you don't even need the concrete classes (if that's all they are supposed to do).
You can do so by using reflection.
get property name
string PropertyName = T.GetType().Name + "s";
retrive the entity property
var property = db.GetType().Properties.Where(x => x.Name.CompareTo(PropertyName) == 0).FirstOrDefault();
then work with it directly
Thank you for all of your effort to answer :).
I found my answer, I hope it will help you too:
public abstract class RepositoryBase<T>:IRepository<T> where T:class
{
public void Add(T item)
{
db.Set<T>().Add(item);
db.SaveChanges();
}
public void Update(int id,T item)
{
db.Entry(db.Set<T>().Find(id)).CurrentValues.SetValues(item);
db.SaveChanges();
}
public void Delete(T item)
{
db.Set<T>().Remove(item);
db.SaveChanges();
}
public List<T> SelectAll()
{
return db.Set<T>().ToList();
}
public T SelectByID(int id)
{
return db.Set<T>().Find(id);
}
}

C# Attributes that figures out if another attribute is applied

I am working on a Asp.net MVC project and I am wondering if there is a way for the attributes to talk to other attributes.
For example, I have the following attributes
public class SuperLoggerAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Do something super
}
}
public class NormalLoggerAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Do something normal ONLY if the super attribute isn't applied
}
}
And I have the following controllers
[NormalLogger]
public class NormalBaseController : Controller
{
}
public class PersonController: NormalBaseController
{
}
[SuperLogger]
public class SuperController: NormalBaseControler
{
}
So basically, I want my SuperController to use SuperLogger and ignore NormalLogger (which was applied in the base), and PersonController should use the NormalLogger since it's not "overrided" by the SuperLogger. Is there a way to do that?
Thanks,
Chi
Why not just have SuperLoggerAttribute inherit from NormalLoggerAttribute and override the Log method?
I think this should work:
public enum LoggerTypes
{
Normal,
Super
}
public class LoggerAttribute : ActionFilterAttribute
{
public LoggerAttribute() : base()
{
LoggerType = LoggerTypes.Normal;
}
public LoggerAttribute(LoggerTypes loggerType) : base()
{
LoggerType = loggerType;
}
public LoggerTypes LoggerType
{
get;
set;
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (LoggerType == LoggerTypes.Super)
{
//
}
else
{
//
}
}
Usage:
[Logger(LoggerTypes.Normal)]
or
[Logger(LoggerTypes.Super)]

Dynamically selecting the type of a component given the type of its generic type parameter

I frequently seems to come up to a situation where I have an abstract type which needs to be processed differently depending on which concrete implementation it has.
As an example, an abstract class Payment could be subclassed as class CreditCard or class StoredCredit. To actually process the payment, we want to use an implementation of
interface IPaymentTaker {
PaymentProcessingResult Process(Payment payment); }
i.e. either
class CreditCardPaymentTaker : IPaymentTaker { ... }
or
class StoredCreditPaymentTaker : IPaymentTaker { ... }
In the past I have injected an IDictionary into the parent component and then done
_paymentTakers[payment.GetType()].Process(payment);
The downside of this is that the IPaymentTaker implementations are not strongly typed enough, so the first bit of the Process method has to be:
Process(Payment payment)
{
var creditCardPayment = payment as CreditCardPayment;
if (creditCardPayment == null)
throw new Exception("Payment must be of type CreditCard");
}
I'm sure there must be a name for the pattern I'm trying to implement but I don't know what it is!
Ideally I would
(a) be able to instantiate the PaymentProcessor based just on the type of the Payment, without creating the dictionary;
(b) be able to have strongly typed PaymentProcessors that only accept the subclass they can use.
Does anyone have a neat way of solving this problem?
You can solve this with a visitor:
interface IPaymentVisitor {
void Visit(CreditCard payment);
void Visit(StoredCredit payment);
}
abstract class Payment {
public abstract void Accept(IPaymentVisitor visitor);
}
class CreditCard : Payment {
public override void Accept(IPaymentVisitor visitor) {
visitor.Visit(this);
}
}
class StoredCredit : Payment {
public override void Accept(IPaymentVisitor visitor) {
visitor.Visit(this);
}
}
class PaymentTaker : IPaymentVisitor, IPaymentTaker {
public void Visit(CreditCard payment) {
// ...
}
public void Visit(StoredCredit payment) {
// ...
}
public PaymentProcessingResult Process(Payment payment) {
payment.Accept(this);
// ...
}
}
If you still want to separate the different payment takers, or if your hierarchy jitters, you can use an acyclic visitor (pdf):
interface IPaymentVisitor {
}
interface IPaymentVisitor<TPayment> : IPaymentVisitor where TPayment : Payment {
void Visit(TPayment payment);
}
abstract class Payment {
public abstract void Accept(IPaymentVisitor visitor);
}
class CreditCard : Payment {
public override void Accept(IPaymentVisitor visitor) {
if (visitor is IPaymentVisitor<CreditCard>) {
((IPaymentVisitor<CreditCard>)visitor).Visit(this);
}
}
}
class StoredCredit : Payment {
public override void Accept(IPaymentVisitor visitor) {
if (visitor is IPaymentVisitor<StoredCredit>) {
((IPaymentVisitor<StoredCredit>)visitor).Visit(this);
}
}
}
class CreditCardPaymentTaker : IPaymentVisitor<CreditCard>, IPaymentTaker {
public void Visit(CreditCard payment) {
// ...
}
public PaymentProcessingResult Process(Payment payment) {
payment.Accept(this);
// ...
}
}
class StoredCreditPaymentTaker : IPaymentVisitor<StoredCredit>, IPaymentTaker {
public void Visit(StoredCredit payment) {
// ...
}
public PaymentProcessingResult Process(Payment payment) {
payment.Accept(this);
// ...
}
}
interface IPayment
{
IPaymentTaker Taker {get;}
}
class CreditCardPayment : IPayment
{
IPaymentTaker Taker{ get {return new CreditCardPaymentTaker();}}
}
payment.Taker.Process(payment);
Even though James' method is ideal, using an IoC container could be difficult. Here's my Reflection or dynamics based approach. Doing the following will allow you to still use an IoC to setup the mapping between the PaymentTaker and Payment.
public class Payment
{
}
public class CreditCardPayment : Payment
{
}
public class StoreCreditPayment : Payment
{
}
public interface IPaymentTaker
{
}
public interface IPaymentTaker<T> : IPaymentTaker
{
void Process(T payment);
}
public static class PaymentTaker
{
public static void Process(Payment payment)
{
var paymentType = payment.GetType();
// You would have these already setup and loaded via your IOC container...
var paymentTakers = new Dictionary<Type, IPaymentTaker>();
paymentTakers.Add(typeof(CreditCardPayment), new CreditCardPaymentTaker());
paymentTakers.Add(typeof(StoreCreditPayment), new StoreCreditPaymentTaker());
// Get the payment taker for the specific payment type.
var paymentTaker = paymentTakers[paymentType];
// Execute the 'Process' method.
paymentTaker.GetType().GetMethod("Process").Invoke(paymentTaker, new object[]{ payment });
// If .NET 4.0 - dynamics can be used.
// dynamic paymentTaker = paymentTakers[paymentType];
// paymentTaker.Process((dynamic)payment);
}
}
public class CreditCardPaymentTaker : IPaymentTaker<CreditCardPayment>
{
public void Process(CreditCardPayment payment)
{
Console.WriteLine("Process Credit Card Payment...");
}
}
public class StoreCreditPaymentTaker : IPaymentTaker<StoreCreditPayment>
{
public void Process(StoreCreditPayment payment)
{
Console.WriteLine("Process Credit Card Payment...");
}
}
And then you can use it like this:
var cc = new CreditCardPayment();
PaymentTaker.Process(cc);
If you can ensure the names of the Payment and PaymentTaker match you can use something like this:
Process(Payment payment)
{
String typeName = "YourPathToPaymentTakers." + payment.GetType().Name + "Taker";
Type type = typeof(IPaymentTaker).Assembly.GetType(typeName);
IPaymentTaker taker = (IPaymentTaker)Activator.CreateInstance(type);;
}
I have used this approach in the past, but if you do not have 100% control of the names of the classes this could be a problem.

Categories

Resources