如何在.net core mvc中使用ModelState包装类分离业务逻辑层

Posted

技术标签:

【中文标题】如何在.net core mvc中使用ModelState包装类分离业务逻辑层【英文标题】:How to separate business logic layer using ModelState wrapper class in .net core mvc 【发布时间】:2020-09-19 23:36:09 【问题描述】:

我正在使用 ASP.Net MVC 5(.net 框架)开发 Web 应用程序,现在尝试使用 .NET Core 3.1 和实体框架 Core(使用代码优先方法)开发我的下一个项目。

我正在一个单独的 Wrapper 类中尝试单独的业务逻辑,例如:

public interface IValidationDictionary

    void AddError(string key, string errorMessage);
    bool IsValid  get; 


public class ModelStateWrapper : IValidationDictionary

    private ModelStateDictionary _modelState;

    public ModelStateWrapper(ModelStateDictionary modelState)
    
        _modelState = modelState;
    

    #region IValidationDictionary Members

    public void AddError(string key, string errorMessage)
    
        _modelState.AddModelError(key, errorMessage);
    

    public bool IsValid
    
        get  return _modelState.IsValid; 
    
    #endregion

在 EmployeeRepo 类中:

    private Models.IValidationDictionary _modelState;
    public EmployeeRepo(Models.IValidationDictionary modelState)
    
        _modelState = modelState;
    

   public int Create(Models.Employee ObjToCreate)
   
        if (!Validate(ObjToCreate))
            return 0;

        _context.Employee.Add(ObjToCreate);
        _context.SaveChanges();

        return ObjToCreate.Id;
   

    protected bool Validate(Models.Employee objToValidate)
    
        if (objToValidate.Name.Trim().Length == 0)
            _modelState.AddError("Name", "Name is required.");

        if (null == objToValidate.DOB)
            _modelState.AddError("DOB", "DOB is required");
        return _modelState.IsValid;
    

在控制器中:

private Repository.IEmployeeRepo repo;
public EmployeesController(ApplicationDbContext context)

    _context = context;
    repo = new Repository.EmployeeRepo(new Models.ModelStateWrapper(this.ModelState));


    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Create([Bind("Name,DOB,Department")] Employee employee)
    
        var respId = repo.Create(employee);
        if (0 != respId.Id)
        
            return RedirectToAction(nameof(Details), new  id = respId.Id );
        
        return View(employee);
    

我希望 ModelState 错误会在由包装类添加的控制器中更新,但模型验证错误不会在控制器中更新。

感谢您的宝贵时间和任何回复。

致以最诚挚的问候, 拉朱·穆克吉

【问题讨论】:

我建议你在Create方法中加个断点来测试,确认员工是否收到了对应的数据,然后再确认是哪一段代码有问题,看不到如何在自定义 Create 方法中调用 _context @YongqingYu 在调试检查期间,我发现 EmployeeRepo 的 Validate() 方法为空 DOB 和 ModelState.IsValid 添加了模型错误,如预期的那样,但当它返回 0 到 Controller 时仍然没有 ModelState更新即 ModelState.IsValid 为 True 且 EmployeeRepo 添加的错误无法在视图中显示。对于 _context 我删除了计时代码,因为我在 Repo 类创建 DbContext 对象期间发现错误,因为这部分由在 CORE MVC 的 Startup.cs 类中配置的 DI 管理...谢谢 您提到错误无法在视图中显示,所以请提供您的视图代码供我们参考,并且Create方法最终返回一个int类型,我认为respId.Id是错误的。跨度> @YongqingYu 正如提到的在存储库中添加的模型错误未反映在控制器中,因此无法出现在用户视图中。 (respId.Id 错误,一旦我从 Create 返回 Employee 对象类型,请忽略它)查看代码供您参考:' ' 【参考方案1】:

你只想用自定义的验证方式来验证这两个 领域,对吧?

你写的方法太复杂了。

要绑定对应的报错信息,需要在[Required]等对应字段上方添加自定义验证属性。

其实只需要继承ValidationAttribute方法,重写IsValid方法即可。

    public class Employee
     
        public int Id  get; set; 

        [CustomValidate]
        public string Name  get; set; 

        [CustomValidate]
        public string DOB  get; set; 

        public string Department get; set; 
    

自定义方法:

 public class CustomValidateAttribute : ValidationAttribute
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        
            if (value == null || string.IsNullOrEmpty(value.ToString().Trim()))
            
                return new ValidationResult(validationContext.DisplayName + " is required.");
            

            return ValidationResult.Success;
        
    

创建:

 [HttpPost]
        public IActionResult Create([Bind("Name,DOB,Department")]Employee employee)
         
            if (ModelState.IsValid)
            
                _context.Employee.Add(employee); 
                _context.SaveChanges();
                return RedirectToAction(nameof(Details), new  id = employee.Id );
            
            return View(employee);
        

这是测试结果:

【讨论】:

请参考主题,我实际上是在尝试让 Repository 类负责业务逻辑验证(与服务层或 BLL 相同)。仅使用数据注释或自定义验证验证少数字段不是此 POC 项目的目的:如果我添加类似 ' if (null == employee.DOB) ModelState.AddModelError("DOB", "Date ofbirth is required") 之类的代码;'在 Controller Post Create 方法中,如果 DOB 字段为 null 提供,我得到 ModelState.IsValid FALSE 和模型验证错误,在 Repository 类中写入相同并期望相同的结果。 请建议您是否有任何简单的解决方案来完成同样的任务,代码在 .NetFramework 4.5 中使用 ASP.Net MVC 5 多年来运行良好 @raju1208,如果你必须根据你提供的方法显示错误信息,我建议你可以使用jquery ajax调用Create动作,然后在成功方法中添加相应的信息ajax通过action返回的内容,你能接受这个方案吗?如果可能,我会更新我的帖子。 对于大型项目,这将不起作用,无论如何出现错误消息不是目标,问题是开发具有良好实践的应用程序,以便将来易于维护和增强。

以上是关于如何在.net core mvc中使用ModelState包装类分离业务逻辑层的主要内容,如果未能解决你的问题,请参考以下文章

如何在.net core mvc中使用ModelState包装类分离业务逻辑层

如何在 ASP.NET Core MVC 中使用 ADO.NET 向存储过程添加参数?

如何在 ASP.NET Core MVC 中使用依赖注入设计存储库模式?

如何使用 C# 在 ASP.NET Core 3.1 MVC 中使用会话变量

如何在带有 ADO.NET 的 ASP.NET Core MVC 中使用 jQuery Ajax 自动完成

ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)