Будет ли метод работать асинхронно

Объясните, пожалуйста, про асинхронность!

В проекте у меня есть ajax.beginform во View Index.cshtml, в которой выпадающий список и по имени это все отсылается в метод возвращающий частичное представление.

View Index.cshtml

@model IEnumerable<Checkitlink.Models.ViewModels.UserVM>

@{
    ViewBag.Title = "Список пользователей";

    AjaxOptions ajaxSort = new AjaxOptions()
    {
        UpdateTargetId = "list",
        Url = Url.Action("UsersQueryPartial")
    };
}

@using (Ajax.BeginForm(ajaxSort))
        {
            <ul class="navbar-nav userDropdown btn-group btn btn-info" style="margin-right: 15px; border-radius: 15px;">
                <li class="nav-item dropdown">
                    <a class="dropdown-toggle userDropdown" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                        Сортировать
                    </a>
                    <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
                        <li class="dropdown-submenu">
                            <a class="dropdown-item dropdown-toggle" data-toggle="dropdown" href="#">Статус</a>
                            <ul class="dropdown-menu">
                                <li>
                                    <button name="sort" value="user_active">Активные</button>
                                </li>
                                <li>
                                    <button name="sort" value="user_block">Заблокированные</button>
                                </li>
                            </ul>
                        </li>
                        <li class="dropdown-submenu">
                            <a class="dropdown-item dropdown-toggle" data-toggle="dropdown" href="#">Кол-ву ссылок</a>
                            <ul class="dropdown-menu">
                                <li>
                                    <button class="dropdown-item" name="sort" value="linksCount_asc">Возрастанию</button>
                                </li>
                                <li>
                                    <button class="dropdown-item" name="sort" value="linksCount_desc">Убыванию</button>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </li>
            </ul>
        }

<div id="list">
    @Html.Action("UsersQueryPartial")
</div>

Родительский и дочерний метод из контроллера

public ActionResult Index()
        {
            return View();
        }

        public ActionResult UsersQueryPartial(string sort, string filter, int? page)
        {
            List<UserVM> usersList = new List<UserVM>();

            var pageNumber = page ?? 1;

            using(ChekitDB chekitDB = new ChekitDB())
            {
                string SortQuery = string.IsNullOrEmpty(sort) ? "login_asc" : sort;

                switch (SortQuery)
                {
                    case "login_asc":
                        usersList = chekitDB.Users.ToArray().Where(x => x.BanStatus == false).OrderBy(x => x.Login).Select(x => new UserVM(x)).ToList();
                        break;
                    case "user_active":
                        usersList = chekitDB.Users.ToArray().Where(x => x.BanStatus == false).OrderBy(x => x.Login).Select(x => new UserVM(x)).ToList();
                        break;
                    case "user_block":
                        usersList = chekitDB.Users.ToArray().Where(x => x.BanStatus == true).OrderBy(x => x.Login).Select(x => new UserVM(x)).ToList();
                        break;
                    case "linksCount_asc":
                        usersList = chekitDB.Users.ToArray().Where(x => x.BanStatus == false).OrderBy(x => x.LinksCount).Select(x => new UserVM(x)).ToList();
                        break;
                    case "linksCount_desc":
                        usersList = chekitDB.Users.ToArray().Where(x => x.BanStatus == false).OrderByDescending(x => x.LinksCount).Select(x => new UserVM(x)).ToList();
                        break;
                    default:
                        usersList = chekitDB.Users.ToArray().Where(x => x.BanStatus == false).OrderBy(x => x.Login).Select(x => new UserVM(x)).ToList();
                        break;
                }

                if(filter != null)
                {
                    usersList = usersList.Where(x => x.SearchInfo().ToLower().Contains(filter.ToLower())).ToList();
                }
            }

            var usersOnPage = usersList.ToPagedList(pageNumber, 20);
            ViewBag.usersOnPage = usersOnPage;

            return PartialView("_UsersQueryPartial", usersOnPage);
        }

Частичное представление _UsersQueryPartial.cshtml

@model IEnumerable<Checkitlink.Models.ViewModels.UserVM>

@using PagedList.Mvc;
@using PagedList;

