Using FluentValidation in .NET Core with Dependency Injection - c#

I have a .NET Core Web Api Application which is arranged in the following manner -
Controller layer which injects Business Service
Business Service which injects Unit Of Work (to interact with database)
Business Service might also make a call to a FluentValidation class
FluentValidation will inject the Unit Of Work to perform database checks (Exists, etc.)
So having said all of that here is an example. If I want to create a User in the system I have a route/method called "PostUser" located inside of the "UsersController". The "UsersController" injects the "UserService". The "UserService" has a method called "CreateUser". So inside of the "PostUser" method of the controller it looks like this -
var user = _userService.CreateUser(user);
Now inside of the "CreateUser" method it looks like this -
UserValidation validation = new UserValidation(UnitOfWork, DatabaseOperation.Create);
ValidationResult validationResult = await validation.ValidateAsync(user);
So the UnitOfWork is passed into the UserService via dependency injection and then passed along to the FluentValidation class "UserValidation" so the validation class can perform database checks. I also pass an enum into the UserValidation class to specify whether or not the validation is intended for an Update or a Create.
The User object I am trying to validate will have properties such as "Role" and "Company" and I also have separate validation classes for each (RoleValidation and CompanyValidation). Both of these validation classes will also pass in a UnitOfWork and whether or not this is a create or an update.
Here is an example of my UserValidation Class -
public class UserValidation : AbstractValidator<UserDTO>
{
private IUnitOfWork _unitOfWork;
public UserValidation(IUnitOfWork unitOfWork, DatabaseOperation databaseOperation)
{
_unitOfWork = unitOfWork;
if (databaseOperation == DatabaseOperation.Create)
{
// Do Create specific validation
}
RuleFor(x => x.Company)
.SetValidator(new CompanyValidator(_unitOfWork, databaseOperation));
}
}
Now understanding all of this I wanted to create Unit Tests for my "UserService" class. But I believe in order to properly do this I would need to Mock out the FluentValidation class in some cases and as you can see in my "UserService" CreateUser method I instantiate the concrete class for my Validation. So in order to do this I would have to create an interface for each of my fluentvalidation classes and inject them into the business services that use them. So I did the following in my Startup.cs file -
services.AddScoped<IValidator<User>>(x => new UserValidation(x.GetRequiredService<IUnitOfWork>()));
So now after doing that I can inject the IValidator into my UserService Constructor and use that instead of instatiating a Concrete class inside of my UserService methods.
So with this brings me to ask the following questions.
In your opinion, the way I already have my project structured, is this the best way to use dependency injection with FluentValidation and allow for unit testing of the service method along with unit testing of the FluentValidation class?
Is there a better way using dependency injection with FluentValidation to do all of this, and at the same time let the FluentValidation class know if it is a "Create" or an "Update", instead of creating one class called "UserCreateValidation" and "UserUpdateValidation" or passing in a variable "DatabaseOperation" to the constructor of the Validator?
Appending to (2) when trying to setup the FluentValidation DependencyInjection I am having trouble passing in the "DatabaseOperation" variableservices.AddScoped<IValidator<User>>(x => new UserValidation(x.GetRequiredService<IUnitOfWork>(), <How to figure out if its a create or an update>));
On Top of that I will have to also add two lines to the "Startup.cs" file to create the Scoped DependencyInjection of the "CompanyValidation" and the "RoleValidation" to be used inside of the "UserValidation" and both of those validation classes will also pass in whether or not it is an update or a create.
Any help/suggestions would be appreciated. I am really stuck on this issue. If anyone needs anymore clarification on the issues I am facing please do not hesitate to ask.
Thank You

