Переопределить асинхронный метод с обработкой исключений для результата

Один из методов, с которыми у меня возникают трудности, это:

if (ModelState.IsValid)
{
    var user = new User { UserName = model.Email, Email = model.Email };
    IdentityResult result = null;
    try
    {
        result = await this._userManager.CreateAsync(user, model.Password).Result;
    }
    catch (Exception ex)
    {
    }

    if (result != null && result.Succeeded)
    {
      // not important code
    }
    AddErrors(result);
}

// If we got this far, something failed, redisplay form
return View(model);

Я считаю, что в методе CreateAsync(TUser user, string passwor) есть ошибка (Microsoft.AspNet.Identity, Microsoft.AspNet.IdentityCore.dll, v2.0.0.0). Если я настрою диспетчер пользователей с помощью средства проверки пароля, а пароль не будет проверен, исключения не будет (хороший путь), и IdentityResult будет выглядеть так:

Errors      {string[1]}
- string[]  {string[1]}
-- [0]      "Passwords must have at least...."

Однако при передаче существующего пользователя вместо хорошего IdentityResult метод выдает исключение EntityValidationErrors (неверный путь). Я хотел бы вернуть приведенный выше код к оригиналу без попытки перехвата и действительно полагаться на IdentityResult:

if (ModelState.IsValid)
{
    var user = new User { UserName = model.Email, Email = model.Email };

    var result = this._userManager.CreateAsync(user, model.Password);

    if (result.Succeeded)
    {
      // not important code
    }
    AddErrors(result);
}

И переопределите метод CreateAsync():

public override Task<IdentityResult> CreateAsync(User user, string password)
{
    Task<IdentityResult> result = null;
    try
    {
        var ir = base.CreateAsync(user, password);

        return ??;
    }
    catch (DbEntityValidationException ex)
    {
        var errors = ex.EntityValidationErrors
            .Where(e => e.IsValid)
            .SelectMany(e => e.ValidationErrors)
            .Select(e => e.ErrorMessage)
            .ToArray();
        var ir = new IdentityResult(errors);

        return ??;
    }

    return result;
}

Однако я просто не знаю, как вернуть задачу и правильно ли это направление с точки зрения решения проблемы.

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

result = Task.Factory.StartNew(() =>
{
  return ir;
});

person Erik Philips    schedule 14.05.2014    source источник


Ответы (1)


Просто сделайте свой метод async, await рассматриваемой задачей, а затем просто верните альтернативное значение в предложении catch.

public override async Task<IdentityResult> CreateAsync(User user, string password)
{
    try
    {
        return await base.CreateAsync(user, password);
    }
    catch (DbEntityValidationException ex)
    {
        var errors = ex.EntityValidationErrors
            .Where(e => e.IsValid)
            .SelectMany(e => e.ValidationErrors)
            .Select(e => e.ErrorMessage)
            .ToArray();
        return new IdentityResult(errors);
    }
}
person Servy    schedule 14.05.2014
comment
Я не могу return base.CreateAysnc(), потому что он не выдаст исключение до тех пор, пока не будет получен доступ к свойству .Result, которое находится за пределами этой попытки/поймать. - person Erik Philips; 15.05.2014
comment
@ErikPhilips Правильно, в таком случае просто сделайте метод async, и жизнь станет проще. - person Servy; 15.05.2014
comment
Я не знал, что могу добавить async к override! - person Erik Philips; 15.05.2014
comment
@ErikPhilips async не влияет на общедоступный API метода. Несмотря на то, что он находится в сигнатуре метода, с технической точки зрения любому, кто вызывает этот метод, не нужно знать или заботиться о том, является ли он async. Очевидно, им нужно знать, является ли он асинхронным в более общем смысле, но метод можно сделать асинхронным с использованием или без использования async. (Кроме того, метод async может быть синхронным, если он ничего не ожидает.) - person Servy; 15.05.2014