В Web API.Core, как сделать проверку модели в каждом методе? - PullRequest
0 голосов
/ 23 мая 2018

Я вхожу в ASP.Net Core 2.0 с веб-API.

Один из моих первых методов - мой логин:

/// <summary>
/// API endpoint to login a user
/// </summary>
/// <param name="data">The login data</param>
/// <returns>Unauthorizied if the login fails, The jwt token as string if the login succeded</returns>
[AllowAnonymous]
[Route("login")]
[HttpPost]
public IActionResult Login([FromBody]LoginData data)
{
    var token = _manager.ValidateCredentialsAndGenerateToken(data);
    if (token == null)
    {
        return Unauthorized();
    }
    else
    {
        return Ok(token);
    }
}

Мой LoginData с использованием DataAnnotations:

public class LoginData
{
    [Required]
    [MaxLength(50)]
    public string Username { get; set; }

    [Required]
    public string Password { get; set; }

    [Required]
    [MaxLength(16)]
    public string IpAddress { get; set; }
}

Таким образом, мой ModelState автоматически заполняется автоматически, когда происходит вход в систему, и, например, пароль пуст (конечно, на стороне клиента должна быть проверка для него позже).

Мой вопросявляется:
Каков наилучший способ а) проверить состояние модели, б) получить читаемую строку из всех ошибок и в) вернуть BadRequest с этой ошибкой?

Конечно, я мог бы написать этовсе сам в вспомогательном методе ... Но я подумал о фильтре, может быть?

Ответы [ 3 ]

0 голосов
/ 23 мая 2018

Чтобы проверить, является ли состояние модели действительным, используйте свойство ModelState (предоставляемое классом ControllerBase, от которого наследуется класс Controller)

ModelState.IsValid

Чтобы получить ошибки из ModelState, вы можете отфильтровать ошибкииз словаря и вернуть их в виде списка

var errors = ModelState
    .Where(a => a.Value.Errors.Count > 0)
    .SelectMany(x => x.Value.Errors)
    .ToList();

Затем можно проверить состояние в каждом методе / контроллере, но я рекомендую вам выполнить проверку в базовом классе, который проверяет модель в
Метод OnActionExecuting, подобный этому

public class ApiController : Controller
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!ModelState.IsValid)
        {
            var errors = ModelState
                .Where(a => a.Value.Errors.Count > 0)
                .SelectMany(x => x.Value.Errors)
                .ToList();
            context.Result = new BadRequestObjectResult(errors);
        }
        base.OnActionExecuting(context);
    }
}

Тогда каждый контроллер, который должен иметь автоматическую проверку состояния модели, просто наследуется от базового класса

public class TokenController : ApiController
{
    /// <summary>
    /// API endpoint to login a user
    /// </summary>
    /// <param name="data">The login data</param>
    /// <returns>Unauthorizied if the login fails, The jwt token as string if the login succeded</returns>
    [AllowAnonymous]
    [Route("login")]
    [HttpPost]
    public IActionResult Login([FromBody]LoginData data)
    {
        var token = _manager.ValidateCredentialsAndGenerateToken(data);
        if (token == null)
        {
            return Unauthorized();
        }
        else
        {
            return Ok(token);
        }
    }
}
0 голосов
/ 12 июня 2019

Я бы настоятельно рекомендовал использовать [ApiController] и другие атрибуты, которые помогают упростить проверку в проектах на основе веб-API.

[ApiController] этот атрибут выполняет всю базовую проверку для модального режима перед тем, как он входит в метод.Таким образом, вам нужно только проверить модальный режим, если вы хотите выполнить какую-либо форму пользовательской проверки.

0 голосов
/ 23 мая 2018

Как проверить состояние модели?

Проверьте контроллер ModelState в действии, чтобы получить состояние модели.

получениечитаемая строка из всех ошибок и возвращает BadRequest с этой ошибкой?

Используйте BadRequest(ModelState), чтобы вернуть HTTP-запрос неверного запроса, который проверит состояние модели и создаст сообщение с использованием ошибок.

Завершенный код

/// <summary>
/// API endpoint to login a user
/// </summary>
/// <param name="data">The login data</param>
/// <returns>Unauthorizied if the login fails, The jwt token as string if the login succeded</returns>
[AllowAnonymous]
[Route("login")]
[HttpPost]
public IActionResult Login([FromBody]LoginData data) {
    if(ModelState.IsValid) {
        var token = _manager.ValidateCredentialsAndGenerateToken(data);
        if (token == null) {
            return Unauthorized();
        } else {
            return Ok(token);
        }
    }
    return BadRequest(ModelState);
}

Конечно, я мог бы написать все сам вспомогательным методом ... Но я подумал о фильтре, может быть?

Чтобы избежатьповторяющийся код ModelState.IsValid в каждом действии, где требуется проверка модели, вы можете создать фильтр для проверки состояния модели и короткого замыкания запроса.

Например,

public class ValidateModelAttribute : ActionFilterAttribute {
    public override void OnActionExecuting(ActionExecutingContext context) {
        if (!context.ModelState.IsValid) {
            context.Result = new BadRequestObjectResult(context.ModelState);
        }
    }
}

Может применятьсянепосредственно к действию

[ValidateModel] //<-- validation
[AllowAnonymous]
[Route("login")]
[HttpPost]
public IActionResult Login([FromBody]LoginData data) {
    var token = _manager.ValidateCredentialsAndGenerateToken(data);
    if (token == null) {
        return Unauthorized();
    } else {
        return Ok(token);
    }    
}

или добавлено глобально для применения ко всем запросам, где необходимо проверить состояние модели.

Ссылка Проверка модели в ASP.NET Core MVC

...