I am facing a similar issue. However you helped me out.
What I did differently/Would do differently. instead of Create or Update, you can use RuleSets, depending on the name it will execute different RuleSets, this will allow you to identify the operation when you are validating it: https://fluentvalidation.net/start#rulesets. You should not be injecting anything that is dependen on the runtime result at this point such indication if it is create or update.
Answering your questions:
Question 1. I think I pointed one mistake above. Otherwise looks fine to me. It is not needed to create a wrapper to unit test your validation, you can simple do this like in this example:
[Test]
public void Should_have_error_when_val_is_zero()
{
validator = new TestModelValidator();
TestModel testRequest = new TestModel();
//populate with dummy data
var result = validator.Validate(testRequest);
Assert.That(result.Errors.Any(o => o.PropertyName== "ParentVal"));
}
Question 2: I would inject just a single scopedFactory to the validator and let it resolve its depedencies himself, instead of injecting everything that it needs. However what are you doing inside new CompanyValidator(_unitOfWork, databaseOperation) ? It seems strange to me to inject anything in Validator since it is not really something you would inject that resolves the rule. I am not sure what is your case for that, but otherwise I would have, as I said, scopedFactory injected or a Nested class to do that.
Question 3: I think I answered that one already.
Question 4: I would try to create a generic dependency injection, or inject an Array of Validators into somekind of factory which would resolve based on type.
services.AddScoped(typeof(IValidationFactory<>), typeof(ValidationFactory<>));
Which would resolve which validator I need based on type.
Hope this makes sense.
UPDATE
So inside the CreateMethod pass the RuleSet name to the validate method for him to solve if it is a Create or Update. About scoped factory https://csharp.hotexamples.com/examples/-/IServiceScopeFactory/-/php-iservicescopefactory-class-examples.html
For example:
Instead of this:
ValidationResult validationResult = await validation.ValidateAsync(user);
You can do this:
validator.Validate(person, ruleSet: "Create");
As well you can resolve dependencies and inject necessary validator like this for example (I am resolving by request type you can use a string key if needed):
services.AddSingleton<IValidator, Validator1>();
services.AddSingleton<IValidator, Validator2>();
services.AddSingleton<IValidator, Validator3>();
services.AddScoped<Func<Type, IValidator>>(serviceProvider => typeKey =>
{
if (typeKey == typeof(Validator1))
{
return serviceProvider.GetService<Validator1>();
}
if (typeKey == typeof(Validator2))
{
return serviceProvider.GetService<Validator2>();
}
if (typeKey == typeof(Validator3))
{
return serviceProvider.GetService<Validator3>();
}
return null;
});
And this is usage example:
public GenericValidator(Func<Type, IValidator> validatorFactory)
{
_validatorFactory = validatorFactory ?? throw new ArgumentNullException(nameof(validatorFactory));
}
public async Task<IEnumerable<string>> ValidateAsync<T, TK>(TK objectToValidate) where TK : class
{
var validator = _validatorFactory(typeof(T));
if (validator == null)
{
throw new ValidationException($"Failed to get validator for type: {typeof(T)}");
}
var validationResult = await validator.ValidateAsync(objectToValidate);
return validationResult.Errors.Select(x => x.ErrorMessage);
}
And inject: IServiceScopeFactory serviceScopeFactory to your validator which will help resolve any external dependencies. You can find examples here: https://csharp.hotexamples.com/examples/-/IServiceScopeFactory/-/php-iservicescopefactory-class-examples.html

Related

How do I get info on the requesting service when using Autofac?

I was wondering whether Autofac allows me to grab information about the requesting context so I can modify my resulting service for the respective binding based on it.
For example something like this:
builder.Register(ctx =>
{
var name = ctx.Request.Name; // How do I do something like this?
return new MyService(name);
})
.As<IMyService>()
.SingleInstance();
public class MyClass
{
public MyClass(IMyService myService)
{
...
}
}
In this context, I would like to infer information about the calling context into a specific service (For e.g. logging purposes), but I didn't find any information on how Autofac would allow me to do such a thing. Basically, I would like to get a hold of the MyClass type in this case, but since I don't know upfront who might use the IMyService binding, I can't hardcode it.
Apparently Autofac does allow conditional binding, but the requesting side always has to provide metadata, so the flow is kind of turned the other way round.
I've used other IoC containers like Ninject before, and for Ninject it was simply included in one of the parameters of the lambda registration.
Is this possible?

