访问WebApi 2的FluentValidation中的路径数据

时间:2016-03-03 20:22:17

标签: c# asp.net-web-api fluentvalidation

我有一个基本的C#Web Api 2控制器,它有一个POST方法来创建一个实体

public HttpResponseMessage Post(UserModel userModel){ ... }

还有一个更新所述模型的PUT方法

public HttpResponseMessage Put(int id, UserModel userModel) { ... }

这是UserModel

public class UserModel
{
    public virtual Name { get; set; }
    public virtual Username { get; set; }
}

对于我的验证器,我想验证该名称未在Post上使用 - 很简单。对于PUT,我需要验证其他用户不会使用该名称,但当然这个特定用户将拥有相同的用户名。

public class UserModelValidator : AbstractValidator<UserModel>
{
    public UserModelValidator()
    {
        RuleFor(user => user.Username)
            .Must(NotDuplicateName).WithMessage("The username is taken");

    }

    private bool NotDuplicateName(string username)
    {
        var isValid = false;

        //Access repository and check to see if username is not in use
        //If it is in use by this user, then it is ok - but user ID is
        //in the route parameter and not in the model.  How do I access?

        return isValid;
    }
}

我正在使用AutoFac,所以也许有办法将HttpRequest注入验证器并以这种方式获取路径数据。

或者我可以创建一个模型绑定器来查找路径数据并将其添加到模型中?

或者有一种简单的方法吗?

2 个答案:

答案 0 :(得分:0)

最简单的方法是将Id添加到UserModel。您必须在PostPut操作上添加一些额外的检查。第一个应该在客户端提供它时忽略Id。第二个可以检查路径中的Id是否与模型中的Id相同。如果没有,则返回BadRequest

改变型号:

public class UserModel
{
    public virtual Id { get; set; }
    public virtual Name { get; set; }
    public virtual Username { get; set; }
}

改变方法:

public HttpResponseMessage Post(UserModel userModel)
{
   // ignore provided userModel.Id
}

public HttpResponseMessage Put(int id, UserModel userModel)
{
   if(id != userModel.Id)
   {
       // return bad request response
   }
}

<强>更新

在路线和模型中都有Id确实允许两者之间存在差异,如您所评论的那样。尊重的API消费者可能不会发布带有未对齐ID的请求。但是恶意消费者(也就是黑客)最有可能会这样做。因此,当Ids不匹配时,您应该返回BadRequest

您当然不希望使用Id更新UserModel,否则您可能最终会被用户2的详细信息覆盖(用户2的详细信息)({ {1}})。

答案 1 :(得分:0)

我找到了另一种将 console.log('index', index) 注入验证器的解决方案。有了这个,我可以访问 ROUTE 参数,而无需特殊的模型绑定。

Startup.cs

IActionContextAccessor

UserModelValidator.cs

services.AddHttpContextAccessor();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();