ASP.Net MVC 4 Custom ValidationAttributedependency injection

在我目前正在开发的ASP.Net MVC 4应用程序中,有许多具有仓库属性的模型。 我希望所有这些模型都有validation,以确保输入的仓库是有效的仓库。 看起来最简单的方法是使用自定义ValidationAttribute类。 然后validation代码将被集中,我可以将属性添加到每个模型中的属性。

我需要调用一个服务来确保仓库是一个有效的仓库。 我有一个代表此服务的接口,我使用Ninject在我使用此服务的应用程序中执行dependency injection。 这样我就可以使用模拟并轻松地对应用程序进行unit testing。

我希望我的自定义ValidationAttribute类在使用此服务时使用dependency injection。 这是我创建的类:

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 GetServices(Type serviceType) { return kernel.GetAll(serviceType); } private void AddBindings() { kernel.Bind().To(); } } 

dependency injection正常工作,但不容易测试。 在unit testing中无法将模拟IInventService注入到类中。 通常为了解决这个问题,我会让类构造函数接受一个I​​InventService参数,这样我就可以在unit testing中传入一个模拟对象。 但是我不认为我可以让这个类构造函数将一个IInventService类作为参数,因为我相信当我在我的类中添加这个属性时我必须传入该参数。

有没有办法让这段代码更可测试? 如果没有,那么有更好的方法来解决这个问题吗?

您需要在ASP.NET MVC中使用DependencyResolver类。 如果正确连接容器, DependencyResolver.Current将使用您的容器来解析依赖关系。

 public class MustBeValidWarehouse : ValidationAttribute { public override bool IsValid(object value) { if (value is string) { string warehouse = value.ToString(); IInventService inventserv = DependencyResolver.Current.GetService(); return (inventserv.GetWarehouses().Where(m => m.WarehouseId == warehouse).Count() != 0); } return false; } } 

在你的类测试中,你可以像这样为DepedencyResolver.Current提供一个模拟:

 DependencyResolver.SetResolver(resolverMock);