使用 c# 为非常不同的方法实现横切验证器
Implement a cross cutting validator for very different methods using c#
我有一个带有 Client/Server 架构的小框架 我在我的业务层中使用这个工具:
DI = SimpleInjector
用于拦截的 DynamicProxy = Castle.Core
现在我需要验证一些验证!例如看这个方法:
public void DeleteFakeItem (Guid userId, Guid fakeItemId)
{
userAccountService.IsAuthorized(userId, FeatureIndex.DeleteFakeItem);
if (fakeItemId == Guid.EmptyGuid || userId == Guid.EmptyGuid)
throw new ArgumentNullException("parameters are not correct!");
if (!repo.IsFakeItemIsDeletable(fakeItemId))
throw new Exception("you can not delete this item!");
var fakeItem = repo.GetFakeItem(fakeItemId);
if (fakeItem == null)
throw new Exception("this fakeItem dose not exists!");
repo.DeleteActivityCenter(fakeItem);
}
但是,我有很多方法,我的方法各不相同,那么解决方法在哪里呢?因为我无法为我的方法创建一个好的抽象。
我如何实现横切功能来验证我的参数?
我想我可以使用拦截器和属性来做到这一点,例如每个参数的属性 [Validate(ValidateEnum.NotNull)]
。
正确的方法是什么?
我的实体的第二个问题:
我可以获得流畅的 API 验证规则来验证基于它们的实体使用反射和拦截器吗?
例如我想获取规则,如果有 IsRequired()
规则,则验证为不为空。
我不想使用装饰器模式,因为它让我进行了很多重构;
我对问题的解决方案如下 (you can find it here) :
- 接口和实现 class 以便能够更改验证逻辑 - 验证逻辑中可能存在错误或更改。
- 使大部分方法无效并使用全局异常处理程序抛出异常。
- 将不同程序集中的实现和接口分开。通过这个,我获得了单元测试的性能优势。我有用于消息服务、缓存服务、持久性服务的单独程序集,因为它们的实现非常庞大并且有很多依赖项,这会减慢单元测试 运行s 以致于被遗忘。当您的单元测试仅引用接口程序集时,测试编译和 运行 会快很多。 这一点对大型和长期项目有非常大的影响。 - 这会影响代码库的质量!
我只是通过将反射与通用接口相结合来解决我的问题,所以我唯一需要做的就是为每个实体实现通用接口。
我有一个拦截所有方法的拦截器。它对我有用。但是任何人都可以给我一些关于性能的信息吗?这是进行验证的正确方法吗?
拦截器:
public class ValidatorInterceptor : IInterceptor
{
private readonly IServiceFactory factory;
public ValidatorInterceptor(IServiceFactory _factory)
{
factory = _factory;
}
public void Intercept(IInvocation invocation)
{
var methodParameterSet = invocation.InvocationTarget.GetType().GetMethod(invocation.Method.Name).GetParameters().ToList();
for (var index = 0; index < methodParameterSet.Count; index++)
{
var parameter = methodParameterSet[index];
var paramType = parameter.ParameterType;
var customAttributes = new List<object>();
var factoryMethod = factory.GetType().GetMethod("GetService");
var baseValidatorType = typeof(IValidator<>);
var validatorType = baseValidatorType.MakeGenericType(paramType);
factoryMethod = factoryMethod.MakeGenericMethod(validatorType);
var validator = factoryMethod.Invoke(factory, null);
customAttributes.AddRange(parameter.GetCustomAttributes(true).Where(item => item.GetType().Name.StartsWith("Validate")));
foreach (var attr in customAttributes)
{
dynamic attribute = attr;
var method = validator.GetType().GetMethod("Validate");
method = method.MakeGenericMethod(paramType);
object[] parameterSet = {invocation.Arguments[index], attribute.Rule, attribute.IsNullCheck};
method.Invoke(validator, parameterSet);
}
}
invocation.Proceed();
}
}
UserAccount 实体的 IValidator 的实现是这样的:
public class ValidateUserAccount<T> : IValidator<T> where T : UserAccount
{
public void Validate<T>(T entity, object obj1 = null, object obj2 = null) where T : class
{
var item = (UserAccount) Convert.ChangeType(entity, typeof(UserAccount));
if (item == null)
throw new ArgumentNullException("user account cant be null");
}
}
对于字符串验证器:
public class ValidateString : IValidator<string>
{
public void Validate<T>(T entity, object rukeObj = null, object nullChekcObj = null) where T : class
{
var item = (string) Convert.ChangeType(entity, typeof(string));
var rule = (Regex)Convert.ChangeType(rukeObj, typeof(Regex));
var reqItem = Convert.ChangeType(nullChekcObj, typeof(bool));
var isRequire = reqItem != null && (bool) reqItem;
if (isRequire && string.IsNullOrEmpty(item))
throw new ArgumentException("value can not be null!");
if (!rule.Match(item).Success)
throw new ArgumentException("[" + item + "] is not a valid input!");
}
}
我有一个带有 Client/Server 架构的小框架 我在我的业务层中使用这个工具:
DI = SimpleInjector
用于拦截的 DynamicProxy = Castle.Core
现在我需要验证一些验证!例如看这个方法:
public void DeleteFakeItem (Guid userId, Guid fakeItemId)
{
userAccountService.IsAuthorized(userId, FeatureIndex.DeleteFakeItem);
if (fakeItemId == Guid.EmptyGuid || userId == Guid.EmptyGuid)
throw new ArgumentNullException("parameters are not correct!");
if (!repo.IsFakeItemIsDeletable(fakeItemId))
throw new Exception("you can not delete this item!");
var fakeItem = repo.GetFakeItem(fakeItemId);
if (fakeItem == null)
throw new Exception("this fakeItem dose not exists!");
repo.DeleteActivityCenter(fakeItem);
}
但是,我有很多方法,我的方法各不相同,那么解决方法在哪里呢?因为我无法为我的方法创建一个好的抽象。
我如何实现横切功能来验证我的参数?
我想我可以使用拦截器和属性来做到这一点,例如每个参数的属性 [Validate(ValidateEnum.NotNull)]
。
正确的方法是什么?
我的实体的第二个问题: 我可以获得流畅的 API 验证规则来验证基于它们的实体使用反射和拦截器吗?
例如我想获取规则,如果有 IsRequired()
规则,则验证为不为空。
我不想使用装饰器模式,因为它让我进行了很多重构;
我对问题的解决方案如下 (you can find it here) :
- 接口和实现 class 以便能够更改验证逻辑 - 验证逻辑中可能存在错误或更改。
- 使大部分方法无效并使用全局异常处理程序抛出异常。
- 将不同程序集中的实现和接口分开。通过这个,我获得了单元测试的性能优势。我有用于消息服务、缓存服务、持久性服务的单独程序集,因为它们的实现非常庞大并且有很多依赖项,这会减慢单元测试 运行s 以致于被遗忘。当您的单元测试仅引用接口程序集时,测试编译和 运行 会快很多。 这一点对大型和长期项目有非常大的影响。 - 这会影响代码库的质量!
我只是通过将反射与通用接口相结合来解决我的问题,所以我唯一需要做的就是为每个实体实现通用接口。
我有一个拦截所有方法的拦截器。它对我有用。但是任何人都可以给我一些关于性能的信息吗?这是进行验证的正确方法吗? 拦截器:
public class ValidatorInterceptor : IInterceptor
{
private readonly IServiceFactory factory;
public ValidatorInterceptor(IServiceFactory _factory)
{
factory = _factory;
}
public void Intercept(IInvocation invocation)
{
var methodParameterSet = invocation.InvocationTarget.GetType().GetMethod(invocation.Method.Name).GetParameters().ToList();
for (var index = 0; index < methodParameterSet.Count; index++)
{
var parameter = methodParameterSet[index];
var paramType = parameter.ParameterType;
var customAttributes = new List<object>();
var factoryMethod = factory.GetType().GetMethod("GetService");
var baseValidatorType = typeof(IValidator<>);
var validatorType = baseValidatorType.MakeGenericType(paramType);
factoryMethod = factoryMethod.MakeGenericMethod(validatorType);
var validator = factoryMethod.Invoke(factory, null);
customAttributes.AddRange(parameter.GetCustomAttributes(true).Where(item => item.GetType().Name.StartsWith("Validate")));
foreach (var attr in customAttributes)
{
dynamic attribute = attr;
var method = validator.GetType().GetMethod("Validate");
method = method.MakeGenericMethod(paramType);
object[] parameterSet = {invocation.Arguments[index], attribute.Rule, attribute.IsNullCheck};
method.Invoke(validator, parameterSet);
}
}
invocation.Proceed();
}
}
UserAccount 实体的 IValidator 的实现是这样的:
public class ValidateUserAccount<T> : IValidator<T> where T : UserAccount
{
public void Validate<T>(T entity, object obj1 = null, object obj2 = null) where T : class
{
var item = (UserAccount) Convert.ChangeType(entity, typeof(UserAccount));
if (item == null)
throw new ArgumentNullException("user account cant be null");
}
}
对于字符串验证器:
public class ValidateString : IValidator<string>
{
public void Validate<T>(T entity, object rukeObj = null, object nullChekcObj = null) where T : class
{
var item = (string) Convert.ChangeType(entity, typeof(string));
var rule = (Regex)Convert.ChangeType(rukeObj, typeof(Regex));
var reqItem = Convert.ChangeType(nullChekcObj, typeof(bool));
var isRequire = reqItem != null && (bool) reqItem;
if (isRequire && string.IsNullOrEmpty(item))
throw new ArgumentException("value can not be null!");
if (!rule.Match(item).Success)
throw new ArgumentException("[" + item + "] is not a valid input!");
}
}