Неправильный тип данных передается в частичное представление?

#c# #asp.net #asp.net-core #asp.net-core-mvc

#c# #asp.net #asp.net-core #asp.net-core-mvc

Вопрос:

Я пытаюсь создать простое приложение для чата, с которым можно начать ASP.NET и мое частичное представление, похоже, получает тип данных, переданный в Index.cshtml вместо данных, которые я намеревался передать в PersistantMessagesPartial.cshtml.

Ошибка:

Исключение InvalidOperationException: элемент модели, переданный в ViewDataDictionary, имеет тип ‘System.Коллекции.Generic.List 1[WebChat.Areas.Identity.Data.AppUser]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.List 1[Веб-чат.Модели.MessageModel]’.***

В HomeController.cs:

  public async Task<IActionResult> Index()
    {
        Debug.WriteLine("debug1");
        return View(await _AppUserDBContext.userList.ToListAsync());
    }
    
    public async Task<IActionResult> _PersistantMessagesPartial()
    {
        Debug.WriteLine("debug2");
        return PartialView("_PersistantMessagesPartial", await _MessageModelDBContext.messageList.ToListAsync());
    }
  

В _PersistantMessagesPartial.cshtml:

 @model List<WebChat.Models.MessageModel>
<script>
    console.log("test");
</script>
@foreach(var item in Model)
{
    <script>
        console.log("MessagePartial");
        console.log(@item.Contents);
    </script>
}
  

Как я могу отобразить частичное представление в _Layout.cshtml:

 <partial name="_PersistantMessagesPartial" />
  

Index.cshtml получает список AppUser, и это работает правильно. Я не уверен, как заставить _PersistantMessagesPartial получать список MessageModel вместо списка AppUser.

Комментарии:

1. Вы должны добавить model в свой тег частичного просмотра. Вот так: <partial name="_PersistantMessagesPartial" model="@Model.GoesHere" /> . Я думаю, что он получает модель из вашего индексного представления, переданную ему. Это не вызывает ваш _PersistantMessagesPartial в вашем контроллере, возможно, вам потребуется создать модель представления или превратить частичное представление и действие в компонент представления

2. @zgood предложение компонента view является допустимым и предпочтительным. Однако информация здесь: learn.microsoft.com/en-us/aspnet/core/mvc/views /… может помочь вам передать модель, отличную от родительской ViewDataDictionary ..

Ответ №1:

Вместо передачи списка объектов я бы создал класс:

 public class PersistantMessagesPartialModel{
    public List<WebChat.Models.MessageModel> Messages{get;set;}
}
  

и передайте объект, используя атрибут for, вот так:

 @model IndexViewModel

<partial name="_PersistantMessagesPartial.cshtml" for="PersistantMessagesPartialModel" />
  

Тогда ваше частичное представление будет выглядеть:

 @model PersistantMessagesPartialModel

@foreach(var item in Model.Messages)
{
    <script>
        console.log("MessagePartial");
        console.log(@item.Contents);
    </script>
}
  

Контроллер будет выглядеть следующим образом:

   [HttpGet]
  public async Task<IActionResult> Index()
  {
       var viewModel = new IndexViewModel(){
          PersistantMessagesPartialModel = new 
          PersistantMessagesPartialModel(){
                Messages = await 
           _AppUserDBContext.userList.ToListAsync()
            };
      return View(viewModel);
   }
  

IndexViewModel Будет выглядеть так:

 public class IndexViewModel{
    public PersistantMessagesPartialModel  
    PersistantMessagesPartialModel {get;set;}
}
  

Я знаю, что ASP.NET MVC позволяет вам определять модель данной страницы в виде списка объектов, однако я верю в правило, согласно которому каждая страница .cshtml должна иметь один класс модели. Это дает вам огромную гибкость, когда вы хотите добавить какую-то новую логику в представление. Просто представьте простой случай, когда вы хотите добавить в свое частичное представление некоторый оператор if, который будет работать на основе некоторого значения, установленного в серверной части вашего приложения. В таком случае вам нужно будет использовать ViewBag, ViewData objects для передачи его в представление, и это немного сложнее поддерживать, особенно если ваше приложение большое.
В моем решении вы бы просто добавили это дополнительное поле в PersistantMessagesPartialModel , и даже в том случае, когда вы хотите выполнить некоторое переименование и т.д. это просто быстрее и безопаснее.

Комментарии:

1. Извините, я в замешательстве. Откуда частичное получит экземпляр PersistantMessagesPartialModel? Тот же вопрос, другая формулировка: откуда атрибут for получил бы модель, если бы не передавался с использованием представлений?

2. Например. у вас есть представление Home.cshtml. Это представление @model будет HomeViewModel . Это выглядело бы как public class HomeViewModel { public PersistantMessagesPartialModel PersistantMessagesPartialModel {get; set;} // and some other properties} . Когда вы добавляете <partial name="_PersistantMessagesPartial.cshtml" for="PersistantMessagesPartialModel" /> в Home.cshtml, for атрибут будет принимать значение из свойства HomeViewModel

3. В другом случае, например, если вы хотите добавить свое частичное представление в _layout.cshtml, я бы использовал ViewBag в действии контроллера для установки частичной модели и передачи значения с помощью model атрибута, например <partial name="_PersistantMessagesPartial" model="@ViewBag['PersistantMessagesPartialModel']" />

4. Если вы все еще чего-то не понимаете, не стесняйтесь задавать вопросы, я постараюсь объяснить вам все более подробно, если это необходимо 😉

5. О, так у вас HomeViewModel действует как оболочка данных. Теперь у меня все работает нормально, большое вам спасибо! 🙂