10+ razor page code behind get dbcontexts via dependency injection - c#

I develop an C# ASP.NET Core MVC app with a lot of razor pages.
Most of my razor pages use logging, sending e-mails and use multiple dbcontextes.
A lot of class looks like this:
class A : PageModel
{
private readonly ADbContext _context;
private readonly UserManager<ApplicationUser> _userManager;
private readonly IEmailSender _emailSender;
private readonly ILogger<MyModel> _logger;
public UpdateModel(ADbContext context,
UserManager<ApplicationUser> userManager,
IEmailSender emailSender,
ILogger<MyModel> logger)
{
_context = context;
_userManager = userManager;
_emailSender = emailSender;
_logger = logger;
}
}
I have 10+ pages like this.
When I create a page, I have to add these fields. So for a lot of times.
What would be the ideal approach to get rid of lot of field declarations? A base class that inherits every page model that I develop? But this base class would be a really general base class with logging, with Email and with contextes that really not similarly fit to each other.
Is it a good architectural choice to declare these fields every time I declare a class that uses them?

In general, yes, this is just what you do. Your dependencies are being injected, which means you need ivars to hold them and a constructor to accept them. It can feel and seem repetitive, but it's actually a good thing. It makes your class glanceable: you can quickly see what dependencies the class has at a glance.
You can create a base class if you like. However, you should be careful to only include things in your based class that are truly applicable to every derivation. The danger is in adding dependencies that aren't actually needed in all cases, and then now you have a bunch of pages loading dependencies they don't need and don't utilize.
You can also use abstractions to some extent here. For example, if each page depends on a context, but it might be different contexts in different scenarios, you can make the ivar typed as DbContext, instead of your concrete context type, and then you can set it to any valid derivation of DbContext. The same goes for your logger. You'd actually want to inject ILogger<MyPageModel>, but you can make the ivar on the base class just ILogger, which will then accept any logger.
Still, when you start to do this, you make it harder to suss out the dependencies of your classes, so it's a give and take. Personally, I'd only use a base class for shared logic, if any exists. If the only purpose of the base class is to define a particular set of dependencies, it's not worth having.

could it be a good occasion to use Filters instead ? Your filter dependencies could be injected via DI ?
https://www.learnrazorpages.com/razor-pages/filters
You can also simplify some cases of DI by injecting directly at function level where the service is required instead of inject at constructor level by adding '[FromService]' juste above the parameter :
[HttpGet]
public ActionResult OnGetDoSomething([FromServices] IEmailSender emailService)
{
// Do something
}
This way, you won't have to instanciate thoses services if the aren't required.

What about something like this?
class A : BasePage {
public UpdateModel(IServiceProvider provider) : base(provider) {
// here you can access the base properties
}
}
class BasePage : PageModel {
public ADbContext _context { get; set; }
public UserManager<ApplicationUser> _userManager; { get; set; }
public IEmailSender _emailSender; { get; set; }
public ILogger<MyModel> _logger; { get; set; }
public UpdateModel(IServiceProvider provider) : base(provider) {
Context = (ADbContext)provider.GetRequiredService(typeof(ADbContext));
UserManager = (UserManager)provider.GetRequiredService(typeof(UserManager));
EmailSender = (IEmailSender)provider.GetRequiredService(typeof(IEmailSender));
Logger = (ILogger)provider.GetRequiredService(typeof(ILogger));
}
}

Related

Dependency Injection in Unit of work with Autofac

Im going through a tutorial which uses EF 6 and a UnitOfWork pattern. The idea is to introduce Autofac and im not entirely sure how i should convert this line of code so it fits in with the project to introduce Dependency Injection
private readonly ContactsContext _context;
public UnitOfWork(ContactsContext context)
{
_context = context;
Customers = new CustomerRepository(_context);
}
public ICustomerRepository Customers { get; }
I can't change
Customers = new CustomerRepository(_context);
to
Customers = new ICustomerRepository(_context);
Note the Interface as it throws an error.
I can post the ICustomerRepository if required but I don't know how I should be handling the dependency in this case?
I can post more code if required but I didn't know if this is enough and I'm missing something simple or not?
The standard way to do this would be to take a constructor dependency on ICustomerRepository instead of instantiating a CustomerRepository yourself within the constructor:
private readonly ContactsContext _context;
public UnitOfWork(ContactsContext context, ICustomerRepository customerRepository)
{
_context = context;
Customers = customerRepository;
}
public ICustomerRepository Customers { get; }
Of course, you will also need to register CustomerRepository with Autofac as the implementation of ICustomerRepository.
builder.RegisterType<CustomerRepository>().As<ICustomerRepository>();
This means that you will be relying on Autofac to create the repository instead of doing so yourself (Autofac will 'know' to inject the ContactsContext into the constructor of CustomerRepository). That's the pervasive aspect of dependency injection - it ends up requiring you to adopt it all the way down.

