AOP: Custom Model Binder Attribute using Ninject - c#

In short: I am trying to create a custom model binder that will take in the type of user and get their id, then use a service class to retrieve the strongly typed object.
If there is a better way to do this, please let me know.
Elabaration:
I have ninject setup with all my bindings within my DomainService layer, 3 web ui's are hooked up to the domain service layer. Each asp.net mvc app loads the bindings into the kernal.
//my custom model binder
public class UserModelBinder : IModelBinder
{
private IAuthenticationService auth;
public UserModelBinder(IAuthenticationService _auth, EntityName type,
string loggedonuserid)
{
this.auth = _auth;
CurrentUserType = type;
CurrentUserId = loggedonuserid;
}
public EntityName CurrentUserType { get; private set; }
private string CurrentUserId { get; set; }
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
object loggedonuser = null;
if (CurrentUserType == EntityName.Client)
loggedonuser = GetLoggedOnClientUser(CurrentUserId);
else if (CurrentUserType == EntityName.Shop)
loggedonuser = GetLoggedOnShopUser(CurrentUserId);
else
throw new NotImplementedException();
return loggedonuser;
}
public ClientUser GetLoggedOnClientUser(string loggedonuserid)
{
var user = _auth.GetLoggedOnClientUser(loggedonuserid);
if (user == null)
throw new NoAccessException();
return user;
}
public ShopUser GetLoggedOnShopUser(string loggedonuserid)
{
var user = _auth.GetLoggedOnShopUser(loggedonuserid);
if (user == null)
throw new NoAccessException();
return user;
}
}
my Global.aspx.cs
// using NInject to override application started
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
// hand over control to NInject to register all controllers
RegisterRoutes(RouteTable.Routes);
//how do I instantiate?
ModelBinders.Binders.Add(typeof(object), new
UserModelBinder(null,EntityName.Client, User.Identity.Name));
}
My problem is IAuthentication is a service, it is connected to other things like a repository, how do I actually instantiate this properly? Should I create a new NinjectModule? I am really confused with this so any help is greatly appreciated. I have tried to pass in Container.Get(); - but it is null...
NOTE: the reason why I am creating a modelbinder- all controllers will require the type of user as I my service layer requires which type of user is making a request, most methods in my service layer will have overloads where it will do one thing for a ShopUser or ClientUser or any other user in the system...
EDIT:
I could very easiy within my controller call upon the IAuthenticationService and get the type of user and pass into my domainservice layer to process the relevant tasks but I just want to know how it is possible with the ModelBindings (and if it makes sense to do it that way).
Edit2: Is there a working sample of using a custom Attribute with AOP with the custom attribute calling/binding/getting an instance of ISomethingService?

You can use the Service Locator pattern here. Pass the Ninject Container (IKernel?) to the constructor and resolve the AuthenticationService each time you need to bind something.
A refinement of this could be to have a constructor argument Func where you pass the function to resolve the service. This would be more explicit and removes the dependency on Ninject. Something like this:
public class MyModelBinder : IModelBinder
{
Func<IAuthenticationService> _resolveAuthService;
public MyModelBinder(Func<IAuthenticationService> resolveAuthService)
{
_resolveAuthService = resolveAuthService;
}
public override object Bind(Context c)
{
var authService = _resolveAuthService();
authService.GetSomething();
// etc...
}
}

Related

How to use multiple repository with unit of work?

In the code below I want to get data using Repository or from multiple repositories in a controller.
I have two question:
How not to use an empty constructor?
and when used the uncommented code returns a null exception?
public class StudentController : Controller
{
private IStudentRepository _studentRepository;
public StudentController() { }
public StudentController(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
public ActionResult Index()
{
var x = _studentRepository.GetAll().ToList();
return View();
//using (var unitOfWork = new UnitOfWork(new PollingSystemDbContext()))
//{
// var x = unitOfWork.IStudentRepository.GetAll();
// var list = x.ToList();
// return View();
//}
}
}
• By default Controllers require a parameter-less constructor to function. If you don't want to keep the unused parameter-less constructor in the Controller, you can either:
Override the DefaultControllerFactory and wire it so it returns a new instance of a Controller with your dependencies.
public class CustomControllerFactory : DefaultControllerFactory {
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
if (controllerType == typeof(StudentController)) {
return new StudentController(new StudentRepository());
}
return base.GetControllerInstance(requestContext, controllerType);
}
}
Then register the new factory in global.asax
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
Keep in mind, that for each controller, you'll need to wire the dependencies yourself.
A better approach is to look into using an IoC Container such as StructureMap to wire up the dependencies for you.
Simply install the following package StructureMap.MVC5.Update.
If your dependencies follow the default convention of IDependency for interfaces, and Dependency for implementations, they will be automatically picked up and wired by StructureMap.
If you need to wire a specific dependency, navigate to DefaultRegistry.cs and add your dependencies.
• The commented code returns null reference exception because you're not passing the model back to the view
var list = x.ToList();
return View(list); //pass the list back