How do I access DI registered instance from within POCO?

This is in a .NET Core project. In the Startup I register a singleton for my translation service that gets initialized with configuration settings from appsettings.json. Once it's set the whole app will use that service. This works great in my controllers and repositories, I just define the constructor to take that interface and it injects as expected:
services.AddSingleton<Foo.Bar.ITranslationService>(
new Foo.Bar.SomeTranslator(config.TranslationSettings));
But the issue I ran into is one where a POCO needed to use that translation service. And my POCOs all get generated as generics by the repository, so for example a repository method might look like this:
public TEntity GetById(object id){
return connection.Get<TEntity>(id);
}
So the repository has the injected TranslationService passed into it, but is there a way to cleanly pass that along to the POCO that needs it using DI? Or do I need to hack it somehow? I'm trying to figure out the cleanest way to do this, thanks!
How about property injection?
public TEntity GetById(object id){
var entity = connection.Get<TEntity>(id);
if (entity is ITranslatable t)
{
t.Translator = _translationService;
}
return entity;
}
You basically need to add the translation interface to the constructor of that object.
public class MYPOCO
{
private Foo.Bar.ITranslationService translator
public MYPOCO(Foo.Bar.ITranslationService translator)
{
this.translator = translator;
}
}
This then allow you to use the translator service in the class. But your going to run into a number of issues there.
Unless the framework explicitly creates your POCO then it will not
get injected. For example it would need to be a Controller of some
sort that would be created by the framework as soon as a route is
called.
You may need your own factories to create instances of the POCO.
To keep the POCO as clean as possible, you probably want a Factory, which would create an instance of your POCO and set the translations appropriately. The Factory would take an instance of the translator service.

Mocking out a specific method during a unit test

