Implement controller with arguments in constructor - c#

I have alot of not always static values (slogan, banner, description...) and PartialViews (block_head, block_footer, block_right), where i should display it. So, i need to pass big collection of this values into Partial in every Action and it's not very good for me.
I've found interesting solution here: http://www.asp.net/mvc/tutorials/passing-data-to-view-master-pages-cs , in part "Good solution". I could move all initialization of this values in ApplicationController and Implement it from my controllers.
But, i'd like to go forward and initialize my Interfaces in ApplicationController too :) If i could do it, i think it should be fantastic. I use Ninject, so, some code:
public abstract class ApplicationController : Controller
{
//
// GET: /Application/
private readonly IModuleRepository _moduleRepository;
public IModuleRepository moduleRepository
{
get { return _moduleRepository; }
}
public ApplicationController(IModuleRepository moduleRepository)
{
_moduleRepository = moduleRepository;
foreach (var module in _moduleRepository.GetAllModules())
ViewData[module.name] = module.value;
}
}
Implementing:
public class HomeController : ApplicationController
{
//I can use here moduleRepository without HomeController initialization
}
Just one problem, i don't know how to Implement ApplicationController, if it has arguments. Is it good way and is it any solution for my problem? In future i'm going to set 5-7 Interfaces and have about 10-15 Controllers, so it could be very good to Initialize them all in ApplicationController and Implement in other. Thx, sorry if the questiong is stupid.
Ok, adding:
Now, if i have 10 interfaces, it should be like this:
public class HomeController
{
private IModuleRepository _moduleRepository;
private IBookRepository _bookRepository;
private ITableRepository _tableRepository;
private IClassRepository _classRepository;
private IRoomRepository _roomRepository;
private IUserRepository _userRepository;
private IWindowRepository _windowRepository;
private IChairRepository _chairRepository;
private IDoorRepository _doorRepository;
private IWCRepository _wcRepository;
public HomeController(IModuleRepository moduleRepository, IBookRepository bookRepository, ITableRepository tableRepository, IClassRepository classRepository, IRoomRepository roomRepository, IUserRepository userRepository, IWindowRepository windowRepository, IChairRepository chairRepository, IDoorRepository doorRepository, IWCRepository wcRepository)
{
_moduleRepository = moduleRepository;
_bookRepository = bookRepository;
_tableRepository = tableRepository;
_classRepository = classRepository;
_roomRepository = roomRepository;
_userRepository = userRepository;
_windowRepository = windowRepository;
_chairRepository = chairRepository;
_doorRepository = doorRepository;
_wcRepository = wcRepository;
}
public ActionResult Index()
{
ViewBag.Windows = _windowRepository.GetAllWindows();
ViewBag.Doors = _doorRepository.GetAllDoors();
// e.t.c.
return View();
}
}
And i have to initialize this in each of my Controller, where i need to use this repositories (Home, Admin, ...).
So, if i could to make something like this:
public class HomeController : ApplicationController
{
public ActionResult Index()
{
ViewBag.Windows = windowRepository.GetAllWindows();
ViewBag.Doors = doorRepository.GetAllDoors();
return View();
}
}
And initialize just one time here:
public abstract class ApplicationController : Controller
{
public ApplicationController(IModuleRepository moduleRepository, IBookRepository bookRepository, ITableRepository tableRepository, IClassRepository classRepository, IRoomRepository roomRepository, IUserRepository userRepository, IWindowRepository windowRepository, IChairRepository chairRepository, IDoorRepository doorRepository, IWCRepository wcRepository)
{
// Initialize repositories just one time here
}
}
it could be very good, but i need to pass arguments in constructor of implementing class

It looks like you may be talking about Constructor Injection. The constructor of your sub type can invoke the constructor of your base type in order to inject the IModuleRepository
public class HomeController : ApplicationController
{
public HomeController(IModuleRepository moduleRepository) : base(moduleRepository)
{
//other constructor code here
}
public HomeController() : this(null)
{
//default constructor
}
}
public abstract class ApplicationController : Controller
{
public IModuleRepoistory _moduleRepository { get; private set; }
public ApplicationController(IModuleRepository moduleRepository)
{
_moduleRepository = moduleRepository ?? new DefaultModuleRepository();
//...
}
}
If in future you intend to inject a lot of interfaces then you'll probably be better off using Setter Injection

