ASP.NET MVC5项目逻辑层依赖注入与层级调用优化咨询
问题描述
我正在开发一个基于ASP.NET MVC5+jQuery的项目,原本仅做前端验证,通过$.ajax调用API,但API层与SQL Server存储过程均无验证机制,用户可轻易传入错误值调用API。因此决定添加逻辑层,将原有结构:
jQuery -> Api layer -> Db layer
调整为严格的分层调用结构:
jQuery -> Api layer -> Logic layer -> Db layer
项目现状
- 所有层级为同一解决方案下的独立项目
- 逻辑层与Db层为类库文件
- Db层分为接口(db.Interface)与实现类(db.Class)两个子项目,逻辑层同样分为Logic.Interface与Logic.Class两个类库项目
已完成Db层的依赖注入实现,global.asax.cs中的初始化代码:
//Helps to find all the classes of Dblayer string dbName = ConfigurationManager.AppSettings["DB"]; string dbDAL = Path.Combine(Server.MapPath("./DAL"), "DocPro.DMS.BusinessLayer." + dbName + ".dll"); AssemblyName an = AssemblyName.GetAssemblyName(dbDAL); Assembly assembly = Assembly.Load(an); Type[] assemblyTypes = assembly.GetTypes(); DALFinder.Initialize(assemblyTypes);
API项目中的DALFinder类:
public static class DALFinder { private static List<Type> TypeList { get; set; } = new List<Type>(); public static void Initialize(Type[] typelist) { TypeList.Clear(); TypeList = typelist.ToList<Type>(); } public static object GetInstance(Type plugin) { foreach (Type type in TypeList) { if (type.IsInterface || type.IsAbstract) { continue; } else { if (type.GetInterface(plugin.FullName) != null) { return Activator.CreateInstance(type, new object[] { Program.GetConnectionString() }); } } } return null; } }
当前问题:API控制器同时实例化逻辑层与Db层,直接跳过逻辑层调用Db层,不符合预期分层结构。示例控制器代码如下:
public class DocTemplateController : ApiController { private LogicLayer.IAdmin.IDocTemplate _LogicLayer; private BusinessLayer.IAdmin.IDocTemplate _Businesslayer; public DocTemplateController() { _LogicLayer = (LogicLayer.IAdmin.IDocTemplate)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IAdmin.IDocTemplate)); _Businesslayer = (BusinessLayer.IAdmin.IDocTemplate)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IDocTemplate)); } [HttpPost] [Route("api/Admin/DocTemplate/GetDocTemplates")] [Authorize] [Filters.AuthorizeLoginApi()] public async Task<GetTemplatesList> GetDocTemplates(DocTemplate request) { var response = new GetTemplatesList() { LogicLayerValidation = false }; try { response = _LogicLayer.GetDocTemplates(request); if (response.LogicLayerValidation != false) response.GetTemplates = await _Businesslayer.GetDocTemplates(request.TemplateName, request.AccountId); } catch (Exception ex) { Utils.Logger.Instance.LogException(ex); response.LogicLayerValidation = false; response.LogicLayerMessage = ex.Message; } return response; } }
补充控制器示例:
[RateLimitApi] public class UserController : ApiController { private readonly LogicLayer.IAdmin.IUsers _LogicLayer;//Logic layer private readonly LogicLayer.IGlobalValidation _CommonLogicLayer; //common logic layer private readonly BusinessLayer.IAdmin.IUsers _Businesslayer;// business layer private readonly BusinessLayer.IAccess.IUser _IAccessBusinesslayer;//business layer which is being used in another api private BusinessEntities.Response.LogicLayerValidationResult _Llv; //entity for logiclayer private SPResponse _Sp; //response entity for add/edit private readonly ErrorLogger _Er; //error log class private readonly BusinessEntities.Response.Admin.GetUsersList _UserList; //user list private readonly BusinessEntities.Response.Admin.GetUsersSingle _UserSingle; //single user public UserController() { _LogicLayer = (LogicLayer.IAdmin.IUsers)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IAdmin.IUsers)); _Businesslayer = (BusinessLayer.IAdmin.IUsers)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IUsers)); _IAccessBusinesslayer = (BusinessLayer.IAccess.IUser)DALFinder.GetInstance(typeof(BusinessLayer.IAccess.IUser)); _CommonLogicLayer = (LogicLayer.IGlobalValidation)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IGlobalValidation)); _Llv = new BusinessEntities.Response.LogicLayerValidationResult() { LogicLayerValidation = false }; _Sp = new SPResponse(); _Er = new ErrorLogger(); _UserList = new BusinessEntities.Response.Admin.GetUsersList(); _UserSingle = new BusinessEntities.Response.Admin.GetUsersSingle(); } // GET: Admin/Users [HttpPost] [Authorize] [ActionName("GetList")] [Filters.AuthorizeLoginApi()] public async Task<BusinessEntities.Response.Admin.GetUsersList> GetList(DocPro.DMS.BusinessEntities.Request.Admin.UsersRequest request) { try { // had to call logic layer and then call the business layer like below _Llv = _LogicLayer.GetList(request); if (_Llv.LogicLayerValidation) { _UserList.GetUsers = await _Businesslayer.GetList(request.LoginText, request.Name, request.Email, request.UserTypeId, request.IsActive, Convert.ToInt32(request.LoggedInUserId)); } } catch (Exception ex) { _Llv = _Er.LogExceptionWithLogicLayerValidations(ex, _Llv); } _UserList.LogicLayerValidation = _Llv; return _UserList; } }
需要调整实现,确保严格遵循jQuery->API层->逻辑层->Db层的调用结构。
解决方案
1. 重构逻辑层,让逻辑层接管Db层调用
修改逻辑层的实现类,让其内部依赖Db层接口,并在验证通过后直接调用Db层,将Db层的调用逻辑从API层转移到逻辑层:
// Logic.Class项目中的IDocTemplate实现类 public class DocTemplate : LogicLayer.IAdmin.IDocTemplate { private readonly BusinessLayer.IAdmin.IDocTemplate _dbLayer; // 通过构造函数注入Db层接口实例 public DocTemplate() { // 复用已有的DALFinder获取Db层实例 _dbLayer = (BusinessLayer.IAdmin.IDocTemplate)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IDocTemplate)); } public async Task<GetTemplatesList> GetDocTemplates(DocTemplate request) { var response = new GetTemplatesList() { LogicLayerValidation = false }; // 执行逻辑验证 if (!ValidateRequest(request)) { response.LogicLayerMessage = "请求参数不合法:模板名称不能为空,账号ID必须大于0"; return response; } // 验证通过后调用Db层 try { response.GetTemplates = await _dbLayer.GetDocTemplates(request.TemplateName, request.AccountId); response.LogicLayerValidation = true; } catch (Exception ex) { // 逻辑层内部捕获Db层异常,封装后返回 response.LogicLayerMessage = $"数据查询失败:{ex.Message}"; } return response; } // 私有方法实现参数验证逻辑 private bool ValidateRequest(DocTemplate request) { return !string.IsNullOrWhiteSpace(request.TemplateName) && request.AccountId > 0; } }
2. 简化API层代码,仅依赖逻辑层
API控制器只需要实例化逻辑层,所有业务流程(验证+数据操作)都由逻辑层完成,无需直接操作Db层:
public class DocTemplateController : ApiController { private readonly LogicLayer.IAdmin.IDocTemplate _logicLayer; public DocTemplateController() { _logicLayer = (LogicLayer.IAdmin.IDocTemplate)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IAdmin.IDocTemplate)); } [HttpPost] [Route("api/Admin/DocTemplate/GetDocTemplates")] [Authorize] [Filters.AuthorizeLoginApi()] public async Task<GetTemplatesList> GetDocTemplates(DocTemplate request) { // 直接调用逻辑层,无需关心内部Db调用细节 return await _logicLayer.GetDocTemplates(request); } }
3. 初始化逻辑层实例查找
在global.asax.cs中添加逻辑层的初始化代码,与Db层初始化逻辑一致:
// 初始化逻辑层 string logicAssemblyPath = Path.Combine(Server.MapPath("./Logic"), "DocPro.DMS.LogicLayer.Class.dll"); AssemblyName logicAn = AssemblyName.GetAssemblyName(logicAssemblyPath); Assembly logicAssembly = Assembly.Load(logicAn); Type[] logicAssemblyTypes = logicAssembly.GetTypes(); BusinessLayerFinder.Initialize(logicAssemblyTypes);
4. 统一异常处理(可选)
可以在逻辑层内部处理Db层异常,或者将异常抛出到API层统一处理。推荐在逻辑层封装异常信息,API层仅负责返回响应和记录日志:
// API层调整后的异常处理 public async Task<GetTemplatesList> GetDocTemplates(DocTemplate request) { var response = new GetTemplatesList() { LogicLayerValidation = false }; try { response = await _logicLayer.GetDocTemplates(request); } catch (Exception ex) { Utils.Logger.Instance.LogException(ex); response.LogicLayerMessage = "服务异常,请稍后重试"; } return response; }
内容的提问来源于stack exchange,提问作者Ibrahim shaikh
相关产品推荐
相关产品推荐

