Возвращение кодов состояния из класса за пределами моего контроллера - PullRequest
0 голосов
/ 18 апреля 2019

Я пытаюсь перенести логику, которую я выполняю на всех своих контроллерах, в класс, чтобы следовать принципу «Не повторяй себя».То, с чем я борюсь, это как элегантно вернуть код ошибки.

Вот несколько примеров того, что я сейчас делаю в каждом контроллере:

public class SomethingRequest
{
    public SomethingModel Something { get; set; }


    public string Token { get; set; }
}

public ActionResult GetSomething(SomethingRequest request)
{

    var something = request.Something;

    var token = request.Token;

    if (something == null)
    {        
        return BadRequest("Something object is null. You may have sent data incorrectly");
    }

    if (token == null || token != "1234")
    {
        return Unauthorized("Token object is null");
    }
}

Теперь я хочу переместитьпоследние две части этого в свой собственный класс:

public class RequestValidation
{

    public void TokenCheck(string token)
    {
        if (token == null || token != "1234")
        {
            // doesn't work
            return Unauthorized("Token object is null");
        }
    }

    public void DataCheck(object someObject)
    {
        if (someObject == null)
        {
            // doesn't work
            return BadRequest("Object is null. You may have sent data incorrectly");
        }
    }       
}

А потом я хочу вызвать их из SomethingController, например,

RequestValidation.TokenCheck(token);

и

RequestValidation.DataCheck(something);

и затем попросите их вернуть неверный запрос или исключение.

Как мне это сделать?

Ответы [ 2 ]

1 голос
/ 18 апреля 2019

Обычный способ сделать это - иметь вспомогательный класс, который возвращает результат проверок и / или операций в контроллер:

public class ValidationResult
{
    public bool Succeeded { get; set; }
    public string Message { get; set; }
    public int StatusCode { get; set; }
}

Поскольку вопрос помечен с помощью ASP.NET Core, правильный способ сделать это - сначала создать интерфейс:

public interface IRequestValidationService
{
    ValidationResult ValidateToken(string token);
    ValidationResult ValidateData(object data);
}

Затем создайте реализацию:

public class RequestValidationService : IRequestValidationService
{
    public ValidationResult ValidateToken(string token)
    {
        if (string.IsNullOrEmpty(token) || token != "1234")
        {
            return new ValidationResult
            {
                Succeeded = false,
                Message = "invalid token",
                StatusCode = 403
            };
        }

        return new ValidationResult { Succeeded = true };
    }

    ...
}

Добавьте его в контейнер DI (в классе запуска):

services.AddScoped<IRequestValidationService, RequestValidationService>();

Вставьте его в SomethingController:

public SomethingController(IRequestValidationService service)
{
    _requestValidationService = service;
}

И, наконец, используйте его:

public IActionResult GetSomething(SomethingRequest request)
{
    var validationResult = _requestValidationService.ValidateToken(request?.Token);

    if (!validationResult.Succeeded)
    {
        return new StatusCode(validationResult.StatusCode, validationResult.Message);
    }
}

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

public class SomethingRequest
{
    [Required(ErrorMessage = "Something is required, check your data")]
    public SomethingModel Something { get; set; }

    [Required(ErrorMessage = "Token is required!")]
    public string Token { get; set; }
}
0 голосов
/ 22 апреля 2019

@ Идея Камило Теревинто вывела меня на правильный путь.Его метод сработает, но из того, что я прочитал в документации , правильный способ - "1003 * Фильтры действий ".

Я использовал эту статью как дополнительное вдохновение.

Вот мой фильтр, который я назвал ValidationFilterAttribute

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Routing;
using System.Diagnostics;
using Microsoft.Extensions.Logging;

namespace Name_Of_Project.ActionFilters
{   
    // This filter can be applied to classes to do the automatic token validation.
    // This filter also handles the model validation.
    // inspiration https://code-maze.com/action-filters-aspnetcore/
    public class ValidationFilterAttribute: IActionFilter
    {
        // passing variables into an action filter https://stackoverflow.com/questions/18209735/how-do-i-pass-variables-to-a-custom-actionfilter-in-asp-net-mvc-app    

        private readonly ILogger<ValidationFilterAttribute> _logger;
        public ValidationFilterAttribute(ILogger<ValidationFilterAttribute> logger)
        {
            _logger = logger;
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            //executing before action is called

            // this should only return one object since that is all an API allows. Also, it should send something else it will be a bad request
            var param = context.ActionArguments.SingleOrDefault();
            if (param.Value == null)
            {
                _logger.LogError("Object sent was null. Caught in ValidationFilterAttribute class.");
                context.Result = new BadRequestObjectResult("Object sent is null");
                return;
            }

            // the param should be named request (this is the input of the action in the controller)
            if (param.Key == "request")
            {
                Newtonsoft.Json.Linq.JObject jsonObject = Newtonsoft.Json.Linq.JObject.FromObject(param.Value);

                // case sensitive btw
                string token = jsonObject["Token"].ToString();

                // check that the token is valid
                if (token == null || token != "1234")
                {
                    _logger.LogError("Token object is null or incorrect.");
                    context.Result = new UnauthorizedObjectResult("");
                    return;
                }
            }

            if (!context.ModelState.IsValid)
            {
                context.Result = new BadRequestObjectResult(context.ModelState);
            }
        }


        public void OnActionExecuted(ActionExecutedContext context)
        {
            // executed after action is called
        }
    }
}

Тогда мой Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    // Adding an action Filter
    services.AddScoped<ValidationFilterAttribute>();

}

Затем я могу добавить его в свой контроллер.


using Name_Of_Project.ActionFilters;

namespace Name_Of_Project.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class SomethingController : ControllerBase
    {

        // POST api/something
        [HttpGet]
        [ServiceFilter(typeof(ValidationFilterAttribute))]
        public ActionResult GetSomething(SomethingRequest request)
        {
            var something= request.Something;

            var token = request.Token;
    }
}

Поскольку я хочу многократно использовать этот фильтр действий, мне нужно найти способ передачи параметра длянулевая проверка (может быть много разных объектов, входящих под именем «request», которые необходимо проверить). Это ответ Я буду искать эту часть решения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...