I'm relatively new to unit testing, and brand new to Moq. I have been tasked with writing up some unit tests for some pre-existing code.
I am struggling with the following method, as it makes a call to model.importing.RunJob, which as the name suggests, kicks off a job.
Obviously, I don't want it to actually DO the job, I just want to know that it's called the method.
How would I go about achieving this (ideally avoiding any code changes):
public ActionResult ImportsAndLoads(ImportsAndLoadsViewModel importsAndLoadsModel)
{
Initialise(importsAndLoadsModel);
LoadData(importsAndLoadsModel);
if (importsAndLoadsModel.ActionToPerform == "RunJob")
{
using (var model = new Model())
{
List<Message> lstMessage;
model.importing.RunJob((Jobs)Enum.ToObject(typeof(Jobs), importsAndLoadsModel.SelectedJob), out lstMessage);
importsAndLoadsModel.lstMessages = lstMessage;
}
}
return View(importsAndLoadsModel);
}
As has been discussed in the comments on your question, you can't really test your ImportsAndLoads method in isolation in its current form, using Moq. If you are using a high enough version of Visual Studio, then you may be able to test the method using Shims, however if you're not already using this in your project, it's probably not the right way to go.
As it stands, your code is a little confusing. It's a bit weird having a class called Model, that you're creating, in order to access a property in order to call a RunJob method. If this really is the code, then you might want to encourage the team to revisit the Model class.
One of the suggestions was that you inject your Model dependency instead of creating it (or inject a factory and call out to the factory for creation). This would be the preferable way to go, however it's not a trivial change in approach and really your team needs to buy into it as an approach rather than you making the change as a one-off.
If you aren't using an IOC container already (AutoFac, CastleWindsor, Ninject), then you may want to consider using one. They will make switching to dependency injection easier. If you want to do it by hand, then you can do, but it's harder.
Without knowing about the structure of more of your classes, it's hard to give a complete example, but one approach might be the following:
// Create an importer interface
public interface IImporter {
void RunJob(Jobs job, out List<Message> listMessages);
}
// Implement it in a concrete class
public class Importer : IImporter{
public void RunJob(Jobs job, out List<Message> listMessages) {
// Do whatever it is it does.
}
}
// Modify the constructor of your controller to allow the IImporter
// interface to be injected. Default to null if not supplied, so that
// it can still be crated without parameters by the default MVC plumbing
public class ImportController : Controller
{
private IImporter _importer;
public ImportController(IImporter importer = null) {
// If importer not injected, created a concrete instance
if (null == importer) {
importer = new Importer();
}
// Save dependency for use in actions
_importer = importer;
}
// Use the injected importer in your action, rather than creating a model
public ActionResult ImportsAndLoads(ImportsAndLoadsViewModel importsAndLoadsViewModel)
{
List<Message> listMsgs;
_importer.RunJob(Jobs.One, out listMsgs);
importsAndLoadsViewModel.lstMessages = listMsgs;
return View(importsAndLoadsViewModel);
}
}
This would then allow you to write a test to validate that importsAndLoadsViewModel has been updated as expected, using a test like this:
[Test]
public void TestModelMessagesAreUpdatedFromJobRunner() {
var mockImporter = new Mock<IImporter>();
List<Message> expectedMessages = new List<Message>();
mockImporter.Setup(x=>x.RunJob(It.IsAny<Jobs>(), out expectedMessages));
var model = new ImportsAndLoadsViewModel();
// Inject the mocked importer while constructing your controller
var sut = new ImportController(mockImporter.Object);
// call the action you're testing on your controller
ViewResult response = (ViewResult)sut.ImportsAndLoads(model);
// Validate the the model has been updated to have the messages
// returned by the mocked importer.
Assert.AreEqual(expectedMessages,
((ImportsAndLoadsViewModel)response.Model).lstMessages);
}
This is simplification of what would need to be done / tested to demonstrate an approach. One of the issues to be aware of with injecting dependencies is that it's quite easy to end up creating abstractions of abstractions, pushing the actual logic deeper and deeper into your code, only to find that you've just pushed the problem deeper and that you still don't know how to test a particular piece of logic because in essence it hasn't changed.

Dependency Injection With Unity Using Constructors With Runtime Parameters

I have the basics down of dependency injection but where I'm struggling is trying to put it together properly in an MVC API C# application using Unity. The issue I have is that I will have a controller that has a method, and in that method it will have say two objects. One of these objects will have a dependency on a data access layer and the other doesn't. I'm not quite sure on exactly how to set this up.
Lets say I have a controller with the following method that gets users from a search object. It also uses a SearchParameters object to perform the search. If you search with no name you get all results, or if you put a name you get any users with that name.
public Users[] GetUsers(string name) {
Company.SearchParameters searchParams = new Company.SearchParameters(name);
Company.UserSearchService searchService = new Company.UserSearchService(searchParams);
return searchService.Search();
}
This is of course a super simplified version but in this case UserSearchService in the Search method is doing an explicit database call. So I know that is a dependency I'd have to give it. SearchParameters really is just a class that holds data.
Here is where I'm not sure on exactly what to do next. The Controller itself doesn't have a dependency but since UserSearchService does I'm not sure how using unity I properly set that up and take into account runtime values for the constructor. I'm also not sure if SearchParameters is supposed to be considered a dependency or not.
Additionally SearchParameters and UserSearchService do not have any sort of backing interface if that matters and there are other methods on this controller that interact with other classes that have a similar need of a data access layer dependency such as perhaps Company.UserAccount.
The search parameters shouldn't be part of constructor; it should be part of the "Search" method. The SearchParameter object should not even be known outside of the UserSearchService class (Encapsulation). There should be some refactoring as neleus suggested. At the very least, to get things going, it should be refactored to something similar this:
public Users[] GetUsers(string name) {
// Or however you end up with your UserSearchService object.
// Ideally as an interface and an injected dependency...
Company.UserSearchService searchService = new Company.UserSearchService();
return searchService.Search(name);
}
Company.UserSearchService:
public Users[] Search(string name) {
// A factory would be a better option. This should also be an interface.
Company.SearchParameters searchParams = new Company.SearchParameters(name);
// Your logic here
}
I see here two tasks. The first is a refactoring where static dependencies have to be replaced with interfaces. The second task is to register your stuff in IoC container.
For the first task a minimum you need is to replace all references to Database in your UserSearchService with IDatabase interface (so that it can also be mocked) and allow it to be passed to constructor (constructor injection). To be able to provide an instance of IDatabase to the service you have to create the same dependency for the controller (again constructor injection). Then register the IDatabase implementation as shown in this post.
Update
I agree that dependency has to be removed from the controller. As you #Topojijo have suggested a factory for the UserSearchService can be used in this case. Guessing you have several cervices you need to make a factory for each and there may be an overhead if their count is large. In such case it's better to resolve the service directly from Unity container and move the searchParams to Search method:
public Users[] GetUsers(string name) {
Company.SearchParameters searchParams = new Company.SearchParameters(name);
Company.UserSearchService searchService = container.Resolve<Company.UserSearchService>();
return searchService.Search(searchParams);
}

