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

时间:2015-05-13 11:20:46

标签: c# asp.net asp.net-mvc inversion-of-control autofac

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

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

此stackoverflow问题可能包含答案,但我完全不理解: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;
        }
    }
}

存储库:EmployeeRepository

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

namespace ValidationContextDemo.Models
{
    public class EmployeeRepository
    {
        public EmployeeRepository()
        {
            Employees = new List<Employee>() { 
            new Employee{Id=1, Name="Alpha", DepartmentId=1},
            new Employee{Id=2, Name="Beta", DepartmentId=1},
            new Employee{Id=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);
        }
    }
}

验证来源:Enum

namespace ValidationContextDemo.Enums
{
    public enum Department
    {
        Engineering=1,
        Sales=2,
        Shipping=3,
        HumanResources=4
    }
}

服务:EmployeeService

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;
        }
    }
}

Controller:EmployeeController

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部分为空。

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

我的问题是,如何在模型绑定之前在我的ValidationContext中使用此_serviceProvider。

如果仍然不清楚,请告诉我。

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

1 个答案:

答案 0 :(得分:0)

首先,您的上述代码示例与您所面临的问题无关,因为您可以通过在Employee模型中进行简单的空检查来解决问题,因为您明确地验证了它:

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

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

PS:解决方案迎合了MVC,但我没有看到任何可以为API调整的原因。