I have this (simplified) controller setup:
[CustomAuthorizeAttribute]
public class MainController : Controller {}
public class AccountController : MainController
{
private IService _iService;
public AccountController()
{
_service = DependencyFactory.Resolve<IService>(SessionManager.ServiceKey)
}
public AccountController(IService service)
{
_service = service;
}
}
And CustomAuthorizeAttribute looks something like:
public CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool serviceKeyIsGood = CheckServiceKey(SessionManager.ServiceKey);
return serviceKeyIsGood;
}
}
The goal is to only have the account controller run if the user is authenticated, as defined by the presence of a "good" service key.
The problem I'm having is that the constructor for AccountController runs before OnAuthorize runs which causes the service to blow up (by design) since its service key is bad.
What's the best way to manage this? I'd like to take advantage of the simplicity of the CustomAuthorizeAttribute, and I have to avoid re-architecting the way our services are instantiated. (And the dependency factory is necessary as MVC complains about now having parameterless constructors.)
You can use injection of factorymethod instead of service itself:
[CustomAuthorizeAttribute]
public class MainController : Controller
public class AccountController : MainController
{
private Func<IService> _serviceFactory;
public AccountController()
{
_serviceFactory= DependencyFactory.Resolve<Func<IService>>(SessionManager.ServiceKey)
}
public AccountController(Func<IService> serviceFactory)
{
_serviceFactory= serviceFactory;
}
}
and use: to get service: service = _serviceFactory() when you need it.
PS: I recommend you to use standard methods for DI in MVC (controller factory or internal dependency resolver) to avoid code such _serviceFactory= DependencyFactory.Resolve<Func<IService>>(SessionManager.ServiceKey)
Related
I'm using Ninject 3.0 to inject service layer data access classes into my controllers. I would like to add the client's domain user ID to these classes at runtime, but cannot figure out what approach I should use. Currently my NinjectModule looks something like this:
public class NinjectBindModule : NinjectModule
{
public override void Load()
{
Bind<ISomeRepo>().To<SomeRepo>();
}
}
My question, in two parts really is:
Should I use WithConstructorArgument to get the user ID into SomeRepo, or something else (property?). Can I even do this in the bind module, or does it have to be done at the kernel or controller level?
What method should I use to retrieve the client's domain user ID? I don't think I can use the Controller.User property at the kernel level or in the bind module, can I?
public class NinjectBindModule : NinjectModule
{
public override void Load()
{
Bind<ISomeRepo>().To<SomeRepo>();
Bind<IPrincipal>()
.ToMethod(ctx => HttpContext.Current.User)
.InRequestScope();
}
}
and then:
public class SomeRepo : ISomeRepo
{
private readonly IPrincipal _principal;
public SomeRepo(IPrincipal principal)
{
_principal = principal;
}
... some methods that will have access to the principal
}
I need to setup a policy in base controller that applies to all controller instance, like below:
public class BaseController : Controller
{
private IPolicy Policy;
public BaseController()
{
this.Policy= new Policy(HttpContext);
}
}
Within the Policy class, I need to do something like:
this.httpContextBase.User.
Questions: (Update)
What is the better way to design the BaseController in terms of using HttpContext and Unit test.
What is the correct way to unit test HttpContext?
Absolutely no way. You are using the HttpContext inside the constructor of a controller when this context is still not initialized. Not only that this code cannot be tested but when you run the application it will also crash with NRE. You should never use any HttpContext related stuff in a constructor of a controller.
One possibility is to refactor your code and perform this inside the Initialize method:
public class BaseController : Controller
{
private IPolicy Policy;
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
this.Policy = new Policy(HttpContext);
}
}
This being said, that's not the approach I would recommend. I would recommend you using dependency injection instead of service location which is considered by many as an anti-pattern.
So:
public abstract class BaseController : Controller
{
protected IPolicy Policy { get; private set; }
protected BaseController(IPolicy policy)
{
Policy = policy;
}
}
Now, all that's left is to configure your favourite Dependency Injection framework to inject the correct instance into the constructor. For example with Ninject.Mvc3 this is achieved with a single line of code:
kernel.Bind<IPolicy>().To<Policy>();
Now you can feel more than free to mock this IPolicy in your unit test without even caring about any HttpContext.
For example let's suppose that you have the following controller that you want to unit test:
public class FooController : BaseController
{
public FooController(IPolicy policy): base(policy)
{ }
[Authorize]
public ActionResult Index()
{
Policy.DoSomething();
return View();
}
}
Now, all that you need to do is pick up your favorite mock framework (Rhino Mocks in my case) and do the mocking:
[TestMethod]
public void Index_Action_Should_DoSomething_With_The_Policy()
{
// arrange
var policyStub = MockRepository.GenerateStub<IPolicy>();
var sut = new FooController(policyStub);
// act
var actual = sut.Index();
// assert
Assert.IsInstanceOfType(actual, typeof(ViewResult));
policyStub.AssertWasCalled(x => x.DoSomething());
}
First off, I'm new to Ninject, but whilst this question targets Ninject, it would seem to apply to DI in general.
I think I'm missing something here. Suggested solutions so far all seem to be horribly complex.
I had something like this:
public class MyController : Controller
{
private IMyService _Service;
public MyController()
:this(null)
{ }
public MyController(IMyService service)
{
_Service = service ?? new MyService(ModelState);
}
}
public IMyService
{}
public class MyService : IMyService
{
private ModelStateDictionary _Model;
public MyService(ModelStateDictionary model)
{
_Model = model;
}
}
And so I thought I'd go Ninject on it. And came up with this:
public class MyController : Controller
{
private IMyService _Service;
public MyController()
:this(null)
{
_Service = Locator.Kernel.Get<IMyService>(new Ninject.Parameters.ConstructorArgument("model", ModelState));
}
}
public class MyServiceModule : NinjectModule
{
public override Load()
{
Bind<IMyService>().To<MyService>(); //here
}
}
It seems to me though, I should be able to change the bit where it binds (marked here) so it knows at that point to get the modelstate, rather than when I want an instance in the constructor, which requires advance knowledge of the concrete service class.
Am I worrying needlessly or is there a better way of doing this?
Simon
Does MyService really need a ModelStateDictionary to be constructed?
I would look towards refactoring that, so that I was passing the ModelStateDictionary into the method I was calling, rather than requiring it for construction of the Service class.
If such a refactoring is unreasonable, you will probably want to add a layer of abstraction over the ModelStateDictionary
public interface IModelStateProvider {
ModelStateDictionary GetModelState();
}
And make an implementation of that interface that can retrieve the current context's ModelStateDictionary, then setup the binding of that interface and change your service class to take it in the constructor:
public class MyService : IMyService
{
private ModelStateDictionary _Model;
public MyService(IModelStateProvider modelStateProvider)
{
_Model = modelStateProvider.GetModelState();
}
}
I'm using Ninject to do some dependancy injection. (Mainly for the DAL), my project consists of 3 aspects and are as follows,
Project.Lib (Everything database,
services and anythign else that is
logic)
Project.Admin (Administration)
Project.Web (Front end what the user
see's)
Now, each of my controllers within my projects inherit from a BaseController
public abstract class BaseController : Controller
{
protected BaseController(ISession session)
{
_Session = session;
}
public ISession _Session { get; private set; }
}
And then and example controller might be like so,
public class ImageController : BaseController
{
private MediaService _mediaService;
public ImageController(ISession session) : base(session)
{
_mediaService = new MediaService(session);
}
[HttpGet]
public ActionResult List()
{
var RetVal = _mediaService.GetAllImages();
return View(RetVal);
}
}
As you can see the "Session" is passed from the controller to the service layer. I'm curious as to if this is good practie? ANy negitives to what we are doing here?
I'd avoid referencing ISession through your controller. A better solution would be to use Ninject to inject your services into your controllers. In this instance you'll need to create an abstraction for your MediaService class e.g.:
public interface IMediaService
{
SomeCollection GetAllImages();
// ...
}
You'd then use Ninject to supply an implementation of the above interface to your controller:
public class ImageController : BaseController
{
private IMediaService _mediaService;
public ImageController(IMediaService mediaService)
{
_mediaService = mediaService
}
[HttpGet]
public ActionResult List()
{
var RetVal = _mediaService.GetAllImages();
return View(RetVal);
}
}
Greetings
On all my controllers I recycle the same code that wraps my models and to accesses the service layer -- and I'm tired for copy / pasting it into each controller:
private IProjectService _service;
public New()
{
_service = new ProjectService(new ModelValidation(this.ModelState));
}
public New(IProjectService service)
{
_service = service;
}
Is there someplace where I can place this where all my controllers access it?
You could put in a base controller class that all your other controllers inherit from:
public class BaseController : Controller
{
protected IProjectService Service { get; private set; }
public New()
{
Service = new ProjectService(new ModelValidation(this.ModelState));
}
public New(IProjectService service)
{
Service = service;
}
}
Alternatively, you could read up on dependency injection and look at using an IOC container to inject these dependencies.
Welcome to the wonderful world of code smells. You have found one without even knowing what it was. Whenever you think to yourself. "There has to be a better way." There is. In this case a base class would go a long way toward solving your problem.
Controller base class?
Create a base controller, and derive your controllers from it.
public class BaseController : Controller
{
protected IProjectService _service;
public New()
{
_service = new ProjectService(new ModelValidation(this.ModelState));
}
public New(IProjectService service)
{
_service = service;
}
}
public class MyController : BaseController
{
public ActionResult Index()
{
}
}