• asp.net 自定义的模板方法接口通用类型


    本来想写这个帖子已经很久了,但是公司事情多,做着做着就忘记了。公司因为需要做接口,而且用的还是asp.net的老框架,使用Handler来做,没得办法,自己照着MVC写了一个通过的接口操作模板。

    上送json数据,返回的也是json数据。可以像MVC一样自动绑定并可以进行DataAnnotations验证。尽量达到在业务逻辑处理区域不用对上送参数做过多的获取和判断,能一次搞定就一次搞定。

    话不多说,上代码!!!

    BaseClass:用作接口参数的基类。接口参数类型可以继承该类,也可以不继承,或自己定义其他基类。

    public abstract class BaseClass { }

    EmptyClass:一个空类。当做一个参数类型传入到接口中,占用地方而已。

    public class EmptyClass : BaseClass { }

    ModelError:错误消息载体类型。

        [Serializable]
        public class ModelError {
            public ModelError(Exception exception) : this(exception, null) { }
    
            public ModelError(string errorMessage) {
                this.ErrorMessage = errorMessage ?? string.Empty;
            }
    
            public ModelError(Exception exception, string errorMessage) : this(errorMessage) {
                if (exception == null)
                    throw new ArgumentNullException("exception");
                this.Exception = exception;
            }
    
            public Exception Exception { get; private set; }
            public string ErrorMessage { get; private set; }
        }  

    ModelErrorCollection:错误消息载体集合。

        [Serializable]
        public class ModelErrorCollection : Collection<ModelError> {
            public void Add(string errorMessage) {
                base.Add(new ModelError(errorMessage));
            }
    
            public void Add(Exception exception) {
                base.Add(new ModelError(exception));
            }
        }

    ModelState:模型绑定状态。

        /// <summary>
        /// 模型绑定状态
        /// </summary>
        [Serializable]
        public class ModelState {
            private ModelErrorCollection _errors = new ModelErrorCollection();
            public bool IsValid {
                get {
                    return _errors.Count == 0;
                }
            }
            public ModelErrorCollection Errors {
                get {
                    return _errors;
                }
            }
        }

    ModelBinder:模型绑定抽象类,需要继承此抽象类。用来绑定上送参数并验证的基类。

        /// <summary>
        /// 模型绑定抽象类,需要继承此抽象类。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public abstract class ModelBinder<T> where T : class {
            protected ModelState _modelState;
    
            /// <summary>
            /// 模型绑定状态
            /// </summary>
            public ModelState ModelState {
                get {
                    if (_modelState == null)
                        _modelState = new ModelState();
                    return _modelState;
                }
            }
    
            /// <summary>
            /// 绑定操作
            /// </summary>
            /// <returns></returns>
            public abstract T Binder();
    
            /// <summary>
            /// 验证实体数据合法性。如果有错误,请在ModelState参数中获取。
            /// </summary>
            /// <param name="entity"></param>
            protected void Valide(object entity) {
                if (entity == null)
                    return;
                //获取T类型的所有公共属性
                Type type = entity.GetType();
                PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
    
                if (properties != null && properties.Count() > 0) {
                    //针对每一个公共属性,获取其特性
                    foreach (var property in properties) {
                        //如果当前属性为一个自定义类型
                        if (property.PropertyType != typeof(object) && Type.GetTypeCode(property.PropertyType) == TypeCode.Object) {
                            this.Valide(property.GetValue(entity, null));
                        }
                        else
                            ValideProperty(entity, property);
    
                        if (!_modelState.IsValid)
                            break;
                    }
                }
            }
    
            /// <summary>
            /// 验证属性的每一个特性约束
            /// </summary>
            /// <param name="entity"></param>
            /// <param name="property"></param>
            private void ValideProperty(object entity, PropertyInfo property) {
                if (entity != null && property != null) {
                    var attributes = property.GetCustomAttributes(typeof(ValidationAttribute), false);
                    foreach (ValidationAttribute attribute in attributes)
                        ValidatePropertyAttribute(entity, property, attribute);
                }
            }
    
            /// <summary>
            /// 使用特性对属性进行验证
            /// </summary>
            /// <param name="entity"></param>
            /// <param name="property"></param>
            /// <param name="attribute"></param>
            private void ValidatePropertyAttribute(object entity, PropertyInfo property, ValidationAttribute attribute) {
                if (entity != null && property != null && attribute != null) {
                    //找到该属性
                    //注明:每一个函数都应当具有独立性.
                    PropertyInfo currentProperty = entity.GetType().GetProperties().Where(p => p.Name == property.Name).FirstOrDefault();
    
                    //判断当前特性是否有IsRequiredInstance字段,这是自定义的特性,用于验证同一个实例中两个不同共有属性的值
                    PropertyInfo[] pros = attribute.GetType().GetProperties();
                    if (pros.Where(it => it.Name == "IsRequiredInstance" && it.PropertyType == typeof(bool)).FirstOrDefault() != null)
                        attribute.GetType().GetProperty("Instance").SetValue(attribute, entity, null);
    
                    if (currentProperty != null) {
                        var value = currentProperty.GetValue(entity, null);
                        if (!attribute.IsValid(value))
                            _modelState.Errors.Add(attribute.ErrorMessage);
                    }
                }
            }
    
        }

    BaseHandler:一般处理逻辑的基类。

        /// <summary>
        /// 一般处理逻辑的基类。
        /// </summary>
        /// <typeparam name="T">请求参数模型</typeparam>
        /// <typeparam name="R">返回参数模型</typeparam>
        public abstract class BaseHandler<T, R> : ModelBinder<T> where T : class where R : class {
            protected readonly ILog log;
            public BaseHandler() {
                log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
            }
            public BaseHandler(string typeName) {
                if ((typeName ?? "").Trim() != "")
                    log = LogManager.GetLogger(typeName);
                else
                    log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
            }
    
            /// <summary>
            /// 处理接口API消息
            /// </summary>      
            /// <returns></returns>
            public abstract R Process();
    
            /// <summary>
            /// 真正需要处理的接口逻辑
            /// </summary>
            /// <param name="param">客户端传过来的请求参数</param>
            /// <returns></returns>
            protected abstract R DoWork(T param);
        }

    IndexHandler:一般业务接口的模板方法处理器。该接口是基础性接口,如果有其他业务需求,请自行另外自定义或继承该接口。

        /// <summary>
        /// 一般业务接口的模板方法处理器。
        /// 该接口是基础性接口,如果有其他业务需求,请自行另外自定义或继承该接口。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public abstract class IndexHandler<T> : BaseHandler<T, BaseResponseResult> where T : class {
            public IndexHandler() : base() { }
            public IndexHandler(string typeName) : base(typeName) { }
    
            /// <summary>
            /// 对实体模型进行绑定和参数的特性验证
            /// </summary>
            /// <returns></returns>
            public override T Binder() {
                //初始化模型
                T rc = default(T);
    
                try {
                    //初始化ModelState
                    if (_modelState == null)
                        _modelState = new ModelState();
                    else
                        _modelState.Errors.Clear();
    
                    //获取数据
                    Stream stream = HttpContext.Current.Request.InputStream;
                    stream.Seek(0, SeekOrigin.Begin);
                    byte[] buffer = new byte[stream.Length];
                    int count = stream.Read(buffer, 0, buffer.Length);
                    if (count > 0) {
                        string requestParam = Encoding.UTF8.GetString(buffer);
                        //绑定数据
                        rc = new JavaScriptSerializer().Deserialize<T>(requestParam);
                        if (rc != null) {
                            //验证数据合法性
                            base.Valide(rc);
                        }
                        else
                            _modelState.Errors.Add("绑定数据失败!");
                    }
                    else
                        _modelState.Errors.Add("请求参数为空!");
                }
                catch (Exception ex) {
                    _modelState.Errors.Add("绑定数据出现错误!");
                }
    
                return rc;
            }
    
            /// <summary>
            /// 处理接口API消息
            /// </summary>      
            /// <returns></returns>
            public override BaseResponseResult Process() {
                BaseResponseResult rc = new BaseResponseResult(ErrorCode.OperationError);
    
                try {
                    //绑定请求参数
                    T requestParam = Binder();
                    //开启逻辑操作
                    if (_modelState.IsValid)
                        rc = DoWork(requestParam);
                    else {
                        StringBuilder sbuilder = new StringBuilder();
                        foreach (var error in _modelState.Errors)
                            sbuilder.Append(error.ErrorMessage);
    
                        rc.SetResult(ErrorCode.InvalideParameter, sbuilder.ToString());
                    }
                }
                catch (Exception ex) {
                    rc.SetResult(ErrorCode.SystemError);               
                    rc.returnData = null;
                    log.Error("Process", ex);
                }
    
                return rc;
            }
        }

    BaseResponseResult:返回结果。

        /// <summary>
        /// 返回结果
        /// </summary>
        public class BaseResponseResult {
            public BaseResponseResult() { }
    
            public BaseResponseResult(int returnValue, string returnMsg) {
                _code = returnValue;
                _message = returnMsg;
            }
    
            public BaseResponseResult(ErrorCode code, string returnMsg="") {
                SetResult(code, returnMsg);
            }
    
            private int _code = 0;
            private string _message = "";
            private string _contentType = "application/json";
            /// <summary>
            /// 错误码,0表示成功,其他表示失败
            /// </summary>
            public virtual int returnValue { get { return _code; } }
            /// <summary>
            /// 错误码,0表示成功,其他表示失败
            /// </summary>
            public virtual string returnMsg { get { return _message; } }
            /// <summary>
            /// 返回的数据,json格式
            /// </summary>
            public virtual object returnData { get; set; }
    
            /// <summary>
            /// 设置返回状态码
            /// </summary>
            /// <param name="code"></param>
            public virtual void SetCode(int code) {
                _code = code;
            }
    
            /// <summary>
            /// 设置返回状态码
            /// </summary>
            /// <param name="code"></param>
            public virtual void SetCode(ErrorCode code) {
                SetResult(code);
            }
    
            /// <summary>
            /// 设置返回消息
            /// </summary>
            /// <param name="message"></param>
            public virtual void SetMessage(string message) {
                _message = message;
            }
            /// <summary>
            /// 设置返回状态码和消息
            /// </summary>
            /// <param name="returnValue"></param>
            /// <param name="returnMsg"></param>
            public virtual void SetResult(int returnValue, string returnMsg) {
                _code = returnValue;
                _message = returnMsg;
            }
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="code">ErrorCode代码</param>
            /// <param name="returnMsg">返回消息。如果此项不输入值,则自动设置默认值!</param>
            public virtual void SetResult(ErrorCode code, string returnMsg="") {
                this._code = (int)code;
                this._message = (returnMsg??"").Trim()!=""?returnMsg:ErrorMsg.ErrorMessage[code];
            }
            /// <summary>
            /// 设置返回消息体
            /// </summary>
            /// <param name="obj"></param>
            public virtual void SetReturnData(params object[] obj) {
                if (obj != null && obj.Length > 0) {
                    this.returnData = obj.ToList();
                }
            }
    
            public virtual void SetReturnData(object obj) {
                this.returnData = obj;
            }
    
            public virtual void SetContentType(string contentType) {
                this._contentType = contentType;
            }
    
            /// <summary>
            /// 将当前结果转化为JSON字符串
            /// </summary>
            /// <returns></returns>
            public virtual string ToJson() {
                return new JavaScriptSerializer().Serialize(this);
            }
    
            public virtual void Response(bool isEnd = true) {
                HttpContext.Current.Response.ContentType = _contentType;
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
                HttpContext.Current.Response.Write(this.ToJson());            
                if (isEnd)
                    HttpContext.Current.Response.End();
            }
        }

    ErrorCode:返回状态码枚举。

     public enum ErrorCode {
            /// <summary>
            /// 操作错误
            /// </summary>
            OperationError = -1,
            /// <summary>
            /// 成功
            /// </summary>
            Success = 0,
            /// <summary>
            /// 失败
            /// </summary>
            Failed = 1,
            /// <summary>
            /// 无数据
            /// </summary>
            NoData=2,
            /// <summary>
            /// 不存在此页面
            /// </summary>
            NotExistPage=3,
            /// <summary>
            /// 无权限
            /// </summary>
            NoPermission=4,
            /// <summary>
            /// 未登录
            /// </summary>
            NoLogin=5,
            /// <summary>
            /// 被禁止
            /// </summary>
            Forbidden=6,
            /// <summary>
            /// 请求参数格式不符合要求
            /// </summary>
            InvalideParameter = 98,
            /// <summary>
            /// 无此接口
            /// </summary>
            NoAction = 99,
            /// <summary>
            /// 系统错误
            /// </summary>
            SystemError = 100,
        }
    
        public class ErrorMsg {
            public static Dictionary<ErrorCode, string> ErrorMessage = new Dictionary<ErrorCode, string> {
                { ErrorCode.OperationError,"服务器响应错误!"},
                { ErrorCode.Success,"成功!"},
                { ErrorCode.Failed, "失败!"},
                { ErrorCode.NoData, "查无数据!"},
                { ErrorCode.NotExistPage,"此页码不存在!"},
                { ErrorCode.InvalideParameter,"请求参数非法!"},
                { ErrorCode.NoAction,"无此接口!"},
                { ErrorCode.SystemError,"系统错误!"},
                { ErrorCode.NoPermission,"无权限操作此功能!" },
                { ErrorCode.NoLogin,"未登录!"},
                { ErrorCode.Forbidden,"操作被禁止!"},
            };
        }

    接下来介绍使用方法

    IndexHandler_Base64:定义一个接收base64字符串参数的接口处理器。代码如下:

        /// <summary>
        /// 一般业务接口的模板方法处理器,适用于参数为base64字符串的请求
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public abstract class IndexHandler_Base64<T> : IndexHandler<T> where T:class {
            //当前接口是否需要登录后才能操作
            protected bool _isLoginRequired = false;
    
            /// <summary>
            /// 实例化一个只接收base64字符串的接口操作
            /// </summary>
            /// <param name="isLoginRequired">当前接口是否需要登录。true:需要 false:不需要(默认)</param>
            public IndexHandler_Base64(bool isLoginRequired = false) : base() { _isLoginRequired = isLoginRequired; }
            /// <summary>
            /// 实例化一个只接收base64字符串的接口操作
            /// </summary>
            /// <param name="typeName">发起日志记录的类名</param>
            /// <param name="isLoginRequired">当前接口是否需要登录。true:需要 false:不需要(默认)</param>
            public IndexHandler_Base64(string typeName,bool isLoginRequired=false) : base(typeName) { _isLoginRequired = isLoginRequired; }
    
            /// <summary>
            /// 对实体模型进行绑定和参数的特性验证
            /// </summary>
            /// <returns></returns>
            public override T Binder() {
                //初始化模型
                T rc = default(T);
    
                try {
                    //初始化ModelState
                    if (_modelState == null)
                        _modelState = new ModelState();
                    else
                        _modelState.Errors.Clear();
    
                    //获取数据
                    Stream stream = HttpContext.Current.Request.InputStream;
                    stream.Seek(0, SeekOrigin.Begin);
                    byte[] buffer = new byte[stream.Length];
                    int count = stream.Read(buffer, 0, buffer.Length);
                    if (count > 0) {
                        string requestParam = Encoding.UTF8.GetString(buffer);
                        requestParam = Encoding.UTF8.GetString(Convert.FromBase64String(requestParam));
                        //绑定数据
                        rc = new JavaScriptSerializer().Deserialize<T>(requestParam);
                        if (rc != null) {
                            //验证数据合法性
                            base.Valide(rc);
                        }
                        else
                            _modelState.Errors.Add("绑定数据失败!");
                    }
                    else
                        _modelState.Errors.Add("请求参数为空!");
                }
                catch (Exception ex) {
                    _modelState.Errors.Add("绑定数据出现错误!");
                }
    
                return rc;
            }
    
            public override BaseResponseResult Process() {
                //如果该接口需要登录后才能操作,则检查当前用户是否登录
                if (_isLoginRequired) {
                    int userId = 0;
                    try {
                        userId = Login.GetSession("UserID");
                    }
                    catch { }
                    if (userId <= 0)
                        return new BaseResponseResult(ErrorCode.NoLogin);
                }
    
                return base.Process();
            }
        }

    接下来定义一个Index.ashx文件,开始使用模板接口。

        /// <summary>
        /// index 的摘要说明
        /// </summary>
        public class Index : IHttpHandler {
            private readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
            //当前登录的用户
            public static int _thisUserId {
                get {
                    return Login.GetSession("UserID");
                }
            }
            public void ProcessRequest(HttpContext context) {
                BaseResponseResult rc = new BaseResponseResult(ErrorCode.OperationError, "获取数据失败!");
    
                try {              
                    string action = GetAction();
    
                    switch (action) {
                        //获取 xxx列表
                        case "1001":
                            rc = new ListHandler().Process();
                            break;
                        //获取 xxx信息
                        case "1002":
                            rc = new ItemHandler().Process();
                            break;                    default:
                            rc.SetResult(ErrorCode.NoAction);
                            break;
                    }
    
                }
                catch (Exception ex) {
                    log.Error("ProcessRequest", ex);
                    rc.SetResult(ErrorCode.SystemError);
                }
    
                rc.Response();
            }
    
            public bool IsReusable {
                get {
                    return false;
                }
            }
    
            /// <summary>
            /// 获取Action接口名称
            /// </summary>
            /// <returns></returns>
            private string GetAction() {
                string rc = "";
    
                try {
                    rc = HttpContext.Current.Request["action"] ?? "";
                    if ((rc ?? "").Trim() == "") {
                        Stream stream = HttpContext.Current.Request.InputStream;
                        if (stream != null) {
                            byte[] buffer = new byte[stream.Length];
                            int count = stream.Read(buffer, 0, buffer.Length);
                            if (count > 0) {
                                try {
                                    string requestParam = Encoding.UTF8.GetString(buffer);
                                    requestParam = Encoding.UTF8.GetString(Convert.FromBase64String(requestParam));
                                    JsonData jd = JsonMapper.ToObject(requestParam);
                                    if (jd != null && jd.Keys.Contains("action"))
                                        rc = jd["action"].ToString();
                                }
                                catch { }
                            }
                        }
                    }
                }
                catch (Exception ex) {
                    log.Error("GetAction", ex);
                }
    
                return rc;
            }
    
        }
    
        #region 接口处理区
    
        #region 1001 获取 xxx列表
        public class ListReqModel {
            
            [Required(ErrorMessage = "请上送需要类型!")]
            [Range(0,5, ErrorMessage = "type参数值有误!")]
            public int type { get; set; }
           /// <summary>
            /// 页码索引,从0开始
            /// </summary>
            [Required(ErrorMessage = "请上送页码索引!")]
            [Min(0, ErrorMessage = "pageIndex参数值有误!")]
            public int pageIndex { get; set; }
    
            /// <summary>
            /// 每页个数
            /// </summary>
            [Required(ErrorMessage = "请上送每页的个数!")]
            [Min(1, ErrorMessage = "pageSize参数值有误!")]
            public int pageSize { get; set; }
    
        }
        public class ListHandler : IndexHandler_Base64<ListReqModel> {       public ListHandler() : base("ListHandler") { }
            protected override BaseResponseResult DoWork(ListReqModel param) {
                BaseResponseResult rc = new BaseResponseResult(ErrorCode.OperationError);
                int totalCount = 0;
                ProjectBLL biz = new ProjectBLL();
                DataTable table = biz.GetList(param.type ,Index._thisUserId, out totalCount, param.pageIndex, param.pageSize);
               
                if (table != null && table.Rows.Count > 0) {               
                    rc.SetReturnData(new
                        {
                            //总个数
                            totalCount = totalCount,
                            list = table.AsEnumerable().Select(it => new
                            {
                                id = it["ID"].ToInt64(),
                                title = it["Title"].ToNormalString(),
                                frontCover = it["FrontCover"].ToNormalString()
                            }).ToList()
                        });
                    rc.SetResult(ErrorCode.Success, "成功!");
                }
                else if (totalCount > 0)
                    rc.SetResult(ErrorCode.NotExistPage, "当前页码不存在!");
                else
                    rc.SetResult(ErrorCode.NoData, "没有数据哟!");
    
                return rc;
            }
        }
        #endregion
    
        #region 1002 获取xxx信息
    
        public class ItemReqModel {
            [Required(ErrorMessage = "请上送项目标识!")]
            [Min(1, ErrorMessage = "id参数值有误!")]
            public long id { get; set; }
        }
    
        public class ItemHandler : IndexHandler_Base64<ItemReqModel> {
            public ItemHandler() : base("ItemHandler") { }
    
            protected override BaseResponseResult DoWork(ItemReqModel param) {
                BaseResponseResult rc = new BaseResponseResult(ErrorCode.OperationError);return rc;
            }
        }
    
        #endregion#endregion

    ajax的使用方式:

    //接入说明:
    //1、请使用POST方式上传;
    //2、请将参数组装为Json字符串,如:{'action':'xxx','xx':'xx'};
    //3、Json字符串组装好以后,将其变为Base64字符串后上传。
    
    //上送数据案例如下所示:
    $.ajax({
            type: "POST",
            dataType: "json",
            url: GetHost() + 'Index.ashx',
            data: Base.encode('{"action":"1001","type":"' + type + '","pgIndex":' + pageIndex + ',"pgSize":' + pageSize + '}'),
            contentType:"application/json",
            success: function (data) {
                    //获取数据
                    if (data) {
                        //成功获取数据
                        if (data.returnValue == 0) {
                            //处理数据
                        }
                    }
                 }
         });

    至此,完毕!以上的通用接口处理器采用了模板方法设计模式,尽量减少重复工作量。

    说明:本篇文章为作者原创,如需转载,请说明来源及出处!

  • 相关阅读:
    (40)C#windows服务控制
    (6)C#事务处理
    (1)sqlite基础
    bzoj 2456 mode
    bzoj 2763 [JLOI2011]飞行路线
    bzoj1010[HNOI2008] 玩具装箱toy
    bzoj1034 [ZJOI2008]泡泡堂BNB
    [bzoj1059] [ZJOI2007] 矩阵游戏 (二分图匹配)
    [bzoj1066] [SCOI2007] 蜥蜴
    bzoj1072 [SCOI2007]排列perm
  • 原文地址:https://www.cnblogs.com/williamwsj/p/7809875.html
Copyright © 2020-2023  润新知