asp.net 核心 post 方法、标签助手和查询字符串
asp.net core post method, tag helpers and query string
我从我开始学习的 asp.net 核心得到了这种意外行为。
我的视图中有以下表格:
<form asp-controller="Account" asp-action="Login" method="post">
<button type="submit">LOGIN</button>
</form>
是的,我在这里使用标签助手。这是控制器:
public class AccountController : Controller
{
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login(string returnUrl)
{
if (string.IsNullOrEmpty(returnUrl) || !Url.IsLocalUrl(returnUrl))
return RedirectToAction("index", "home");
else
return LocalRedirect(returnUrl);
}
}
现在,根据我目前的理解,returnUrl 应该会自动获取查询字符串值(如果它存在于查询字符串中)。但是通过这种设置,它不会发生。绞尽脑汁后,我在网上找到了一个解决方案,改变了我的看法:
<form method="post">
<button type="submit">LOGIN</button>
</form>
然后它开始工作。但是为什么会有这种行为,是什么原因造成的,为什么表单标签助手不允许查询字符串绑定到这个 post 方法表单???
您正在执行 POST 请求,因此模型绑定程序会尝试从请求正文中获取参数。
您可以将字段添加到表单中:
<form asp-controller="Account" asp-action="Login" method="post">
<input type="hidden" name="returnUrl" value="http://some_url" />
<button type="submit">LOGIN</button>
</form>
或者,如果您想执行 POST 请求并仍然从查询字符串中获取 returnUrl 参数,那么您需要使用 FromQuery
属性指示模型绑定器这样做:
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromQuery(Name = "returnUrl")] string returnUrl)
{
if (string.IsNullOrEmpty(returnUrl) || !Url.IsLocalUrl(returnUrl))
return RedirectToAction("index", "home");
else
return LocalRedirect(returnUrl);
}
编辑
在您的最后一个示例中,您只是使用标准 HTML 代码而没有任何 ASP.NET 帮助器,因此带有参数的 URL 将按原样发送到服务器,即没有任何由框架处理,因此它被正确解析,但如果您更改 post 操作名称,如果您的控制器中有多个 post 操作,或者如果您定义了更复杂的路由,这可能会停止工作。
如果你使用没有标签助手的默认表单,它会默认获取查询字符串。
如果您使用标签助手来指定控制器和操作,您的代码将转化为:
<form method="post" action="/Account/Login">
这导致 returnUrl 始终为 null。
为了获取returnUrl,需要像下面这样使用asp-route-{value}
指定路由,否则会进入默认路由模板:
<form asp-controller="Account" asp-action="Login" asp-route-returnUrl="yourUrl" method="post">
<button type="submit">LOGIN</button>
</form>
这将转化为:
<form method="post" action="/Account/Login?returnUrl=yourUrl">
参考:
我从我开始学习的 asp.net 核心得到了这种意外行为。
我的视图中有以下表格:
<form asp-controller="Account" asp-action="Login" method="post">
<button type="submit">LOGIN</button>
</form>
是的,我在这里使用标签助手。这是控制器:
public class AccountController : Controller
{
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login(string returnUrl)
{
if (string.IsNullOrEmpty(returnUrl) || !Url.IsLocalUrl(returnUrl))
return RedirectToAction("index", "home");
else
return LocalRedirect(returnUrl);
}
}
现在,根据我目前的理解,returnUrl 应该会自动获取查询字符串值(如果它存在于查询字符串中)。但是通过这种设置,它不会发生。绞尽脑汁后,我在网上找到了一个解决方案,改变了我的看法:
<form method="post">
<button type="submit">LOGIN</button>
</form>
然后它开始工作。但是为什么会有这种行为,是什么原因造成的,为什么表单标签助手不允许查询字符串绑定到这个 post 方法表单???
您正在执行 POST 请求,因此模型绑定程序会尝试从请求正文中获取参数。
您可以将字段添加到表单中:
<form asp-controller="Account" asp-action="Login" method="post">
<input type="hidden" name="returnUrl" value="http://some_url" />
<button type="submit">LOGIN</button>
</form>
或者,如果您想执行 POST 请求并仍然从查询字符串中获取 returnUrl 参数,那么您需要使用 FromQuery
属性指示模型绑定器这样做:
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromQuery(Name = "returnUrl")] string returnUrl)
{
if (string.IsNullOrEmpty(returnUrl) || !Url.IsLocalUrl(returnUrl))
return RedirectToAction("index", "home");
else
return LocalRedirect(returnUrl);
}
编辑
在您的最后一个示例中,您只是使用标准 HTML 代码而没有任何 ASP.NET 帮助器,因此带有参数的 URL 将按原样发送到服务器,即没有任何由框架处理,因此它被正确解析,但如果您更改 post 操作名称,如果您的控制器中有多个 post 操作,或者如果您定义了更复杂的路由,这可能会停止工作。
如果你使用没有标签助手的默认表单,它会默认获取查询字符串。
如果您使用标签助手来指定控制器和操作,您的代码将转化为:
<form method="post" action="/Account/Login">
这导致 returnUrl 始终为 null。
为了获取returnUrl,需要像下面这样使用asp-route-{value}
指定路由,否则会进入默认路由模板:
<form asp-controller="Account" asp-action="Login" asp-route-returnUrl="yourUrl" method="post">
<button type="submit">LOGIN</button>
</form>
这将转化为:
<form method="post" action="/Account/Login?returnUrl=yourUrl">
参考: