如何在ASP.NET CORE Razor Pages中创建共享表单?

6

我需要在页面头部创建一个可重用的表单,它应该在每个页面上显示。表单包括简单的输入框和提交按钮,这些数据将通过POST方法发送。

目前我知道的选项是使用局部视图或视图组件来实现。我查看了视图组件的文档,但并没有提到如何处理表单,只有InvokeAsync方法可以用于初始化视图。

使用局部视图可能很难定义其页面模型,也不清楚如何添加POST处理程序。

另一个选项是直接在_Layout.cshtml中放置表单,但是同样缺少其页面模型(据我所知)。

那么,有什么方法可以创建共享表单,并且POST请求应该在哪里处理?

2个回答

6

您应该使用视图组件,因为这样可以实现相对自包含的模型和视图交互。

public class SharedFormViewComponent : ViewComponent
{
    public Task<IViewComponentResult> InvokeAsync() =>
        Task.FromResult(View(new SharedFormViewModel()));
}

然后,将您的表单HTML代码放在Views\Shared\Components\SharedForm\Default.cshtml中。对于您的表单操作,您需要指定一个路由。稍后会详细说明。然后,要显示您的表单:

@await Component.InvokeAsync("SharedForm")

现在,正如您已经有所了解的那样,视图组件无法进行发布。这不是“不支持表单”的问题; 它们实际上不是请求管道的一部分,因此无法响应诸如POST之类的请求。您需要一个独立的操作来处理某个控制器上的POST。然后,在您的组件的表单标签上:

<form asp-action="SharedFormHandlerAction" asp-controller="Foo" asp-area="" method="post">
asp-area 属性应该在不同区域的上下文中使用时提供。
您还需要一个“返回URL”。这将是当前页面的URL,以便用户成功提交表单后,他们将返回到提交表单的页面。您可以通过向表单添加隐藏输入来实现:
<input type="hidden" name="returnUrl" value="@(Context.Request.Query["returnUrl"].FirstOrDefault() ?? (Context.Request.Path + Context.Request.QueryString))" />

你的处理程序操作应该接受一个参数,例如 string returnUrl = null,成功后应该执行以下操作:

return !string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl)
    ? Redirect(returnUrl)
    : RedirectToAction("SomeDefaultAction");

在处理验证错误时,情况会变得有点棘手。由于您正在发布到不同的操作,因此无法返回用户之前所在的视图以显示布局中表单内的验证错误或其他内容。相反,您需要为此处理程序操作创建一个特定的视图,该视图将仅是共享表单。您可以使用此处的视图组件作为部分视图:

<partial name="~\Views\Shared\Components\SharedForm\Default.cshtml" />

我使用了部分视图的方法,因为我不需要重复使用那个表单,但是使用 asp-controller 的方法非常好,这正是我一直缺少的。 - Roma Kostelnyy
你可以从请求头中获取referer,而不是使用隐藏的表单输入。例如:Redirect(Request.Headers["Referer"].ToString()) - Steven B.
  1. 这个头部不一定存在。它是由客户端添加的,可以被修改或省略。
  2. 它也不总是你需要的。例如,在第一篇文章中,它可能与 returnUrl 相同,但如果用户返回到页面以修复错误,则引用者现在是该页面,而不是用户最初来自的位置。而 returnUrl 将在多个帖子之间保持一致。
- Chris Pratt

2
如果您想使用PageModel,可以在一个继承自PageModelBasePageModel类中使用它,并使所有页面都继承自该类。您可以在BasePageModel类中使用命名处理程序(https://www.learnrazorpages.com/razor-pages/handler-methods#named-handler-methods)来处理表单提交。将表单直接添加到布局中,该布局需要一个@model指令,用于指定您的BasePageModel类型。
public class BasePageModel : PageModel
{
    [BindProperty]
    public string SearchString { get; set; }

    public void  OnPostBaseSearch()
    {
        // process the search
    }
}

这个答案对我很有用。如果你遇到了“表达式树可能不包含动态操作”的错误,那么这意味着你忘记在_Layout.chtml的顶部添加@model BasePageModel了。 - DeveloperDan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接