C# WebApi Unit Testing and Mocking Controllers

I am working on this WebAPI project and I need to create unit tests for it. The base of the project was created using VS 2010 , and then an WebApi Module was added.
The workings of the controller are kinda getting in the way of testing/mocking. I am using xUnit and Moq , but there is absolutely no need to stick with those two.
The application uses specific objects to deal with database access, so I have the
controllerObject and its contructor requires the DataAccessObject
I am having problem with mocking the controller / dataaccess pair. The first test i´m trying to run is a GetAllFromDataBase, but i dont really have a clue on how to do it.
EDIT:
I did what Cuong Le told me and the whole is moving now, i really apreciate it. But i stumped into another problem. To access the API, there is a username/password pair and my controller uses Thread.CurrentPrincipal.Identity.Name; right now i would need to set this value for it to fully work I guess.
Also the valueServiceMock.Setup(service => service.GetValues())
.Returns(new[] { "value1", "value2" });
does not seem to be working. as the code tries to reach for the database, and gets nothing since it cant get a valid username to look for
In order to get your app testable, you need to design for testability in mind.Technically, to design to testability, your app should be loose coupling as much as possible between layers, between components and even between classes.
A lot of hints to design for testability: avoid sealed, static class... But the most popular thing you need to be aware of is dependency injection pattern, instead of creating object inside contructors or methods of other objects, this object should be injected. With this way we make loose dependency between class and easy for us to fake by mocking framework. Esp, for the objects which depend on external resource: network, file or database.
How to inject object by using dependency injection: that's why IocContainer is the right tool for this, it will inject objects for you automatically. IoC Container which I prefer to use is: Autofac and NInject.
Example in here to inject ValueService into ValuesController:
public class ValuesController : ApiController
{
private readonly IValueService _valueService;
public ValuesController(IValueService valueService)
{
_valueService = valueService;
}
public string[] Get()
{
return _valueService.GetValues();
}
public string Get(int id)
{
return _valueService.GetValue(id);
}
}
And below is the simple code to unit test with Moq:
var valueServiceMock = new Mock<IValueService>();
valueServiceMock.Setup(service => service.GetValues())
.Returns(new[] { "value1", "value2" });
var controller = new ValuesController(valueServiceMock.Object);
var values = controller.Get();
Assert.AreEqual(values.Length, 2);
Assert.AreEqual(values[0], "value1");
Assert.AreEqual(values[1], "value2");

Categories

Resources