WebApi: Per Request Per Action DbSession using IoC, how?

Our existing database deployment has a single 'master' and a read-only replica. Using ASP.NET's Web API2 and an IoC container I want to create controller actions whose attribute (or lack there of) indicate which database connection is to be used for that request (See Controller and Services usage below)...
public MyController : ApiController
{
public MyController(IService1 service1, IService2 service2) { ... }
// this action just needs the read only connection
// so no special attribute is present
public Foo GetFoo(int id)
{
var foo = this.service1.GetFoo(id);
this.service2.GetSubFoo(foo);
return foo;
}
// This attribute indicates a readwrite db connection is needed
[ReadWrteNeeded]
public Foo PostFoo(Foo foo)
{
var newFoo = this.service1.CreateFoo(foo);
return newFoo;
}
}
public Service1 : IService1
{
// The dbSession instance injected here will be
// based off of the action invoked for this request
public Service1(IDbSession dbSession) { ... }
public Foo GetFoo(int id)
{
return this.dbSession.Query<Foo>(...);
}
public Foo CreateFoo(Foo newFoo)
{
this.dbSession.Insert<Foo>(newFoo);
return newFoo;
}
}
I know how to setup my IoC (structuremap or Autofac) to handle per request IDbSession instances.
However, I'm not sure how I would go about making the type of IDbSession instance for the request to key off the indicator attribute (or lack there of) on the matching controller's action. I assume I will need to create an ActionFilter that will look for the indicator attribute and with that information identify, or create, the correct type of IDbSession (read-only or read-write). But how do I make sure that the created IDbSession's lifecycle is managed by the container? You don't inject instances into the container at runtime, that would be silly. I know Filters are created once at startup (making them singleton-ish) so I can't inject a value into the Filter's ctor.
I thought about creating an IDbSessionFactory that would have 'CreateReadOnlyDbSession' and 'CreateReadWriteDbSession' interfaces, but don't I need the IoC container (and its framework) to create the instance otherwise it can't manage its lifecycle (call dispose when the http request is complete).
Thoughts?
PS During development, I have just been creating a ReadWrite connection for every action, but I really want to avoid that long-term. I could also split out the Services methods into separate read-only and read-write classes, but I'd like to avoid that as well as placing GetFoo and WriteFoo in two different Service implementations just seems a bit wonky.
UPDATE:
I started to use Steven's suggestion of making a DbSessionProxy. That worked, but I was really looking for a pure IoC solution. Having to use HttpContext and/or (in my case) Request.Properties just felt a bit dirty to me. So, if I had to get dirty, I might as well go all the way, right?
For IoC I used Structuremap and WebApi.Structuremap. The latter package sets up a nested container per Http Request plus it allows you to inject the current HttpRequestMessage into a Service (this is important). Here's what I did...
IoC Container Setup:
For<IDbSession>().Use(() => DbSession.ReadOnly()).Named("ReadOnly");
For<IDbSession>().Use(() => DbSession.ReadWrite()).Named("ReadWrite");
For<ISampleService>().Use<SampleService>();
DbAccessAttribute (ActionFilter):
public class DbAccessAttribute : ActionFilterAttribute
{
private readonly DbSessionType dbType;
public DbAccessAttribute(DbSessionType dbType)
{
this.dbType = dbType;
}
public override bool AllowMultiple => false;
public override void OnActionExecuting(HttpActionContext actionContext)
{
var container = (IContainer)actionContext.GetService<IContainer>();
var dbSession = this.dbType == DbSessionType.ReadOnly ?
container.GetInstance<IDbSession>("ReadOnly") :
container.GetInstance<IDbSession>("ReadWrite");
// if this is a ReadWrite HttpRequest start an Request long
// database transaction
if (this.dbType == DbSessionType.ReadWrite)
{
dbSession.Begin();
}
actionContext.Request.Properties["DbSession"] = dbSession;
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var dbSession = (IDbSession)actionExecutedContext.Request.Properties["DbSession"];
if (this.dbType == DbSessionType.ReadWrite)
{
// if we are responding with 'success' commit otherwise rollback
if (actionExecutedContext.Response != null &&
actionExecutedContext.Response.IsSuccessStatusCode &&
actionExecutedContext.Exception == null)
{
dbSession.Commit();
}
else
{
dbSession.Rollback();
}
}
}
}
Updated Service1:
public class Service1: IService1
{
private readonly HttpRequestMessage request;
private IDbSession dbSession;
public SampleService(HttpRequestMessage request)
{
// WARNING: Never attempt to access request.Properties[Constants.RequestProperty.DbSession]
// in the ctor, it won't be set yet.
this.request = request;
}
private IDbSession Db => (IDbSession)request.Properties["DbSession"];
public Foo GetFoo(int id)
{
return this.Db.Query<Foo>(...);
}
public Foo CreateFoo(Foo newFoo)
{
this.Db.Insert<Foo>(newFoo);
return newFoo;
}
}
I assume I will need to create an ActionFilter that will look for the indicator attribute and with that information identify, or create, the correct type of IDbSession (read-only or read-write).
With your current design, I would say an ActionFilter is the way to go. I do think however that a different design would serve you better, which is one where business operations are more explicitly modelled behind a generic abstraction, since you can in that case place the attribute in the business operation, and when you explicitly separate read operations from write operations (CQS/CQRS), you might not even need this attribute at all. But I'll consider this out of scope of your question right now, so that means an ActionFilter is the the way to go for you.
But how do I make sure that the created IDbSession's lifecycle is managed by the container?
The trick is let the ActionFilter store information about which database to use in a request-global value. This allows you to create a proxy implementation for IDbSession that is able to switch between a readable and writable implementation internally, based on this setting.
For instance:
public class ReadWriteSwitchableDbSessionProxy : IDbSession
{
private readonly IDbSession reader;
private readonly IDbSession writer;
public ReadWriteSwitchableDbSessionProxy(
IDbSession reader, IDbSession writer) { ... }
// Session operations
public IQueryable<T> Set<T>() => this.CurrentSession.Set<T>();
private IDbSession CurrentSession
{
get
{
var write = (bool)HttpContext.Current.Items["WritableSession"];
return write ? this.writer : this.reader;
}
}
}

