Стратегия ASP.NET Core для возврата частичных представлений через запросы AJAX.

У меня есть веб-приложение ASP.NET Core 5, и я хотел бы знать, какую стратегию использовать для частичных и обычных представлений.

Так, например, когда пользователь переходит в веб-браузере к /bars, я хотел бы загрузить страницу со списком Bar (вместе с меню, верхними и нижними колонтитулами и другими общими элементами макета).

Однако, если пользователь щелкнет меню Bars, я хотел бы перезагрузить только основной контейнер (без меню, верхних и нижних колонтитулов и т. д.).

В Controller я должен создать Action для каждой страницы с PartialAction, например:

public async Task<IActionResult> Index()
{
    return View(await _repository.ListAsync<T>());
}
    
public async Task<IActionResult> IndexPartial()
{
    return PartialView(await _repository.ListAsync<T>());
}

А потом вызвать AJAX в меню с помощью /Bar/IndexPartial, оставив основное действие для обычного просмотра? Связано, должен ли я создавать отдельные представления для каждого действия?

введите здесь описание изображения


person serge    schedule 22.01.2021    source источник
comment
По умолчанию тег привязки будет перемещаться по тому маршруту, на который вы его настроили. Чтобы асинхронно перезагрузить только часть страницы, вам нужно написать код на стороне клиента. Вам нужно будет обработать этот щелчок по ссылке, сделать вызов ajax, а затем заменить возвращенный HTML в основной div. Похоже, вы пытаетесь создать одностраничное приложение. Вы, вероятно, захотите взглянуть на использование одной из фреймворков реактивности переднего плана, таких как Angular или VueJS, если вы надеетесь иметь маршруты на стороне клиента.   -  person tnk479    schedule 22.01.2021
comment
Я понимаю, что клиентская сторона должна быть основным действующим лицом, однако я спрашиваю, как управлять ею со стороны сервера, поведением контроллера.   -  person serge    schedule 22.01.2021
comment
Привет @serge. Вы помните, касался ли мой ответ или любой другой ответ на этот вопрос? Если да, не могли бы вы отметить соответствующий ответ как принятый?   -  person Jeremy Caney    schedule 23.07.2021


Ответы (3)


и вызвать ajax в меню с помощью /bar/IndexPartial, оставив основное действие для обычного просмотра? (мне, кстати, создавать отдельные представления для каждого действия?)

Да, действие Index для обычного просмотра индекса. Создайте новое частичное представление с именем _IndexPartial.cshtml для содержимого, которое может измениться в основном представлении. Здесь вы можете просто поместить main container в свой частичный вид. При нажатии кнопки используйте ajax, чтобы запросить IndexPartial, чтобы получить возвращаемый HTML-контент частичного представления, а затем заменить его в основном представлении.

Простой пример для понимания:

Index.cshtml:

@model List<Book>
@{
    ViewData["Title"] = "Home Page";
}

<label>BookList:</label>
<div id="bookpartial">
    @foreach(var book in Model)
    {
        <div>
            @book.Name
        </div>
    }
</div>

<button id="update">Update</button>

@section scripts{
    <script>
        $("#update").click(function () {
            $.ajax({
                method: 'get',
                url: 'Home/IndexPartial',
                success: function (result) {
                    $('#bookpartial').empty();
                    $('#bookpartial').html(result);
                }
            })
        })
    </script>
}

_IndexPartial.cshtml:

@model List<Book>

@foreach (var book in Model)
{
    <div>
        @book.Name
    </div>
}

Контроллер:

public IActionResult Index()
{
    var books = new List<Book>
    {
        new Book{ BookId = 1, Name = "BookA"},
        new Book{ BookId = 2, Name = "BookB"},
        new Book{ BookId = 3, Name = "BookC"},
    };
    return View(books);
}

public IActionResult IndexPartial()
{
    var newbooks = new List<Book>
    {
        new Book{ BookId = 4, Name = "BookD"},
        new Book{ BookId = 5, Name = "BookE"},
        new Book{ BookId = 6, Name = "BookF"},
    };
    return PartialView("_IndexPartial", newbooks);
}

Результат:

введите здесь описание изображения

person mj1313    schedule 22.01.2021
comment
Я скорее удивляюсь щелчку по Книге, если бы он был в меню рядом с Домом и Конфиденциальностью. - person serge; 22.01.2021
comment
обновил OP с изображением, чтобы лучше отразить вопрос - person serge; 22.01.2021
comment
Я думаю, что изображение может использовать что-то вроде страницы макета, но не частичное представление, потому что вы можете увидеть измененный URL-адрес и перезагрузку страницы при нажатии кнопки меню. Это также реализовано в проекте шаблона asp.net core mvc. Вы можете обратиться к документу. - person mj1313; 25.01.2021
comment
@ mj1313: В настоящее время вы повторяете логику обработки книг внутри Index.cshtml и IndexPartial.cshtml. Для предварительно обработанного представления я бы рекомендовал просто вызвать частичное представление, например, с помощью @await Html.PartialAsync("_IndexPartial", Model) для централизации кода. (Я понимаю, что это, вероятно, является вспомогательным по отношению к вашей основной мысли, но это простое улучшение, которое помогает продемонстрировать, как вызывать партиал из представления, в дополнение к его возврату из действия.) - person Jeremy Caney; 06.02.2021

