我学习了asp.net身份,async / 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(当我在GetPermission中尝试Task<bool>
时,我在SomeModel中使用Task<bool>
。
在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;
}
我尝试使用async / await和Task执行此操作,但我的尝试都是错误的。所以我认为我必须在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身份和异步/等待以及它们的使用......
你能帮助我 - 我该怎么办?因为现在,调用GetPermission
太晚了,所以app崩溃了。当我在人员查询中调用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 :(得分:0)
您的问题与async / await无关。您的问题是因为您执行的查询多于一个。每个foreach / ToList / ToArray等都将从头开始执行查询,并将创建新对象。因为linq内部的结果是`yield return new {.....}'并且会创建新对象。这就是为什么你在下一个foreach上失去了IsAdmin位的原因。 (方法之外)
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函数。
答案 1 :(得分: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>
。至少我可以在sql查询中使用我的函数GetPermissions。 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,他们试图提供帮助。