You could always use the Ninject dependency resolver to get the instance, so instead of_:
public ApplicationController(IModuleRepository moduleRepository, IBookRepository bookRepository, ITableRepository tableRepository, IClassRepository classRepository, IRoomRepository roomRepository, IUserRepository userRepository, IWindowRepository windowRepository, IChairRepository chairRepository, IDoorRepository doorRepository, IWCRepository wcRepository)
{
// Initialize repositories just one time here
}
you could do
protected readonly IModuleRepository ModuleRepository;
// same for the rest...
public ApplicationController()
{
this.ModuleRepository = MvcApplication.Container.Get<IModuleRepository>();
// same for rest or your modules.
}
if you're on MVC3 it would be:
protected readonly IModuleRepository ModuleRepository;
public ApplicationController()
{
this.ModuleRepository = DependencyResolver.Current.GetService<IModuleRepository>();
// same for rest or your modules.
}

Yeap, it's really better than first answer because now i have:
public abstract class ApplicationController : Controller
{
protected readonly IModuleRepository _moduleRepository;
public IModuleRepository moduleRepository
{
get { return _moduleRepository; }
}
public ApplicationController()
{
this._moduleRepository = DependencyResolver.Current.GetService<IModuleRepository>();
foreach (var module in _moduleRepository.GetAllModules())
ViewData[module.name] = module.value;
}
}
And i don't need to make any changes in my controllers. Just implement and could work with repositories:
public class HomeController : ApplicationController
{
public ActionResult Index()
{
ViewBag.Modules = moduleRepository.GetAllModules();
return View();
}
}
And in all of my Controllers i have full collection of ViewData values, which passing in PartialViews. Thx alot, awesome :) !

Related

Using factories with dependency injection to optimize object creation in a web request

Long story short, this is the type of controllers that i see in every code base professionally:
//All in One Service interfaces
public class DiController : ControllerBase
{
private readonly IDiService _diService;
public DiController(IDiService diService)
{
_diService = diService;
}
[HttpGet]
public IActionResult GetA()
{
return Ok(_diService.GetA());
}
[HttpGet]
public IActionResult GetB()
{
return Ok(_diService.GetB());
}
}
//Task-based interfaces
public class DiController : ControllerBase
{
private readonly IAService _aService;
private readonly IBService _bService;
public DiController(IAService aService, IBService bService)
{
_aService = aService;
_bService = bService;
}
[HttpGet]
public IActionResult GetA()
{
return Ok(_aService.Handle());
}
[HttpGet]
public IActionResult GetB()
{
return Ok(_bService.Handle());
}
}
Now to keep the post small, imagine that you have one repository for A and other for B, to be used by the service(s). Every component here is Scoped (the same object for every request). DonĀ“t matter what you choose, you end up with a situation like this:
This is in the case of the Task-based interface, and as you can see, you are not using the service B but you get one instance regardless. In the other case you will have the two repositories instantiated.
To solve this problem i used Factories like this:
1 - An abstract class that holds the container and a property that supplies an instance of the Type.
public interface IGenericFactory<out T>
{
T Service { get; }
}
public abstract class GenericFactory<T> : IGenericFactory<T> where T : class
{
private readonly Container _container;
public T Service => _container.GetInstance<T>();
protected GenericFactory(Container container)
{
_container = container;
}
}
2- The interface to be registered in the container
public interface IAServiceFactory : IGenericFactory<IAService>
{
}
3- The class to be registered in the container
public class AServiceFactory : GenericFactory<IAService>, IAServiceFactory
{
public AServiceFactory(Container container) : base(container)
{
}
}
4- Register the factories as Singletons and the services as Scoped/Transient (according to the use case). This would be an example (in Simple Injector) of how the registration for the Task-Based Interface Controller is done:
_container.Register<IAService, AService>(Lifestyle.Scoped);
_container.Register<IBService, BService>(Lifestyle.Scoped);
_container.Register<IAServiceFactory, AServiceFactory>(Lifestyle.Singleton);
_container.Register<IBServiceFactory, BServiceFactory>(Lifestyle.Singleton);
The final product will be this:
An instance of A, and no B.
Is this correct? I have been in projects where you would have a dozen of Services or Repositories, and only one would be used in each call.
Thank you.
You can inject into the action:
public IActionResult About([FromServices] IDateTime dateTime)
{
ViewData["Message"] = $"Current server time: {dateTime.Now}";
return View();
}
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection?view=aspnetcore-2.2#action-injection-with-fromservices

