Реализация проверки подлинности Entity Framework / WebApi 2

asp.net-web-api asp.net-web-api2 c# entity-framework entity-framework-6

Вопрос

Я пишу простое приложение «Todo», используя ASP.NET WebApi 2 и Entity Framework 6.1.0-alpha1. Моя цель - ограничить доступ, каждый пользователь должен только просматривать / редактировать свои собственные Todos.

Пример:

    // GET api/Todo/5
    [ResponseType(typeof(Todo))]
    public async Task<IHttpActionResult> GetTodo(int id)
    {
        var todo = await _db.Todos.FindAsync(id);

        if (todo == null)
        {
            return NotFound();
        }

        if (todo.CreatorId != _currentUser.Id)
        {
            return StatusCode(HttpStatusCode.Forbidden); 
        }

        return Ok(todo);
    }

Это нормально. Аналогичная проверка добавлена ​​для удаления, а при создании она устанавливает CreatorId на текущий идентификатор пользователя. Однако у меня проблема с обновлением.

Я попробовал это:

    // GET api/Todo/5
    [ResponseType(typeof(Todo))]
    public async Task<IHttpActionResult> GetTodo(int id)
    {
        var todo = await _db.Todos.FindAsync(id);

        if (todo == null)
        {
            return NotFound();
        }

        if (todo.CreatorId != _currentUser.Id)
        {
            return StatusCode(HttpStatusCode.Forbidden); 
        }

        return Ok(todo);
    }

Однако System.InvalidOperationException оно выбрасывает на отмеченной строке:

System.InvalidOperationException

Прикрепление объекта типа «ModernWeb.Domain.Models.Todo» не удалось, потому что другой объект того же типа уже имеет такое же значение первичного ключа. Это может произойти при использовании метода «Прикрепить» или установки состояния объекта в «Без изменений» или «Модифицировано», если любые объекты на графике имеют конфликтующие значения ключей. Это может быть связано с тем, что некоторые объекты являются новыми и еще не получили значения ключей базы данных. В этом случае используйте метод «Добавить» или «Добавленное» состояние объекта для отслеживания графика, а затем, если необходимо, установите состояние не новых объектов «Без изменений» или «Модифицировано».

Если я удалю блок с помощью FindByAsync (), он не будет генерировать исключение.

Я также попытался использовать _db.Entry(todo).OriginalValue , но не смог найти рабочий синтаксис.

Как я могу решить эту проблему? Любая лучшая практика для подобных ситуаций?

Принятый ответ

Когда вы вызываете FindAsync , возвращаемый экземпляр объекта уже привязан к контексту. Поэтому нет причин для _db.Entry(todo).State = EntityState.Modified;

Обновить

Кажется, я вижу, что вы пытаетесь сделать здесь. Попробуйте это вместо этого:

var original = await _db.Todos.AsNoTracking()
    .SingleOrDefaultAsync(x => x.Id == id);

if (original.CreatorId != _currentUser.Id || original.CreatorId != todo.CreatorId)
{
    return StatusCode(HttpStatusCode.Forbidden);
}
// --- No exception if I remove this block - END ---

_db.Entry(todo).State = EntityState.Modified;

Когда вы вызываете .AsNoTracking().SingleOrDefaultAsync вместо FindAsync , original возвращенный объект не будет привязан к контексту. Затем вы можете установить тот, который был передан в действие контроллера как Modified , и поскольку контекст еще не отслеживает другой объект с тем же идентификатором, вы больше не должны получать это исключение.

В качестве вторичного примечания, поскольку объект Todo, переданный в ваш аргумент, уже имеет свойство Id, не должно быть необходимости передавать его в качестве отдельного аргумента в действие контроллера. Вы должны быть в состоянии сделать это:

var original = await _db.Todos.AsNoTracking()
    .SingleOrDefaultAsync(x => x.Id == id);

if (original.CreatorId != _currentUser.Id || original.CreatorId != todo.CreatorId)
{
    return StatusCode(HttpStatusCode.Forbidden);
}
// --- No exception if I remove this block - END ---

_db.Entry(todo).State = EntityState.Modified;



Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему