美文网首页AngualrABPABP
ABP:后台验证多语言

ABP:后台验证多语言

作者: 诸葛_小亮 | 来源:发表于2018-07-11 21:55 被阅读108次

目的

ABP已经封装好了一套DTO的验证机制,如果DTO数据不符合,ABP会自动弹窗显示错误信息。
但是这样有个限制,使用DataAnnotations特性时,后台验证返回的信息,一直是应为状态,如果修改成从多语言系统中读取呢?
例如下面的信息:


当UserName为空时,希望在英文状态下是UserName is not allow null,中文状态下用户名不能为空
当Name为空时,希望在英文状态下Name is not allow null,中文环境下是名字不能为空

实现方案一:ErrorMessageResourceTypeErrorMessageResourceName

使用ErrorMessageResourceTypeErrorMessageResourceName
这两个是DataAnnotations特性的属性,为了使用它们,需要自定义ErrorMessageResourceType

自定义ErrorMessageResourceType AbpAlainResourceManager

public class AbpAlainResourceManager
    {
        public static string GetStringKey(string name)
        {
            var localizationManager = IocManager.Instance.Resolve<ILocalizationManager>();
            return localizationManager.GetString(AbpAlainConsts.LocalizationSourceName, name);
        }

        public static string UserNameNotNull {
            get
            {
                return GetStringKey("UserNameNotNull");
            }
        }
    }

自定义ErrorMessageResourceType必须提供ErrorMessageResourceName对应名称的的静态属性,如代码中的public static string UserNameNotNull,将静态属性的get操作返回ABP多语言体系的内容,使用后的代码如下

使用代码

Swagger调用验证

为了验证以上的内容,我们通过Swagger调用上述接口信息


调用参数 中文

缺点

使用该方法,需要针对每种语言信息编写对应的静态属性,代码繁琐。


实现方案二:高级进阶AOP

ABP的扩展性很高,除了一般的接口替换外,可扩展的另外一种途径就是AOP了,使用AOP动态切入到目标方法体内,替换自己想要的内容

ABP 如何验证 DataAnnotations特性

通过阅读ABP源码,可查阅一下代码MvcActionInvocationValidator

ABP源码
public class MvcActionInvocationValidator : ActionInvocationValidatorBase
    {
        protected ActionExecutingContext ActionContext { get; private set; }

        public MvcActionInvocationValidator(IValidationConfiguration configuration, IIocResolver iocResolver)
            : base(configuration, iocResolver)
        {
        }

        public void Initialize(ActionExecutingContext actionContext)
        {
            ActionContext = actionContext;

            base.Initialize(actionContext.ActionDescriptor.GetMethodInfo());
        }

        protected override object GetParameterValue(string parameterName)
        {
            return ActionContext.ActionArguments.GetOrDefault(parameterName);
        }

        protected override void SetDataAnnotationAttributeErrors()
        {
            foreach (var state in ActionContext.ModelState)
            {
                foreach (var error in state.Value.Errors)
                {
                    ValidationErrors.Add(new ValidationResult(error.ErrorMessage, new[] { state.Key }));
                }
            }
        }
    }

MvcActionInvocationValidator类继承自ActionInvocationValidatorBase,ActionInvocationValidatorBase记者曾自MethodInvocationValidator
阅读MvcActionInvocationValidator中的SetDataAnnotationAttributeErrors方法可知是在这里进行验证 DataAnnotations特性的。
那么又是如何处理验证不同的错误信息呢,源代码中MethodInvocationValidator

代码
在第87行中,得知如果出现了错误信息,会抛出异常
87行
查阅ThrowValidationError方法
ThrowValidationError
发现这里是抛出了AbpValidationException异常信息,同时我们注意到,ThrowValidationErrorvirtual方法,这为我们使用AOP提供了基础。
我们使用的AOP的切入点就是这里了,在方法抛出异常信息之前,改变ValidationErrors的信息即可
因此,我们需要编写拦截器,拦截MvcActionInvocationValidator类中的ThrowValidationError方法

MvcActionInvocationValidatorInterceptor 拦截器代码

