Access controller data from ViewModel - c#

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 :)

Related

DBContext between business layers

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.

Passing a service to a controller in .NET MVC framework

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.

Injecting ModelState into Service

I am trying to inject the ModelState of the controller into my Service layer to add business logic related validation errors (e.g. entry already exists).
For this I created a new IValidationDictionary that gets injected into my service through an Initialize() function. Nothing new at all and judging by my google searches something quite some people do in MVC.
The Controller constructor looks like this:
public AccountController(IAccountService accountService)
{
_accountService = accountService;
_accountService.Initialize(new ValidationDictionary(ModelState));
}
This all works fine and I can add errors in my service. The issue comes when leaving the service again. At that point none of my errors are present in the controller ModelState. After some debugging I found out that the ModelState in the constructor of the controller is not the same as in the Action. At some point it seems to create a new ModelState.
One alternative seems to be to call the Initialize() to inject the ModelState at start of every Action. Before I do that, I wanted to ask if anyone has a more elegant way (as in less to type) of solving this.
Edit:
The IValidationDictionary:
On buisness layer:
public interface IValidationDictionary
{
void AddError(string key, string message);
bool IsValid { get; }
}
In controller:
public class ValidationDictionary : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ValidationDictionary(ModelStateDictionary modelState)
{
_modelState = modelState;
}
public bool IsValid
{
get
{
return _modelState.IsValid;
}
}
public void AddError(string key, string message)
{
_modelState.AddModelError(key, message);
}
}
First and foremost, you shouldn't do that because you will be mixing two things and break separation of concerns and tightly-couple your application.
Tightly coupling
ModelState property is of type ModelStateDictioanry which is a ASP.NET Core specific class. If you use it in your business layer, you create a dependency on ASP.NET Core, making it impossible to reuse your logic anywhere outside of ASP.NET Core, i.e. Background Worker process which is a pure console application because you neither reference ASP.NET Core nor you'll have HttpContext or anything else there.
Separation of concerns
Business validation and input validation are two different things and should be handled differently. ModelStateDictionary is used for input validation, to validate the input passed to your controller. It is not meant to validate business logic or anything like that!
Business validation on the other side is more than just a rough validation of the fields and its patterns. It contains logic and validation may be complex and depend on multiple properties/values as well as of the state of the current object. So for example, values that may pass the input validation may fail in business validation.
So by using both together, you will violate separation of concerns and have a class do more than one thing. This is bad for maintaining code in the long run.
How to work around it?
Convert IDicitionary<string, ModelStateEntry> to a custom validation model/ValidationResult
ValidationResult is defined in System.Components.DataAnnotations` assembly which is not tied to ASP.NET Core but is port of .NET Core/full .NET Framework, so you don't get a dependency on ASP.NET Core and can reuse it in console applications etc. and pass it around in your validation service using i.e. a factory class
public interface IAccoutServiceFactory
{
IAccountService Create(List<ValidationResult> validationResults);
}
// in controller
List<ValidationResult> validationResults = ConvertToValidationResults(ModelState);
IAccountService accountService = accountServiceFactory.Create(
This solves the issue of dependencies, but you still violate separation of concerns, especially if you use the same model in your business layer as you use as controller parameter.
Custom validatior (completely separated)
Its bit more work at the beginning, but your validation will be completely independent and you can change one of it w/o affecting the other one.
For it you can use frameworks like Fluent Validations which may make the validation a bit easier and more managed
You write a custom validator, that will validate the logic of a certain class/model.
The custom validator can be from as simple as writing your own validators per model which may implement such an interface
public interface IValidator<T> where T : class
{
bool TryValidate(T model, out List<ValidationErrorModel> validationResults);
List<ValidationErrorModel> Validate(T model);
}
and wrap this around your validator class
public class ModelValidator : IModelValidator
{
public List<ValidationErrorModel> Validate<T>(T model)
{
// provider is a IServiceProvider
var validator = provider.RequireService(typeof(IValidator<T>));
return validator.Validate(model);
}
}
Custom validatior (validation attribute based)
An alternation of the above, but using the validation attributes as base and custom logic. You can use Validator.TryValidateObject from System.ComponentModel.DataAnnotations to validate a models ValidatorAttributes. Be aware though, that it only will validate the passed models attributes and not of child models.
List<ValidationResult> results = new List<ValidationResult>();
var validationContext = new ValidationContext(model);
if(!Validator.TryValidateObject(model, validateContext, results))
{
// validation failed
}
and then additionally perform custom logic. See this blog post on how to implement child model validation.
Imho the cleanest way to do is a custom validator, as its both separated and decoupled and easily allows you to change logic of a model w/o affecting the validation of other models.
If you are only validating messages (i.e. commands/queries in CQRS) you can use the second approach with the validation attributes.
Thanks to user Ruard, here is how I did it with .NET Core 5.0
In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
...
}
In Controller
AccountService _service;
public AccountController(IActionContextAccessor actionContextAccessor)
{
//this.actionContextAccessor = actionContextAccessor;
_service = new AccountService(actionContextAccessor);
}
In Service Layer class
public class AccountService
{
private readonly IActionContextAccessor _actionContextAccessor;
public AccountService(IActionContextAccessor actionContextAccessor)
{
_actionContextAccessor = actionContextAccessor;
}
public void Login(string emailAddress, string password)
{
_actionContextAccessor.ActionContext.ModelState.AddModelError("Email", "Your error message");
}
}
In Action, you use like
_service.Login(model.Email, model.Password);
if(!ModelState.IsValid)
return View(model);
There is an easier way to access the ModelState.
Configure IActionContextAccessor in startup:
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
And inject it in the service:
public class MyService : IMyService
{
private readonly IActionContextAccessor _actionContextAccessor;
public MyService(IActionContextAccessor actionContextAccessor)
{
_actionContextAccessor = actionContextAccessor;
}
public bool IsValid
{
get
{
return _actionContextAccessor.ActionContext.ModelState.IsValid;
}
}
}
Please note that it is important to keep a reference to IActionContextAccessor (for similar reasons as with IHttpContextAccessor).
A new controller gets created for every request. Depending whether you configured your service as transient or singleton, a new IAccountService is created with every request, or a single instance reused. Since you manage state per request, I assume you have a transient service, that is, a new instance with every request. Once the request is gone, those instances get unreferenced.
I don't know what you mean with leaving the service though. I hope this provides the right input to track down your problem.

How to properly separate model validation from Controller into Service?

I'm in the middle of re-factoring the project I'm working on. In my existing controllers I do use the repository pattern, but I was still performing a little too much scaffolding than I felt comfortable with. That and some of my controllers could have 10+ repositories passed in (via Ninject). So, I decided to introduce a service layer where my intention is to have one service per controller and each service will instead have the multiple repositories injected into it and do the work I need. This works great so far, but I'm running into a confusion of sorts: How do I move the model validation away from the controller and into the service layer?
For example, take a look this Edit method on my OfficesController:
[HttpPost]
public async Task<RedirectToRouteResult> Edit(
short id,
FormCollection form,
[Bind(Prefix = "Office.Coordinates", Include = "Latitude,Longitude")] Coordinate[] coordinates) {
if (id > 0) {
Office office = await this.OfficesService.GetOfficeAsync(id);
if ((office != null)
&& base.TryUpdateModel(office, "Office", new string[2] {
"Name",
"RegionId"
}, form)
&& base.ModelState.IsValid) {
this.OfficesService.UpdateOfficeAsync(office, coordinates);
}
return base.RedirectToAction("Edit", new {
id = id
});
}
return base.RedirectToAction("Default");
}
The problem with it in comparison to the methods of the controller is that I still grab an Office object from the database, do the update, validate it, and then save it again. In this case the complexity increased rather than decrease. Before, I called the repository in the method, now I call the service which calls the repository to perform the same function. So far this increase in complexity has only show it self in my Edit methods, everywhere else the complexity decreased substantially, which is what I want.
So, what would be a proper way move validation, and now that I think about it, the model updating logic out of the controller and into the service? Recommendations are appreciated!
For reference, here's how my project is structured:
Data: Contains all of my model classes
Data.Google.Maps: Contains all classes I need to deserialize a specific Kml
Data.Models: Contains my DbContext, configurations, view models and partial view models
Data.Repositories: Contains all of my repositories that talk to the DbContext. Since EF is a pseudo repository on it's own, I'm leveraging my "repositories" as a more specific way of querying for data. For Example: FindTechnicians() or FindActive(), etc.
Data.Services: Contains all of the services I will use. The services will have one or more repository injected into them and perform all of logic I need done before I pass a completed view model back to the controller.
Identity: Contains my implementation of ASP.NET Identity.
Web.Private: Contains the actual MVC project.
Here are 2 articles you should read if you haven't already:
https://cuttingedge.it/blogs/steven/pivot/entry.php?id=91
https://cuttingedge.it/blogs/steven/pivot/entry.php?id=92
The answers to your problem are FluentValidation.NET and dependency decoration.
With it, you could do something like this:
private readonly IExecuteCommands _commands;
[HttpPost]
public async Task<RedirectToRouteResult> Edit(short id, UpdateOffice command) {
// with FV.NET plugged in, if your command validator fails,
// ModelState will already be invalid
if (!ModelState.IsValid) return View(command);
await _commands.Execute(command);
return RedirectToAction(orWhateverYouDoAfterSuccess);
}
The command is just a plain DTO, like a viewmodel. Might look something like this:
public class UpdateOffice
{
public int OfficeId { get; set; }
public int RegionId { get; set; }
public string Name { get; set; }
}
... and the magic validator:
public class ValidateUpdateOfficeCommand : AbstractValidator<UpdateOffice>
{
public ValidateUpdateOfficeCommand(DbContext dbContext)
{
RuleFor(x => x.OfficeId)
.MustFindOfficeById(dbContext);
RuleFor(x => x.RegionId)
.MustFindRegionById(dbContext);
RuleFor(x => x.Name)
.NotEmpty()
.Length(1, 200)
.MustBeUniqueOfficeName(dbContext, x => x.OfficeId);
}
}
Each of these validation rules will be run before your action method even gets executed, provided you have the validators set up for dependency injection and that you are using the FV MVC validation provider. If there is a validation error, ModelState.IsValid will be false.
You have also just solved the over injection problems in both your controller and (maybe) service layers. You can run any query, execute any command, or validate any object with only 3 interface dependencies.

Repository Pattern IRepository<T> inside IServiceRepository

I have implemented repository pattern and it works pretty well.
public interface IServiceRepository
{
User GetUser(int id);
User GetUser(string email);
User GetUser(string email, byte[] password);
//SkipCode
}
//Service repository where I keep extended methods for database manipulation
public class ServiceRepository : IServiceRepository
{
private readonly IRepository<User> _userRepository;
private readonly IRepository<Order> _orderRepository;
private readonly IUnitOfWork _unitOfWork;
public ServiceRepository(IRepository<User> userRepository, IRepository<Order> orderRepository, IUnitOfWork unitOfWork)
{
}
//SkipImplementation
}
When I want to access some methods from IServiceRepository in Controller I do this
public class AccountController : Controller
{
private readonly IRepository<OrderDetail> _orderDetailRepository;
private readonly IRepository<UserDetail> _userDetailRepository;
private readonly IServiceRepository _serviceRepository;
public AccountController(IRepository<OrderDetail> orderDetailRepository, IRepository<UserDetail> userDetailRepository, IServiceRepository serviceRepository)
{
_orderDetailRepository = orderDetailRepository;
_userDetailRepository = userDetailRepository;
_serviceRepository = serviceRepository;
}
}
As you see I inject IRepositories and IServiceRepository in this scenario. Sometimes I inject only IRepositories or IServiceRepository depending on a needs.
Question would be maybe I should move all IRepositories into IServiceRepository. And in all controllers embed only IServiceRepository and access IRepositories from IServiceRepository? This implementation looks more clear to me because only IServiceRepository will be injected in controllers. But to access for example one Repositorie<User> from ServiceRepository will need to build and inject all other repositories in ServiceRepository, so it may slow down the whole application. What do you think?
My answer is controversial, so please bear with me :)
To the point
Building and injecting repositories should take almost no time. I assume your repositories do not open any connections when they are created, so do not bother about micro optimisation, just get it working :)
You can merge your interfaces, as long as the result interface is small (say no more than 10 or so methods), focused and has a clear purpose.
Side comments
What is the need for the repository pattern? Do you allow (or in the nearest future plan) to easily switch between databases? For most cases repository is a massive overkill and a maintenance problem.
Consider this code
public interface IServiceRepository
{
User GetUser(int id);
User GetUser(string email);
User GetUser(string email, byte[] password);
//SkipCode
}
What does it tell me? Well, from the generic name I couldn't understand what this interface does, it is like service of a service, abstraction over abstraction. But from the method definitions I see it does something with Users.
Why do you explicitly using IUnitOfWork? Is it not already implemented by the data provider you using?
Instead of all this architecture (of course if possible), just use ORM directly, this is easy to do and maintain, reliable and fast.
Your ServiceRepository seems to be closer to a domain service in a Service Layer than a repository of its own.
A domain service typically coordinates a sequence of interactions with various data repositories, for example loading a customer from a customer repository and a list of orders from an order repository to present a unified view of a customer and all their orders. As such domain services are used to create an operational boundary around an application - abstracting the various sequences of data access.
This is a fine approach, but I think the problem you have is that you have not taken it far enough. If you decide that the operations of the application should be encapsulated into a series of domain services, then there will be no need for a Controller to access repositories. If on the other hand you decide that the Controllers will take that reposibility, and access repositories themselves, then your ServiceRepository class, and others like it, basically become utility classes.
I see that you have two options - improve your service layer to such an extent that controllers no longer need repositories:
public class AccountController
{
public AccountController(IAccountsService service)
{
_service = service;
}
public void SomeActionMethod(Foo someParams)
{
_service.SomeAction(someParams);
}
}
or call the ServiceRepository what it is, a shortcut utility for doing a fixed sequence of data accesses...
public class AccountController
{
public AccountController(ICustomerRepository customerRepo, IOrderRepository orderRep)
{
_customerRepo = customerRepo;
_orderRepo = orderRepo;
}
public void SomeActionMethod(Foo someParams)
{
var utility = new CustomerOrderBuilderUtility(_customerRepo, _orderRepo);
var customerWithOrders = utility.GetCustomerAndOrders(someParams.CustomerId);
// some domain logic...
}
}

Categories