How to make Account and Manage controllers inherit from a BaseController without errors

I've made a custom controller called BaseController and I'm making all my controllers inherit from that one.
This controller is useful for changing header color, adding custom texts, logos, etc. and I would really like to make my Manage and Account controller inherit from it too to make my Web Application have the same "style" in every page.
The problem is that the Account and Manage controllers can't inherit from BaseController because they already have two constructors, one empty, and one with parameters ApplicationUserManager and ApplicationSignInManager.
If I try to inherit from BaseController it gives me errors on these two constructors saying that they don't have the required formal parameters that I should pass from BaseController.
There is no argument given that corresponds to the required formal parameter (1stParam) of BaseController.BaseController(Type1stParam, Type2ndParam, Type3rdParam, Type4thParam)
I've searched for a while on StackOverflow to find an answer but I couldn't find much so I decided to create this question.
This is the custom controller.
public abstract class BaseController : Controller
{
readonly Servix2Repo.IUtente Utente;
readonly Servix2Repo.IMenu Menu;
readonly Servix2Repo.IAzienda Azienda;
readonly ServixMVCModel _context;
public BaseController(ServixMVCModel context, Servix2Repo.IUtente utenteRepo, Servix2Repo.IMenu menuRepo, Servix2Repo.IAzienda aziendaRepo)
{
_context = context;
this.Utente = utenteRepo;
this.Menu = menuRepo;
this.Azienda = aziendaRepo;
}
(Other methods)
}
This is one of the two controllers that I have problems with. I get the error on the empty constructor and the last one.
public class AccountController : BaseController
{
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
public AccountController(ServixMVCModel context, Servix2Repo.IUtente utenteRepo, Servix2Repo.IMenu menuRepo, Servix2Repo.IAzienda aziendaRepo) : base(context, utenteRepo, menuRepo, aziendaRepo)
{
}
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager )
{
UserManager = userManager;
SignInManager = signInManager;
}
(Other methods)
}
Thanks to anyone who is willing to help me and I'm sorry if I made some wording mistakes.
Fixed using Thangadurai's suggestion in the comments:
In your BaseController, you do not have any default constructor that accepts no parameters. So, In all your AccountController constructors you should call the base constructor in the same way how you did it for the first constructor OR you must include one default constructor in the base class

Exception in Autofac : No parameterless constructor defined for this object