C# Dependency injection duplicating

I'm making an ASP.NET Core Razor Pages web application. In my application I use the following code:
public class MyClass
{
private readonly ApplicationDbContext _dbContext;
private readonly ICalendarService _calendarService;
public MyClass(ApplicationDbContext dbContext, ICalendarService calendarService)
{
_dbContext = dbContext;
_calendarService = calendarService;
}
public void MyFunction()
{
// here I need to use _dbContext and _calendarService
}
But when I use this class I need to do the following:
public class MySecondClass
{
private ImportIntoCalendar ImportHintSchedule;
public MySecondClass()
{
MyClass= new MyClass(_dbContext, _calendarService);
}
// Do something with variable ImportHintSchedule
ImportHintschedule.Function()
}
Everytime I need to add the dbcontext and the calendarservice into the parameters. So both need to be available in the other class. This feels like I'm doing something stupid, like I'm duplicating the same step. Does anybody know a better way to do this. Or is this just fine?
Edit:
I have this line in my startup.cs
services.AddScoped<ICalendarService, CalendarService>();
In your ConfigureServices you can add the IOC scopes.
For example, something like this. I don't know all of your code so the is just an example.
services.AddScoped<ICalendarService, CalendarService>();
services.AddScoped<IApplicationDbContext, ApplicationDbContext>();
You can also add singletons if that meets your needs as well.
Here is an example singleton call I use in my application
services.AddSingleton<IRepository<BaseItem>>(x => new Repository<BaseItem>(Configuration["MongoConnection:DefaultConnection"]));
I would suggest to create an Interface of your class, something like:
public interface IMyClass {
void MyFunction();
}
Then, implement that in your class:
public class MyClass : IMyClass {
private readonly ApplicationDbContext _dbContext;
private readonly ICalendarService _calendarService;
public MyClass(ApplicationDbContext dbContext, ICalendarService calendarService)
{
_dbContext = dbContext;
_calendarService = calendarService;
}
public void MyFunction()
{
// here I need to use _dbContext and _calendarService
}
}
And the add that to injector:
public void ConfigureServices(IServiceCollection services)
{
// existing code
services.AddTransient<IMyClass, MyClass>();
}
and finally use IMyClass in Controller constructor.
public class MyController:Controller
{
private IMyInterface _myClass;
public MyController(IMyInterface myclass) {
_myClass = myClass;
}
public IActionResult MyAction() {
_myClass.MyFunction();
return View();
}
}

How can I pass a mock object when I am doing setter injection in ASP.NET MVC Controller

Say, I have the below Controller
public class UsersController : Controller
{
private IUsersRepository UsersRepository { get; }
public UsersController()
{
UsersRepository = DependencyResolver.Current.GetService(typeof(IUsersRepository)) as IUsersRepository;
}
public ActionResult Index ()
{
MyUserDefinedModel data = UsersRepository.MyRepository();
return View(data);
}
}
Now I want to mock the IUsersRepository and pass it to the controller in my test script.
Below my test code
public class UsersListTest
{
private UsersController usersController = new Mock<IUsersRepository>();
private Mock<IUsersRepository> usersRepository = new UsersController();
[TestMethod]
public void TestMethod1()
{
//usersRepository.Setup(x => x.Get()).Returns(users);
}
}
As because private IUsersRepository UsersRepository { get; } private, I'm not able to pass the mock of IUsersRepository.
What would be the good idea to write unit test and mock in such case.
The reason that you have trouble with testing is because your Controller class uses the Service Locator anti-pattern. A Service Locator is a either a global instance (the DependencyResolver.Current) or an abstraction that allows resolving dependencies at runtime. One of the many downsides of the Service Locator is the problems it causes with testing.
You should move away from the Service Locator pattern and use dependency injection instead, favorably constructor injection. Your application components should have a single public constructor and those constructors should do nothing more than storing the incoming dependencies. This will result in the following UsersController implementation:
public class UsersController : Controller
{
private IUsersRepository usersRepository;
public UsersController(IUsersRepository usersRepository)
{
this.usersRepository = usersRepository;
}
public ActionResult Index()
{
return View(this.usersRepository.MyRepository());
}
}
With this in place, unit testing became trivial:
public class UsersControllerTests
{
[TestMethod]
public void Index_Always_CallsRepository()
{
// Arrange
var repository = new Mock<IUsersRepository>();
var controller = CreateValidUsersController(repository.Instance);
// Act
var result = controller.Index();
// Assert
Assert.IsTrue(repository.IsCalled);
}
// Factory method to simplify creation of the class under test with its dependencies
private UsersController CreateValidUsersController(params object[] deps) {
return new UsersController(
deps.OfType<IUsersRepository>().SingleOrDefault() ?? Fake<IUsersRepository>()
// other dependencies here
);
}
private static T Fake<T>() => (new Mock<T>()).Instance;
}
This does however, force you to change MVC's default IControllerFactory, since out-of-the-box, MVC can only handle controllers with a default constructor. But this is trivial and looks as follows:
public sealed class CompositionRoot : DefaultControllerFactory
{
private static string connectionString =
ConfigurationManager.ConnectionStrings["app"].ConnectionString;
protected override IController GetControllerInstance(RequestContext _, Type type) {
if (type == typeof(UsersController))
return new UsersController(new UsersRepository());
// [other controllers here]
return base.GetControllerInstance(_, type);
}
}
Your new controller factory can be hooked into MVC as follows:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start() {
ControllerBuilder.Current.SetControllerFactory(new CompositionRoot());
// the usual stuff here
}
}
You can find a more complete example here.
You could add a constructor that allows you to supply a mock of IUsersRepository. Your default constructor would call this with the instance from the DependencyResolver, like this:
public class UsersController : Controller
{
private IUsersRepository UsersRepository { get; }
public UsersController(IUsersRepository usersRepository)
{
UsersRepository = usersRepository;
}
public UsersController():this(DependencyResolver.Current.GetService(typeof(IUsersRepository)) as IUsersRepository)
{
}
public ActionResult Index ()
{
MyUserDefinedModel data = UsersRepository.MyRepository();
return View(data);
}
}

