C# 在asp.net mvc控制器操作中验证失败时,如何保留url
如果我从详细信息页面开始:C# 在asp.net mvc控制器操作中验证失败时,如何保留url,c#,asp.net-mvc,C#,Asp.net Mvc,如果我从详细信息页面开始: http:\\www.mysite.com\App\Detail 我有一个名为更新的控制器操作,通常会调用重定向到操作返回到详细信息页面。但我有一个在验证中捕获的错误,我需要在重定向之前返回(以避免丢失所有ModelState)。这是我的控制器代码: public override ActionResult Update(Application entity) { base.Update(entity); if (!Mode
http:\\www.mysite.com\App\Detail
我有一个名为更新的控制器操作,通常会调用重定向到操作返回到详细信息页面。但我有一个在验证中捕获的错误,我需要在重定向之前返回(以避免丢失所有ModelState)。这是我的控制器代码:
public override ActionResult Update(Application entity)
{
base.Update(entity);
if (!ModelState.IsValid)
{
return View("Detail", GetAppViewModel(entity.Id));
}
return RedirectToAction("Detail", new { id = entity.Id })
但是现在我看到了带有验证错误消息的视图(因为我使用的是HTML.ValidationSummary()),但url如下所示:
http:\\www.mysite.com\App\Update
不管怎样,我是否可以避免URL更改,而不用将modelstate放入一些临时变量?这里是否有最佳实践,因为我所看到的唯一示例是在调用重定向到操作之间的tempdata中放入ModelState,您要求的最佳实践实际上是您解释不允许的:将ModelState放入tempdata。Tempdata就是为它设计的,这就是为什么我不会称它为黑客
如果这是一段重复性很强的代码,那么可以使用MVCContrib的属性modeldatatotempdata。但是存储仍然是TempData。从ASP.NET MVC 2开始,当从另一个操作方法调用
return View()
时,没有任何这样的API调用来维护原始操作方法的URL
因此,在ASP.NET MVC中,推荐的解决方案和公认的约定是使用相应的、名称类似的操作方法,该方法只接受HTTPPOST
动词。因此,在您的情况下,使用另一个名为Detail
的类似操作方法可以解决验证失败时使用不同URL的问题
[HttpPost]
public ActionResult Detail(Application entity)
{
base.Update(entity);
if (ModelState.IsValid)
{
//Save the entity here
}
return View("Detail", new { id = entity.Id });
}
此解决方案符合ASP.NET MVC最佳实践,还避免了在moderate和tempdate上乱动 此外,如果您还没有研究过此选项,那么asp.net mvc中的客户端验证也可能为您的URL问题提供一些解决方案。我强调一些,因为当浏览器上禁用javascript时,这种方法不起作用
因此,最好的解决方案是使用名为
Detail
的操作方法,但只接受httppost
动词。这里的问题实际上是由您的实现引起的。这并不能回答你的问题,但它描述了你一开始犯的错误
如果您想要一个用于更新或编辑项目的页面,URL应该反映这一点。比如说
您可以访问http:\www.mysite.com\App\Detail,它会显示一些信息。这就是URL描述的它将要做的事情。在控制器中,Detail()方法将返回Detail.aspx视图
要编辑项目,请访问http:\www.mysite.com\App\edit并更改要更新的信息,表单将发回同一URL-您可以使用以下方法在控制器中处理此问题:
[HttpGet]
public ActionResult Edit() {
MyModel model = new MyModel();
...
return View(model);
}
[HttpPost]
public ActionResult Edit(MyModel model) {
...
if (ModelState.IsValid) {
// Save and redirect
...
return RedirectToAction("Detail");
}
return View(model);
}
如果你发现自己在做这件事
return View("SomeView", model);
你让自己的生活变得更艰难(同时也打破了URL背后的原则)
如果要重复使用视图的一部分,请将其设置为局部视图,并在以控制器上的方法命名的视图中进行渲染
我很抱歉,这可能没有多大帮助,但通过从不同名称的方法显示相同的视图,您正在落入MVC反模式陷阱。正如@Malcolm sais所说,最佳做法是将
ModelState
放在TempData
中,但不要手动执行!如果在每个相关的控制器操作中手动执行此操作,将引入大量重复代码,并大大增加维护成本
相反,实现几个属性来完成这项工作。(向下滚动到帖子末尾)这已经被广泛传播,埃文·纳格尔展示了一个与卡齐基本相同但名字不同的名字。因为他还提供单元测试来确保属性工作,所以在代码中实现它们将意味着很少或没有维护成本。唯一需要注意的是,控制器操作使用适当的属性进行修饰,这些属性也可以进行测试
当属性就绪时,控制器可能看起来像这样(我特意简化了,因为我不知道从哪个类继承):
您提到您觉得将ModelState
放在TempData
中感觉像是“黑客”——为什么?我同意你的观点,在每一个控制器动作中使用重复的代码似乎有点骇人,但这不是我们现在要做的。事实上我不认为上面的代码看起来有问题。。。你知道吗
虽然有一些解决这个问题的方法看起来更简单,比如重命名action方法以保留URL,但我强烈建议不要使用这种方法。它确实解决了这个问题,但还引入了一些其他问题-例如,您仍然无法防止双重表单提交,并且您的操作名称非常混乱(调用
详细信息实际上会更改服务器上的内容)。@Bikal Gurung-谢谢。我一直认为这是一种奇怪的做法,因为操作的名称并不真正代表您正在做的事情,但我确实同意,这将解决我所问的问题您可以使用[ActionName(“细节”)]public ActionResult WhatEverMethodName()解决这个问题,现在该方法将对应于“/Details”“此解决方案符合ASP.NET MVC最佳实践…”-我认为它实际上不符合最佳实践。从POST调用返回视图与PRG模式直接冲突,PRG模式是整个web的最佳实践,而不仅仅是ASP.NET MVC。遵守PRG的方法很多
[HttpPost, PassState]
public ActionResult Update(EntityType entity)
{
// Only update if the model is valid
if (ModelState.IsValid) {
base.Update(entity);
}
// Always redirect to Detail view.
// Any errors will be passed along automagically, thanks to the attribute.
return RedirectToAction("Detail", new { id = entity.Id });
}
[HttpGet, GetState]
public ActionResult Detail(int id)
{
// Get stuff from the database and show the view
// The model state, if there is any, will be imported by the attribute.
}