当前位置: 首页 > 知识库问答 >
问题:

Web API中的依赖注入验证

杨赞
2023-03-14

在MVC中,我可以创建一个模型验证器,它可以接受依赖关系。我通常使用FluentValidation来实现这一点。例如,这允许我在帐户注册时检查电子邮件地址是否未被使用(注意:这是一个简化的示例):

public class RegisterModelValidator : AbstractValidator<RegisterModel> {
    private readonly MyContext _context;
    public RegisterModelValidator(MyContext context) {
        _context = context;
    }
    public override ValidationResult Validate(ValidationContext<RegisterModel> context) {
        var result = base.Validate(context);
        if (context.Accounts.Any(acc => acc.Email == context.InstanceToValidate.Email)){
            result.Errors.Add(new ValidationFailure("Email", "Email has been used"));
        }
        return result;
    }
}

Web API与FluentValidation不存在这样的集成。在这方面已经进行了几次尝试,但都没有解决依赖注入方面,并且只使用静态验证器。

这是由于MVC和Web API在ModelValidatorProvider和ModelValidator实现上的不同。在MVC中,这些是按请求实例化的(因此注入上下文很容易)。在Web API中,它们是静态的,ModelValidatorProvider维护每个类型的ModelValidator的缓存,以避免对每个请求进行不必要的反射查找。

我自己一直在尝试添加必要的集成,但是一直在尝试获取依赖范围。相反,我想我应该退后一步,询问是否有其他的解决方案来解决这个问题--如果有人想出了在可以注入依赖项的地方执行模型验证的解决方案。

我不想在控制器内执行验证(我正在使用ValidationActionFilter来保持此分离),这意味着我无法从控制器的构造函数注入中获得任何帮助。

共有3个答案

葛炜
2023-03-14

null

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Services.Clear(Type.GetType("System.Web.Http.Validation.IModelValidatorCache, System.Web.Http"));
    }
}
昝晗昱
2023-03-14

null

null

最后,要使 起作用,您需要确保筛选器以特定的顺序执行。

我已经在github上打包了我的解决方案,在NuGet上有一个版本。

沈长恨
2023-03-14

我能够使用GetDependencyScope()扩展方法从请求注册并访问Web API依赖关系解析器。这允许在验证过滤器执行时访问模型验证器。

如果这不能解决您的依赖注入问题,请随时澄清。

Web API配置(使用Unity作为IoC容器):

public static void Register(HttpConfiguration config)
{
    config.DependencyResolver   = new UnityDependencyResolver(
        new UnityContainer()
        .RegisterInstance<MyContext>(new MyContext())
        .RegisterType<AccountValidator>()

        .RegisterType<Controllers.AccountsController>()
    );

    config.Routes.MapHttpRoute(
        name:           "DefaultApi",
        routeTemplate:  "api/{controller}/{id}",
        defaults:       new { id = RouteParameter.Optional }
    );
}

验证操作筛选器:

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

模型验证程序:

public class AccountValidator : AbstractValidator<Account>
{
    private readonly MyContext _context;

    public AccountValidator(MyContext context) : base()
    {
        _context = context;
    }

    public override ValidationResult Validate(ValidationContext<Account> 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;
    }
}

null

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

null

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<Account> Accounts
    {
        get
        {
            return _accounts;
        }
    }
    private readonly List<Account> _accounts = new List<Account>();
}
 类似资料:
  • 本文向大家介绍webapi中如何使用依赖注入,包括了webapi中如何使用依赖注入的使用技巧和注意事项,需要的朋友参考一下 本篇将要和大家分享的是webapi中如何使用依赖注入,依赖注入这个东西在接口中常用,实际工作中也用的比较频繁,因此这里分享两种在api中依赖注入的方式Ninject和Unity;由于快过年这段时间打算了解下vue.js,所以后面对webapi的分享文章可能会慢点更新,希望支持

  • 我有一个控制器 服务接口 我想在我的控制器中使用@autowired来使用该服务,但当我运行应用程序时,我得到以下错误 org.springframework.beans.factory.beanCreationException:创建名为“demo application”的bean时出错:注入autowired依赖项失败;嵌套异常为org.SpringFramework.Beans.Facto

  • 在React中,想做依赖注入(Dependency Injection)其实相当简单。请看下面这个例子: // Title.jsx export default function Title(props) { return <h1>{ props.title }</h1>; } // Header.jsx import Title from './Title.jsx'; export defa

  • 依赖注入 Dependency Injection is a strong mechanism, which helps us easily manage dependencies of our classes. It is very popular pattern in strongly typed languages like C# and Java. 依赖注入是一个很强大的机制,该机制可以帮

  • 简介 Hyperf 默认采用 hyperf/di 作为框架的依赖注入管理容器,尽管从设计上我们允许您更换其它的依赖注入管理容器,但我们强烈不建议您更换该组件。 hyperf/di 是一个强大的用于管理类的依赖关系并完成自动注入的组件,与传统依赖注入容器的区别在于更符合长生命周期的应用使用、提供了 注解及注解注入 的支持、提供了无比强大的 AOP 面向切面编程 能力,这些能力及易用性作为 Hyper

  • 出自维基百科 Wikipedia: 依赖注入是一种允许我们从硬编码的依赖中解耦出来,从而在运行时或者编译时能够修改的软件设计模式。 这句解释让依赖注入的概念听起来比它实际要复杂很多。依赖注入通过构造注入,函数调用或者属性的设置来提供组件的依赖关系。就是这么简单。