You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 00:56:08