Here is how my application makes a call to the database:
Web App -> Business Layer -> Data Layer
Everything is using dependency injection.
For example:
In the controller in my Web app I make a call like this:
await _manager.GetCustomers();
Which goes into my Business Layer:
public class CustomerManager : ICustomerManager
{
private ICustomerRepo _repository;
public CustomerManager(ICustomerRepo repository)
{
_repository = repository;
}
public Task<IList<Customer>> GetCustomers(string name = null)
{
return _repository.GetCustomers(name);
}
}
Which goes into my Data Layer:
public class CustomerRepo : BaseRepo, ICustomerRepo
{
public CustomerRepo(IConfigurationRoot configRoot)
: base(configRoot)
{
}
public Customer Find(int id)
{
using (var connection = GetOpenConnection())
{
...
}
}
}
The trick here is that CustomerRepo inherits from BaseRepo to be able to use the GetOpenConnection() function. But at the same time BaseRepo needs an IConfigurationRoot injected into it from the web application. How can I do both?
public class BaseRepo
{
private readonly IConfigurationRoot config;
public BaseRepo(IConfigurationRoot config)
{
this.config = config;
}
public SqlConnection GetOpenConnection(bool mars = false)
{
string cs = config.GetSection("Data:DefaultConnection:ConnectionString").ToString();
...
}
}
How would you instantiate (or even compile) a CustomerRepo at all, regardless of dependency injection? You need an IConfigurationRoot parameter to pass through to the base constructor. Like:
public CustomerRepo(IConfigurationRoot configRoot)
: base(configRoot)
{
}
See https://msdn.microsoft.com/en-us/library/hfw7t1ce.aspx for info on the base keyword.
Related
How can I inject a specific setting (of possibly many) from an array appSettings.json in a C# .NET Core Web API, based on a runtime input value?
appSettings.json:
{
"SettingProfiles": [
{
"Name": "Profile1",
"SettingA": "SettingAValue1",
"SettingB": "SettingBValue1"
},
{
"Name": "Profile2",
"SettingA": "SettingAValue2",
"SettingB": "SettingBValue2"
}
...
}
Settings Classes:
public class Settings {
public List<SettingsProfile> SettingsProfiles { get; set; }
}
public class SettingsProfile {
public string Name { get; set; };
public string SettingA { get; set; };
public string SettingB { get; set; };
}
Service class:
public class MyService : IMyService {
private readonly SettingsProfile _Profile;
public MyService(SettingsProfile profile) {
_Profile = profile;
}
public void DoStuff() {
Console.WriteLine($"Setting A: {_SettingsProfile.SettingA}, Setting B: {_SettingsProfile.SettingB}")
}
}
The user will enter the setting name they want to apply. I am unsure how to do this if the service is configured in Startup.cs, at which point I don't yet have the setting to use.
I am understanding that "newing" the service would be bad practice, although that's the only way I can figure out how to make it work:
public class MyController {
private readonly Settings _Settings;
public MyController(Settings settings) {
_Settings = settings;
}
public IActionResult DoStuff(profileName) {
SettingsProfile profile = _Settings.Where(profile => profile.Name == profileName);
MyService service = new Service(profile);
}
}
I'm obviously missing something, but I've been watching YouTube videos on Dependency Injections and reading StackOverflow until my eyes bleed, and haven't figured it out yet. Can someone help me with a pattern that I should be following?
This is how I think it should work.
It will be a lot cleaner if you use another pattern: Factory.
interface ISettingServiceFactory{
MyService GetService(string profileName);
}
class SettingServiceFactory: ISettingServiceFactory
{
MyService GetService(string profileName){
}
}
Now you can implement GetService in two ways.
The first one is by creating new as you did in the controller and is not that bad as this is the purpose of the factory. In this way you kind of move that logic somewhere else.
A second one would be a bit uglier but something like this
interface ISettingServiceFactory{
MyService GetService(string profileName);
void SetCurrentProfile(SettingsProfile profile);
}
class SettingServiceFactory: ISettingServiceFactory
{
private IServiceProvider _serviceProvider;
private Settings _Settings;
public SettingServiceFactory(IServiceProvider serviceProvider,Settings settings){
_serviceProvider = serviceProvider;
_Settings = settings;
}
MyService GetService(string profileName){
var service = _serviceProvider.GetRequiredService<MyService>();
var profile = _Settings.Where(profile => profile.Name == profileName);
service.SetCurrentProfile(profile);
return service;
}
}
This second approach would be useful only if the implementation of MyService has a lot of other dependencies by itself and if you want to avoid new at any cost.
In both cases you will inject the factory in the controller
public MyController(ISettingServiceFactory settingServiceFactory) {
_settingServiceFactory= settingServiceFactory;
}
public IActionResult DoStuff(profileName) {
MyService service = _settingServiceFactory.GetService(profileName)
}
Given the following ASP.NET Core controller :
public class MyController : Controller {
public MyController(IDependency dependency) { this.dependency = dependency; }
}
public interface IDependency;
public class DependencyImplementation : IDependency {
public DependencyImplementation(Controller controller) { ... }
}
I want MyController to have a new instance of DependencyImplementation injected, constructed with the controller it's being passed to. Ideally using Ninject.
The non-IoC version would be:
public class MyController : Controller {
public MyController() { this.dependency = new DependencyImplementation(this); }
}
This would cause circular dependency. Only idea I have is to introduce factory:
public interface IDependencyFactory
{
IDependency Create(Controller controller);
}
public class MyController : Controller
{
private IDependency dependency;
public MyController(IDependencyFactory dependencyFactory)
{
this.dependency = dependencyFactory.Create(this);
}
}
var kernel = new StandardKernel();
kernel.Bind<Controller>().To<MyController>();
kernel.Bind<IDependency>().To<DependencyImplementation>();
kernel.Bind<IDependencyFactory>().ToFactory();
var controller = kernel.Get<Controller>();
Or maybe rather reconsider whole design.
I am going to make up an example here just to get my point across. Please consider the following class:
public class MovieController : Controller
{
private readonly IMovieService _movieService;
private readonly IUserService _userService;
public MovieController(IMovieService movieService, IUserService userService)
{
_movieService = movieService;
_userService = userService;
}
public ViewModel GetMovies()
{
return View("Movies", _movieService.GetMovies());
}
public ViewModel GetAuthors()
{
return View("Authors", _userService.GetAuthors());
}
}
With the example above, whenever the MovieController is created, it will create both services. Each service will require its services and repositories in the constructor. So, in reality, I may be creating some classes each time MovieController is called. For this reason, I want to implement Lazy loading as I believe it will improve performance. For this reason, please consider the next class:
public class MovieController : Controller
{
private readonly IMovieService _movieService;
private readonly IUserService _userService;
private MovieService
{
get
{
if (_movieService == null) _movieService = new MovieService();
return _movieService;
}
}
private UserService
{
get
{
if (_userService == null) _userService = new UserService();
return _userService;
}
}
public MovieController() { }
public ViewModel GetMovies()
{
return View("Movies", MovieService.GetMovies());
}
public ViewModel GetAuthors()
{
return View("Authors", UserService.GetAuthors());
}
}
The problem with the above example is that I lost DI. Now I understand the benefit of DI, and I very much want to keep it, and as such, I came up with the following example:
public class MovieController : Controller
{
private readonly IMovieService _movieService;
private readonly IUserService _userService;
private MovieService
{
get
{
if (_movieService == null) _movieService = DependencyResolver.Current.GetService(typeof(IMovieService));
return _movieService;
}
}
private UserService
{
get
{
if (_userService == null) _userService = DependencyResolver.Current.GetService(typeof(IUserService));
return _userService;
}
}
public MovieController() { }
public ViewModel GetMovies()
{
return View("Movies", MovieService.GetMovies());
}
public ViewModel GetAuthors()
{
return View("Authors", UserService.GetAuthors());
}
}
Is my third example in this question a bad practice? If so, why? Am I losing on performance by doing this or is there another reason why this would be considered bad practice?
Using the dependency resolver this way means that you are using the service locator anti-pattern.
Is there any reason why you think that creating MovieService and UserService will have performance issues? Are you doing something significant in the constructor of these classes? If so, then you probably shouldn't. In the constructor you should almost always just accept the dependencies and store them in private fields.
If for some reason, you still want lazy loading, then you can create something like this:
public class LazyMovieService : IMovieService
{
private readonly Lazy<IMovieService> lazyInstance;
public LazyMovieService(Func<IMovieService> instanceFactory)
{
lazyInstance = new Lazy<IMovieService>(instanceFactory);
}
public string[] GetMovies()
{
return lazyInstance.Value.GetMovies();
}
}
This class allows you to use the first code example in your code while still being able to lazily load your services.
In the Composition Root, you would simply do something like:
var controller =
new MovieController(
new LazyMovieService(() => new MyOriginalMovieService(...)),
...);
I'm trying to make an application that changes the DbConnection string based on the authenticated user.
So, after the user login, I have to get that user, see a field like "connectionName" and look for that connectionString on my app.config to connect to my database.
I already know how to set my Dependency Injection to pass the constructor params, but how do I get at my dependency injector Project the logged user ?
Something like this.
This is in a Project called "Project.Infra"
DBContext
public class MyDbContext : DbContext
{
//ConnectionStringBasedOnUserLogged will be a propertie on my userModel
//so I have to get the logged user before have it.
public MyDbContext(string ConnectionStringBasedOnUserLogged)
: base(ConnectionStringBasedOnUserLogged)
{
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
}
//DbSets...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Mappings...
}
}
This is in a Project called "Project.Infra"
Repository
public class MyRepository : IMyRepository
{
private MyDbContext _ctx;
public MyRepository(MyDbContextcontext)
{
this._ctx = context;
}
//Implementation of interface...
}
This is in a Project called "Project.Api"
Controller
public class MyController : ApiController
{
private IMyRepository _repo;
public MyController(IMyRepository repo)
{
this._repo = repo;
}
//Implementation
}
This is in a Project called "Project.Startup"ยด
DepencyInjection
public static class DependencyResolver
{
public static void Resolve(UnityContainer container)
{
//How do I get here some details about the logged user at my application ?
container.RegisterType<MyDbContext, MyDbContext>(new HierarchicalLifetimeManager(), new InjectionConstructor("HereWillComeTheConnection"));
container.RegisterType<IMyRepository, MyRepository>(new HierarchicalLifetimeManager()); }
}
I am using Ninject to do some IoC in my ASP.NET MVC application.
I have an interface "IService.cs" :
public interface IService
{
string method();
}
I have the corresponding implementation "Service.cs" :
public class Service
{
string method()
{
return "result";
}
}
I have done the binding in another class heriting from NinjectModule :
public class MyNinjectModule : NinjectModule
{
public override void Load()
{
RegisterServices();
}
private void RegisterServices()
{
Kernel.Bind<IService>().To<Service>();
}
}
I have my class A which use this service :
public class A
{
private readonly IService _service;
private int i;
public A(IService service, int i)
{
this._service=service;
this.i=i;
}
}
The problem is that now, I don't know how to instantiate my class A in my application. This is where am I stuck, how can I call Ninject
to tell my app to go get the implementation of my interface:
var myClass=new A(????)
The main problem is that your Service class does not implement IService.
public class Service
{
string method()
{
return "result";
}
}
It should be
public class Service : IService
{
public string method()
{
return "result";
}
}
But as for instantiating a class, the best approach is to use a composition root to build an object graph. In MVC, that is best handled by implementing IControllerFactory.
public class NinjectControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public NinjectControllerFactory(IKernel kernel)
{
this.kernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null
? null
: (IController)this.kernel.Get(controllerType);
}
}
Usage
using System;
using Ninject;
using DI;
using DI.Ninject;
using DI.Ninject.Modules;
internal class CompositionRoot
{
public static void Compose()
{
// Create the DI container
var container = new StandardKernel();
// Setup configuration of DI
container.Load(new MyNinjectModule());
// Register our ControllerFactory with MVC
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(container));
}
}
In Application_Start, add:
CompositionRoot.Compose();
You will also need to create an interface for your class A and register it. An integer cannot be resolved automatically, you have to do that explicitly.
Kernel.Bind<IClassA>().To<A>()
.WithConstructorArgument("i", 12345);
And then you would add your dependency to a controller. Dependencies of dependencies are resolved automatically.
public class HomeController : Controller
{
private readonly IClassA classA;
public HomeController(IClassA classA)
{
if (classA == null)
throw new ArgumentNullException("classA");
this.classA = classA;
}
public ActionResult Index()
{
// Use this.classA here...
// IService will be automatically injected to it.
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
}