Here is my class where dependencies are resolved
namespace TestProj
{
public static class Bootstrapper
{
public static void Run()
{
SetAutofacWebAPI();
}
private static void SetAutofacWebAPI()
{
var builder = new ContainerBuilder();
builder.RegisterType<UserService>().As<IUserService>().InstancePerRequest();
builder.RegisterType<Encryption>().As<IEncryption>().InstancePerRequest();
DependencyResolver.SetResolver(new AutofacDependencyResolver(builder.Build()));
}
}
}
In the Global.asax, I have this : Bootstrapper.Run();
Here is my UserService class:
public class UserService : IUserService
{
private readonly IEncryption _Encryption;
public UserService(Encryption Encryption)
{
_Encryption = Encryption;
}
//Rest of the service here
}
the Encryption class is a similar one.
And the controller is here :
public class UserController : Controller
{
private readonly IUserService _UserService;
public AccountController(UserService UserService)
{
_UserService = UserService;
}
public JsonResult GetLoginLogs(int Id)
{
var Logs = _UserService.GetLoginLogById(Id);
return Json(Logs, JsonRequestBehavior.AllowGet);
}
//The rest of the controller
}
here is the version info:
Autofac : 3.5.2
MVC : 4.0.40804.0
DOTNET : 4
And then, when try localhost:5000/Account/GetLoginLogs/1 this exception comes up:
No parameterless constructor defined for this object.
Someone please help. I am in seriously in trouble!
I think you are confusing how you registered the dependencies.
Update from comments by #Amy:
You also failed to register your MVC controllers
// You can register controllers all at once using assembly scanning...
builder.RegisterControllers(Assembly.GetExecutingAssembly());
Source: documentation
Also use the interfaces instead of the concrete classes when explicitly injecting into the dependent classes as that is what you registered with the container.
public class UserService : IUserService {
private readonly IEncryption _Encryption;
public UserService(IEncryption Encryption) {
_Encryption = Encryption;
}
//Rest of the service here
}
public class UserController : Controller {
private readonly IUserService _UserService;
public AccountController(IUserService UserService) {
_UserService = UserService;
}
public JsonResult GetLoginLogs(int Id) {
var Logs = _UserService.GetLoginLogById(Id);
return Json(Logs, JsonRequestBehavior.AllowGet);
}
//The rest of the controller
}
Actually, I believe the exception you get is not misleading if you get deeper into it and analyze the exception message and stack trace. You would find exactly which service could not be found and created by the container - in this case it would be UserService in AccountController (and later, Encryption in UserService as well). The exception with "no parameterless contructor found" simply says that in existing contructor with parameters there is one or more parameters which cannot be resolved by the container, and, because the parameterless constructor is missing, required type cannot be created.
It can also mean you forgot to register your controllers in the container, so the Autofac has no idea it should inject any dependecies into the controllers.
Going further - Autofac is very explicit with the registrations - you can only inject/resolve what you registered at the start up of the application.
If you simply use builder.RegisterType<UserService>() - without any As<> you can only inject UserService directly. But when you add .As<>: builder.RegisterType<UserService>().As<IUserService>(), you cannot inject UserService anymore, but IUserService. To keep the possibility to inject UserService you would have to use AsSelf(): builder.RegisterType<UserService>().As<IUserService>().AsSelf(). Then, you can inject both IUserService and UserService. Keep in mind Autofac registration API is fluent, you can amend as many As<> as you want.
In Dependecy Injection world we do not like tidly coupled components, so injecting concrete classes, instead of interfaces - like you did - is not recommended - you should use interfaces wherever it is possible. So your registrations are correct, but you should inject IUserService instead of UserService and IEncryption instead of Encryption in your components.
It would ease potential unit testing of these components, allowing you mocking up dependencies easily.
Also, you should register your controllers as well:
builder.RegisterControllers(Assembly.GetExecutingAssembly())‌​;

IoC/MEF container

