ASP.Net MVC, Ninject IOC - asp.net-mvc

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

Related

AuthorizeAttribute, constructors, and stopping dependency injection

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)

asp.net mvc 3 - call nonaction from other controller

I have 2 controllers CustomerController and PrivatemessageController
Customers has a nonaction method
private readonly ICustomerService _customerService;
public Customer(....) << autofac Ioc
{
}
[NonAction]
protected CustomerNavigationModel GetCustomerNavigationModel(Customer customer)
{
var model = new CustomerNavigationModel();
.... _customerSerice...
return model;
}
I'd like to get GetCustomerNavigationModel value from CustomerController as I don't want to recreate the same method for PrivateMessageController, is that possible in ASP.NET MVC 3.0 ?
Two options come to mind here.
Make the method public static:
[NonAction]
public static CustomerNavigationModel GetCustomerNavigationModel(Customer customer)
{
var model = new CustomerNavigationModel();
.... _customerSerice...
return model;
}
Create a base controller and implement the method there. Have both your controllers derive from your base controller:
public abstract class MyBaseController : Controller
{
[NonAction]
protected CustomerNavigationModel GetCustomerNavigationModel(Customer customer)
{
var model = new CustomerNavigationModel();
.... _customerSerice...
return model;
}
}
public class CustomerController : MyBaseController
{
....
}
public class PrivatemessageController : MyBaseController
{
....
}
Refactor the method into a separate class and use that class from your controllers. You can also just make the method static, and call it from PrivatemessageController using:
CustomerController.GetCustomerNavigationModel(customer);

ASP.NET MVC Ninject / DI - No parameterless constructor defined for this object

I am using trying to get my head round unit testing with DI/Mocks (Ninject/Moq) to inject a Product repository into my controller which I then pass to my view model in order to allow testing of that.
It is working great and is allowing me to unit test the controller action and the view model. However, when I run the application I get "No parameterless constructor defined for this object"....now I know this is due to the controller trying to initialise the View Model which doesn't have a parameterless constructor.
I could create the constructor and call my concrete repository from that (so unit tests still use the injected/mocked one).
Is this the correct approach? Any advice would be greatly appreciated!
Controller:
public class ProductsController : Controller
{
private readonly IProductRepository productRepository;
public ProductsController(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
//
// GET: /Products/
public ActionResult Index(ViewModels.ProductsIndex vm)
{
return View(vm);
}
}
View model:
public class ProductsIndex
{
public List<CTEntities.Product> ProductList { get; set; }
public ProductsIndex(IProductRepository prods)
{
ProductList = prods.List().ToList();
}
//Adding this constructor would fix my issue but is there a cleaner way?
public ProductsIndex()
{
var prod = new CTDAL.Product();
ProductList = prod.List().ToList();
}
}
Your View Model should be a DTO (Data Transfer Object) ... in that it should only contain properties, and it should NOT be responsible for getting data. Your controller should get the data for the View Model, like so:
New View Model:
public class ProductsIndex
{
public List<CTEntities.Product> ProductList { get; set; }
}
New Controller:
public class ProductsController : Controller
{
private readonly IProductRepository productRepository;
public ProductsController(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
//
// GET: /Products/
public ActionResult Index()
{
var products = productRepository.List().ToList();
return View(products);
}
}
One approach would be to let Ninject resolve your ProductsIndex instances. If you do that, it will automatically fill in the constructor arguments as required, provided IProductRepository is resolved using Ninject as well.
In your case could be something like:
Kernel.Bind<IProductRepository>().To<CTDAL.Product>();
Kernel.Bind<ProductsIndex>().ToSelf();
Now your ProductsController could look like this:
public class ProductsController : Controller
{
private readonly IProductRepository productRepository;
private readonly ProductsIndex productsIndex;
public ProductsController(IProductRepository productRepository,
ProductsIndex productsIndex)
{
this.productRepository = productRepository;
this.productsIndex = productsIndex;
}
//
// GET: /Products/
public ActionResult Index()
{
return View(productsIndex);
}
}
Keep in mind that this would not allow for request values to be mapped to your Viewmodel, so the data in your Viewmodel would only be dependent on the parameters you pass into it at the time you resolve it (in this case the product repository).

MVC Model State

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

ASP.NET MVC dependency injection and helpers

In asp.net MVC, dependency injection with controllers is simple and straightforward. Now, I'd like to remove most of the logic from views by using helpers. The problem is that these helpers use some of the objects that are injected.
Let me write an example:
public interface ISessionData
{
List<string> IdList {get;}
}
public MyController : Controller
{
public MyController(ISessionData sessionData)
{
...
}
}
session data is injected into controller. So far so good. But now I have a helper. Let's say it looks like this:
public class MyHelper
{
private readonly ISessionData sessionData;
public MyHelper(ISessionData sessionData)
{
this.sessionData = sessionData;
}
public bool CheckSomethingExistsInSession(string id)
{
return sessionData.IdList.Any(x => x.Id.Equals(id));
}
}
Now what? I'd like MyHelper to be injected into view. Only way I can see is adding this helper to model and passing it to view every time. Any other ideas?
In MVC it is better to pass ISessionData data from Controller to View (using ViewModel or ViewData):
ViewData["Session"] = sessionData.IdList.ToList();
And remove ISessionData dependency from the helper. Something like this:
public class MyHelper
{
//private readonly ISessionData sessionData;
public MyHelper(/*ISessionData sessionData*/)
{
//this.sessionData = sessionData;
}
public bool CheckSomethingExistsInSession(string id, IList<...> sessionData)
{
return sessionData.Any(x => x.Id.Equals(id));
}
}
In View:
<% var somethingExists = new MyHelper().CheckSomethingExistsInSession(
1, ViewData["Session"] as IList<...>); %>
UPDATED:
public static class MyHelper
{
public static bool CheckSomethingExistsInSession(string id, IList<...> sessionData)
{
return sessionData.Any(x => x.Id.Equals(id));
}
}
<% var somethingExists = MyHelper.CheckSomethingExistsInSession(
1, ViewData["Session"] as IList<...>); %>
You should remove session logic from your controller's constructor and insert it into the controllers action method by using an IModelBinder. See below:
public class SessionDataModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Get/create session data implementating ISeesionData or whatever here. This will be return to the controller action method.
return new SessionData()
}
}
On you controller you would do something like:
public MyController : Controller
{
public MyController()
{
....
}
public ActionResult Index(ISessionData sessionData)
{
// do stuff with ISessionData.
// Redirect or whatever.
return this.RedirectToAction("Index");
}
}
You need to add your IModelBinder like below for it to be called. You can do this in the http application's startup.
System.Web.Mvc.ModelBinders.Binders[typeof(ISessionData)] = new SessionDataModelBinder();

Resources