In a ASP.Net MVC 4 application that I am currently working on there are a number of models that have a warehouse property. I want all of these models to have validation that makes sure that the warehouse entered is a valid warehouse. It seemed like the easiest way to do this was to use a custom ValidationAttribute class. Then the validation code would be centralized, and I could just add the attribute to the property in each of the models.
I need to call a service to make sure that the warehouse is a valid warehouse. I have a interface that represents this service and I am using Ninject to do dependency injection in my applications where this service is used. That way I can use mocking and easily do unit testing on the application.
I want my custom ValidationAttribute class to use dependency injection when using this service. Here is the class that I have created:
public class MustBeValidWarehouse : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value is string)
{
string warehouse = value.ToString();
NinjectDependencyResolver depres = new NinjectDependencyResolver();
Type inventServiceType = typeof(IInventService);
IInventService inventserv = depres.GetService(inventServiceType) as IInventService;
return (inventserv.GetWarehouses().Where(m => m.WarehouseId == warehouse).Count() != 0);
}
else
{
return false;
}
}
}
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver()
{
kernel = new StandardKernel();
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
kernel.Bind<IInventService>().To<InventService>();
}
}
The dependency injection works correctly, however it is not easy to test. There is no way to inject a mock IInventService into the class in a unit test. Normally in order to resolve this I would have the class constructor take a IInventService parameter so that I could pass in a mock object in my unit test. However I don't think that I can have this class constructor take a IInventService class as a parameter because then I believe that I would have to pass in that parameter when I added this attribute in my class.
Is there a way to make this code more testable? If not then is there a better way to approach this?
You need to use DependencyResolver
class in ASP.NET MVC. If you wire your container correctly DependencyResolver.Current
will use your container to resolve the dependencies.
public class MustBeValidWarehouse : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value is string)
{
string warehouse = value.ToString();
IInventService inventserv = DependencyResolver.Current.GetService<IInventService>();
return (inventserv.GetWarehouses().Where(m => m.WarehouseId == warehouse).Count() != 0);
}
return false;
}
}
In your class tests you can provide a mock for DepedencyResolver.Current
like this:
DependencyResolver.SetResolver(resolverMock);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With