Повторно используемые компоненты в ASP.NET MVC

У меня есть функция на моем веб-сайте (некоторый пользовательский интерфейс и связанные с ней функции), которую я хочу повторно использовать на нескольких страницах. Для целей этого вопроса скажем, что это функция «Комментарии».

В моем приложении есть область для компонентов, и внутри этой области находятся контроллер: /Controllers/CommentController и два частичных представления: /Views/Comment/Index.ascx (для вывода комментариев) и /Views/Comment/Create.ascx (для создания комментариев).

CommentController выглядит примерно так:

public class CommentController : Controller
{      
  [ChildActionOnly]
  public ActionResult Index()
  {
      return PartialView(GetComments());
  }

  [HttpGet]
  [ChildActionOnly]
  public ActionResult Create()
  {
      return PartialView(); //this is wrong.
  }

  [HttpPost]
  [ChildActionOnly]
  public ActionResult Create(FormCollection formValues)
  {
      SaveComment(formValues);

      return RedirectToAction("Index"); //this is wrong too.
  }
}

Частичный просмотр индекса:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>

<div>
  <% foreach (var item in Model) { %>    
      <div>
          <%: item.Comment %>
      </div>
  <% } %>

  <%: Html.ActionLink("Add a Comment", "Create", "Comment", new { area = "Components" }, null) %>
</div>

Создать частичный вид:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<div>
    <% using (Html.BeginForm())
       {%>
        Enter your comment:
        <div>
            <input type="text" name="comment" />
        </div>
        <p>
            <input type="submit" value="Create" />
            <% //also render a cancel button and redirect to "Index" view  %>
        </p>
    <% } %>
</div>

Частичное представление Index включено в представление с RenderAction, например:

<% Html.RenderAction("Index", "Comment", new { area = "Components" }); %>

Этот код не работает, потому что формы в частичных представлениях подчиняются действиям в CommentController, помеченным [ChildActionOnly] (это сделано специально, я не хочу, чтобы «Компоненты» запрашивались независимо от страницы хостинга).

Как я могу заставить этот «компонентный» подход работать, то есть иметь частичное представление, которое отправляет форму для изменения состояния компонента на странице без потери самой страницы хостинга?

EDIT: Чтобы уточнить, использование [ChildActionOnly] здесь не моя проблема. Если я удалю атрибут из своих методов действий, мой код «работает» только в том смысле, что он не генерирует исключение. Мой «компонент» все еще вырывается из своей страницы хостинга, когда его форма отправляется (потому что я говорю форме отправить URL-адрес частичного представления!).


person kristian    schedule 10.11.2010    source источник
comment
Компоненты не могут быть запрошены независимо, если вы не предоставите им допустимый маршрут. Действительный маршрут не требуется для выполнения RenderAction.   -  person Robert Harvey    schedule 10.11.2010
comment
Что касается вашего редактирования: вы можете отправить всю страницу только по URL-адресу, а не только частичное представление, если только вы не хотите делать что-то ajaxy с частичным. Ajax — это то, как этот сайт публикует комментарии.   -  person Robert Harvey    schedule 10.11.2010


Ответы (2)


Вы заставляете MVC бороться с самим собой, запрашивая у формы действие, помеченное как ChildActionOnly.

Мое решение этой проблемы, когда я разрабатывал многоразовую среду мастера, заключалось в том, чтобы НЕ помечать действия как ChildActionOnly, а вместо этого определять, был ли запрос запросом ajax или просто обычным запросом.

Код для всего этого упакован в базовый класс контроллера. В ваших производных контроллерах вы делаете что-то вроде:

[WizardStep(4, "Illness Details")]
public ActionResult IllnessDetails()
{            
    return Navigate();
}

Где метод Navigate() базового контроллера решил, следует ли возвращать полное представление или только частичное представление, в зависимости от того, является ли это запросом ajax или нет. Таким образом, вы никогда не сможете вернуть частичное представление изолированно.

Чтобы убедиться, что это запрос Ajax, я использовал комбинацию Request.IsAjaxRequest() и TempData. TempData необходим, потому что моя структура мастера реализует шаблон PRG из коробки, поэтому мне нужно сохранить тот факт, что исходный пост был ajax.

Я думаю, это всего лишь одно решение, и потребовалось немного проб и ошибок, чтобы найти его правильное. Но теперь я живу долго и счастливо, разрабатывая волшебников, как Джоан Роулинг...

person awrigley    schedule 10.11.2010

Используйте Ajax для публикации партиала.

person Robert Harvey    schedule 10.11.2010