我有一个 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的路由功能而不了解技术后果的选择。您知道他们说的是“好朋友互相阻止对方做愚蠢的事情”。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top