Generics and Property binding in Ninject - c#

I'm looking for a good way to incorporate settings inside my webapp (asp mvc). I've came across a really nice implementation in NopCommerce. NopCommerce stores the values in a database table, with a name and value. The name is derived from the class and property name (e.g. customersettings.settingname1)
The exact way NopCommerce works with settings can be found in this question: Understanding how Nop Commerce settings are loaded from the database
NopCommerce uses Autofac as DI framework to bind the Settings to the ConfigurationProvider as follows (as I'm correct).
return RegistrationBuilder
.ForDelegate((c, p) => c.Resolve<IConfigurationProvider<TSettings>>().Settings)
.InstancePerHttpRequest()
.CreateRegistration();
In the appropriate classes, you can now use ClientSettings as a parameter, and it's automatically filled with data from the database.
I really like this implementation, because it is very flexible. The problem however is that I'm using Ninject. I've tried several things to get the correct bindings, but can't seem to find the correct implementation. Does anyone have an idea how to get this working?
EDIT:
I found a way to bind ClientSettings directly:
kernel.Bind<ClientSettings>()
.ToMethod(ctx => ctx.Kernel.Get<IConfigurationProvider<ClientSettings>>().Settings)
.InRequestScope();
But is there a way to achieve this?
kernel.Bind<ISettings>()
.ToMethod(ctx => ctx.Kernel.Get<IConfigurationProvider<ISettings>>().Settings)
.InRequestScope();
EDIT 2
I think I'm getting close, but still run into some problems. I create a custom Binding Generator:
public class SettingsBindGenerator : IBindingGenerator
{
static readonly MethodInfo BuildMethod = typeof(SettingsBindGenerator).GetMethod(
"BuildRegistration",
BindingFlags.Static | BindingFlags.NonPublic);
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
var obj = typeof (object).IsAssignableFrom(type);
if (type != null && typeof(ISettings).IsAssignableFrom(type))
{
var buildMethod = BuildMethod.MakeGenericMethod(type);
var methodResult = buildMethod.Invoke(null, new object[]{bindingRoot});
var castedResult = methodResult as IBindingWhenInNamedWithOrOnSyntax<object>;
yield return castedResult;
}
}
static IBindingWhenInNamedWithOrOnSyntax<TSettings> BuildRegistration<TSettings>(IBindingRoot bindingRoot) where TSettings : ISettings, new()
{
return bindingRoot.Bind<TSettings>().ToMethod(
ctx => ctx.Kernel.Get<IConfigurationProvider<TSettings>>().Settings);
}
}
This works for 99%. However, for some reason, buildMethod.Invoke returns an BindingConfigurationBuilder, and not an IBindingWhenInNamedWithOrOnSyntax. Therefor, castedResult is always NULL. Anybody got an idea how to correct this?
LAST EDIT
I don't know why, but suddenly it works! Glad I've finally figured it out. Thanx Remo!

You have several options:
Do it like NopCommerce and scan for the settings classes and call the registration method from your first edit using reflection.
Use the conventions extension to register all classes implementing ISettings using a custom binding generator https://github.com/ninject/ninject.extensions.conventions/wiki/Projecting-Services-to-Bind
Use the conventions extension to register all classes implementing ISettings to bind all interfaces. And add a custom IActivationStrategy to Ninject that does assigns the properties like NopCommerce does.

Related

Using FluentValidation in .NET Core with Dependency Injection

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

Use ExpandoObject to create a 'fake' implementation of an interface - adding methods dynamically

