ASP.NET MVC-使用模型活页夹无查询字符串值或精美路由
-
22-10-2019 - |
题
我有一个 ASP.NET MVC 当前使用默认模型活页用于此类参数的默认模型活页夹和URL运行良好的应用程序:
example.com/controller/action?a=hello&b=world&c=1&d=2&e=3 (注意问号)
不同的URL使用内置模型粘合剂自动映射到操作方法参数。我想继续使用标准模型活页夹,但我需要摆脱查询字符串。我们想将这些URL放在一个 不支持因查询字符串而异的资源(Amazon Cloud Front)而变化的CDN 因此,我们需要从我们的URL中删除问号,并做些愚蠢的事情
example.com/controller/action/a=hello&b=world&c=1&d=2&e=3 (没有问号)
这些URL仅通过Ajax使用,因此我对使它们变得用户或SEO友好不感兴趣。我只想删除问号并将所有代码保持完全相同。障碍是,我不确定如何继续使用MVC模型粘合剂并放弃它将是很多工作。
我不想使用复杂的路由来映射我的对象 像这个问题一样 而且,我打算使用一条像下面的简单路线
routes.MapRoute(
"NoQueryString", // Route name
"NoQueryString/{action}/{query}", // 'query' = querystring without the ?
new {
controller = "NoQueryString",
action = "Index",
query = "" } // want to parse with model binder - By NOT ROUTE
);
选项1(首选):OnActionExeCuting我计划在上面的路由中使用CATCHALL“查询”值,以在控制器操作使用Controller Actions执行我的控制器中的OnActionExecuting方法之前将旧查询字符串注入默认模型活页夹中。但是,我有点不确定是否可以添加问号。 我可以这样做吗?您如何建议修改URL?
选项2:自定义模型活页夹我还可以制作某种自定义模型活页夹,该粘合剂只能告诉默认模型活页夹像查询字符串一样对待“查询”值。 您喜欢这种方法吗?您能指出我的相关例子吗?
我有点担心这是一个边缘案例,并且在开始尝试实现选项1或选项2并偶然发现不预定的错误之前会喜欢一些输入。
解决方案
您可以使用带有Catchall路线的自定义值提供商:
routes.MapRoute(
"NoQueryString",
"NoQueryString/{controller}/{action}/{*catch-em-all}",
new { controller = "Home", action = "Index" }
);
和价值提供商:
public class MyCustomProvider : ValueProviderFactory
{
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
var value = controllerContext.RouteData.Values["catch-em-all"] as string;
var backingStore = new Dictionary<string, object>();
if (!string.IsNullOrEmpty(value))
{
var nvc = HttpUtility.ParseQueryString(value);
foreach (string key in nvc)
{
backingStore.Add(key, nvc[key]);
}
}
return new DictionaryValueProvider<object>(
backingStore,
CultureInfo.CurrentCulture
);
}
}
您注册的 Application_Start
:
ValueProviderFactories.Factories.Add(new MyCustomProvider());
现在剩下的就是一个模型:
public class MyViewModel
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string D { get; set; }
public string E { get; set; }
}
和一个控制器:
public class HomeController : Controller
{
[ValidateInput(false)]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
然后导航到: NoQueryString/Home/Index/a=hello&b=world&c=1&d=2&e=3
. 。这 Index
被击中,模型是绑定的。
备注:注意 ValidateInput(false)
在控制器动作上。这可能是需要的,因为ASP.NET不允许您使用特殊字符,例如 &
作为URI的一部分。您可能还需要对Web.config进行一些调整:
<httpRuntime requestValidationMode="2.0" requestPathInvalidCharacters=""/>
有关这些调整的更多信息,请确保您已经阅读了Scott Hansleman's 博客文章.
其他提示
“复杂”路由定义的问题是什么?您链接到的问题非常简单。默认值可能会走很长一段路。最好使用MVC的默认功能转弯:
example.com/Controller/Action/a=hello&b=world&c=1&d=2&e=3
进入
example.com/Controller/Action/hello/world/1/2/3
而不是开始重新布线核心位,例如Routevalue处理(选项1)或实现自定义模型粘合剂。
我知道这没有回答您的问题,但是似乎您选择了不使用MVC的路由功能而不了解技术后果的选择。您知道他们说的是“好朋友互相阻止对方做愚蠢的事情”。