【问题标题】:ASP.NET Core MVC submit form in partial view / ViewComponentASP.NET Core MVC 在局部视图/ViewComponent 中提交表单
【发布时间】:2018-10-12 12:03:29
【问题描述】:

我有一个菜单和一个内容区域,它根据菜单中的选定项目显示内容。由于允许用户更改主菜单的结构,因此我决定将所有内容都放在 /home/index 页面上,并为需要显示的内容分配一个 guid。我开始的想法是引入局部视图,但意识到 ASP.NET Core 不再有 RenderAction 并被 ViewComponents 取代。 所以我使用了 ViewComponents,一切正常,除了我偶然发现我需要一个组件作为提交表单的情况。

在一个示例中:一个菜单项是菜单是显示用户列表的组件。另一个菜单项是创建新用户的组件。在创建用户组件时,我将有一个需要填写的表单,并且在成功提交时,我想将用户重定向到显示用户列表的组件。在提交不成功、错误、输入错误的情况下,我当然不想将用户重定向到用户列表。

由于 ViewComponents 的工作是显示视图,我应该如何处理这个问题?我正在寻找正确方向的指针。 我在这个领域没有什么经验,所以任何帮助都将不胜感激。

更新

Index.cshtml中:

<tbody>
    @foreach (string item in Model.Components)
    {
        <tr>
            <td>
                <div class="col-md-3">
                    @await Component.InvokeAsync(@item)
                </div>
            </td>
        </tr>
    }
</tbody>

这是在内容区域内。 Components 是我想在内容区域中显示的组件的字符串名称(目前一个接一个地列出)。

当我单击菜单项以显示表单时将调用我的 ViewComponent:

public class TestFormViewComponent : ViewComponent
{
    public async Task<IViewComponentResult> InvokeAsync()
    {
        return View("_TestForm", new TestModelPost());
    }
}

我的 _TestForm.cshtml 组件:

@model TestModelPost
<form asp-controller="Home" asp-action="TestPost" method="post">
    <label asp-for="Name"></label>
    <input asp-for="Name" /><br />
    <label asp-for="Surname"></label>
    <input asp-for="Surname" /><br />
    <button type="submit">Go</button>
</form>

TestPost 调用的动作:

[HttpPost]
public IActionResult TestPost(TestModelPost model)
{
    // Save model data, etc
    // !ModelState.IsValid -> go back to form

    // Success -> go to specific id
    return RedirectToAction("Index", new { id = 1 });
}

我应该如何处理这个问题?或者更确切地说,我是否走在正确的轨道上?如果输入不正确,我不确定如何“返回”到我在 _TestForm 组件中创建的视图。

【问题讨论】:

    标签: asp.net-core-mvc form-submit asp.net-mvc-partialview asp.net-core-viewcomponent


    【解决方案1】:

    视图组件,就像 ASP.NET MVC 中的子操作一样,不支持 POST。您需要一个完整的操作来处理表单发布,这需要返回一个完整的视图。本质上,您只需要更抽象地考虑它。

    视图组件最终只是将一些 HTML 转储到最终响应中的一种方式。当完整的响应返回给客户端时,没有什么是视图组件、部分视图等的概念。它只是一个 HTML 文档。该 HTML 文档的一部分是您的表单。该表单将具有一个操作,最终应该是由您的控制器操作之一处理的路由。传统的表单发布会导致整个浏览器视图发生变化,因此此操作的响应应该是完整视图或重定向到返回完整视图的操作。重定向是更合适的路径,遵循 PRG 模式。然后,最终返回该视图的责任是确定内容是如何构造的,酌情使用视图组件、部分等。

    总而言之,这与您的视图组件完全无关。它所做的只是将表单代码放到页面上。

    对于此类属于布局一部分的表单,通常最好在表单中包含一个包含“返回 URL”的隐藏输入。处理表单的操作,然后可以在完成它需要做的事情后重定向回这个 URL,以使用户看起来一直在同一个地方。

    【讨论】:

      【解决方案2】:

      请参考以下链接:

      https://andrewlock.net/an-introduction-to-viewcomponents-a-login-status-view-component/
      

      可能有帮助

      public class LoginStatusViewComponent : ViewComponent
      {
          private readonly SignInManager<ApplicationUser> _signInManager;
          private readonly UserManager<ApplicationUser> _userManager;
      
          public LoginStatusViewComponent(SignInManager<ApplicationUser> signInManager, UserManager<ApplicationUser> userManager)
          {
              _signInManager = signInManager;
              _userManager = userManager;
          }
      
          public async Task<IViewComponentResult> InvokeAsync()
          {
              if (_signInManager.IsSignedIn(HttpContext.User))
              {
                  var user = await _userManager.GetUserAsync(HttpContext.User);
                  return View("LoggedIn", user);
              }
              else
              {
                  return View();
              }
          }
      }
      

      我们的 InvokeAsync 方法很容易解释。我们正在检查当前用户是否使用 SignInManager 登录,如果是,我们从 UserManager 获取关联的 ApplicationUser。最后我们调用辅助视图方法,传入要渲染的模板和模型用户。如果用户没有登录,我们调用没有模板参数的帮助视图。

      根据您的代码段,您可以尝试如下修改:

      public class TestFormViewComponent : ViewComponent
      {
          public async Task<IViewComponentResult> InvokeAsync()
          {
            if (_signInManager.IsSignedIn(HttpContext.User))
              {
             //user list display
              return View("_TestForm", new TestModelPost());
              }
            else
              {
                return View();
              }
          }
      }
      

      【讨论】:

      • 你好,我用我写的代码更新了我的第一篇文章。任何进一步的指针?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多