In my interface package i have this following piece of code that runs when the user wants to change some info about a artist:
IArtist artistToChange = ContainerHelper.Container.GetExportedValue<IArtist>();
artistToChange.Load(new Guid("provided guid"));
artistToChange.SomeProperty = newValue;
artistToChange.Update();
Being Artist a entity in my domain it is composed among other stuff by a IUser CreatedBy & IUser LastAlteredBy properties that must be loaded (think of Many-To-One relationship). Each Entity also has its own repository. IArtist has a IArtistRepository the same way IUser has IUserRepository.
My problem is the following: How can I get a instance of a concrete implementation of IUser inside of IArtist.Load() while maintaining IoC (without the concrete implementation of IArtist not knowing about the concrete implementation of IUser)?
(To make things easy let's call of CArtist the concrete implementation of IArtist, and CUser the implementation of IUser.)
With that in mind i though about passing the container to the Entities so they could also request parts, but i dont know if that is a good idea or even a anti-pattern, mainly because im using constructor injection and my constructor for 'CArtist' looks like this:
[ImportingConstructor]
public CArtist(IArtistRepository repository)
{
this.repository = repository;
}
but i cant get the container to inject itself with something like
[ImportingConstructor]
public CArtist(IArtistRepository repository, CompositionContainer container)
{
this.container = container
this.repository = repository;
}
So this is basically it... i'm quite lost here... this turned out to be a cry for help/guidance more than a question on itself...
PS: If any other information is necessary pls ask for it!
Assuming you properly export a concrete IArtist class, you can do the following in your code, and then as long as the dll's are available, when you compose the CArtist class, the IArtist type would get injected into the class. You may be able to even get away with a private variable private IArtist _someArtist; (marked with the import attribute)
public class CArtist : IArtist
{
[ImportingConstructor]
public CArtist(IArtistRepository repository)
{
this.repository = repository;
}
public void Load(Guid guid)
{
this.SomeArtist.DoSomething(guid);
...
}
[Import(typeof(IArtist))]
private IArtist SomeArtist { get; set; }
}
Another approach, would be to, again use a property or var in the class, and import it in the constructor
private IArtist _artist;
[ImportingConstructor]
public CArtist(IArtistRepository repository, IArtist artist)
{
this.repository = repository;
this._artist = artist;
}
Aside from those possible approaches, imho passing the container wouldn't be too big of a problem, it would work and you still maintain the separation, I've seen that done in a few places, but I'm no expert in IoC to know definitively whether it's a good or bad practice.

Where to keep dictionaries in app using Dependency Injection

I have a legacy code, and I have a problem with reconstructor it.
At start of my application I load from WCF to property on App (this is SL application) list of users.
Then every control (for sending emails, view calendar and assigning tasks) use this property as
(App.Current as App).Users
Now, I'm trying to create Unit Test for one of controls that use this lists, and I'm stuck.
Should I make a Constructor Injection(I'm using Unity) with App as parameter? Or maybe introduce some class to hold this list?
Updated with OP's implementation as the pseudocode was incomplete.
I propose create an interface for all your application services
Inject IApplicationService to your modules.
You can use this interface for all the services the application provides(probably you will need more). Mock the interface for the unit tests
OP's implemantation
public interface IApplicationService
{
List<User> Users{get;set;}
}
public class ApplicationService : IApplicationService
{
public List<User> Users
{
get { return (App.Current as App).Users; }
set { (App.Current as App).Users = value; }
}
}
public partial class MainWindow : UserControl
{
readonly IApplicationService _applicationService
public MainWindow(IApplicationService applicationService)
{
_applicationService=applicationService;
}
}
I would create a wrapper class that will expose the list of users. In production code this class will just be a wrapper around your App.Current property and it can be injected in the constructor trough Unity.
In your Unit Tests you can easily mock the App parameter and pass it when constructing a new SUT.
Something like:
public interface IUserList
{
List<User> Users { get; }
}
public class SUT
{
private IUserList UserList { get; set; }
public SUT(IUserList userList)
{
this.UserList = userList;
}
}
public class AppUserList : IUserList
{
public List<User> Users
{
get
{
return ((App)App.Current).Users;
}
}
}
For Silverlight there is an extension model called Application Extension Services.
For infrastructure purposes that might be a better alternative than adding properties to your app class and casting App.Currentback and forth.
Downside of that model is the creation of a singleton you would have to initialize for your unit tests. It would also hide the dependency on Users in your consuming classes.
Your users seem to be just data. Making that data an ambient context which can be accessed and edited everywhere in your application will bite you. You don't know who does what with that data and when he does it. This is like a session state.
So making the dependency on your data explicit would be a first step to be able to track abuse of that data.
If it makes sense to you to create a "data holder object" that has a property for Users or directly inject that data into your consumers is up to you. If there is more data than just Usersit is tempting to put all of them into the same central data store object, even if your specific consumers don't need them.
Jimmy's answer is great, but can be provide quite a bit, and some errors fixed. Differences are explained at the bottom below the code/instructions:
Create a public interface: IUserService
public interface IUserService
{
// Implemented functionality as methods where possible for better
// extendability (like IoC)
IEnumerable<User> Users();
// Add any other user service stuff as you see fit.
void AddUser(User user);
}
Write a UserService that implements IUserService
public class UserService : IUserService
{
// If you need DI for this service, follow the same pattern of using
// fields and controller injection. I left examples in comment below.
// private readonly IRepository _repository;
// Constructor is unnecessary if you do not need DI example.
public UserService(/* IRepository repository */)
{
// _repository = repository;
}
// Methods
public IEnumerable<User> Users()
{
return ((App)App.Current).Users;
}
public void AddUser(User user)
{
((App)App.Current).Users.Add(user);
}
}
Inject IUserService into classes via their Constructor
In this case your MainWindow as an example:
public partial class MainWindow : UserControl
{
private readonly IUserService _userService;
public MainWindow(IUserService userService)
{
_userService = userService;
}
// Example method consuming the service
public IEnumerable<User> GetUsers()
{
return _userService.Users();
}
}
Differences:
Separate your User Services from a central Application Service
Better modularity. In addition I use an IApplicationService for more central/global data like Api Keys, Timeouts, cleanup, DB prepping, etc.
Return IEnumerable<T> instead of List<T>
This is just a golden rule of thumb for keeping things dry and not imposing hard instantiations on your consuming classes. Refactoring is easier/safer, and your code more extensible.
Use methods instead of properties
This is preference, but I think it smart in a service layer to use methods where possible so that you can introduce filters and overloads or continue to use dependency injection - for example, you could add GetUsers(string lastName), GetUsers(string lastName, string firstName) and maintain a clean interface for your consuming classes.
Cast App.Current without the as keyword
This is a good practice because using the as keyword means when the cast fails it will return null, rather than throw an exception. I prefer the exception because 99% of the time, if your cast fails, your next operations will too. :)
Enjoy!

Categories