Это интересный вопрос! Ваш общий подход к отображению действия для каждой страницы и возврату PartialViewResult для внутреннего содержимого этой страницы имеет для меня смысл.

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

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

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

Посмотреть модели

Для начала вы можете установить общую модель представления, которая обрабатывает весь контент страницы. Это может включать свойства, например. элементы навигации. Но он также будет содержать имя (частичного) представления, а также модель представления для этого представления, так как они вам, вероятно, понадобятся для предварительного рендеринга внутреннего содержимого:

public class PageViewModel 
{
    …
    public string View { get; set; }
    public object ViewModel { get; set; }
}

Затем у вас будут отдельные модели просмотра для каждой страницы, например:

public class BarListViewModel 
{
    public Collection<Bar> Bars { get; } = new();
}

Контроллер

Теперь в вашем контроллере вы введете метод, который устанавливает BarListViewModel, так что вам не нужно повторять свою логику между вашей точкой входа, а также действиями, которые возвращают частичное представление:

[NonAction]
public BarListViewModel GetBarListViewModel() 
{
    var viewModel             = new BarListViewModel() 
    {
        Bars                  = …
    };
    return viewModel;
}

Теперь у вас может быть действие, которое доставляет вашу страницу Bars, подобное тому, что вы предложили:

public IActionResult Bars() => PartialView(GetBarListViewModel());

Но вместо того, чтобы иметь разные действия Index для каждого фрагмента, вы могли бы вместо этого иметь что-то вроде следующего

public IActionResult Index(Page page = "Home") 
{
    var viewModel = new PageViewModel 
    {
        View = page.ToString(),
        ViewModel = page switch 
        {
            "Bars" => GetBarListViewModel(),
            _ => GetDefaultViewModel()
        }
    };
    return View("Index", viewModel);
}

Это обеспечивает единую «диспетчеризацию» для подключения любой точки входа без необходимости создавать новое действие или представление для каждой из них.

Вид

Наконец, в вашем Index.cshtml у вас будет что-то вроде следующего для динамического внедрения правильного частичного представления на основе модели представления:

@model PageViewModel

…
<main>
  @await Html.PartialAsync(Model.View, Model.ViewModel)
</main>
…

Это загрузит, например. Bars.cshtml, который будет содержать логику для цикла по свойству BarListViewModel.Bars.

Примечание. Предполагается, что вы хотите предварительно отрендерить свое частичное представление на стороне сервера. Очевидно, что если вы хотите, чтобы начальная загрузка происходила через AJAX, вам не нужно передавать вложенный BarListViewModel или вызывать PartialAsync().

Маршрутизация

Предположительно, вышеприведенное будет сочетаться с конфигурацией маршрута, которая позволит передавать page в качестве параметра маршрута — возможно, даже запекая значения по умолчанию Controller и Action для вашей точки входа:

app.UseEndpoints(endpoints => 
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{page?}", 
        new { controller = "Home", action = "Index" }
    );
});

Примечание. Очевидно, что вам нужно быть осторожным, чтобы не заблокировать вызовы AJAX или другие точки входа с чрезмерно жадным маршрутом. Вышеупомянутое предназначено только как базовая демонстрация того, как захватить параметр маршрута page.

Вывод

Это похоже на подход, предложенный @User1997, но позволяет повторно использовать их предложенное Index.cshtml и подразумеваемое Index() действие для < em>все ваши точки входа. И, конечно же, если бы у вас было несколько контроллеров, которые следовали этому шаблону, его можно было бы даже обобщить как базовый контроллер.

person Jeremy Caney    schedule 05.02.2021

Вы должны создать два представления и один контроллер для каждого представления. Одно частичное представление: _IndexPartial.cshtml и обычное представление: Index.cshtml.

Частичное представление отображает часть содержимого представления, поэтому вы должны включить в обычное представление Index.cshtml, когда страница визуализируется в первый раз. Таким образом вы удаляете переписывание кода. Каждый раз, когда вы хотите изменить содержимое, сделайте запрос к контроллеру ParitalView и добавьте ответ (частичное представление) в элемент html, который отображает частичное представление.

@model List<T>
@{
    ViewData["Title"] = "Test";
}

<label>Partial Content</label>
<div id="partialContent">
    @await Html.PartialAsync("_IndexPartial.cshtml", Model)
</div>

<button id="UpdateContent">Update</button>

@section scripts{
    <script>
        $("#UpdateContent").click(function () {
            $.ajax({
                method: 'get',
                url: 'Home/IndexPartial',
                success: function (response) {
                    $('#partialContent').html(response);
                }
            })
        })
    </script>
}
person Lirzae    schedule 22.01.2021