ASP.Net Core Call a controller from another controller - dependency-injection

In my ASP.Net Core MVC 6 solution I have two sets of controllers. One set contains the webpages with their regular views. Another set contains the API controllers.
To avoid duplicating db logic the web controllers are using the API controllers. Currently I am creating an instance of the required controller manually by handing it a DbContext as constructor argument. This is the DbContext given to web controller by dependency injection.
But whenever I add another constructor parameter to the API controller I need to modify all web controllers that use this API controller.
How can I use the dependency injection system builtin to ASP.Net 5 to create an instance of the required API controller for me? Then it would fill in the required constructor parameters automatically.
One solution could be to move the db logic from the API controllers to a separate layer and call that from both API and web controllers. This would not solve my problem since the new layer would still need the same parameters and I'm not fan of the unnecessary wiring.
Another solution would be to have the web controllers access the API through a web call, but that just adds complexity to the app.
Today I am doing this:
public IActionResult Index()
{
using (var foobarController = new Areas.Api.Controllers.FoobarController(
// All of these has to be in the constructor of this controller so they can be passed on to the ctor of api controller
_dbContext, _appEnvironment,
_userManager, _roleManager,
_emailSender, _smsSender))
{
var model = new IndexViewModel();
model.Foo = foobarController.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = foobarController.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
}
And I am hoping for something like this:
(This example does not work.)
using (var foobarController = CallContextServiceLocator.Locator.ServiceProvider.GetService<Areas.Api.Controllers.FoobarController>())
{
var model = new IndexViewModel();
model.Foo = foobarController.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = foobarController.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}

How can I use the dependency injection system builtin to ASP.Net 5 to create an instance of the required API controller for me?
In your Startup.cs can tell the MVC to register all your controllers as services.
services.AddMvc().AddControllersAsServices();
Then you can simply inject the desired controller in your other controller via the DI mechanism and invoke its action method.

Don't do it. Move that logic to another component that gets shared between the 2 controllers. The controller is dispatched to by the framework as a result of an HTTP call, its not your public API surface. In general, your controllers should be used as a the place where the HTTP request is transformed into business objects. Operations on those objects should be delegate to another layer (especially if it needs to be used from more than one place in your application).

To be able to use a controller from another controller you need to:
Register the controller in Startup.cs ConfigureServices: services.AddTransient <Areas.Api.Controllers.FoobarController, Areas.Api.Controllers.FoobarController>();
You must pass the controller you want to access as a ctor parameter into the main controller.
If you need to access local properties in the controller such as User or Url there are two ways to do this.
The first way is to use DI to get an instance of IHttpContextAccessor to access User and IUrlHelper to access Url objects:
public class FoobarController : Controller
{
private readonly ApplicationDbContext _dbContext;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUrlHelper _urlHelper;
public FoobarController(ApplicationDbContext dbContext, IHttpContextAccessor httpContextAccessor, IUrlHelper _urlHelper, [...])
{
_dbContext = dbContext;
_httpContextAccessor = httpContextAccessor;
_urlHelper = urlHelper;
}
public FoobarResponse List(FoobarRequest request)
{
var userId = _httpContextAccessor.HttpContext.User.GetUserId();
var response = new FoobarResponse();
response.List = _dbContext.Foobars.Where(f => f.UserId == userId).ToList();
response.Thumb =
return response;
}
}
The second way is to set it in the calling controller:
public class HomeController : Controller
{
private Areas.Api.Controllers.FoobarController _foobarController;
public HomeController(Areas.Api.Controllers.FoobarController foobarController)
{
_foobarController = foobarController;
}
private void InitControllers()
{
// We can't set this at Ctor because we don't have our local copy yet
// Access to Url
_foobarController.Url = Url;
// Access to User
_foobarController.ActionContext = ActionContext;
// For more references see https://github.com/aspnet/Mvc/blob/6.0.0-rc1/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs
// Note: This will change in RC2
}
public IActionResult Index()
{
InitControllers();
var model = new IndexViewModel();
model.Foo = _foobarController.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = _foobarController.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
}
The source code for ASP.Net Core MVC6 RC1 Controller can be found here. It is however undergoing heavy rewrite for RC2 and with it the properties that has to be copied to get access to User and Url will change.

#B12Toaster is correct for MVC but if you only use ApiController you should do it like this:
services.AddControllers().AddControllersAsServices();

Why would your new layer need wiring up? Why not take in an object into both controllers and call a method on that object. The DI container could resolve the dependencies of this new object without duplicated wiring couldn't it?
ie you could have this:
public class MvcController
{
SharedComponent sharedComponent;
public MvcController(SharedComponent sharedComponent)
{
this.sharedComponent = sharedComponent;
}
public IActionResult Index()
{
var model = new IndexViewModel();
model.Foo = shredComponent.List(new FoobarRequest() { Foo = true, Bar = false });
model.Bar = shredComponent.List(new FoobarRequest() { Foo = false, Bar = true });
return View(model);
}
}
//Repeat this for the API controller
public class SharedComponent
{
public SharedComponent(DBContext dbContext, AppEnvironment appEnvironment, UserManager userManager, RoleManager roleManager,
EmailSender emailSender, SmsSender smsSender)
{
...Store in fields for later usage
}
}

I'd have to agree with others that injecting the controller may not be the best route. Mostly because it marries the business logic with ASP.Net instead of treating it like an IO device like, in my opinion, it should be.
Let's say we have an interface that looks like this:
public interface ICalculator {
int Add(int left, int right);
}
and we have an implementation that stores the business logic:
public class MyCalculator : ICalculator {
public int Add(int left, int right) => left + right;
}
This implementation can be used as a background service, within the same process as a WPF application, or as an ASP.NET WebAPI controller. It would look something like this:
[ApiController]
[Route("api/{controller}")]
public void CalculatorController : Controller, ICalculator {
private readonly ICalculator _calculator;
public CalculatorController(ICalculator calc) => _calculator = calc;
[Route("Add")]
public int Add(int left, int right) => _calculator.Add(left, right);
}
If that controller has a dependency on a repository you can inject that interface too. Personally I like defining a collection of repositories (like IUserRepository for example) and injecting only what is needed instead of the entire DbContext.
public CalculatorController(ICalculator calculator, IDbContext db) { }
There's nothing wrong with a controller depending on more than just the thing it is decorating. Just make sure you have a set of tests that assert various things. For example you could assert that when a particular controller method is called the particular method on the other interface is also called.
Personally I find this approach a better fit. It's okay to use certain technologies but they should be kept at arm's length from the business rules. A developer should be able to take the business rules that govern a particular part of the code and switch from a WCF service to ASP.NET WebAPI trivially.
I've personally been a part of a couple projects where we had to switch from one database technology to another (SQL Server to CouchDB) and one where our micro-services needed to be running as restful Web API services instead of Windows services. If you architect things this way those types of projects become relatively trivial compared to how things are normally composed.

Related

C# Web Api 2 use StructureMap to pass request data into injected dependency constructor parameter

I'm getting my feet wet with C# IoC frameworks. I chose StructureMap.Webapi2 to integrate into an existing api.
I have the following scenario which I am not sure what the best way to implement is.
public class MyController : ApiController
{
public IHttpActionResult MyAction(string clientCode, [FromBody]MyDto bodyData)
{
var client = new ClientManager().GetClientByCode(clientCode);
var someData = new SomeData
{
User = bodyData.User,
ClientCode = clientCode,
SomeField = client.SomeField
};
var myService = new WorkerService(someData);
myService.DoSomething();
return Ok();
}
}
A peek a the WorkerService:
public WorkerService(SomeData someData)
{
_someData = someData;
_someCollection = GetSomeData(); // GetSomeData uses _someData
}
public DoSomething()
{
// some code that uses _someData and _someCollection
}
Approach 1:
Make WorkerService's constructor parameterless and add a public SomeData property that can be initialized inside MyController MyAction.
Then both ClientManager and WorkerService can be injected by the IoC into a constructor to be added to the controller.
The Action would then look like:
public IHttpActionResult MyAction(string clientCode, [FromBody]MyDto bodyData)
{
var client = _clientManager.GetClientByCode(clientCode);
var someData = new SomeData
{
User = bodyData.User,
ClientCode = clientCode,
SomeField = client.SomeField
};
_myService.SomeData = someData;
_myService.DoSomething();
return Ok();
}
Approach 2 (the one I'm not sure how to implement)
Keep WorkerService constructor as is (with a parameter). Inject the service into the Controller's constructor (requires building and pass the service's argument (SomeData) at runtime, instead of having the MyAction build SomeData).
Somehow build SomeData (maybe using a factory) before for each request is handled by the controller. This would mean that ClientManager would have to be injected to that somehow/factory. The output of the somehow/factory would be used by the IoC when building the WorkerService to be injected into the controller, per request.
To me, Approach 1 seems quicker and simple, but Approach 2 seems to be more attractive, more challenging and with more learnings.
I ended up finding a solution for the problem:
Create a passive attribute and add to the action
Create an ActionFilter, which checks for the attribute and when found, gets data from the request.
Since I didn't like the approach of reading the request body in the ActionFilter, I changed the request and moved the data I needed from the body (server and data base names) to the url of the request. Then I created a POCO for that data that I inject into the ActionFilter and populate with the data from the url. That POCO isntance is now available in every service down the dependency chain that needs it.
For the rest of the data I needed in my SomeData object, I followed approach 1, made WorkerService's constructor parameterless and passed the data like:
_myService.DoSomething(someData);
One final trick was adding the ActionFilter to config.Filters, because my filter has it's own dependencies, I couldn't just do:
config.Filters.add(new MyActionFilter(What_About_The_Parametes_???))
I had to get the structureMap's container instance and have it return a instance of my filter which will the cause all the dependencies to be injected into it, and then I can add the filter instance to config.Filters:
var container = StructuremapMvc.StructureMapDependencyScope.Container;
config.Filters.Add(container.GetInstance<IMyActionFilter>());

In MVC can ViewModels access service layer?

Currently I'm using DI and service locator pattern to get the instance of Service. (Note that Service just generic term im using, and is nothing but the C# class which calls EF repository and perform data operations. Its NOT WCF service)
Is it okay to have Service instance in ViewModel? If yes, the what's the proper way to pass Service instance?
1>Should the controller pass the service instance to ViewModel. In this case Service properly get disposed when controller get disposed
2>or should the ViewModel get service instance using DI & Service Locator. In this case how service will get disposed?
BaseController
public class BaseController:Controller
{
private MyDomainService _myDomainServiceInstance = null;
protected MyDomainService MyDomainServiceInstance
{
get
{
if (_myDomainServiceInstance == null)
{
_myDomainServiceInstance = DefaultServiceLocator.Instance.GetInstance<MyDomainService>();
}
return _myDomainServiceInstance;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (_myDomainServiceInstance != null)
{
_myDomainServiceInstance.Dispose();
}
}
}
Controller
public class MyController:BaseController
{
public ActionResult DoSomething()
{
var model = new SummaryVM(MyDomainServiceInstance);
}
}
ViewModel
public class SummaryVM
{
MyDomainService _myDomainService = null;
public SummaryVM(MyDomainService myDomainService)
{
//Approache 1: Controller is passing the service instance
_myDomainService = myDomainService;
}
public SummaryVM()
{
//Aprooche 2: Use DI & Service locator pattern to get the instance
_myDomainService = DefaultServiceLocator.Instance.GetInstance<MyDomainService>();
}
public int[] SelectedClients { get; set; }
public string[] SelectedStates { get; set; }
public IEnumerable<Clients> PreSelectedClients
{
get
{
if (SelectedClients == null || !SelectedClients.Any())
{
return new List<AutoCompletePreSelectedVM>();
}
return _myDomainService.GetClients(SelectedClients);
}
}
}
View models are intended to provide information to and from views and should be specific to the application, as opposed to the general domain. Controllers should orchestrate interaction with repositories, services (I am making some assumptions of the definition of service here), etc and handle building and validating view models, and also contain the logic of determining views to render.
By leaking view models into a "service" layer, you are blurring your layers and now have possible application and presentation specific mixed in with what should focused with domain-level responsibilities.
Just don't mix concepts. If your service deals with view models then it should be a presentation service and be layered over top of the actual Model.
View models should be flat and simple DTOs purposed toward binding with the view. They should not be part of a DI container graph because that complicates things and makes reasoning about the code more difficult.
I had passed through similar situation. I think it is okay having the domain service get instantiated inside view model. The domain service can implement IDisposable, so I would instantiate it inside the get method instead of create the service as an attribute.

ASP.NET MVC ViewHelpers and Dependency Injection

I'd like to create a ViewHelper to localize my ASP.NET MVC application. Something like this:
public class Translator
{
private readonly ITranslationRepository _repo;
public Translator(ITranslationRepository repo)
{
_repo = repo;
}
public static string Translate(TranslationEnum translationEnum)
{
return _repo.GetTranslation(translationEnum, Session.LanguageId);
}
}
Usage in a (Razor) View looks like this:
<p>#Translator.Translate(TranslationEnum.WelcomeMessage)</p>
Now the problem is of course, I cannot make the Translate method static, because I need to access the instance variable _repo.
How can I inject the repository into a ViewHelper so I can use it in a View like above?
The responsibility of the view is just to transform the data that comes back from the controller to a HTML structure. Views are hard (to impossible) to test automatically, so best is to keep them as dumb as possible.
Instead of using the Translator in your view, inject it into your controller and let the controller call the Translator. This solves a range of problems:
It keeps the view simple.
It improves maintainability.
It improves testability.
It improves the verifiability of your object graphs (because you don't fall back on static method calls or the Service Locator anti-pattern).
Long story short, add a property to the controller's view model and return that to the view. Example:
public class HomeController : Controller {
private readonly ITranslator translator;
public HomeController(ITranslator translator) {
this.translator = translator
}
public ActionResult Index() {
this.View(new HomeViewModel {
WelcomeMessage = this.translator.Translate(TranslationEnum.WelcomeMessage)
});
}
}
And your view can look as follows:
#model HomeViewModel
<p>#Model.WelcomeMessage</p>
first of all, the intention of your design is wrong because it violates the single responsibility principal. Why is a translator dependent on repository?
secondly, why do you need a translator, you can use asp.net globalization?
click me We should not reinvent the wheel.
thirdly, all the html helpers are extension methods which have to be static.
so my suggestion is if you have to use translator, please refactor the Translator class, decouple the repository from it then create a extension methods from there.
or you can use globalization, it sounds horrible to start with but trust me it's not as hard as it looks.
public class Translator
{
private static ITranslationRepository _repo;
public static ITranslationRepository Repo
{
get { /*check null here before return*/ return _repo; } set { _repo = Repo; }
}
public Translator()
{
}
public static string Translate(TranslationEnum translationEnum)
{
return _repo.GetTranslation(translationEnum, Session.LanguageId);
}
}

ASP.NET MVC - Service layer, single or many services in each controller action?

I'm starting to implement a service layer to my MVC project to thin down some bloated controllers (it also has repository / unitofwork pattern).
My question is if you have a complicated view model for a page with lots of child objects etc, and quite a lot of logic going on behind the scenes (to give you an idea the controller the original developer wrote had almost 4000 lines of code!!) is it OK to have multiple services going off doing their thing? or should I just have one big ReportService which does everything?
My controller is starting to look like this? and if I carry on I could end up having quite a lot of different services being called to build up the view model.
Does this look OK or is it starting to go in the wrong direction?
public ViewResult Index(int? reportId)
{
// get the base report object
var reportService = new ReportService();
var report = reportService.GetByReportId(reportId);
var model = Mapper.Map<Report, ReportViewModel>(report);
// get the current active user
var userService = new UserService();
var user = userService.GetCurrentUser();
model.User = Mapper.Map<User, ReportViewModel.UserViewModel>(user);
// get the first unread message
var messageService = new MessageService();
var message = messageService.GetFirstUnread(user.Id);
model.Message = Mapper.Map<Message, ReportViewModel.MessageViewModel>(message);
// get the category navigation
var categoryService = new CategoryService();
var categoryNavigation = categoryService.GetCategoryNavigation(report.Id);
model.CategoryNavigation = Mapper.Map<IEnumerable<Category>, IEnumerable<ReportViewModel.CategoryNavigationViewModel>>(categoryNavigation);
return View(model);
}
It's fine to have multiple small services in your controller. However, there is one thing that's wrong here:
You services should be available through the entire controller and injected through the constructor to achieve loose-coupling.
So something like this:
private readonly IReportService _reportService;
private readonly IUserService _userService;
public SomeConstructor(IReportService reportService, IUserService userService, etc.)
{
_reportService = reportService;
_userService = userService;
// etc
}
That does look like a good approach, an alternative approach would to be split some of this up by using Child Actions - the best solution will depend upon your specific use case though.
If, for example, the ViewModel property CategoryNavigation was being used by the view to create a sort of navigation 'widget' that might be useful in several different Views, you might be better spliting this off into a ChildAction e.g.
[ChildActionOnly]
public ActionResult CategoryNavigationWidget(int reportId)
{
// get the category navigation
var categoryService = new CategoryService();
var categoryNavigation = categoryService.GetCategoryNavigation(report.Id);
return PartialView(categoryNavigation);
}
Any View could then render that ChildAction by going:
#{ Html.RenderAction("CategoryNavigationWidget", "Report",
new { reportId = Model.ReportId }); }
Whether or not this is a good idea will probably depend upon whether or not the 'widget' is reusable.

Selecting Instances of an Interface Based On Specific Value

I'll start here with a little bit of background. We have an ASP.Net MVC web application that sits upon a structure roughly based upon the Onion Architecture concept. Therefore, we have the following (simplified) vertical structure:
ASP.Net MVC controller layer
Application service layer
Business Service layer
NOTE: The above is simplified because it doesn't deal with the views, repositories, domain objects, etc which aren't relevant to this question.
For a horizontal structure, we have some major areas defined by what we call "Item Types" (for the sake of simplicity, this question will deal with two sample item types: "ItemTypeA", "ItemTypeB", etc).
We have a business service interface which has a separate implementation per item type:
public interface ISampleBusinessService
{
string SampleMethod(string arg);
}
public class ItemTypeASampleBusinessService : ISampleBusinessService
{
public string SampleMethod(string arg)
{
return "Item Type A: " + arg;
}
}
public class ItemTypeBSampleBusinessService : ISampleBusinessService
{
public string SampleMethod(string arg)
{
return "Item Type B: " + arg;
}
}
Sitting above that is an application service that uses the business service:
public interface ISampleAppService
{
string SampleMethod(string arg);
}
public class SampleAppService
{
private readonly ISampleBusinessService service;
public SampleAppService(ISampleBusinessService service)
{
this.service = service
}
public string SampleMethod(string arg)
{
return service.SampleMethod(arg);
}
}
And sitting above that is our controller which uses the application service:
public class SampleController : Controller
{
private ISampelAppService service
public SampleController(ISampleAppService service)
{
this.service = service;
}
public PartialViewResult SampleAction(string arg)
{
return PartialView( service.SampleMethod(arg) );
}
}
Note that the controller, application service interface and implementation, and business service interface are all generic - they don't care about which item type is being used. However, the business service implementations are specific to the item type. We know which item type we're dealing with at the time we call the action method on the controller (via RenderAction in the views) but we aren't sure what the best way to determine which business service implementation to use. There are a few options we've considered:
Base class the controller and create item type-specific controller inheritors, then something similar with the app services. This feels like a weak solution - we would end up writing a few classes that add nothing in terms of functionality except to work out which item type we're dealing with.
Pass a flag down to the service layer and create the service implementation in a factory (i.e. a SampleBusinessServiceFactory which takes an "itemType" argument in its CreateInstance method). The problem with this is that we're passing a variable down several layers just so that we can decide upon an implementation. We have used this approach so far.
Generics - we haven't really thought this one through but it seems that there would be some difficulties with this as well (how would you call an Action method with generics from an ActionResult call in the view?). It would be similar, in a sense to passing a flag down, but would be based upon strongly typing object/services instead of using enums/magic strings.
What approach would be best suited to solving this problem? New options would be welcomed.
Any help provided will be much appreciated.
Cheers,
Zac
This smells like Big Design Up Front ( http://en.wikipedia.org/wiki/Big_Design_Up_Front )
However its very possible to invoke both controllers and action methods generically:
In asp.net mvc is it possible to make a generic controller?
Some info about invoking actions with generic action results ( which result in the same effect ).
http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/12/12/enabling-ioc-in-asp-net-actionresults-or-a-better-actionresult.aspx
I am a big fan of this approach and learning about these techniques is helpful to anybody who wants to keep their controllers extraordinarily slim.
Comment Answer:
You don't really need to call the generic action method, you just need a way to pass the generic parameter to your controller. The basic flow is to include your modelType as a route parameter. You could easily call generic render actions with the correct RouteValueDictionary. Here is some sample code from an older project of mine:
Start of my generic controller:
public GenericController()
{
TypeTranslator.Configure("Brainnom.Web.Model", "Brainnom.Web");
}
[UrlRoute(Path="admin/{modelType}/add", Order=9000)]
public virtual ActionResult Add()
{
return View( new MODEL() );
}
[HttpPost]
[UrlRoute(Path = "admin/{modelType}/add", Order = 9000)]
public virtual ActionResult Add( MODEL model, string modelType)
{
if (!ModelState.IsValid)
return View(model);
var postedModel = new MODEL();
UpdateModel(postedModel);
using (var session = new MongoSession())
{
session.Add(postedModel);
}
return RedirectToRoute("Browse", new { modelType });
}
and my GenericControllerFactory ( which I do need to refactor someday )
using System;
using System.Web.Mvc;
using System.Web.Routing;
namespace Brainnom.Web.Controllers
{
public class GenericControllerFactory : DefaultControllerFactory
{
protected override Type GetControllerType(System.Web.Routing.RequestContext requestContext, string controllerName)
{
//the generic type parameter doesn't matter here
if (controllerName.EndsWith("Co"))//assuming we don't have any other generic controllers here
return typeof(GenericController<>);
return base.GetControllerType(requestContext, controllerName);
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
//are we asking for the generic controller?
if (requestContext.RouteData.Values.ContainsKey("modelType"))
{
string typeName = requestContext.RouteData.Values["modelType"].ToString();
//magic time
return GetGenericControllerInstance(typeName, requestContext);
}
if (!typeof(IController).IsAssignableFrom(controllerType))
throw new ArgumentException(string.Format("Type requested is not a controller: {0}",controllerType.Name),"controllerType");
return base.GetControllerInstance(requestContext, controllerType);
}
/// <summary>
/// Returns the a generic IController tied to the typeName requested.
/// Since we only have a single generic controller the type is hardcoded for now
/// </summary>
/// <param name="typeName"></param>
/// <returns></returns>
private IController GetGenericControllerInstance(string typeName, RequestContext requestContext)
{
var actionName = requestContext.RouteData.Values["action"];
//try and resolve a custom view model
Type actionModelType = Type.GetType("Brainnom.Web.Models." + typeName + actionName + "ViewModel, Brainnom.Web", false, true) ??
Type.GetType("Brainnom.Web.Models." + typeName + ",Brainnom.Web", false, true);
Type controllerType = typeof(GenericController<>).MakeGenericType(actionModelType);
var controllerBase = Activator.CreateInstance(controllerType, new object[0] {}) as IController;
return controllerBase;
}
}
}

Resources