Dependency-Injected Validation in Web API

后端 未结 6 955
遥遥无期
遥遥无期 2021-02-04 09:05

In MVC, I can create a Model Validator which can take Dependencies. I normally use FluentValidation for this. This allows me to, for example, check on account registration tha

6条回答
  •  佛祖请我去吃肉
    2021-02-04 09:46

    I was able to register and then access the Web API dependency resolver from the request using the GetDependencyScope() extension method. This allows access to the model validator when the validation filter is executing.

    Please feel free to clarify if this doesn't solve your dependency injection issues.

    Web API Configuration (using Unity as the IoC container):

    public static void Register(HttpConfiguration config)
    {
        config.DependencyResolver   = new UnityDependencyResolver(
            new UnityContainer()
            .RegisterInstance(new MyContext())
            .RegisterType()
    
            .RegisterType()
        );
    
        config.Routes.MapHttpRoute(
            name:           "DefaultApi",
            routeTemplate:  "api/{controller}/{id}",
            defaults:       new { id = RouteParameter.Optional }
        );
    }
    

    Validation action filter:

    public class ModelValidationFilterAttribute : ActionFilterAttribute
    {
        public ModelValidationFilterAttribute() : base()
        {
        }
    
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            var scope   = actionContext.Request.GetDependencyScope();
    
            if (scope != null)
            {
                var validator   = scope.GetService(typeof(AccountValidator)) as AccountValidator;
    
                // validate request using validator here...
            }
    
            base.OnActionExecuting(actionContext);
        }
    }
    

    Model Validator:

    public class AccountValidator : AbstractValidator
    {
        private readonly MyContext _context;
    
        public AccountValidator(MyContext context) : base()
        {
            _context = context;
        }
    
        public override ValidationResult Validate(ValidationContext context)
        {
            var result      = base.Validate(context);
            var resource    = context.InstanceToValidate;
    
            if (_context.Accounts.Any(account => String.Equals(account.EmailAddress, resource.EmailAddress)))
            {
                result.Errors.Add(
                    new ValidationFailure("EmailAddress", String.Format("An account with an email address of '{0}' already exists.", resource.EmailAddress))
                );
            }
    
            return result;
        }
    }
    

    API Controller Action Method:

    [HttpPost(), ModelValidationFilter()]
    public HttpResponseMessage Post(Account account)
    {
        var scope = this.Request.GetDependencyScope();
    
        if(scope != null)
        {
            var accountContext = scope.GetService(typeof(MyContext)) as MyContext;
            accountContext.Accounts.Add(account);
        }
    
        return this.Request.CreateResponse(HttpStatusCode.Created);
    }
    

    Model (Example):

    public class Account
    {
        public Account()
        {
        }
    
        public string FirstName
        {
            get;
            set;
        }
    
        public string LastName
        {
            get;
            set;
        }
    
        public string EmailAddress
        {
            get;
            set;
        }
    }
    
    public class MyContext
    {
        public MyContext()
        {
        }
    
        public List Accounts
        {
            get
            {
                return _accounts;
            }
        }
        private readonly List _accounts = new List();
    }
    

提交回复
热议问题