0

Я изучаю с идентичностью asp.net, асинхронным/Await, и у меня есть эта проблема:метод Асинхронного синтаксис запроса

У меня есть некоторые функции для IEnumerable<T> list. Этот список я заливка с использованием синтаксиса запросов и выглядит следующим образом:

private IEnumerable<SomeModel> GetPersons(int categoryId) { 
IEnumerable<SomeModel> persons = from g in db.Categories 
           join c in db.Persons on g.PersonTypeId equals c.PersonTypeId 
           where g.CategoryId == categoryId 
           select new SomeModel 
           { 
            PersonName = c.FirstName + " " + c.LastName, 
            //....etc. 
            //And here I need call asynchronous function something like this: 
            IsAdmin = GetPermission(c.Email) 
           } 
    if (persons.Any()) { 
     return persons; 
    } 

    return Enumerable.Empty<SomeModel>(); 
} 

В SomeModel является IsAdmin, как BOOL (когда я попытался Task<bool> в GetPermission я использую Task<bool> в SomeModel). В GetPermission() это:

private bool GetPermission(string email) { 
    var user = SomeMembershipService.GetUser(email); //SomeMembershipService is Interface with Tasks and so on. 
    var roles = SomeMembershipService.GetRoles(user.Id); //user.Id is as string 
    bool result = false; 
    if (roles != null) { 
     var adm = roles.Result.FirstOrDefault(x => x.Name.Contains("Admin")); 
     result = adm != null; 
    } 
    return result; 
} 

Я попробовал эту запись с асинхронным/ждать и как задача, но обе мои попытки были ложными. Поэтому я подумал, что мне нужно позвонить GetPermission() за пределами IEnumerable<SomeModel> persons, поэтому я добавлю этот блок кода в состояние после. Поэтому код выглядит так:

private IEnumerable<SomeModel> GetPersons(int categoryId) { 
    IEnumerable<SomeModel> persons = from g in db.Categories 
            join c in db.Persons on g.PersonTypeId equals c.PersonTypeId 
            where g.CategoryId == categoryId 
            select new SomeModel 
            { 
             PersonName = c.FirstName + " " + c.LastName 
             //....etc. 
            } 
    if (persons.Any()) 
    { 
     //new code 
     foreach (var p in persons) 
     { 
      p.IsAdmin = GetPermission(p.Email); 
     } 
     //end of new code 
     return persons; 
    } 

    return Enumerable.Empty<SomeModel>(); 
} 

Но это тоже неправильно. Может быть, я понимаю, что плохой идентификатор asp.net и async/await и их использование ... Можете ли вы мне помочь - что мне делать? Потому что теперь GetPermission называется слишком поздно, поэтому приложение сбой. Когда я вызываю GetPermission в запрос лиц, функция называется слишком поздней (после списка заполненных лиц). Я не знаю, как продолжить.

GetUser() - public IUser GetUser(string username) и GetRoles() - public async Task<IEnumerable<IRole>> GetRoles(string userId). Я уверен, что эти два метода работают нормально, я использую их в других кодах и никаких проблем с ними. Значит, это должно быть где-то в коде выше.

Прошу прощения, если это глупый вопрос, но я читал об этой лоте здесь и о msdn, но не могу найти результат. Спасибо всем.


Почему я хочу использовать функцию асинхронной, как описано выше

Я хочу функцию там, потому что, когда я делаю всю функцию асинхронной задачи, другую функцию, которая называют это не работает должным образом.

У меня есть эта функция - это привязки данных для kendogrid():

[HttpPost] 
public ActionResult _PersonsBinding([DataSourceRequest]DataSourceRequest request, int id) 
{ 
    DataSourceResult result = GetPersons(id).ToDataSourceResult(request); 
    return Json(result); 
} 

Когда я делаю функцию IEnumerable<SomeModel> GetPersons, как async Task<IEnumerable<SomeModel>> GetPersons функция связывания не знает ToDataSourceResult(), когда я делаю эту функцию асинхронной тоже. Если это может быть проблема, как я могу ее исправить? Пожалуйста, проявите терпение, я новичок ...

+0

Почему вы проверяете 'if (persons.Any())', это не повлияет, если вы вернете 'person' или' Enumerable.Empty (); ' –

