I have an attribute that I have written that has a dependency on the Data Access Layer so I made a constructor that took the DAL class as a parameter (marked with [DefaultConstructor] and another, blank, constructor that is parameterless. When I call a method that depends on the attribute how do I make StructureMap inject the correct type?
Thanks
Gareth
I have been working on the same problem, i'm using something like this:
ObjectFactory.Initialize(x =>
{
x.PullConfigurationFromAppConfig = true;
x.SetAllProperties(p => p.TypeMatches(t =>
t.GetCustomAttributes(typeof(InjectAttribute), true).Length > 0));
}
I am having some issues injecting onto webform pages but it works when creating instances using ObjectFactory...
Related
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
So I am working on API and using Ninject for DI & IoC. I know how the basic code works using Ninject but in the constructor of one of the classes an object of Logger is being sent. Rather than send it in constructor design item I would like to pass it in NinjectWebCommon.cs file.
public GAMonthlyAPIController() : this(new GAMonthlySQLReader(new NullLogger()))
This is the constructor.
kernel.Bind<IGAMonthlyReader>().To<GAMonthlySQLReader>();
This is the entry in NinjectWebCommon.cs I would like to bind it in NinjectWebCommon.cs rather than default value. How would I pass that? I don't even know what to search for, so I could find answers.
The most practical way to apply the dependency injection pattern is to use constructor injection. This means that the classes GaMonthlyAPIController depend on should be passed in through the constructor, rather than hard-coded inside of the controller.
public class GAMonthlyAPIController
{
private readonly IGAMonthlySQLReader gaMonthlySqlReader;
public GAMonthlyAPIController(IGAMonthlySQLReader gaMonthlySqlReader)
{
this.gaMonthlySqlReader = gaMontlySqlReader
?? throw new ArgumentNullException(nameof(gaMontlySqlReader));
}
// implementation of controller...
}
This should be the only constructor for your controller class. The controller itself doesn't know anything about GAMontlySqlReader or any of its dependencies.
The same goes for GAMonthlySQLReader - it will allow any ILogger implementation to be injected through the constructor.
The idea is that it puts the composition root of the application in charge of how the dependencies are composed together, meaning you can easily switch them around later without making any changes to the components that you are composing. So, Ninject would be used inside of your composition root to map types to their abstraction, and then will build object graphs of all of those dependencies composed together.
kernel.Bind<ILogger>().To<MyLoggerClass>();
kernel.Bind<IGAMonthlyReader>().To<GAMonthlySQLReader>();
For each of the application services, you would allow Ninject to instantiate them (so it can supply the dependencies) rather than using the new keyword inside of your application (new can be used for DTOs and Models, though).
I think you need to add Ninject.Web.WebApi using nuget to your Web Api project. Then use Ninject for creating ApiControllers:
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
And add the Bind() for GAMonthlyAPIController. No need to create a default constructor for your controller.
Have a look to this post:
http://nodogmablog.bryanhogan.net/2016/04/web-api-2-and-ninject-how-to-make-them-work-together/
I'm working with an existing Web Api that uses Simple Injector to register a single database connection. I need to make an endpoint to get info from a different db but I don't know how to register a new connection.
These are the existing registrations for the main db:
_container.Register<IDataBaseSqlServerDapper>(
() => new DataBaseSqlServerDapper(SqlServerDb.ConnectionString(),
LogManager.GetLogger("")));
_container.RegisterWebApiRequest<IDbConnectionFactory>(
() => new OrmLiteConnectionFactory(SqlServerDb.ConnectionString(),
new SqlServerOrmLiteDialectProvider()));
_container.RegisterWebApiRequest(
() => new PetaPoco.Database(Connection.SurveyEngine) {
IsolationLevel = IsolationLevel.Snapshot
});
So I read about RegisterCollection method and I tried the following:
_container.RegisterCollection<IDataBaseSqlServerDapper>(new[]
{
new DataBaseSqlServerDapper(SqlServerDb.ConnectionString(), LogManager.GetLogger("")),
new DataBaseSqlServerDapper(AdmbbDb.ConnectionString(), LogManager.GetLogger(""))
});
_container.RegisterCollection<IDbConnectionFactory>(new[]
{
new OrmLiteConnectionFactory(
SqlServerDb.ConnectionString(),
new SqlServerOrmLiteDialectProvider()),
new OrmLiteConnectionFactory(
AdmbbDb.ConnectionString(),
new SqlServerOrmLiteDialectProvider())
});
_container.RegisterCollection<PetaPoco.Database>(new[]
{
new PetaPoco.Database(Connection.SurveyEngine) {
IsolationLevel = IsolationLevel.Snapshot },
new PetaPoco.Database(Connection.Admbb) {
IsolationLevel = IsolationLevel.Snapshot }
});
SqlServerDb, AdmbbDd and Connection are classes that contains the names of the connection strings.
But I'm getting this error:
The configuration is invalid. Creating the instance for type IDapperQueryFactory failed. The constructor of type DapperQueryFactory contains the parameter with name 'dataBaseSqlServerDapper' and type IDataBaseSqlServerDapper that is not registered. Please ensure IDataBaseSqlServerDapper is registered, or change the constructor of DapperQueryFactory. There is, however, a registration for IEnumerable<IDataBaseSqlServerDapper>; Did you mean to depend on IEnumerable<IDataBaseSqlServerDapper>?
How can I solve this?
In the existing case you specify that type IDataBaseSqlServerDapper can be used for injection, which in turn gets properly injected into your object (in this case a class that implements IDapperQueryFactory).
In the second case you are registering multiple services of type IDataBaseSqlServerDapper. Meaning that your DI does not know how to resolve a single IDataBaseSqlServerDapper, only a collection of them.
This means that you'll either have to change the constructor to accept IEnumerable<IDataBaseSqlServerDapper> or register a non-collection IDataBaseSqlServerDapper
Simple Injector's documentation lists a good example how you can use both Register and Collection.Register side by side to get it working (source).
Now as for your problem, you state:
I need to make an endpoint to get info from a different db but I don't know how to register a new connection.
If you simply want to change where the data is going, can't you just replace the old existing handler?
If your goal is to load data from multiple datasources, you'll need to have some kind of logic that allows your code to determine which source it should use to store/load data.
The example from the simple injector documentation provides a good basis for something like this that does not require you to rewrite classes that use an injected IDataBaseSqlServerDapper.
My situation was similar to this, but a little bit simpler. I am posting my solution for anyone landing here with a problem like mine.
The Problem
I needed a way to use multiple instances of a single concrete-type (in my case NPoco.Database) initialized with different parameters (connection string names). Since the SimpleInjector doc examples use classes that implement ILogger and all have parameter-less constructors, I was finding it difficult to figure out how to make my scenario work.
The Solutuion
I finally came up with creating a simple sub-class of NPoco.Database for each database I needed to connect to, then using Container.RegisterConditional to register the instances. Since RegisterConditional does not have an overload that takes a constructor function, I had to give each of these sub-classes parameter-less constructors which called the base Database class with the proper connection string name. Lastly, some of the consumers were from an external NuGet package (internal to my organization) and relied on IDatabase being injected, not a derived type, so I could not just rely on registering derived types and letting SimpleInjector figure out based on that alone.
The Code
With all that said, here is my solution.
Sub-Classes of NPoco.Database
public class FirstSubDatabase : Database
{
public FirstSubDatabase()
: base("FirstSubConnection") { }
}
public class SecondSubDatabase : Database
{
public SecondSubDatabase()
: base("SecondSubConnection") { }
}
Registration
container.RegisterConditional<IDatabase, FirstSubDatabase>(
Lifestyle.Scoped,
c => c.Consumer.ImplementationType.FullName?.StartsWith(
"external.lib.", StringComparison.OrdinalIgnoreCase) ?? false);
container.RegisterConditional<IDatabase, SecondSubDatabase>(
Lifestyle.Scoped,
c => c.Consumer.ImplementationType == typeof(LocalConsumerClass));
Note: "external.lib." is just the namespace of everything from the external NuGet package. This saves future editors (including myself) of having to spend time figuring out why taking a dependency on another service from that package be instantiated.
I am using DRYIOC for DI in my application. I have interfaces in my MVC application which I want to register to dryIOC. So I am using RegisterMany as below.
container.RegisterMany(new[] { Assembly.Load(DIAssemblyCollection["WebAssembly"]) },
serviceTypeCondition: type => type.IsInterface,
setup: Setup.With(allowDisposableTransient: true));
But I am getting the error as below
Unspecified how to select single constructor for implementation type Web.Enums.Enum1 with 0 public constructors.
Seems like a bug, but need to look at code first.
Meanwhile you can just filter implementation types, keep classes only:
container.RegisterMany(
Assembly.Load(DIAssemblyCollection["WebAssembly"])
.GetLoadedTypes()
.Where(type => type.IsClass),
serviceTypeCondition: type => type.IsInterface,
setup: Setup.With(allowDisposableTransient: true));
Live example
Update
Fixed in DryIoc 2.7
I'm pretty much wanting to do what this guy describes (passing a dependency into a custom attribute):
How to use dependency injection with an attribute?
however, I want to do it with StructureMap 4.0, not Ninject.
My project is set up with the custom attribute in my Data Layer dll, and I already have StructureMap installed and working with my controllers in my UI Layer.
I have determined I probably have to do Setter injection with StructureMap:
http://docs.structuremap.net/ConstructorAndSetterInjection.htm
however, it is not working correctly for me with my custom attribute in the data layer.
I figured that in order to make things work that I should install Structuremap into my data layer as well, and put this in IoC.cs:
public static IContainer Initialize()
{
Container container = new Container(x =>
{
x.ForConcreteType<My_AuthorizeADAttribute>().Configure.Setter<My_AppDataContext>().IsTheDefault(); //not sure about this line
});
return container;
}
oh.. my custom Attribute:
public class My_AuthorizeADAttribute : AuthorizeAttribute
{
public IMy_Data_Context _dataContext;
[SetterProperty]
public IMy_Data_Context DataContext
{
get { return _dataContext; }
set { _dataContext = value; }
}
Is this the right thing to do? I'm thinking I left out a step. (but then again, I haven't really set up Structuremap on multiple dlls in the same project. Wondering if multiple projects with StructureMap needs something more.
At present, the app will run, but the Property in the Custom Attribute won't populate.
Update: This StackOverflow question has been helpful:
How do I get StructureMap working with an AngularJs / MVC5 and WebApi2 web project
It is indeed the line you are unsure of.
x.ForConcreteType<My_AuthorizeADAttribute>().Configure.Setter<My_AppDataContext>().IsTheDefault(); //not sure about this line
This should instead specify what you actually want to inject into the setter on instantiation, like so:
x.ForConcreteType<My_AuthorizeADAttribute>().Configure.SetterDependency<IMy_Data_Context>().Is(new My_AppDataContext());
This will inject your concrete implementation of IMy_Data_Context, My_AppDataContext, into the type My_AuthorizeADAttribute. If you had multiple properties of the IMy_Data_Context type on your attribute you may need to worry about how to assign multiple defaults using the default syntax you were working off of, but that doesn't appear to be your use case.
I responded to you in the StructureMap Gitter room, but I'll do it here too. Are you calling Container.BuildUp(object) against your attribute object after it's created? StructureMap isn't building the attribute objects at runtime, it can only apply setters afterward. See the bottom section of this: http://structuremap.github.io/setter-injection/ for more information on BuildUp().
ok, after much research, apparently this is the best option for me now. it means the Attribute has a dependency on StructureMap, but then again, [SetterProperty] would have it as well.
Asp.Net MVC Custom Validation Attribute With StructureMap