@if (!Model.Any())
{
    <h2>Пользователей не обнаружено</h2>
}
else
{
    <div class="d-table">
        <div class="d-tr">
            <div class="d-td">
                @Html.DisplayNameFor(model => model.Login)
            </div>
            <div class="d-td">
                @Html.DisplayNameFor(model => model.Email)
            </div>
            <div class="d-td">
                @Html.DisplayNameFor(model => model.LinksCount)
            </div>
            <div class="d-td">
                @Html.DisplayNameFor(model => model.BanStatus)
            </div>
            <div class="d-td">
                Действия
            </div>
        </div>
        @foreach (var item in Model)
        {
            <div class="d-tr">
                <div class="d-td">
                    @Html.DisplayFor(modelItem => item.Login)
                </div>
                <div class="d-td">
                    @Html.DisplayFor(modelItem => item.Email)
                </div>
                <div class="d-td">
                    @Html.DisplayFor(modelItem => item.LinksCount)
                </div>
                @if (item.BanStatus == false)
                {
                <div class="d-td text-success">
                    Активный
                </div>
                }
                else
                {
                <div class="d-td">
                    <a class="text-danger" href="~/admin/user/BlackList" style="text-decoration:none" title="Посмотреть причину">Заблокирован</a>
                </div>
                }
                <div class="d-td">
                    @Html.ActionLink("Инфо", "InfoUser", new { id = item.UserId }, new { @class = "btn btn-info" }) |
                    @Html.ActionLink("Редактировать", "EditUser", new { id = item.UserId }, new { @class = "btn btn-primary" }) |
                    @if (item.Role == "Админ")
                    {
                        @Html.ActionLink("Заблокировать", "BanUser", new { id = item.UserId }, new { @class = "btn btn-warning disabled" })
                        string slash = " | ";
                        @slash
                        @Html.ActionLink("Удалить", "DeleteUser", new { id = item.UserId }, new { @class = "btn btn-danger disabled" })
                    }
                    else
                    {
                        @Html.ActionLink("Заблокировать", "BanUser", new { id = item.UserId }, new { @class = "btn btn-warning blockLink" })
                        string slash = " | ";
                        @slash
                        @Html.ActionLink("Удалить", "DeleteUser", new { id = item.UserId }, new { @class = "btn btn-danger delete" })
                    }
                </div>

                <div id="blockUser">
                    <form method="post" action="~/admin/user/BanUser">
                        <p class="text-danger">Блокировка пользователя</p>
                        <p>Укажите причину</p>
                        <input type="hidden" name="id" value="@item.UserId" />
                        <input type="text" name="reason" class="form-control" />
                        <input type="submit" value="Заблокировать" class="btn btn-success" style="margin-top:20px" />
                    </form>
                </div>
                <div id="myOverlay"></div>
            </div>
        }
    </div>
}

@Html.PagedListPager((IPagedList)ViewBag.usersOnPage, page => Url.Action("Index", new { page }))

Так вот, скажите, пожалуйста, будет ли этот метод вести себя как асинхронный? Насколько я знаю, то метод возвращающий частичное представление нельзя сделать асинхронным, а костыли нарытые на просторах интернета у меня применить не получилось.

Резюмируя, нужно понимание:

  1. Будет ли мой код работать, как асинхронный?
  2. Если нет, то возможно у Вас есть идеи, как нужно его переписать, чтобы добиться асинхронной работы

Заранее спасибо


Ответы (1 шт):

Автор решения: Максим Рыжак

Для того, чтоб частичное представление вызывалось из асинхронного метода нужно:

  1. Наполнить модель родительской страницы данными:
        public async Task<ActionResult> Index(int? page)
        {
            List<UserVM> usersList = new List<UserVM>();
            List<UsersDTO> usersDTO;

            var pageNumber = page ?? 1;

            using (ChekitDB chekitDB = new ChekitDB())
            {
                usersDTO = await chekitDB.Users.ToListAsync();
                usersList = usersDTO.ToArray().Where(x => x.BanStatus == false).OrderBy(x => x.Login).Select(x => new UserVM(x)).ToList();
            }

            var usersOnPage = usersList.ToPagedList(pageNumber, 20);
            ViewBag.usersOnPage = usersOnPage;

            return View(usersOnPage);
        }

В родительском представлении добавить рендер дочернего представления с именем cshtml дочернего представления и заполненной моделью:

<div id="list">
    @{
        Html.RenderPartial("_UsersQueryPartial", Model);
    }
</div>
  1. Создать ajax.beginform. Сама форма, например, для поиска:
@{
    AjaxOptions ajaxUserSearch = new AjaxOptions()
    {
        UpdateTargetId = "list",
        Url = Url.Action("AsyncQuery", "User")
    };
}

@using (Ajax.BeginForm(ajaxUserSearch))
{
   <input type="text" name="filter" class="form-control form-search-input" placeholder="Search...">
   <button class="btn btn-default form-control" type="submit">
        <span class="fa fa-search" aria-hidden="true"></span>
   </button>
}
  1. Создать "прокладку" которая будет обрабатывать запрос из формы:

    public async Task<ActionResult> AsyncQuery(string filter, int? page)
    {
        var model = await this.UsersQueryPartial(filter, page);
    
        return PartialView("_UsersQueryPartial", model);
    }
    
  2. И метод, который будет возвращать результат в прокладку:

    public async Task<IPagedList<UserVM>> UsersQueryPartial(string filter, int? page)
    {
        List<UserVM> usersList = new List<UserVM>();
        List<UsersDTO> usersDTO;
    
        var pageNumber = page ?? 1;
    
        using(ChekitDB chekitDB = new ChekitDB())
        {
            usersDTO = await chekitDB.Users.ToListAsync();
                    usersList = usersDTO.ToArray().Where(x => x.BanStatus == 
                   false).OrderBy(x => x.Login).Select(x => new UserVM(x)).ToList();
    
            if(filter != null)
            {
                usersList = usersList.Where(x => x.SearchInfo().ToLower().Contains(filter.ToLower())).ToList();
            }
        }
    
        var usersOnPage = usersList.ToPagedList(pageNumber, 20);
        ViewBag.usersOnPage = usersOnPage;
    
        return usersOnPage;
    }
    

Надеюсь, что в будущем кому-то пригодится!

→ Ссылка