Routing from one view to another controller's action method and passing a parameter to that controller's constructor

I'm creating my first C# MVC site and quite early on I've hit a roadblock where I'm not sure if I'm going about things entirely the wrong way and I can't find an example similar to my own online but it seems like what I'm trying to do should be straightforward.
Basically, I have my initial controller (called ClientController) that sets up a list of clients and then displays them in my list view:
public class ClientController : Controller
{
private readonly IClientManagerRepository _clientManagerRepository;
public ClientController()
: this(new EntityClientManagerRepository())
{
}
public ClientController(IClientManagerRepository repository)
{
_clientManagerRepository = repository;
}
//
// GET: /Client/
public ViewResult List()
{
return View(_clientManagerRepository.GetAllClients());
}
}
Then in my view I have an action link where I want to route to my UserController, passing it the client name, so that it can build the list of users for that particular client.
#Html.ActionLink("View Admin Users","Index","User",new {clientName = item.ClientName},null)
This works with the following code:
public class UserController : Controller
{
private IUserManagerRepository _userManagerRepository;
//
// GET: /User/
public ActionResult Index(string clientName)
{
_userManagerRepository = new EntityUserManagerRepository(clientName);
return View(_userManagerRepository.GetAllUsers());
}
}
And my list of users is displayed correctly in my view.
However, when I then add in my details action method it doesn't work because the _userManagerRepository isn't instantiated:
//
// GET: /User/Details/5
public ActionResult Details(int contactId)
{
return View(_userManagerRepository.GetUser(contactId));
}
I would have to I guess pass in the clientname each time and re-instantiate my _userManagerRepository. That doesn't feel like a very good way though.
Ideally I'd like to create my _userManagerRepository in the constructor of my UserController. I've been looking into how I would do this so I'd have something like:
public class UserController : Controller
{
private IUserManagerRepository _userManagerRepository;
public UserController(string clientname)
: this(new EntityUserManagerRepository(clientname))
{
}
public UserController(IUserManagerRepository repository)
{
_userManagerRepository = repository;
}
I've researched that I can create my own controller factory so that I can have a parameter in my userController constructor however I still don't understand how I would pass my clientname parameter form a view to my UserController.
If you want to instantiate Repository class in controller's constructor,you can use NInject,
it's really nice approach to do it.
1-Install Ninject from Nuget
2-Create Repository Abstract for example ICustomerRepository
public abstract ICustomerRepository
{
string GetCustomerName();
}
3-Create Repository for example CustomerRepository
public class CustomerRepository:ICustomerRepository
{
string GetCustomerName()
{
return ("John");
}
}
4-create CustomerControllerFactory Class
public class CustomControllerFactory : DefaultControllerFactory
{
private static IKernel ninjectKernel;
public CustomControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings(ninjectKernel);
}
protected override IController GetControllerInstance
(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return (new Controllers.MessageController());
}
else
{
return ((IController)ninjectKernel.Get(controllerType));
}
}
public static void AddBindings(IKernel ninjectKernel)
{
Common.DependencyInjection.DependencyManager.GetDependencyInjections().ForEach(current =>
{
if (current.Abstract != null && current.Implementation != null)
{
ninjectKernel.Bind(current.Abstract).To(current.Implementation);
}
});
ninjectKernel.Bind<ICustomerRepository>().To(typeof(CustomerRepository));
}
}
ninjectKernel.Bind().To(typeof(CustomerRepository));
I bind ICustomerRepository to CustomerRepository in upper code
5- Add below code to Application_Start
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
6-Create New Controller
public class CustomerController:Controller
{
public CustomerController(ICustomerRepository customerRepository)
{
//customerRepository instantiate to CustomerRepostory Class automatically
}
}
it's Dependency Injection that i think useful for you
Regards

