- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我在看本教程http://asp-umb.neudesic.com/mvc/tutorials/validating-with-a-service-layer--cs,了解如何在包装器上包装我的验证数据。
我想使用依赖注入(inject)。我正在使用ninject 2.0
namespace MvcApplication1.Models
{
public interface IValidationDictionary
{
void AddError(string key, string errorMessage);
bool IsValid { get; }
}
}
using System.Web.Mvc;
namespace MvcApplication1.Models
{
public class ModelStateWrapper : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ModelStateWrapper(ModelStateDictionary modelState)
{
_modelState = modelState;
}
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}
public bool IsValid
{
get { return _modelState.IsValid; }
}
#endregion
}
}
private IProductService _service;
public ProductController()
{
_service = new ProductService(new ModelStateWrapper(this.ModelState),
new ProductRepository());
}
private IValidationDictionary _validatonDictionary;
private IProductRepository _repository;
public ProductService(IValidationDictionary validationDictionary,
IProductRepository repository)
{
_validatonDictionary = validationDictionary;
_repository = repository;
}
public ProductController(IProductService service)
{
_service = service;
}
最佳答案
该文章给出的解决方案将验证逻辑与服务逻辑混合在一起。这是两个问题,应该分开。当您的应用程序增长时,您将 swift 发现验证逻辑变得复杂,并且在整个服务层中重复出现。因此,我想提出一种不同的方法。
首先,当发生验证错误时,让服务层引发异常会更好,这是IMO所能做到的。这使得它更明确,也更难忘记检查错误。这就将错误处理的方式留给了表示层。以下 list 显示了使用此方法的ProductController
:
public class ProductController : Controller
{
private readonly IProductService service;
public ProductController(IProductService service) => this.service = service;
public ActionResult Create(
[Bind(Exclude = "Id")] Product productToCreate)
{
try
{
this.service.CreateProduct(productToCreate);
}
catch (ValidationException ex)
{
this.ModelState.AddModelErrors(ex);
return View();
}
return RedirectToAction("Index");
}
}
public static class MvcValidationExtension
{
public static void AddModelErrors(
this ModelStateDictionary state, ValidationException exception)
{
foreach (var error in exception.Errors)
{
state.AddModelError(error.Key, error.Message);
}
}
}
ProductService
类本身不应包含任何验证,而应将其委派给专门用于验证的类,即
IValidationProvider
:
public interface IValidationProvider
{
void Validate(object entity);
void ValidateAll(IEnumerable entities);
}
public class ProductService : IProductService
{
private readonly IValidationProvider validationProvider;
private readonly IProductRespository repository;
public ProductService(
IProductRespository repository,
IValidationProvider validationProvider)
{
this.repository = repository;
this.validationProvider = validationProvider;
}
// Does not return an error code anymore. Just throws an exception
public void CreateProduct(Product productToCreate)
{
// Do validation here or perhaps even in the repository...
this.validationProvider.Validate(productToCreate);
// This call should also throw on failure.
this.repository.CreateProduct(productToCreate);
}
}
IValidationProvider
不应自行验证,而应将验证委托(delegate)给专门用于验证一种特定类型的验证类。当一个对象(或一组对象)无效时,验证提供程序应抛出
ValidationException
,该代码可以在调用堆栈的更高位置被捕获。提供程序的实现可能如下所示:
sealed class ValidationProvider : IValidationProvider
{
private readonly Func<Type, IValidator> validatorFactory;
public ValidationProvider(Func<Type, IValidator> validatorFactory)
{
this.validatorFactory = validatorFactory;
}
public void Validate(object entity)
{
IValidator validator = this.validatorFactory(entity.GetType());
var results = validator.Validate(entity).ToArray();
if (results.Length > 0)
throw new ValidationException(results);
}
public void ValidateAll(IEnumerable entities)
{
var results = (
from entity in entities.Cast<object>()
let validator = this.validatorFactory(entity.GetType())
from result in validator.Validate(entity)
select result)
.ToArray();
if (results.Length > 0)
throw new ValidationException(results);
}
}
ValidationProvider
取决于进行实际验证的
IValidator
实例。提供程序本身不知道如何创建这些实例,但是为此使用了注入(inject)的
Func<Type, IValidator>
委托(delegate)。此方法将具有容器特定的代码,例如Ninject的代码:
var provider = new ValidationProvider(type =>
{
var valType = typeof(Validator<>).MakeGenericType(type);
return (IValidator)kernel.Get(valType);
});
Validator<T>
类-我将在稍后显示该类。首先,
ValidationProvider
取决于以下类:
public interface IValidator
{
IEnumerable<ValidationResult> Validate(object entity);
}
public class ValidationResult
{
public ValidationResult(string key, string message)
{
this.Key = key;
this.Message = message;
}
public string Key { get; }
public string Message { get; }
}
public class ValidationException : Exception
{
public ValidationException(ValidationResult[] r) : base(r[0].Message)
{
this.Errors = new ReadOnlyCollection<ValidationResult>(r);
}
public ReadOnlyCollection<ValidationResult> Errors { get; }
}
public abstract class Validator<T> : IValidator
{
IEnumerable<ValidationResult> IValidator.Validate(object entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return this.Validate((T)entity);
}
protected abstract IEnumerable<ValidationResult> Validate(T entity);
}
IValidator
。现在,您可以定义一个从
ProductValidator
派生的
Validator<Product>
类:
public sealed class ProductValidator : Validator<Product>
{
protected override IEnumerable<ValidationResult> Validate(
Product entity)
{
if (entity.Name.Trim().Length == 0)
yield return new ValidationResult(
nameof(Product.Name), "Name is required.");
if (entity.Description.Trim().Length == 0)
yield return new ValidationResult(
nameof(Product.Description), "Description is required.");
if (entity.UnitsInStock < 0)
yield return new ValidationResult(
nameof(Product.UnitsInStock),
"Units in stock cnnot be less than zero.");
}
}
ProductValidator
类使用C#
yield return
语句,这使返回的验证错误更加流畅。
kernel.Bind<IProductService>().To<ProductService>();
kernel.Bind<IProductRepository>().To<L2SProductRepository>();
Func<Type, IValidator> validatorFactory = type =>
{
var valType = typeof(Validator<>).MakeGenericType(type);
return (IValidator)kernel.Get(valType);
};
kernel.Bind<IValidationProvider>()
.ToConstant(new ValidationProvider(validatorFactory));
kernel.Bind<Validator<Product>>().To<ProductValidator>();
Validator<T>
实现。即使大多数实现可能都是空的。
sealed class NullValidator<T> : Validator<T>
{
protected override IEnumerable<ValidationResult> Validate(T entity)
{
return Enumerable.Empty<ValidationResult>();
}
}
NullValidator<T>
:
kernel.Bind(typeof(Validator<>)).To(typeof(NullValidator<>));
NullValidator<Customer>
且未为其注册任何特定实现时,Ninject将返回
Validator<Customer>
。
Validator<T>
实现添加注册,并使Ninject为您动态搜索程序集。我找不到任何示例,但是我认为Ninject可以做到这一点。
NullValidator<T>
的实现(在这种情况下,我将其重命名为
DefaultValidator<T>
。除此之外,仍然可以为其他验证难以实现的自定义验证类提供额外的验证技术。
IProductService
和ICustomerService
之类的抽象方法违反了SOLID原则,从此模式转换为a pattern that abstracts use cases可能会使您受益。
关于c# - 验证: How to inject A Model State wrapper with Ninject?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4776396/
有人在 monodroid 项目中使用 ninject 吗? 如果是这样,将不胜感激有关实现这一目标的任何指示/细节。 最佳答案 我还没有尝试在 Mono For Android 中使用 Ninjec
我找到了this article关于 Ninject 早期版本中的上下文变量。我的问题有两个方面。首先,如何使用 Ninject 2 获得这种行为?其次,上下文变量是否沿着请求链传递?例如,假设我想替
我有一个场景,只要一个对象上的方法返回 true,多个并发 Web 请求就应该重用一个对象。有问题的对象是线程安全的。 所以我需要当前范围内的对象来确定它是否仍在范围内。使用 Ninject 完成此任
我刚刚使用 Ninject 3 更新了我的应用程序。将 App_Start 中的文件从 NinjectMVC3 更改为 NinijectWebCommon.cs。移动了我的文件,更新了 DLLs..
我在 MVC4 应用程序中使用 Ninject 进行 DI 和 Ninject.MVC3 扩展,特别是版本 3.0.0.6。 阅读documentation在 Ninject 的 wiki 上,使用
如何绑定(bind)InitializerForXXX (非通用实现)到 IInitializer (通用接口(interface))使用 Ninject Conventions以便请求 IIniti
我正在开发一个框架扩展,它使用 Ninject 作为 IoC 容器来处理动态注入(inject),但是我在尝试解决如何实现这一点时遇到了一些麻烦。 我的框架的期望是您将传递 IModule(s)所以它
我确信这是一个愚蠢的问题,因为我假设答案是“当对象被 Ninject 实例化时”......但我想仔细检查...... 为了提供更多关于我为什么问这个问题的背景信息,我有一个实现 NinjectHtt
与其手动绑定(bind)每个类,不如推荐哪些方法和模式(如果有)来自动设置绑定(bind)? 例如,绝大多数绑定(bind)看起来像这样: Bind.To(); 一旦模块变大,您最终可能会得到 100
我试图找到一种将构造函数参数传递给子类的构造函数的方法。 这些对象是不可变的,所以我更喜欢使用构造函数参数。 我遇到的问题是 ConstructorArgument 不继承到子实例化,并且以下语句不可
我正在尝试为事件代理/消息代理的开发找到最新的 Ninject 扩展。 我至少可以找到 3 个:messagebroker , weakeventmessagebroker和 bbveventbrok
我有一个 WebApi 服务,我正在尝试使用 Ninject BindHttpFilter 添加身份验证。 使用 BindHttpFilter 允许我将身份验证过滤器绑定(bind)到特定属性。 Au
Autofac 自动为 Func 生成工厂;我什至可以传递参数。 public class MyClass { public MyClass(Func a, Func b) {
我有一个类需要为其类中的一个方法使用 IRepository。 理想情况下,我希望避免将这种依赖关系解析到类的构造函数中,因此我在 Ninject 中发现了方法级注入(inject),并且想知道这是如
我看到了枚举给定服务(类型)的绑定(bind)列表的方法,但我找不到返回已加载模块中绑定(bind)的所有内容列表的方法。我正在寻找类似Kernel::IEnumerable GetAllRegist
对于初学者,我正在使用这个模块: public class AutoMapperModule : NinjectModule { public override void Load()
我想知道 ninject 是否有可能拦截我类的私有(private)方法。我正在尝试进行一些 aop 编程以动态注入(inject)日志记录机制。 最佳答案 不幸的是,所有要拦截的方法都必须是virt
我是 Ninject 的新手,正在努力让这个测试通过。 (此测试通过 Autofac,但行为在 Ninject 中似乎有所不同)。 [Test] public void RegisterInstanc
我在一个小项目中使用过 Ninject,但现在正在将一个较大的 Web 应用程序转换为 mvc,并且需要有关使用 Ninject 的帮助。在新的解决方案中,我拥有 mvc 站点并将一些功能拆分到单独的
目前,我正在使用 ninject 执行以下绑定(bind)的命令模式: kernel.Bind>().To(); kernel.Bind>().To(); kernel.Bind>().To(); 我
我是一名优秀的程序员,十分优秀!