asp.net 查询语法中的异步方法

ccgok5k5  于 2023-05-08  发布在  .NET
关注(0)|答案(2)|浏览(103)

我使用asp.net identity,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和as Task,但两次尝试都失败了。所以我想我必须在IEnumerable<SomeModel> persons之外调用GetPermission(),所以我把这段代码添加到condition after中。代码看起来像这样:

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>();
}

但这也是错误的。也许我对www.example.com的asp.net身份和async/await以及它们的用途理解不好...你能帮我-我该做什么吗?因为现在调用GetPermission太晚了,所以app崩溃了。当我在persons query中调用GetPermission时,函数也被调用得太晚了(在填充了persons list之后)。我不知道该怎么继续。
GetUser()public IUser GetUser(string username)GetRoles()public async Task<IEnumerable<IRole>> GetRoles(string userId)。我敢肯定,这两种方法工作正常,我用他们在其他代码和没有问题与他们.所以我认为它应该在代码的某个地方。
我很抱歉,如果这是愚蠢的问题,但我读了很多关于这个在这里和msdn,但找不到结果。感谢所有人。

我为什么要用上面的async函数

我希望函数在那里,因为当我把整个函数作为异步任务时,另一个调用this的函数不能正常工作。
我有这个函数-它是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(),当我将此函数设置为async时。如果这里有问题,我该如何解决?请耐心等待,我是一个新手。

mwkjh3gx

mwkjh3gx1#

你的问题不在于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()来修复此问题。这样,查询被执行、迭代并存储为Array。

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-Function。

nwwlzxa7

nwwlzxa72#

好吧,我解决了。错误不在上面的代码中,问题在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));
}

这将返回common 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
                               }
....

感谢所有人,特别是杨伦,他试图帮助。

相关问题