如何在 IValidatableObject.Validate 方法的 ValidationContext 参数中提供 IServiceProvider

Posted

技术标签:

【中文标题】如何在 IValidatableObject.Validate 方法的 ValidationContext 参数中提供 IServiceProvider【英文标题】:How can i have a IServiceProvider available in ValidationContext parameter of IValidatableObject.Validate method 【发布时间】:2015-07-24 15:39:51 【问题描述】:

控制器在内部调用IValidatableObject.Validate 并将ValidationContext 对象作为参数传递。我想使用validationContext.GetService() 方法获取服务对象并使用它。

我可以使用 AutoFac(DI Injection dll) 将此服务作为依赖项传递给控制器​​构造函数。我如何使它对ValidationContext 对象可用?

这个 *** 问题可能包含答案,但我不完全理解:Asp.Net MVC3: Set custom IServiceProvider in ValidationContext so validators can resolve services

代码如下:

型号:员工

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace ValidationContextDemo.Models

    public class Employee : IValidatableObject
    
        public int Id  get; set; 
        public string Name  get; set; 
        public int DepartmentId  get; set; 

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        
            var result = new List<ValidationResult>();
            var EmployeeService = (Service.EmployeeService)validationContext.GetService(typeof(Service.EmployeeService));
            if (!EmployeeService.IsValidDepartment(this.DepartmentId))
            
                result.Add(new ValidationResult("This DepartmentId does not exists"));
            
            return result;
        
    

存储库:员工存储库

using System.Collections.Generic;
using System.Linq;

namespace ValidationContextDemo.Models

    public class EmployeeRepository
    
        public EmployeeRepository()
        
            Employees = new List<Employee>()  
            new EmployeeId=1, Name="Alpha", DepartmentId=1,
            new EmployeeId=2, Name="Beta", DepartmentId=1,
            new EmployeeId=3, Name="Gamma", DepartmentId=1
            ;
        
        public List<Employee> Employees  get; set; 

        public void AddEmployee(Employee e)
        
            Employees.Add(e);
        

        public void UpdateEmployee(int id, Employee e)
        
            Employee emp = Employees.Where(x => x.Id == id).FirstOrDefault();
            emp.Name = e.Name;
            emp.DepartmentId = e.DepartmentId;
        

        public void DeleteEmployee(Employee e)
        
            Employees.Remove(e);
        
    

验证来源:枚举

namespace ValidationContextDemo.Enums

    public enum Department
    
        Engineering=1,
        Sales=2,
        Shipping=3,
        HumanResources=4
    

服务:员工服务

using System;
using System.Linq;

namespace ValidationContextDemo.Service

    public class EmployeeService
    
        public bool IsValidDepartment(int departmentId)
        
            return Enum.GetValues(typeof(Enums.Department)).Cast<Enums.Department>().Contains((Enums.Department)departmentId);
        
    

IServiceProvider : EmployeeServiceProvider

using System;

namespace ValidationContextDemo.Service

    public class EmployeeServiceProvider: IServiceProvider
    

        public object GetService(Type serviceType)
        
            if (serviceType==typeof(EmployeeService))
            
                return new EmployeeService();
            
            return null;
        
    

控制器:员工控制器

using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using ValidationContextDemo.Models;
using ValidationContextDemo.Service;

namespace ValidationContextDemo.Controllers

    public class EmployeeController : ApiController
    
        EmployeeRepository _repository;
        EmployeeServiceProvider _serviceProvider;
        public EmployeeController()
        
            _repository = new EmployeeRepository();
            _serviceProvider = new EmployeeServiceProvider();
        
        public IHttpActionResult Get()
        
            return Json(_repository.Employees);
        

        public HttpResponseMessage Post(Employee e)
        
            ValidationContext vContext = new ValidationContext(e, _serviceProvider, null);
            e.Validate(vContext);
            _repository.AddEmployee(e);
            return new HttpResponseMessage(HttpStatusCode.Created);
        

    

注意Employee模型的Validate方法中的ValidationContext参数。在模型绑定之前,验证发生时,ValidationContext 的 IServiceProvider 部分为空。

因此,在模型绑定之后,当代码到达我的控制器操作“Post”内部时,我会使用 _serviceProvider 创建另一个 ValidationContext 并再次调用 Validate。

我的问题是,如何在模型绑定之前在我的 ValidationContext 中拥有这个 _serviceProvider。

如果还不清楚,请告诉我。

注意:我为了这个问题创建了这个例子,在这个例子中我没有使用 Autofac 作为 DI 容器。

【问题讨论】:

你能发布你的代码吗? 当然,马蒂,我需要一些时间.. @MattyM,我发布了我正在使用的代码。这是此问题的示例代码。如果有什么遗漏,请告诉我。 【参考方案1】:

首先,您上面的代码示例与您面临的问题完全无关,因为您可以通过在 Employee 模型中进行简单的空检查来解决该问题,因为您正在显式验证它:

ValidationContext vContext = new ValidationContext(e, _serviceProvider, null);
e.Validate(vContext);

我假设(理想情况下)你不想明确地这样做,不幸的是没有简单的方法。您必须设置大量管道(即模型绑定器等)才能连接到 MVC/WebApi 管道。 This solution 很可能会为您工作,如果您有时间关注它:)。

PS:该解决方案适合 MVC,但我看不出有任何理由可以针对 API 进行调整。

【讨论】:

以上是关于如何在 IValidatableObject.Validate 方法的 ValidationContext 参数中提供 IServiceProvider的主要内容,如果未能解决你的问题,请参考以下文章

如何在表单提交后保留文本(如何在提交后不删除自身?)

如何在异步任务中调用意图?或者如何在 onPostExecute 中开始新的活动?

在 Avkit 中如何使用这三行代码,以及如何将音乐静音”

如何在 JDBC 中启动事务?

如何在 Fragment 中调用 OnActivityResult 以及它是如何工作的?

如何使用 Firebase 在 Web 上托管 Flutter?它的效果如何?