ASP.net MVC - 使用模型Binder没有查询字符串值或花哨的路线 [英] ASP.net MVC - Use Model Binder without query string values or fancy routes

查看:216
本文介绍了ASP.net MVC - 使用模型Binder没有查询字符串值或花哨的路线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Asp.net MVC 应用程序,目前使用默认模型绑定器和具有复杂参数的网址,如下所示:



example.com/Controller/Action?a=hello&b=world&c=1&d=2&e=3 (注意问号)



不同的URL自动映射到使用内置的模型绑定器的Action Method参数。我想继续使用标准模型绑定,但是我需要摆脱查询字符串。我们想把这些网址放在一个 CDN不支持由查询字符串(Amazon Cloud front)不同的资源,因此我们需要从我们的URL中删除问号,并像这样做一些傻事



example.com/Controller/Action/a=hello&b=world&c=1&d=2&e=3 (无问号)



这些网址只能通过AJAX使用,所以我对使用户或SEO友好不感兴趣。我只想放下问号,并保持所有的代码完全一样。挂钩是,我不确定如何继续使用MVC模型绑定器,放弃它将是很多工作。



我不想使用复制路线映射我的对象像这样的问题,而是,我打算使用一个简单的路线,如下所示

  routes.MapRoute(
NoQueryString,//路由名称
NoQueryString / {action} / {query},//'query'= querystring没有?
new {
controller =NoQueryString,
action =Index,
query =} //要用模型绑定器解析 - 通过NOT ROUTE
);

选项1(首选):OnActionExecuting
我计划在控制器操作使用控制器中的OnActionExecuting方法执行之前,使用上面的路由中的catchallquery值将旧查询字符串注入默认模型绑定。但是,我有点不确定是否可以加回问号。我可以这样做吗?您如何建议修改网址?



选项2:自定义模型绑定
我也可以做一些排序的自定义模型绑定器,只是告诉默认模型binder来处理查询值,如查询字符串。你喜欢这种方法吗?你可以指出一个相关的例子吗?



我有点担心这是一个边缘的情况,并希望在开始尝试实现之前的一些输入选项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]作为字符串;
var backingStore = new Dictionary< string,object>();
if(!string.IsNullOrEmpty(value))
{
var nvc = HttpUtility.ParseQueryString(value);
foreach(nvc中的字符串键)
{
backingStore.Add(key,nvc [key]);
}
}
返回新的DictionaryValueProvider< object>(
backingStore,
CultureInfo.CurrentCulture
);
}
}

您在 Application_Start中注册

  ValueProviderFactories.Factories.Add(new MyCustomProvider()); 

现在剩下的是一个模型:

  public class MyViewModel 
{
public string A {get;组; }
public string B {get;组; }
public string C {get;组; }
public string D {get;组; }
public string E {get;组;
}

和控制器:



pre> public class HomeController:Controller
{
[ValidateInput(false)]
public ActionResult索引(MyViewModel模型)
{
return View(model);
}
}

,然后导航到: NoQueryString / Home / Index / a = hello& b = world& c = 1& d = 2& e = 3 索引被击中,模型被绑定。



注意:注意 ValidateInput false)上的控制器动作。这可能是需要的,因为ASP.NET将不允许您使用特殊字符,例如& 作为URI的一部分。您可能还需要调整一下您的web.config:

 < httpRuntime requestValidationMode =2.0requestPathInvalidCharacters =/ > 

有关这些调整的更多信息,请确保您已阅读Scott Hansleman的博客


I have an Asp.net MVC app that currently works well using the default model binder and urls with complex parameters like this:

example.com/Controller/Action?a=hello&b=world&c=1&d=2&e=3 (notice the question mark)

The different urls automatically map to Action Method parameters using the built in model binder. I would like to continue using the standard model binder but I need to get rid of the query string. We want to put these urls behind a CDN that does not support resources that vary by query strings (Amazon Cloud front) so we need to remove the question mark from our urls and do something silly like this

example.com/Controller/Action/a=hello&b=world&c=1&d=2&e=3 (no question mark)

These urls are only used via AJAX, so I'm not interested in making them user or SEO friendly. I want to just drop the question mark and keep all my code exactly the same. The hitch is, I'm unsure about how to keep using the MVC model binder and abandoning it would be a lot of work.

I don't want to use a complex route to map my objects like this question did and, instead, I am planning to use a single simple route like the one below

   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
    );

Option 1 (preferred): OnActionExecuting I plan to use the catchall "query" value in the route above to inject the old query string into the default model binder before the Controller Actions execute using the OnActionExecuting method in my controller. However, I'm a bit unsure if I can just add back the question mark. Can I do this? How would you recommend modifying the url?

Option 2: Custom Model Binder I also could make some sort of Custom Model Binder that just tells the default model binder to treat the "query" value like a query string. Would you prefer this method? Can you point me to a relevant example?

I am a bit worried that this is an edge case and would love some input before I start trying to implement Option 1 or Option 2 and stumble onto unforseen bugs.

解决方案

You could use a custom value provider with a catchall route:

routes.MapRoute(
    "NoQueryString",
    "NoQueryString/{controller}/{action}/{*catch-em-all}",
    new { controller = "Home", action = "Index" }
);

and the value provider:

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
        );
    }
}

which you register in Application_Start:

ValueProviderFactories.Factories.Add(new MyCustomProvider());

and now all that's left is a model:

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; }
}

and a controller:

public class HomeController : Controller
{
    [ValidateInput(false)]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

and then navigate to: NoQueryString/Home/Index/a=hello&b=world&c=1&d=2&e=3. The Index is hit and the model is bound.

Remark: Notice the ValidateInput(false) on the controller action. That's probably gonna be needed because ASP.NET won't allow you to use special characters such as & as part of a URI. You might also need to tweak your web.config a little:

<httpRuntime requestValidationMode="2.0" requestPathInvalidCharacters=""/>

For more information about those tweaks make sure you have read Scott Hansleman's blog post.

这篇关于ASP.net MVC - 使用模型Binder没有查询字符串值或花哨的路线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