A brainteaser for you!
I am developing a modular system, in such a way that module A could need module B and module B could also need module A. But if module B is disabled, it will simply not execute that code and do nothing / return null.
A little bit more into perspective:
Let's say InvoiceBusinessLogic is within module "Core". We also have a "Ecommerce" module which has a OrderBusinessLogic. The InvoiceBusinessLogic could then look like this:
public class InvoiceBusinessLogic : IInvoiceBusinessLogic
{
private readonly IOrderBusinessLogic _orderBusinessLogic;
public InvoiceBusinessLogic(IOrderBusinessLogic orderBusinessLogic)
{
_orderBusinessLogic = orderBusinessLogic;
}
public void UpdateInvoicePaymentStatus(InvoiceModel invoice)
{
_orderBusinessLogic.UpdateOrderStatus(invoice.OrderId);
}
}
So what I want is: When the module "Ecommerce" is enabled, it would actually do something at the OrderBusinessLogic. When not, it would simply not do anything. In this example it returns nothing so it can simply do nothing, in other examples where something would be returned, it would return null.
Notes:
As you can probably tell, I am using Dependency Injection, it is a ASP.NET Core application so the IServiceCollection takes care of defining the implementations.
Simply not defining the implementation for IOrderBusinessLogic will cause a runtime issue, logically.
From a lot of research done, I do not want to make calls to the container within my domain / logic of the app. Don't call the DI Container, it'll call you
These kind of interactions between modules are kept to a minimum, preferably done within the controller, but sometimes you cannot get around it (and also in the controller I would then need a way to inject them and use them or not).
So there are 3 options that I figured out so far:
I never make calls from module "Core" to module "Ecommerce", in theory this sounds the best way, but in practice it's more complicated for advanced scenarios. Not an option
I could create a lot of fake implementations, depending on the configuration decide on which one to implement. But that would of course result in double code and I would constantly have to update the fake class when a new method is introduced. So not perfectly.
I can build up a fake implementation by using reflection and ExpandoObject, and just do nothing or return null when the particular method is called.
And the last option is what I am now after:
private static void SetupEcommerceLogic(IServiceCollection services, bool enabled)
{
if (enabled)
{
services.AddTransient<IOrderBusinessLogic, OrderBusinessLogic>();
return;
}
dynamic expendo = new ExpandoObject();
IOrderBusinessLogic fakeBusinessLogic = Impromptu.ActLike(expendo);
services.AddTransient<IOrderBusinessLogic>(x => fakeBusinessLogic);
}
By using Impromptu Interface, I am able to successfully create a fake implementation. But what I now need to solve is that the dynamic object also contains all the methods (mostly properties not needed), but those ones are easy to add. So currently I am able to run the code and get up until the point it will call the OrderBusinessLogic, then it will, logically, throw an exception that the method does not exist.
By using reflection, I can iterate over all the methods within the interface, but how do I add them to the dynamic object?
dynamic expendo = new ExpandoObject();
var dictionary = (IDictionary<string, object>)expendo;
var methods = typeof(IOrderBusinessLogic).GetMethods(BindingFlags.Public);
foreach (MethodInfo method in methods)
{
var parameters = method.GetParameters();
//insert magic here
}
Note: For now directly calling typeof(IOrderBusinessLogic), but later I would iterate over all the interfaces within a certain assembly.
Impromptu has an example as follows:
expando.Meth1 = Return<bool>.Arguments<int>(it => it > 5);
But of course I want this to be dynamic so how do I dynamically insert the return type and the parameters.
I do understand that a interface acts like a contract, and that contract should be followed, I also understand that this is an anti-pattern, but extensive research and negotiations have been done prior to reaching this point, for the result system we want, we think this is the best option, just a little missing piece :).
I have looked at this question, I am not really planning on leaving .dll's out, because most likely I would not be able to have any form of IOrderBusinessLogic usable within InvoiceBusinessLogic.
I have looked at this question, but I did not really understand how TypeBuilder could be used in my scenario
I have also looked into Mocking the interfaces, but mostly you would then need to define the 'mocking implementation' for each method that you want to change, correct me if I am wrong.
Even tough the third approach (with ExpandoObject) looks like a holy grail, I foster you to not follow this path for the following reasons:
What guarantees you that this fancy logic will be error-free now and at every time in the future ? (think: in 1 year you add a property in IOrderBusinessLogic)
What are the consequences if not ? Maybe an unexpected message will pop to the user or cause some strange "a priori unrelated" behavior
I would definitely go down the second option (fake implementation, also called Null-Object) even though, yes it will require to write some boilerplate code but ey this would offer you a compile-time guarantee that nothing unexpected will happen at rutime !
So my advice would be to do something like this:
private static void SetupEcommerceLogic(IServiceCollection services, bool enabled)
{
if (enabled)
{
services.AddTransient<IOrderBusinessLogic, OrderBusinessLogic>();
}
else
{
services.AddTransient<IOrderBusinessLogic, EmptyOrderBusinessLogic>();
}
}
For as long as there is no other answer for the solution I am looking for, I came up with the following extension:
using ImpromptuInterface.Build;
public static TInterface IsModuleEnabled<TInterface>(this TInterface obj) where TInterface : class
{
if (obj is ActLikeProxy)
{
return default(TInterface);//returns null
}
return obj;
}
And then use it like:
public void UpdateInvoicePaymentStatus(InvoiceModel invoice)
{
_orderBusinessLogic.IsModuleEnabled()?.UpdateOrderStatus(invoice.OrderId);
//just example stuff
int? orderId = _orderBusinessLogic.IsModuleEnabled()?.GetOrderIdForInvoiceId(invoice.InvoiceId);
}
And actually it has the advantage that it is clear (in the code) that the return type can be null or the method won't be called when the module is disabled. The only thing that should be documented carefully, or in another way enforced, that is has to be clear which classes do not belong to the current module. The only thing I could think of right now is by not including the using automatically, but use the full namespace or add summaries to the included _orderBusinessLogic, so when someone is using it, it is clear this belongs to another module, and a null check should be performed.
For those that are interested, here is the code to correctly add all fake implementations:
private static void SetupEcommerceLogic(IServiceCollection services, bool enabled)
{
if (enabled)
{
services.AddTransient<IOrderBusinessLogic, OrderBusinessLogic>();
return;
}
//just pick one interface in the correct assembly.
var types = Assembly.GetAssembly(typeof(IOrderBusinessLogic)).GetExportedTypes();
AddFakeImplementations(services, types);
}
using ImpromptuInterface;
private static void AddFakeImplementations(IServiceCollection services, Type[] types)
{
//filtering on public interfaces and my folder structure / naming convention
types = types.Where(x =>
x.IsInterface && x.IsPublic &&
(x.Namespace.Contains("BusinessLogic") || x.Namespace.Contains("Repositories"))).ToArray();
foreach (Type type in types)
{
dynamic expendo = new ExpandoObject();
var fakeImplementation = Impromptu.DynamicActLike(expendo, type);
services.AddTransient(type, x => fakeImplementation);
}
}

