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
Related
I am working on a web application which is built on ASP.NET Core and I am using Autofac for dependency injection.
I have an interface as ICacheProvider, and there are 3 concrete implementations of this interface - OrderCacheProvider, ProductsCacheProvider and CustomerCacheProvider. The infrastructure and logic are different for the different cache providers. They are registered as below:
builder.RegisterType<CustomerCacheProvider>()
.Keyed<ICacheProvider>(CacheType.Customer);
builder.RegisterType<OrderCacheProvider>()
.Keyed<ICacheProvider>(CacheType.Order);
builder.RegisterType<ProductCacheProvider>()
.Keyed<ICacheProvider>(CacheType.Product);
Now I have 3 controllers - OrdersController, ProductsController and CustomerController. Each controller expects an ICacheProvider in the below fashion
public class OrdersController: BaseController {
private readonly ICacheProvider _cacheProvider;
public OrdersController(ICacheProvider cacheProvider) {
_cacheProvider = cacheProvider;
}
}
Now my problem is how do I inject OrderCacheProvider is injected in OrdersController? The same goes for the CustomerCacheProvder to CustomersController and ProductsCacheProvider?
You can use the WithParameter method when you register your controller to specify which ICacheProvider it should use
builder.RegisterType<OrdersController>()
.WithParameter(ResolvedParameter.ForKeyed<ICacheProvider>(CacheType.Order));
Another option would be to use the KeyFilter attribute
public class OrdersController
{
public OrdersController([KeyFilter(CacheType.Order)]ICacheProvider cacheProvider)
{ }
}
I prefer the first solution than this one which looks more pure, your component just has to request ICacheProvider nothing more.
Another solution would be to create a custom module that will add the parameter for each controller based on conventions.
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry, IComponentRegistration registration)
{
base.AttachToComponentRegistration(componentRegistry, registration);
if (registration.Activator.LimitType.IsSubclassOf(typeof(BaseController)))
{
String controllerName = registration.Activator.LimitType.Name;
controllerName = controllerName.Substring(0, controllerName.Length - 10);
if (Enum.TryParse<CacheType>(controllerName, out CacheType cacheType))
{
registration.Preparing += (sender, e) =>
{
e.Parameters = new Parameter[]
{
ResolvedParameter.ForKeyed<ICacheProvider>(cacheType)
}
.Concat(e.Parameters);
};
}
else
{
// throw, use default cache, do nothing, etc.
throw new Exception($"No cache found for controller {controllerName}");
}
}
}
}
It is more code but you don't have to use the WithParameter for every controller registration, it can be great if you have lot of controller. You still have to register the module :
builder.RegisterModule<CacheProviderModule>();
I'm trying to use a Generic Controller in my Web API. My goal, which I am currently failing at, is to pass in an object from my front end that will have say a typeId. Based on this typeId I was going to use a factory to inject the correct class implementation of a generic interface. I believe my Factory, Interface and Service is correct, but for some reason when I add a Generic to the API I am getting a 404. It works without a generic and just a test method. I am using autofac for my IoC registration.
API Controller:
public class ListItemsController<T> : ApiControllerBase
{
private readonly IListItemsService<T> _service;
public ListItemsController(int listItemTypeId)
{
_service = ListItemsFactory<T>.InitializeService(listItemTypeId);
}
[HttpGet]
[Route("{listItemTypeId: int}")]
public IEnumerable<T> GetAll()
{
return _service.GetAll();
}
[HttpGet]
[Route("test")]
public IHttpActionResult Test()
{
return Ok();
}
}
Factory:
public class ListItemsFactory<T>
{
public ListItemsFactory(IPrimaryContext context) : base()
{
}
public static IListItemsService<T> InitializeService(int listItemType)
{
switch (listItemType)
{
case 1: return (IListItemsService<T>)
new FloorTypeService(new PrimaryContext());
default: return null;
}
}
}
Interface:
public interface IListItemsService<T>
{
IEnumerable<T> GetAll();
void Save(T obj);
T GetById(int id);
void Delete(int id);
}
Error:
No HTTP resource was found that matches the request URI 'http://localhost:9000/api/v1/listitems/test'. No type was found that matches the controller named 'listitems'.
I'm not sure what piece I'm missing here. I'm using routing attributes but here is my API config:
private static void SetupRoutes(HttpConfiguration config)
{
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
config.Routes.MapHttpRoute("DefaultApi", "api/v{version}/{controller}/{id}",
new { id = RouteParameter.Optional });
}
Instead of resolving the type and trying to map to the right Controller, you also can create a Controller for each Type, which inherits from your GenericController. Then you don't have to copy the Code, but have a Controller for each Type, where you can route to by RouteAttribute.:
public class ListItemsController<T> : ApiControllerBase
{
//Properties/Fields should be protected to can be accessed from InstanceController.
protected readonly IListItemsService<T> _service;
// I think listItemTypeId is not necessary, if generic-type T is used?
public ListItemsController()
{
_service = ListItemsFactory<T>.InitializeService();
}
[HttpGet] // No need for RouteAttribute, because it will be in InstanceController.
public IEnumerable<T> GetAll()
{
return _service.GetAll();
}
[HttpGet]
[Route("test")] // This can rest here, because you want to use it.
public IHttpActionResult Test()
{
return Ok();
}
}
The implemented InstanceController can look like this:
[RoutePrefix("api/{controller}")]
public class FloorItemsController ListItemsController<Floor>
{
// delegate the Constructor-call to base()
public ListItemsController()
:base()
{
}
// No need to reimplement Methods.
}
The RouteConfiguration should be set back to default, because RouteAttributes are set for this.
Basically, what you'll need to do is to replace the controller activator, with a custom implementation.
First, createa class that implements the IHttpControllerSelector interface. Take a look at this link for some of the thing you should be aware before creating a custom activator. At the bottom there's a link to some code example of a custom implmentation.
Now, this depends on what your rules will actually be, but for perfomance reasons,you should try to build a solution that always map the same controller name to the same closed type of your generic controller type. A simple implementation for your case would look something like this:
public HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
IHttpRouteData routeData = request.GetRouteData();
if (routeData == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
//get the generyc type of your controller
var genericControllerType = typeof(ListItemsController<>);
// Get the route value from which you'll get the type argument from your controller.
string typeParameterArgument = GetRouteVariable<string>(routeData, 'SomeKeyUsedToDecideTheClosedType');
Type typeArgument = //Somehow infer the generic type argument, form your route value based on your needs
Type[] typeArgs = { typeof(typeArgument) };
//obtain the closed generyc type
var t = genericControllerType.MakeGenericType(typeArgs);
//configuration must be an instance of HttpConfiguration, most likeley you would inject this on the activator constructor on the config phase
new HttpControllerDescriptor(_configuration, t.Name, t);
}
Finally, on your ApiConfig class you'll need to add this line:
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector),
new MyOwnActivatior());
I can't test this code right now, so it might need some tweaking, but hopefully this will guide you on the right direction. Do take notice of the link i pasted above, since there are important considerations you'll need to take into account before implementing a custom activator. Also, check the code example linked on that post to see how to implement the GetControllerMapping method
I am trying to write an API project in code first approach. I written some code but it shows error
An error occurred when trying to create a controller of type 'CatalogController'. Make sure that the controller has a parameterless public constructor.
and
Type Nop.Api.Controllers.CatalogController does not have a default constructor
Controller
public class CatalogController : ApiController
{
private readonly ICatalogModelFactory _catalogModelFactory;
public CatalogController(ICatalogModelFactory catalogModelFactory)
{
_catalogModelFactory = catalogModelFactory;
}
public HttpResponseMessage HomepageCategories()
{
HttpResponseMessage response = new HttpResponseMessage();
var model = _catalogModelFactory.PrepareHomepageCategoryModels();
var result = JsonConvert.SerializeObject(model);
response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(result) };
return response;
}
}
Can anyone please help me how solve this error? I am not getting what is wrong in the constructor part. When debugging this it is not hitting the breakpoint.
Why am I getting this error?
When you request a resource from a controller, the framework needs to process the request. So the routing identifies the controller, action etc. and then it needs to instantiate an instance of the controller in order to invoke the wanted method.
In order to do that, he will either need a public empty constructor or some way to resolve your constructor's dependencies.
In your case, you have one ctor that has a dependency of ICatalogModelFactory. The framework will need you to implement a Dependency Resolver and register you new resolver when the application starts (Global.asax) like this:
DependencyResolver.SetResolver(new MyDependencyResolver());
Here's and example of a UnityContainer custom dependency resolver as found in this link:
public class UnityDependencyResolver : IDependencyResolver
{
IUnityContainer container;
public UnityDependencyResolver(IUnityContainer container)
{
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch
{
return new List<object>();
}
}
}
And the registration occurred in the Global.asax Application_Start method:
IUnityContainer container = GetUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
By the way, another way to do so, is to create a ControllerFactory and simply resolve the controller with a DI container. I prefer using the dependency resolver for resolving controllers.
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.
In a simple mvc 4 app I installed Ninject.MVC3 nuget package.
This is my controller, very basic, ISomeClass is being injected in the constructor by ninject.
public class HomeController : Controller
{
private readonly ISomeClass _someClass;
public HomeController(ISomeClass someclass)
{
_someClass = someclass;
}
public ActionResult Index()
{
return View();
}
[ChildActionOnly]
public PartialViewResult MiniView()
{
return PartialView("miniview", _someClass.GetName());
}
}
This is SomeClass
public class SomeClass : ISomeClass
{
private readonly string _someName;
public SomeClass(string someName)
{
_someName = someName;
}
public string GetName()
{
return _someName;
}
}
In Index.cshtml view I have
#{ Html.RenderAction("MiniView","Home"); }
Now in NinjectWebCommon when I go to register the service I need to know if the request was a child action request or not. Like when I call Html.RenderAction. This is what I am trying but it is not working.
kernel.Bind<ISomeClass>().To<SomeClass>()
.WithConstructorArgument("someName", c => IsChildAction(c) ? "Child" : "Nope");
IsChildAction method - Always returns false.
private static bool IsChildAction(Ninject.Activation.IContext c)
{
var handler = HttpContext.Current.Handler;
/*Cant do this, ChildActionMvcHandler is internal*/
return handler is System.Web.Mvc.Html.ChildActionExtensions.ChildActionMvcHandler;
//OR
//This is how ControllerContext.IsChildAction gets its value in System.Web.Mvc but
//RouteData.DataTokens is empty for me
return ((MvcHandler)handler).RequestContext.RouteData.DataTokens
.ContainsKey("ParentActionViewContext");
}
Any ideas if this can be done?
ps: this is not actual code, just trying something. Is this something I should definately not do? Why?
I ended up checking if the current request has a previous handler. Seems like it is being set only on child actions.
HttpContext.Current.PreviousHandler != null &&
HttpContext.Current.PreviousHandler is MvcHandler;
If the IsChildAction is something only known at runtime and within the controller, I suggest you don't pass an instance of SomeClass. Pass a factory instead and build that instance when you need it using the factory. I think that approach would work best in your case.
For using the factory you can use Ninject.Extensions.Factory or implement one yourself:
public class SomeClassFactory
{
private readonly IKernel _kernel;
public SomeClassFactory(IKernel kernel)
{
_kernel = kernel;
}
public SomeClass Create(string name, bool isChild)
{
var childString = (isChild) ? "Child" : "Nope";
return _kernel.Get<SomeClass>(new ConstructorArgument("someName", childString));
}
}
UPDATE:
After you said a Factory wouldn't work, the only way I could figure out for you to have access to the RequestContext during controller creation would be with a custom controller factory. You won't be able to get it statically in your bindings, I'm afraid.
The code below performs resolution on your SomeClass at runtime depending on whether the RequestContext contains the information about child action. It uses a custom IControllerFactory which certainly could have a better implementation, but it is enough to show how it can be done.
internal class CustomControllerFactory : DefaultControllerFactory
{
internal const string ParentActionViewContextToken = "ParentActionViewContext";
private readonly IResolutionRoot _resolutionRoot;
public CustomControllerFactory(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
public override IController CreateController(RequestContext requestContext, string controllerName)
{
//You can improve this later if you want -> you'll need to figure out if your controller will fit into this case
//You can use marker interfaces, common supertype, etc... that's up to you
if (controllerName.Equals("home", StringComparison.InvariantCultureIgnoreCase))
{
var controllerType = typeof (HomeController);
var isChild = requestContext.RouteData.DataTokens.ContainsKey(ParentActionViewContextToken);
var constructorArgument = new ConstructorArgument("someName", (isChild) ? "Child" : "Nope");
var requestForDependency = _resolutionRoot.CreateRequest(typeof(IServiceClient), null, new Parameter[] { constructorArgument }, true, true);
var dependency = _resolutionRoot.Resolve(requestForDependency).SingleOrDefault();
return (IController)_resolutionRoot.Get(controllerType, new ConstructorArgument("service", dependency));
}
//Will go through the default pipeline (IDependencyResolver will be called, not affecting DI of other controllers)
return base.CreateController(requestContext, controllerName);
}
}
Make sure you bind it:
kernel.Bind<IControllerFactory>().To<CustomControllerFactory>();