[Architect] Abp 框架原理解析(4) Validation

本节目录

 

介绍

Abp中在Application层集成了validation.

直接上代码吧.

 

DataAnnotations

这是微软提供的一套验证框架,只用引用程序集System.ComponentModel.DataAnnotations.

自带的各种特性标签就不说了,默认在MVC中已集成此验证.

这里说下验证方法:

1
2
3
4
5
6
7
static void Main(string[] args)
{
    var obj = new object();
    var rst = new StringLengthAttribute(10) { MinimumLength = 6 }.GetValidationResult("Never", new ValidationContext(obj) { DisplayName = "名称", MemberName = "Name" });
    Console.WriteLine(rst);
    Console.ReadKey();
}

运行结果:

ValidationResult对象

在MVC中,obj指的是验证的对象,DisplayName指DisplayName特性的Name值,Member指字段代码名.

 

 

1
 

 

ICustomValidate

该接口在标准验证结束后调用.

1
2
3
4
public interface ICustomValidate : IValidate
{
    void AddValidationErrors(List<ValidationResult> results);
}

 

通常会如下操作:

1
2
3
4
5
6
7
8
9
10
11
public class CreateTaskInput : IInput, ICustomValidate
{
    public string Name { get; set; }
    public void AddValidationErrors(List<ValidationResult> results)
    {
        if (Name == "xx")
        {
            results.Add(new ValidationResult("Task 名非法"));
        }
    }
}

 

 

当标准验证功能无法完成某些特定的验证功能,可以使用此接口.

 

 

IShouldNormalize

该接口并非验证字段,而是在验证完字段,离开验证过滤器前的时候执行.

一般在此接口做初始化或者其他操作.

1
2
3
4
public interface IShouldNormalize
{
    void Normalize();
}

如:

1
2
3
4
5
6
7
8
public class CreateTaskInput : IInput, IShouldNormalize
{
    public string Name { get; set; }
    public void Normalize()
    {
        Name = DateTime.Now.ToShortDateString() + "-task";
    }
}

  

 

实现Abp Validation

在Abp中大致会经历这3个接口.

在这里,仿照Abp验证

 

先定义接口

1
2
3
4
5
6
7
8
9
10
11
12
public interface IInput
{
 
}
public interface IShouldNormalize
{
    void Normalize();
}
public interface ICustomValidate
{
    void AddValidationErrors(List<ValidationResult> results);
}

 

定义Dto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class CreateTaskInput : IInput, IShouldNormalize, ICustomValidate
{
    [StringLength(10, MinimumLength = 5)]
    public string Name { get; set; }
 
    public void Normalize()
    {
        Name = DateTime.Now.ToShortDateString() + "-task";
    }
 
    public void AddValidationErrors(List<ValidationResult> results)
    {
        if (Name == "xx")
        {
            results.Add(new ValidationResult("Task 名非法"));
        }
    }
}

 

定义ApplicationService

1
2
3
4
5
6
7
8
9
10
11
12
public interface ITaskAppService
{
    void CreateTask(CreateTaskInput input);
}
 
public class TaskAppService : ITaskAppService
{
    public void CreateTask(CreateTaskInput input)
    {
        Console.WriteLine("进入CreateTask方法:" + input.Name);
    }
}

 

定义拦截器

1
2
3
4
5
6
7
8
public class ValidateInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        new MethodInvocationValidator(invocation.Arguments).Validate();
        invocation.Proceed();
    }
}

 

验证逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
internal class MethodInvocationValidator
{
    private readonly object[] _parameterValues;
    private readonly List<ValidationResult> _validationErrors;
 
    /// <summary>
    /// Creates a new <see cref="MethodInvocationValidator"/> instance.
    /// </summary>
    /// <param name="parameterValues">List of arguments those are used to call the <paramref name="method"/>.</param>
    public MethodInvocationValidator(object[] parameterValues)
    {
        _parameterValues = parameterValues;
        _validationErrors = new List<ValidationResult>();
    }
 
    public void Validate()
    {
        //basic validate
        for (var i = 0; i < _parameterValues.Length; i++)
        {
            ValidateObjectRecursively(_parameterValues[i]);
        }
   //throw exception
        if (_validationErrors.Any())
        {
            foreach (var validationResult in _validationErrors)
            {
                Console.WriteLine("{0}:{1}", validationResult.MemberNames.FirstOrDefault(), validationResult.ErrorMessage);
            }
            throw new Exception("有参数异常");
        }<br>       //normalize
        foreach (var parameterValue in _parameterValues)
        {
            if (parameterValue is IShouldNormalize)
            {
                (parameterValue as IShouldNormalize).Normalize();
            }
        }
    }
 
    private void ValidateObjectRecursively(object validatingObject)
    {
        var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>();
        foreach (var property in properties)
        {
            var validationAttributes = property.Attributes.OfType<ValidationAttribute>().ToArray();
            if (validationAttributes.IsNullOrEmpty())
            {
                continue;
            }
 
            var validationContext = new ValidationContext(validatingObject)
            {
                DisplayName = property.Name,
                MemberName = property.Name
            };
 
            foreach (var attribute in validationAttributes)
            {
                var result = attribute.GetValidationResult(property.GetValue(validatingObject), validationContext);
                if (result != null)
                {
                    _validationErrors.Add(result);
                }
            }
        }
    //custom validate
        if (validatingObject is ICustomValidate)
        {
            (validatingObject as ICustomValidate).AddValidationErrors(_validationErrors);
        }
    }
}

  

执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void Main(string[] args)
{
    using (var container = new WindsorContainer())
    {
        container.Register(Component.For<IInterceptor, ValidateInterceptor>());//先注入拦截器
        container.Kernel.ComponentRegistered += Kernel_ComponentRegistered;
        container.Register(Component.For<ITaskAppService, TaskAppService>());
        var person = container.Resolve<ITaskAppService>();
        person.CreateTask(new CreateTaskInput() { Name = "123" });
    }
    Console.ReadKey();
}
 
static void Kernel_ComponentRegistered(string key, Castle.MicroKernel.IHandler handler)
{
    handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(ValidateInterceptor)));
}

 

 

将name改成"12345"

 

本文地址:http://neverc.cnblogs.com/p/5267425.html

posted @   Never、C  阅读(2382)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示