SimpleI Injector - Register multiple database connections

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.

How to inject a dependency into a custom attribute with StructureMap (4.0)? MVC5 project

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

Entities used by ORM in combination with CodeContracts - ensure invariants

I am currently in the process of adding CodeContracts to my existing code base.
One thing that proves difficult is the usage of entities that are hydrated by NHibernate.
Assume this simple class:
public class Post
{
private Blog _blog;
[Obsolete("Required by NHibernate")]
protected Post() { }
public Post(Blog blog)
{
Contract.Requires(blog != null);
_blog = blog;
}
public Blog Blog
{
get
{
Contract.Ensures(Contract.Result<Blog>() != null);
return _blog;
}
set
{
Contract.Requires(value != null);
_blog = value;
}
}
[ContractInvariantMethod]
private void Invariants()
{
Contract.Invariant(_blog != null);
}
}
This class tries to protect the invariant _blog != null. However, it currently fails, because I easily could create an instance of Post by deriving from it and using the protected constructor. In that case _blog would be null.
I am trying to change my code-base in a way that the invariants are indeed protected.
The protected constructor is at first sight needed by NHibernate to be able to create new instances, but there is a way around this requirement.
That approach basically uses FormatterServices.GetUninitializedObject. The important point is, that this method doesn't run any constructors.
I could use this approach and it would allow me to get rid of the protected constructor. The static checker of CodeContracts would now be happy and not report any more violations, but as soon as NHibernate tries to hydrate such entities it will generate "invariant failed" exceptions, because it tries to set one property after the other and every property setter executes code that verifies the invariants.
So, to make all this work, I will have to ensure that the entities are instantiated via their public constructor.
But how would I do this?
Daniel, if I'm not mistaken (it's been a while since I worked with NH) you can have a private constructor and he still should be fine creating your object.
Aside from that, why do you need to be a 100% sure? Is it a requirement in some way or you are just trying to covering all the bases?
I ask that because depending on the requirement we could come with another way of achieving it.
What you COULD do right now to provide that extra protection is wire up an IInterceptor class to make sure that after the load your class is still valid.
I guess that the bottom line is if someone want's to mess up with your domain and classes they WILL do it no matter what you do. The effort to prevent all that stuff doesn't pay off in most cases.
Edit after clarification
If you use your objects to write to the database and you contracts are working you can safely assume that the data will be written correctly and therefore loaded correctly if no one tampers with the database.
If you do change the database manually you should either stop doing it and use your domain to do that (that's where the validation logic is) or test the database changing process.
Still, if you really need that you can still hook up a IInterceptor that will validate your entity after the load, but I don't think you fix a water flooding coming from the street by making sure your house pipe is fine.
Based on the discussion with tucaz, I came up with the following, in its core rather simple solution:
The heart of this solution is the class NHibernateActivator. It has two important purposes:
Create an instance of an object without invoking its constructors. It uses FormatterServices.GetUninitializedObject for this.
Prevent the triggering of "invariant failed" exceptions while NHibernate hydrates the instance. This is a two-step task: Disable invariant checking before NHibernate starts hydrating and re-enable invariant checking after NHibernate is done.
The first part can be performed directly after the instance has been created.
The second part is using the interface IPostLoadEventListener.
The class itself is pretty simple:
public class NHibernateActivator : INHibernateActivator, IPostLoadEventListener
{
public bool CanInstantiate(Type type)
{
return !type.IsAbstract && !type.IsInterface &&
!type.IsGenericTypeDefinition && !type.IsSealed;
}
public object Instantiate(Type type)
{
var instance = FormatterServices.GetUninitializedObject(type);
instance.DisableInvariantEvaluation();
return instance;
}
public void OnPostLoad(PostLoadEvent #event)
{
if (#event != null && #event.Entity != null)
#event.Entity.EnableInvariantEvaluation(true);
}
}
DisableInvariantEvaluation and EnableInvariantEvaluation are currently extension methods that use reflection to set a protected field. This field prevents invariants from being checked. Furthermore EnableInvariantEvaluation will execute the method that checks the invariants if it gets passed true:
public static class CodeContractsExtensions
{
public static void DisableInvariantEvaluation(this object entity)
{
var evaluatingInvariantField = entity.GetType()
.GetField(
"$evaluatingInvariant$",
BindingFlags.NonPublic |
BindingFlags.Instance);
if (evaluatingInvariantField == null)
return;
evaluatingInvariantField.SetValue(entity, true);
}
public static void EnableInvariantEvaluation(this object entity,
bool evaluateNow)
{
var evaluatingInvariantField = entity.GetType()
.GetField(
"$evaluatingInvariant$",
BindingFlags.NonPublic |
BindingFlags.Instance);
if (evaluatingInvariantField == null)
return;
evaluatingInvariantField.SetValue(entity, false);
if (!evaluateNow)
return;
var invariantMethod = entity.GetType()
.GetMethod("$InvariantMethod$",
BindingFlags.NonPublic |
BindingFlags.Instance);
if (invariantMethod == null)
return;
invariantMethod.Invoke(entity, new object[0]);
}
}
The rest is NHibernate plumbing:
We need to implement an interceptor that uses our activator.
We need to implement an reflection optimizer that returns our implementation of IInstantiationOptimizer. This implementation in turn again uses our activator.
We need to implement a proxy factory that uses our activator.
We need to implement IProxyFactoryFactory to return our custom proxy factory.
We need to create a custom proxy validator that doesn't care whether the type has a default constructor.
We need to implement a bytecode provider that returns our reflection optimizer and proxy-factory factory.
NHibernateActivator needs to be registered as a listener using config.AppendListeners(ListenerType.PostLoad, ...); in ExposeConfiguration of Fluent NHibernate.
Our custom bytecode provider needs to be registered using Environment.BytecodeProvider.
Our custom interceptor needs to be registered using config.Interceptor = ...;.
I will update this answer when I had the chance to create a coherent package out of all this and put it on github.
Furthermore, I want to get rid of the reflection and create a proxy type instead that can directly access the protected CodeContract members.
For reference, the following blog posts where helpful in implementing the several NHibernate interfaces:
http://weblogs.asp.net/ricardoperes/archive/2012/06/19/implementing-an-interceptor-using-nhibernate-s-built-in-dynamic-proxy-generator.aspx
http://kozmic.net/2011/03/20/working-with-nhibernate-without-default-constructors/
Unfortunately, this currently fails for entities with composite keys, because the reflection optimizer is not used for them. This is actually a bug in NHibernate and I reported it here.

Categories

Resources