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.
Related
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 have a custom model validator:
public class MyvalidationAttribute : Attribute, IModelValidator {
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context) {
...
}
}
Let's say, for the purposes of validation I need to get some data from the controller. I am not an expert in Reflection voodoo, but I can get some data about controller:
var descriptor = context.ActionContext.ActionDescriptor as ControllerActionDescriptor;
or
var typeInfo = descriptor.ControllerTypeInfo;
but if I have a variable in the controller, say, repository of DbContext that was passed via DI (although I doubt if it is important) - how can I access that variable from the validator?
NOTE: I simplified the use case for MCVE purposes. I realize that this is a very brittle way to go and there are better way to do validation when all I need to do is to do remote validation. My use case is much different.
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 :)
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.
I would like to use a global-scoped action filter in my MVC 3 application using Ninject; however, I'm trying to understand the lifetime of that filter, its dependencies, and how to introduce variations to its dependencies by decorating my controllers and/or action methods.
I'd like to have my filter type depend on objects whose lifetimes are bound to request scope, so, something like this:
public sealed class MyGlobalActionFilter : IActionFilter
{
public MyGlobalActionFilter(IService1 svc1, IService2 svc2, RequestType reqType)
{
// code here
}
// IActionFilter implementation here...
}
... and in the module config ...
Bind<IService1>().To<ConcreteService1>().InRequestScope()
Bind<IService2>().To<ConcreteService2>().InRequestScope()
BindFilter<MyGlobalActionFilter>(FilterScope.Global, null)
.WhenControllerHas<RequestTypeAttribute>()
.WithConstructorArgumentFromControllerAttribute<RequestTypeAttribute>(
"reqType",
x => x.RequestType
);
BindFilter<MyGlobalActionFilter>(FilterScope.Global, null)
.WhenActionMethodHas<RequestTypeAttribute>()
.WithConstructorArgumentFromActionAttribute<RequestTypeAttribute>(
"reqType",
x => x.RequestType
);
BindFilter<MyGlobalActionFilter>(FilterScope.Global)
.When(x => true)
.WithConstructorArgument("reqType", RequestType.Undefined)
And an attribute on controllers and/or action methods to represent an application-specific "request type":
[RequestType(RequestType.Type1)]
public sealed class SomeController : Controller { /* code here*/ }
Am I understanding properly how this should work? Will a new instance of MyGlobalActionFilter get spun up and injected on each HTTP request? If this won't work, what am I missing, and what would be a better way to make this work?
Also, with injecting the RequestType, the BindFilter syntax here seems unnecessarily verbose, I'm not sure if it works like I expect, and it seems there would be a better way to inject a default RequestType into the action filter if a RequestTypeAttribute isn't present on the controller or the action method.
Please enlighten me!
I havn't seen an official documentation from Microsoft when and how often IFilterProvider is called exactly. But from my observations it seems to be called once for each request. This means that transient bound filters are basically InRequestScope bound with the difference that they aren't disposed by Ninject at the end of the request.
There are some changes you should do:
Do not derive from ActionFilterAttribute but implement IActionFilter
instead to prevent that it is accidentially used as attribute.
Rethink the use of FilterScope.Global for all bindings. I consider it
as bad practice to have filters on actions/controllers running with
global priority.
Also be aware that a filter for each matching binding is created and executed. This means that currently the one with RequestType.Undefined is run on every request independent of whether there is an attribute on the action or controller. Additionally, the ones for action and controllers are executed if there is a attribute on them.
if "System.Web.Mvc.GlobalFilters.Filters" is what you mean by "global-scoped action filter", then those filters are supposed to be instantiated once per application start/stop cycle and i doubt IoC container can be of any use here.
as i can see from your sample code you need some controller/action filters to modify beavior of global filters... what about creating base filter and derived filters with varying logic?
public abstract class BaseFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//user some service locator to retrieve IService1, IService2
//some logic based on RequestType
}
protected RequestType { get; set; }
}
public class SomeFilter : BaseFilter
{
public SomeFilter(RequestType requestType)
{
RequestType = requestType;
}
}