Create instance of interface with dependency injection

I have a base controller and before every page load I want to get the current user. I originally had a constructor in my BaseController that looked like this
public BaseController(ISystemUserCommand command)
{
_systemUserCommand = command
}
The problem with this then is that every controller that inherits from the BaseController would have to contain the ISystemUserCommand in its constructor, which I don't think would be good.
Instead I tried to create just an instance of the service class (shown below - it's the commented line under var sid...) but I need to pass in user service. How would I pass in the user service here or is this a bad way of doing it?
public abstract class BaseController : Controller
{
public SystemUserViewModel CurrentUser { get; set; }
private readonly ISystemUserCommand _systemUserCommand;
public SystemUserViewModel GetCurrentUser()
{
if (HttpContext == null || HttpContext.User == null) return null;
if (CurrentUser != null) return CurrentUser;
var sid = System.Web.HttpContext.Current.Request.LogonUserIdentity.User.ToString();
//var command = new SystemUserCommand();
CurrentUser = _systemUserCommand.GetUser(sid);
return CurrentUser;
}
public void SetUserInformation(SystemUserViewModel currentUser)
{
ViewBag.UserId = currentUser.SystemUserId;
ViewBag.FullName = string.Format("{0} {1}", currentUser.FirstName, currentUser.LastName);
ViewBag.FirstName = currentUser.FirstName;
ViewBag.LastName = currentUser.LastName;
ViewBag.CurrentUser = currentUser;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var currentUser = GetCurrentUser();
if (currentUser != null)
{
if (currentUser.IsActive)
{
SetUserInformation(currentUser);
}
else
filterContext.Result = RedirectToAction("denied", "unauthorized");
}
else
filterContext.Result = RedirectToAction("denied", "unauthorized");
base.OnActionExecuting(filterContext);
}
}
public class SystemUserCommand : ISystemUserCommand
{
private readonly ISystemUserBusiness _systemUserBusiness;
public SystemUserCommand(ISystemUserBusiness systemUserBusiness)
{
_systemUserBusiness = systemUserBusiness;
}
...
}
You could use property injection instead of constructor injection, via the base class, eg using unity:
public abstract class BaseController : Controller
{
[Dependency]
public ISystemUserCommand SystemUserCommand { get; set; }
}
This would mean the interface reference is only on the base class.
See here for the full examples.
EDIT, Autofac example:
You don't need property attributes on the dependency,
public abstract class BaseController : Controller
{
public ISystemUserCommand SystemUserCommand { get; set; }
}
Just to register the properites to auto resolve on the autofac builder:
builder.RegisterControllers(typeof(MvcApplication).Assembly).Where(t => t.IsAssignableFrom(typeof(BaseController))).PropertiesAutowired();
See autofac property injection here.
First of all, it does not seem a good idea to have OnActionExecuting override in the controller. You can use filters, that are specially designed for this purpose. And it seems that is the main reason you created the BaseController at all.
Regarding the problem with injecting the system command in all the required service, I would do so, but without inheriting from a base class, since I generally prefer aggregation to inheritance. That would mean that each controller that needs to work with the service will get it.
Another option that I have used few times to abstract some operations is to create a UserSerivce that will provide the required operations to the controllers. It will have ISystemUserCommand and HttpContext injected inside so that all of your controllers won't have to do the job. You can either use HttpContext.Current as static or abstract it away if you need testability.
Moreover I would not recommend property injection since it is more obscure than constructor injection that should be preferred if possible.
You can read more about filters here. Unfortunately if you use filters it's not that easy to inject in filters themselves and mostly done with property injection or ServiceLocator pattern (which is not good usually). It's possible to do better with some amount of voodoo though. I think that SimpleInjector has a lot of examples and tutorials on how to apply DI to filters in MVC, maybe they even have a nuget package now to ahieve that.

How to handle this scenario in mvc c#?

I am working on a multi-tenant app with asp.net mvc. I have to identify tenant for each request so i have created a class below:
public class TenantProvider
{
public static Tenant Tenant
{
get
{
Tenant tenant = HttpContext.Current.Items["Tenant"] as Tenant;
if (tenant == null)
{
var tenantUsername = HelperUtility.GetCurrentRequestHost();
//The below line of code is my problem
TenantRepository tenantRepository = new TenantRepository(new AppointContext());
tenant = tenantRepository.GetByUsername(tenantUsername);
HttpContext.Current.Items.Add("Tenant", tenant);
}
return tenant;
}
}
}
This class static property returning the Tenant for current request. It will first check for the Tenant in cache, if not found than if will get the Tenant from the database, initialize the cache and return the Tenant.
For getting Tenant form the database i am creating a TenantRepository instance. TenantRepository has a dependency over database context, which i am passing it while creating its instance.
Now when i have to do other database operation on current Tenant than i have to create a new Repository instance at some other place and have to pass new Context, so the actual context with which i have extracted the Tenant and the new Context differ which i think may create the problem.
So my question is how can i handle this scenario, so that same context instance will be used ??
The solution you are looking for is the Unit of Work design pattern. From Martin Fowler:
Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.
ref: http://martinfowler.com/eaaCatalog/unitOfWork.html
This pattern allows you to enroll multiple transactions into a single context. This is a very common pattern, and here is one possible implementation. First, create a Unit of Work object which will hold a reference to your central context, and which will initialize your repositories with that context (this implementation uses the Entity Framework):
public class UnitOfWork : IUnitOfWork
{
internal EntitiesContext _context = new EntitiesContext ();
private ITenantRepository _tenantRepository;
private IOtherRepository _otherRepository;
public ITenantRepository TenantRepository
{
get
{
if (_tenantRepository== null)
{
_tenantRepository= new TenantRepository(_context);
}
return _tenantRepository;
}
}
public IOtherRepository OtherRepository
{
get
{
if (_otherRepository== null)
{
_otherRepository= new OtherRepository(_context);
}
return _otherRepository;
}
}
public void Save()
{
_context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
_context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
Note that if you use any repository with this pattern, they will all use the same context.
Your controller should either initializing the Unit of of Work, or even better, have it injected into its constructor:
public TenantController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_tenantRepository = unitOfWork.TenantRepository;
_otherRepository = unitOfWork.OtherRepository;
}
If you need to use the UnitOfWork to another layer, you would typically pass it as an argument to another object's constructor:
public ActionResult Index()
{
TenantProvider provider = new TenantProvider(_unitOfWork);
_otherRepository.DoWork();
_unitOfWork.Save();
}
Now your TenantProvider can do some work with its respective repository, but the Unit of Work's OtherRepository can also do some work using the same context.
In addition to #ChrisHardie, I want to add some MVC specifics: I think it is a very good practice to inject the Unit of Work into the controllers. In order to do so, you can create a custom ControllerFactory that is derived from DefaultControllerFactory and is registered at application startup:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
// Analyze whether instance of controllerType should be created directly or
// whether the Unit of Work should be injected
if (needsUnitOfWork)
return (IController)Activator.CreateInstance(controllerType, unitOfWork);
else
return (IController)Activator.CreateInstance(controllerType);
}
}
In order to discern between controllers that need a Unit of Work and those that do not, you could use reflection (custom attributes or inspecting constructor arguments). Maybe you can also assume that each controller needs a Unit of Work for the moment.
If you are already using an Inversion of Control container, it can support you in creating the instances (IoC containers are usually plugged in in a ControllerFactory in MVC). If not, you might consider to start using one.
You can register the ControllerFactory like this:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// ...
RegisterCustomControllerFactory ();
// ...
}
private void RegisterCustomControllerFactory ()
{
IControllerFactory factory = new CustomControllerFactory();
ControllerBuilder.Current.SetControllerFactory(factory);
}
}
As this answers builds upon the extension points for Dependency Injection in MVC, this link might help.