+0

Были проблемы с возвратом только лица. Я не помню, почему, но это помогло. Это для Кендогрида. Но я думаю, что это не причина моей проблемы. – goldJ

+0

Можете ли вы сказать, почему вы хотите, чтобы там было асинхронное funtionion, кажется, для меня нет смысла! Почему бы вам не поставить всю функцию в async-задачу? –

ответ

0

Хорошо, я разрешаю. Ошибка была не в коде выше, проблема была в async Task<IEnumerable<IRole>> GetRoles(string userId). Этот метод работает отлично, но это плохо для моего кода выше.

Асинхронный получение ролей выглядит следующим образом:

public async Task<IEnumerable<IRole>> GetRolesAsync(string userId) 
{ 
    return await IdentityManager.Roles.GetRolesForUserAsync(userId); 
} 

Но я должен был использовать получать роли, который является в коде ниже. Я сделал новый метод в IMembershipService - public IEnumerable<IRole> GetRoles(string userId) (первый метод переименованного GetRolesAsync) и выглядит следующим образом:

public IEnumerable<IRole> GetRoles(string userId) 
{ 
    return AsyncHelper.RunSync(() => IdentityManager.Roles.GetRolesForUserAsync(userId)); 
} 

Это возвращает общий IEnumerable<T>. По крайней мере, я могу использовать функцию GetPermissions в sql-запросе. GetPermission() теперь выглядит следующим образом:

private bool GetPermission(string email) { 
    var user = SomeMembershipService.GetUser(email); 
    var roles = SomeMembershipService.GetRoles(user.Id); 

    bool result = false; 
    if (roles != null) { 
     var adm = roles.FirstOrDefault(x => x.Name.Contains("Admin")); 
     result = adm != null; 
    } 
    return result; 
} 

в SQL запросе я могу теперь использовать это:

.... 
select new SomeModel 
           { 
            PersonName = c.FirstName + " " + c.LastName, 
            IsAdmin = GetPermission(c.Email) // <-- This 
           } 
.... 

спасибо всем, особенно Jeroen, которые пытались помочь.

0

Ваша проблема не в асинхронном/ожидании. Ваша проблема в том, что вы выполняете запрос больше, чем один. Каждый foreach/ToList/ToArray и т. Д. Выполнит запрос с самого начала и создаст новые объекты. Поскольку в глубине linq результаты получаются с `yield return new {.....} 'и будут создавать новые объекты. Вот почему вы теряете бит IsAdmin на следующем foreach. (за пределами метода)

if (persons.Any()) 
{ 
    // !HERE! <- foreach. this will run the query. 
    foreach (var p in persons) 
    { 
     p.IsAdmin = GetPermission(p.Email); 
    } 

    //Where you foreach in it's caller. 
    return persons; 
} 

Вам нужно материализовать запрос первым. Вы можете исправить это с помощью ToArray()/ToList(). Таким образом, запрос является выполненным, повторным и сохраняется как массив.

private IEnumerable<SomeModel> GetPersons(int categoryId) 
{ 
    IEnumerable<SomeModel> persons = (from g in db.Categories 
            join c in db.Persons on g.PersonTypeId equals c.PersonTypeId 
            where g.CategoryId == categoryId 
            select new SomeModel 
            { 
             PersonName = c.FirstName + " " + c.LastName 
             //....etc. 
            }).ToArray(); // <------ here 
    foreach (var p in persons) 
    { 
     p.IsAdmin = GetPermission(p.Email); 
    } 

    //end of new code 
    return persons; 
} 

Если вы хотите совместить GetPermission() и запрос, вы должны создать SQL-функции.

+0

Второй пример, который я попробовал, но сбой приложения. В первом случае я пытался, как вы писали, но никаких изменений. – goldJ

+0

Первый - это ваш пример, показывающий пятна foreach. Какое исключение вы получили на втором? –

+0

Ошибка в журнале или отладка. Он «замораживается» в строке в GetPermissions() - здесь «var adm = role.Result.FirstOrDefault (x => x.Name.Contains (« Admin »)); 'и после долгого времени я получаю только таймаут соединения (соединение верно, я уверен). – goldJ

Смежные вопросы