public class MvcActionInvocationValidatorInterceptor : IInterceptor
    {
        
        private readonly ILocalizationManager _localizationManager;
        
        public MvcActionInvocationValidatorInterceptor(ILocalizationManager localizationManager)
        {
            this._localizationManager = localizationManager;
        
        }

        public void Intercept(IInvocation invocation)
        {
            var method = invocation.Method.Name;

            if (method!= "ThrowValidationError")
            {
                invocation.Proceed();
                return;
            }

            try
            {
                invocation.Proceed();
            }
            catch (AbpValidationException e)
            {
                foreach (var validationResult in e.ValidationErrors)
                {
                    if (!validationResult.ErrorMessage.Contains("#"))
                    {
                        continue;
                    }

                    var errorStrings = validationResult.ErrorMessage.Split("#");
                    if (errorStrings.Length < 2)
                    {
                        continue;
                    }

                    if (errorStrings[0] != "ABP")
                    {
                        continue;
                    }

                    var key = errorStrings[1];
                    validationResult.ErrorMessage = this._localizationManager.GetString(
                        AbpAlainConsts.LocalizationSourceName,
                        key);
                }
                throw;
            }
        }
    }
66--70
第66到70行表示我们只拦截ThrowValidationError方法,其他不拦截
替换信息
由于原生代码,是抛出异常,所以我们也需要使用try..catch...,并且只捕捉:AbpValidationException异常信息,在这里,将具体的错误给替换掉

注册拦截异常

    internal static class ValidationInterceptorRegistrar
    {
        public static void Initialize(IIocManager iocManager)
        {
            iocManager.IocContainer.Kernel.ComponentRegistered += Kernel_ComponentRegistered;
        }

        private static void Kernel_ComponentRegistered(string key, IHandler handler)
        {
            var name = handler.ComponentModel.Implementation.Name;

            if (name == "MvcActionInvocationValidator")
            {
                handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(MvcActionInvocationValidatorInterceptor)));
            }
        }
    }
177
第117行表示我们只拦截MvcActionInvocationValidatorInterceptor

在module中初始化拦截器


初始化拦截器

使用方式

为了能够读取到多语言信息,我们将ErrorMessage进行了特殊格式化处理,即使用ABP#开头的,才会使用多语言替换

使用方式

swagger验证

参数信息如下


参数信息

运行结果如下


运行结果
我们发现,name的验证错误信息,已经 是我们定义在资源文件中 的内容了

缺点

使用AOP唯一的缺点,就是需要添加ErrorMessage,并且ErrorMessage必须使用ABP#开头,紧跟着多语言的key
相比方案一,则少了许多静态属性的编写。


资源文件

中文
英文

我的公众号

我的公众号

源代码

源代码:https://github.com/ZhaoRd/abp-alain/tree/feature/ValidationLocalization

相关文章

  • ABP:后台验证多语言

    目的 ABP已经封装好了一套DTO的验证机制,如果DTO数据不符合,ABP会自动弹窗显示错误信息。但是这样有个限制...

  • 为什么不要使用 async void的原因分析

    问题 在使用 Abp 框架的后台作业时,当后台作业抛出异常,会导致整个程序崩溃。在 Abp 框架的底层执行后台作业...

  • 替换纯ABP core前端组件库为NG-ZORRO

    https://github.com/yixiangling/abp-ng-Zorro 后台框架:ABP 前端框架...

  • 在阿里云轻量级服务器创建服务

    开发完成ABP应用,需要部署在阿里云轻量级服务器上,需要将ABP应用作为后台服务运行。首先在/etc/system...

  • struts2数据校验

    表单数据的验证: 前台验证:主要是通过JS验证, 表达数据是否合法!后台验证:通过后台java代码进行验证!Str...

  • Struts框架(2) - 数据效验 & Struts

    Struts数据效验 表单数据的验证:前台验证:主要是通过JS验证, 表达数据是否合法!后台验证:通过后台java...

  • java后台验证

    package com.yjys.malls.modules.works.utils; import java.u...

  • SpringBoot 整合 javax.validation 优

    提交表单,要写点严谨的代码,前后台验证是少不了的,前台页面可以使用JQuery等插件进行验证,后台验证,如果一句一...

  • 短信验证码深度解剖

    一、短信验证码运作机制 1. 验证码加密发送 在APP中点击发送验证码,向后台发送一个发送验证码请求; 后台收到请...

  • 验证码对比

    网易网盾 验证过程: 客户端 向网盾后台发起验证码请求 ,网盾后台给回验证码图片地址和 token; 用户滑动后 ...

网友评论

    本文标题:ABP:后台验证多语言

    本文链接:https://www.haomeiwen.com/subject/ueekpftx.html