Dealing with Ninject binding and parameterless constructor

I have a class LkCredentials, which is used to store data from SQL table.
[Table(Name = "Credentials")]
public class LkCredentials : LkTable
{
// Database fields
[Column(Name = "id", IsPrimaryKey = true)]
public Binary Uid { get; set; }
...
// Used for dependency injection through Ninject
public ICustomer Customer { get; set; }
public LkCredentials(ICustomer Customer)
{
this.Customer = Customer;
}
// Data loader from database
public void Load(string login)
{
var user = (new SqlTRepository<LkCredentials>()).DBObject.Where(x => x.Login == login).Single();
... // copying data from user to this
}
I'm using Ninject to inject proper ICustomer class this way:
// Create new instance for correct constructor to run and Ninject to resolve
var cred = new LkCredentials((ICustomer)null);
// Load data from database
cred.Load(model.UserName);
But in the process of loading data (void Load), in the variable user new instance of LkCredentials is created, and compiler demands parameterless constructor to be defined. If I create parameterless constructor, then it will be used to create new instance of LkCredentials, but Ninject will not bind correct class - cause constructor incorrect :( And NullReference exception will be raised.
I tried to create constructors chain:
public LkCredentials() : this((ICustomer)null)
{ }
But it didn't work.
What I can do for Ninject to work properly? Any ideas?
P.S.:
Ninject installed as MVC Extension.
Ninject injection in controllers works great, with the same bindings.
Ninject bindings from NinjectWebCommon.cs:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICustomer>().ToProvider<ObjectProvider<ICustomer, Customer, Customer82>>();
kernel.Bind<IAddress>().ToProvider<ObjectProvider<IAddress, Address, ContactInfo>>();
}
public class ObjectProvider<T1,T2,T3> : IProvider
{
public Type Type { get { return typeof(T1); } }
public object Create(IContext context)
{
var securityInfo = context.Kernel.Get<SecurityInformation>();
if (securityInfo.isAuthenticated & securityInfo.DatabaseType == "81")
return context.Kernel.Get<T2>();
else if (securityInfo.isAuthenticated & securityInfo.DatabaseType == "82")
return context.Kernel.Get<T3>();
else
return context.Kernel.Get<T2>();
}
}
I am a student of Ninject and like it a lot. I think the issue is you need to bind LkCredentials to an ILkCredentials and bind it with a parameter. Something like this:
Bind<ILkCredentials>().To<LkCredentials>().WithConstructorArgument("Customer", "Customer");
In the WithConstructorArgument(, ). It's a little confusing because your parameter name is also the name of the object you want to inject.
Here's another example where the parameter name is "name" and the constructor argument is "Fender":
Bind<IGuitar>().To<Guitar>().WithConstructorArgument("name", "Fender");
Hope that helps.
I left parameterless constructor as is, but at the first point, where a need a Customer, I added:
if (this.Customer == null)
this.Customer = (ICustomer)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(ICustomer));
It was enough.
Great thanks to Stephen Byrne, he gives me great advice!

Categories

Resources