I have a .NET MVC application and I need to pass my service to a controller. The controller should use the service, retrieve all the instruments and pass them to the view. What's the correct approach in order to do that?
Here my controller:
public class MyController: Controller
{
private MyService db;
public IActionResult Index()
{
var res = db.Instrument;
return View(res);
}
}
I'd like to use db but it needs to be passed in some way. Below the MyService service:
public class MyService : IMyService
{
private readonly IServiceProvider serviceProvider;
public MyService(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
Instrument = null;
}
public Instrument Instrument { get; private set; }
}
Firstly, I would set up the controller so that it does not have to create the object on which it relies to do its work (see Inversion of Control).
Therefore, the controller may look like this:
public class MyController: Controller
{
private readonly IMyService myService;
public MyController(IMyService myService)
{
this.myService = myService;
}
...
}
Notice that the service is passed into the controller via the controllers constructor and that the controller replies on the service interface and not the actual service type. The controller does not need to care about where the service has come from or how it was implemented, just that it conforms to the specified interface.
So now, you can use the service to obtain your information:
public class MyController: Controller
{
private readonly IMyService myService;
public MyController(IMyService myService)
{
this.myService = myService;
}
public ViewResult Index()
{
var instruments = this.myService.GetInstruments();
return View(instruments);
}
}
Notice here that I have changed your service implementation to retrieve all the instruments as you specified in your description that you would like to retrieve all the instruments.
Also, notice that I have just passed the returned type from the service directly to the view for simplicity. However, I would usually recommend using a view model but I will leave this as an exercise to the reader.
As for the service itself, you might have:
public class MyService : IMyService
{
private readonly IDataProvider dataProvider;
public MyService(IDataProvider dataProvider)
{
this.dataProvider = dataProvider;
}
public IEnumerable<Instrument> GetInstruments()
{
return dataProvider.GetInstruments();
}
}
I wasn't sure what the IServiceProvider was so I have renamed this to IDataProvider. You can you whatever you need here to obtain the data in the service. For example, you could instead pass in a IDbContext (if using entity framework) into the constructor instead and use that to obtain the data.
I must also point out that if your application is very simple with very simple business use case scenarios then you may not even need this service layer here and pass in the data provider directly into the constructor. Again, I will leave this as an exercise to the reader.
Finally, to pass the implementation of IMyService into the contructor and to pass the implementation of IDataProvider into MyService you could use a dependency injection framework.
When MVC instantiates a controller it will look to the dependency injection framework to find out how to create the required dependencies. In this example, when a call is made to the Index() action, MVC will attempt to create an instance of MyService. It will have the dependency injection framework create an instance that implements IMyService. The dependency injection framework will look to its setting and determine that it needs to create an instance of MyService but this implementation itself requires an instance of IDataProvider. So the dependency injection framework will again look to its settings and determine that it needs to create an instance of DataProvider. It will pass the instance of DataProvider to MyService and will then pass the instance of MyService to MyController, MVC will then eventually call the Index() action method and the action method will then have access to the service.
One example of a common dependency injection framework is Ninject. You may set up rules to tell the framework that for a given interface, this is the instance type that is required. For example:
this.Bind<IMyService>().To<MyService>();
this.Bind<IDataProvider>().To<DataProvider();
And finally, (assuming you are using razor views) the declaration at the top of the view may look something like:
#model IEnumerable<Instrument>
// You are now able to use #Model. in the view to provide you the information you require.
I hope this helps, but this is only a very brief introduction for your situation. I would therefore recommend reading around inversion of control, dependency injection and Ninject as a potential dependency injection framework although there are various others.
Related
I am working on a .net core project where each controller has their own service as DI. All those services share some common stuff so I abstract a BaseService class:
public class BaseService
{
public BaseService(IHttpContextService srv)
{
...
}
}
This BaseService, or in another word, all the services need another service for the HTTP context.
Now I need to inherit from this BaseService if I need a new service for a new controller:
public class MyFirstService : BaseService
{
public MyFirstService(IHttpContextService srvHttp, AdditionalService srvAdditional) {}
}
In its constructor, I will need to specify the IHttpContextService again, and a few additional services this MyFirstService needs.
But this seems wrong because the child is a descendant and therefore should have the IHttpContextService naturally. Not to mention the child doesn't have a constructor with the same parameters as the ancestor which gives a compile error.
Is there a way to DI objects outside of the constructor? Or just get rid of the DI from .net core? Or I should change my design pattern?
It has been well documented, how to inject dependencies into services.
Question: But is it (already) possible in ASP.NET Core 2.0 to have the system's DI mechanism automatically inject a service into a method or into a property?
Sidenote: In PHP-Symfony this pattern is called setter injection.
Example:
Say I have a common MyBaseController class for all controllers in my project and I want a service (e.g. the UserManager service) to be injected into MyBaseController that can be later accessed in all child controllers. I could use constructor injection to inject the service in the child class and pass it via base(userManager) to the parent. But having to perform this in all child constructors of all controllers is pretty tedious.
So I would like to have a setter in MyBaseController like this:
public abstract class MyBaseController : Controller
{
public UserManager<User> userManager { get; set; }
// system should auto inject UserManager here
public void setUserManager(UserManager<User> userManager) {
this.userManager = userManager;
}
}
...so I don't have to do the following in every child constructor just to pass the dependency to the parent:
public class UsersController : MyBaseController
{
public ChildController(UserManager<User> userManager) : base(userManager) {}
Update: The answer given here is what I want to achieve, however the question was asked for ASP.NET Core 1.0, I'm interested in whether any solutions have been added in ASP.NET Core 2.0.
In general it is good advice to avoid non constructor DI as it is considered a bit of an anti pattern, there is a good discussion about it in this related question.
With the default Microsoft.Extensions.DependencyInjection container in aspnet core, the answer is no, but you could swap to something more powerfull like autofac (which has property injection) if you are sure you really need this feature.
You can perform setter injection with the built-in DI container (Microsoft.Extensions.DependencyInjection) using Quickwire. Unlike Autofac, this is not a new DI container, it just extends the default one.
To make it work:
Add this to ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
// Activate controllers using the dependency injection container
services.AddControllers().AddControllersAsServices();
services.ScanCurrentAssembly();
// ...
// Register your other services
}
By default, ASP.NET Core will activate controllers by instantiating them directly without going through the DI container. Fortunately, this behaviour can easily be overridden to force ASP.NET Core to resolve controllers using dependency injection. This is what services.AddControllers().AddControllersAsServices() does.
ScanCurrentAssembly is necessary to get Quickwire to search for services declared in your assembly and register them (which will include your controllers).
Decorate your child controller with [RegisterService]
[RegisterService(ServiceLifetime.Transient)]
public class ChildController : MyBaseController
{
// ...
}
This will make your ChildController discoverable when ScanCurrentAssembly is called in step 1.
Decorate the setter
public abstract class MyBaseController : Controller
{
[InjectService]
public UserManager<User> UserManager { get; private set; }
}
Now the UserManager property in your child controller will be automatically set from the dependency injection container.
You have two kind of DI
Mandatory, it's injection needed for object initialization then it's injection setted in constructor.
Optional, it's injection needed for action.
If DI is doing well, u can have unit test without injection system, if all injections are in ctor then you'll break every unit test, every time for nothing.
So all injections in ctor break open/close principle.
One more point is DI is for interface implementation or module public part, object under this implementation are initialized manually.
So setter is not bad because there are hidden by interface.
I've created two projects:
Web Project, that contains all the viewmodels/data/controllers etc. And a Web Api project to allow form capture.
I simply want to capture the data in the web Api and save it to the database where it will become accessible to the front end.
I am experiencing an issue initialzing the DBcontext within the Api controller and need help.
namespace ZebraCRM.API2.Controllers
{
[Route("api/[controller]")]
public class LeadsController : Controller
{
private readonly ApplicationDbContext _context;
public LeadController(ApplicationDbContext context)
{
_context = context;
}
// POST api/values
[HttpPost]
public void Post(Lead formData)
{
formData.DateCreated = DateTime.Now;
_context.Lead.Add(formData);
_context.SaveChanges();
}
}
The above idea was taken from the controller in the main web project, but is obviously not the right approach in this situation.
the debug outputs the following
System.InvalidOperationException: Unable to resolve service for type 'ZebraCRM.Web.Data.ApplicationDbContext' while attempting to activate 'ZebraCRM.API2.Controllers.LeadsController'.
The framework doesn't know how to constructor a LeadController because it doesn't know how to satisfy the ApplicationDbContext context parameter when it calls the constructor. To solve this, you could simply assign the value as part of your constructor, eliminating the parameter.
namespace ZebraCRM.API2.Controllers
{
[Route("api/[controller]")]
public class LeadsController : Controller
{
private readonly ApplicationDbContext _context;
public LeadController()
{
_context = new ApplicationDbContext();
}
// POST api/values
[HttpPost]
public void Post(Lead formData)
{
formData.DateCreated = DateTime.Now;
_context.Lead.Add(formData);
_context.SaveChanges();
}
}
}
Or, if you do want to leave the constructor parameter in place, you'll need a DI container such as AutoFac or Ninject. If you're new to DI, I suggest you watch this video. When you set things up for Dependency Injection, you will basically pass something to the framework that says "When constructing an object that needs an X, here's how you give it an X". This allows you to better follow SOLID principles. An object can demand an IRepository (an interface) and as part of your DI setup you can say "when an object demands an IRepository, I want to pass it a SqlServerRepository (which would implement IRepository)". Then if you later decided to switch to MySQL, you could modify the setup to use a MySqlRepository instead of SqlServerRepository, without needing to modify anything about the controller, since the controller would use the repository via the interface.
As I am learning about Dependency Injection, so I have also shared my understanding (Please correct me wherever you guys feel to do so). The concept behind the following sample is to check the advantage of using Dependency Injection as it helps in implementing loose coupling in the application which will further prevent me from making lots of changes in the project in the case when concrete definitions (classes) tend to change in future.
IEmailService - Interface:
public interface IEmailService
{
void SendMail();
}
EmailService - Class inheriting above interface
public class EmailService : IEmailService
{
public EmailService(string emailFrom, string emailTo)
{
}
public void SendMail()
{
// Code here
}
}
HomeController
public class HomeController : Controller
{
private IEmailService _service;
public HomeController(IEmailService service)
{
_service = service;
}
public IActionResult Index()
{
_service.SendMail();
return View();
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
...
services.AddTransient<IEmailService, EmailService>();
...
}
Practical assumption
I assume that earlier there was no parameterized constructor in the EmailService class, but in future, I feel like I need to add a parameterized constructor but it shouldn't have an impact on those controllers (like HomeController) which are using abstraction (interfaces) to access them indirectly.
Unfortunately, when I am running the above code, I am getting the following exception which seems to disappear if I am removing the parameterized constructor from EmailService class.
InvalidOperationException: Unable to resolve service for type 'System.String' while attempting to activate 'DependencyInjectionDemo.Services.EmailService'.
You can register your EmailService using a lambda:
services.AddTransient<IEmailService>(_ => new EmailService("from#", "to#"));
emailFrom and emailTo however seem runtime data, which means that the Controller might be responsible of supplying this information to the IEmailService. Since the EmailService is decoupled from the controller, it means that the controller is not responsible of its creation.
In general, you should prevent needing to initialize your components (EmailService in your case) with runtime data, as explained here, the advice is:
Don't inject runtime data into application components during construction; it causes ambiguity, complicates the composition root with an extra responsibility and makes it extraordinarily hard to verify the correctness of your DI configuration. My advice is to let runtime data flow through the method calls of constructed object graphs.
In your case this basically means changing the IEmailService abstraction to the following:
public interface IEmailService
{
void SendMail(string emailFrom, string emailTo);
}
I am developing ASP.NET Core application. To keep controllers lean, most of the data manipulation is done in ViewModels. Everything works fine - the two problems, however, are
ViewModels don't have access to ControllerContext information (or I can't figure out how to get it). For example, Session, User and whatever else Controller gets for free.
ViewModels don't accept Dependency Injection (again, or I can't figure out how to pass it along). For example, if I have constructor MyController(ApplicationDbContext db) I get db passed without any problems. However, if I have ComplexViewModel(ApplicationDbContext db) I get null passed in. Obviously, I have exactly the same services.AddDbContext<ApplicationDbContext>() in Startup
Right now I am passing whatever is required from Controller to ViewModel explicitly. But it feels that there should be a better way.
View models are supposed to be simple POCOs to transfer data between the views and action methods. I think it is a bad idea to mix all your business logic (or even data access) to view models. You may consider doing that in services. You can inject this services to your controllers.
For example.
Yo get a User information, you may consider creating a service
public interface IUserService
{
UserDto GetUser(int id);
}
public class UserService : IUserService
{
IUserDataAccess userDataAccess;
public UserService(IUserDataAccess userDataAccess)
{
this.userDataAccess=userDataAccess;
}
public UserDto GetUser(int id)
{
// with this.userDataAccess, get a User and map to UserDto
// to do : return something
}
}
So your controllers will stay lean
public class UserController : Controller
{
private readonly IUserService userService;
public UserController(IUserService userService)
{
this.userService = userService;
}
public ActionResult Details(int id)
{
var userDto= this.userService.GetUser(id);
return View(userDto);
}
}
Now you can have a UserDataAccess which query your data and inject that to the UserService class.
With this approach your view model does not have any idea what data access technology you are using. Imagine tomorrow you decided to ditch EF for performance reason and want to switch to Dapper, you simply need to create a new implementation of your IUserDataAccess called "DapperUserDataAccess" and udpate your DI config registration to use that. No other code change :)