Добавить статью в Controler Asp net .core - PullRequest
0 голосов
/ 31 августа 2018

Я пытаюсь добавить Article из моего контроллера. Но это не работает. Когда я пользуюсь почтальоном, я получаю ошибку 500

ServiceFilter(typeof(LogUserActivity))]
[Route("api/users/{userId}/[controller]")]
[ApiController]
public class ArticleController : ControllerBase
{
    private readonly IPrmRepository _repo;
    private readonly IMapper _mapper;
    public ArticleController(IPrmRepository repo, IMapper mapper)
    {
        _mapper = mapper;
        _repo = repo;
    }

    public async Task<IActionResult> CretaArticle(int userId, ArticleForCreation articleForCreation)
    {
        var author = await _repo.GetUser(userId, false);
        //check autorization

        if (author.Id != int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value))
            return Unauthorized();

        articleForCreation.AuthorId = userId;

        var article = _mapper.Map<Article>(articleForCreation);

        _repo.Add(article);

        if (await _repo.SaveAll())
        {
            //Mapp Data to return db
            var articleToReturn = _mapper.Map<ArticleToReturnDto>(article);
            return CreatedAtRoute("GetArticle", new {id = article.ArticleId}, articleToReturn);
        }

        throw new Exception("Creating the article failed on save");
    }

Модели, отвечающие за модель в базе данных:

public class Article
{
    public int ArticleId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int AuthorId{get; set;}
    public User Author { get; set; }
}

Дтос:

public class ArticleForCreation
{
    public int AuthorId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

}

public class ArticleToReturnDto
{
    public int Id { get; set; }
    public int AuthorId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
}

AutomapperProfile, отображающий данные в базу данных:

CreateMap<ArticleForCreation, Article>().ReverseMap();
CreateMap<Article, ArticleToReturnDto>();

Может кто-нибудь помочь вам понять, почему он не работает?

1 Ответ

0 голосов
/ 31 августа 2018

Невозможно точно помочь вам без фактического исключения. Однако следующая строка кричит «ошибка»:

if (author.Id != int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value))

У вас есть потенциал NullReferenceException, FormatException и ArgumentNullException, все из этой одной линии.

Во-первых, ни ваш контроллер, ни действие не украшены атрибутом Authorize, и вы не предоставили никакой информации о запросе, который вы делаете, и о том, используете ли вы даже что-то вроде заголовка Authorization с этим, ни с тем, правильно ли вы настроили аутентификацию в Startup.cs, чтобы использовать это, не так ли? Скорее всего, есть вероятность, что на самом деле не существует принципала пользователя, от которого можно получить претензию.

Каждый раз, когда у вас есть что-то, что может быть нулевым (например, возвращение из User.FindFirst), вы должны выполнить проверку на ноль. Это может быть фактический оператор if или троичный, нуль-слияние (??) или более новый нуль-условный (?.). В противном случае, если вы попытаетесь получить доступ к члену из экземпляра, который оказывается пустым, вы получите NullReferenceException. Для этого на самом деле лучшее, что вы можете сделать, это просто использовать User.FindFirstValue вместо этого, что устраняет необходимость разыменования элемента Value впоследствии.

Далее, если возвращаемое значение FindFirstValue заканчивается null, int.Parse выдает ArgumentNullException, поскольку вы не можете разобрать null в int. В результате вам нужно убедиться, что значение не равно нулю, прежде чем вызывать это.

Тогда, если идентификатор на самом деле не является чем-то, что может быть проанализировано в int, как, например, GUID, вы в конечном итоге выбросите FormatException. Вы можете знать, что это int, но вы всегда должны защищать свой код от возможных изменений в будущем. Когда вам нужно проанализировать строку в int (или в любом другом примитивном типе), вы всегда должны использовать TryParse:

if (int.TryParse(myString, out int i)
{
     // you can now use `i` as the parsed int for whatever you need
}

Короче говоря, это гораздо лучший способ написать эту строку кода:

if (!int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier), out int id) || author.Id != id)
    return Unauthorized();

По сути, это говорит о том, что если значение заявки равно нулю / не может быть проанализировано как int или не совпадает с идентификатором автора, то возвращает Unauthorized().

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