No parameterless constructor defined for this object. Make sure that the controller has a parameterless public constructor

I am working on Pro ASP.Net Book MVC3 Framework and suddenly I have this issue.
I am attaching the code for my Product Controller. Seems like problem is here:
Also, I added code for my NinjectController. Would appreciate any help with code.
namespace NordStore.WebUI.Controllers{
public class ProductController : Controller
{
private IProductRepository repository;
public ProductController(IProductRepository productRepository)
{
repository = productRepository;
}
public ViewResult List()
{
return View(repository.Products);
}
}
}
namespace NordStore.WebUI.Infrastructure{
public class NinjectControllerFactory: DefaultControllerFactory
{
private IKernel ninjectKernel;
public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext,
Type controllerType)
{
return controllerType == null
? null
: (IController)ninjectKernel.Get(controllerType);
}
private void AddBindings()
{
// put additional bindings here
ninjectKernel.Bind<IProductRepository>().To<EFProductRepository>();
}
}
}
Your constructor takes a parameter of type IProductRepository. You are probably trying to instantiate your controller like so:
ProductController controller = new ProductController();
But you can't because there is no Constructor that is defined in your controller that takes 0 arguments. You need to either pass an object of type IProductRepository or define a paramterless constructor.
Please look at Dependency Injection frameworks like Unity or Ninject.
In the meanwhile to get your code to work your the poor man's DI method:
Assuming ProductRepository derives from IProductRepository
public class ProductController : Controller
{
private IProductRepository repository;
//The framework will call this constructor
public ProductController() : this(new ProductRepository()) { }
public ProductController(IProductRepository productRepository)
{
repository = productRepository;
}
public ViewResult List()
{
return View(repository.Products);
}
}

Categories