区分 MVC 3 中的 Guid 和字符串参数

发布于 2024-12-06 09:52:32 字数 2215 浏览 0 评论 0原文

使用 ASP.NET MVC(3 或 4DP)中的开箱即用方法定位器,是否有办法让 MVC 框架区分字符串和 Guid,而无需解析控制器操作中的参数?

用法示例是 URL

http://[域]/customer/details/F325A917-04F4-4562-B104-AF193C41FA78

执行

public ActionResult Details(Guid guid)

方法,以及

http://[域名]/customer/details/bill-gates

执行

public ActionResult Details(string id)

方法。

如果没有任何更改,显然这些方法是不明确的,如下所示:

public ActionResult Details(Guid id)
{
    var model = Context.GetData(id);
    return View(model);
}

public ActionResult Details(string id)
{
    var model = Context.GetData(id);
    return View(model);
}

导致错误:

The current request for action 'Details' on controller type 'DataController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Details(System.Guid) on type Example.Web.Controllers.DataController
System.Web.Mvc.ActionResult Details(System.String) on type Example.Web.Controllers.DataController 

我尝试使用自定义约束(基于 如何创建 System.Guid 类型的路由约束?)尝试通过路由推送它:

routes.MapRoute(
    "Guid",
    "{controller}/{action}/{guid}",
    new { controller = "Home", action = "Index" }, 
    new { guid = new GuidConstraint() }
);

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

并切换操作签名to:

public ActionResult Details(Guid guid)
{
    var model = Context.GetData(guid);
    return View(model);
}

public ActionResult Details(string id)
{
    var model = Context.GetData(id);
    return View(model);
}

约束执行并通过,因此参数被发送到一个操作,但看起来仍然是一个字符串,因此对两个方法签名来说是不明确的。我预计操作方法的定位方式会导致歧义,因此可以通过插入自定义模块来定位方法来覆盖。

通过解析字符串参数可以实现相同的结果,但为了简洁起见,避免操作中的逻辑(更不用说希望有一天重用)会非常好。

Using the out-of-the-box method locators in ASP.NET MVC (3 or 4DP), is there a way to have the MVC framework differentiate between a string and Guid without needing to parse the parameter in the controller action?

Usage examples would be for the URL

http://[domain]/customer/details/F325A917-04F4-4562-B104-AF193C41FA78

to execute the

public ActionResult Details(Guid guid)

method, and

http://[domain]/customer/details/bill-gates

to execute the

public ActionResult Details(string id)

method.

With no changes, obviously the methods are ambiguous, as follows:

public ActionResult Details(Guid id)
{
    var model = Context.GetData(id);
    return View(model);
}

public ActionResult Details(string id)
{
    var model = Context.GetData(id);
    return View(model);
}

resulting in the error:

The current request for action 'Details' on controller type 'DataController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Details(System.Guid) on type Example.Web.Controllers.DataController
System.Web.Mvc.ActionResult Details(System.String) on type Example.Web.Controllers.DataController 

I attempted to use a custom constraint (based on How can I create a route constraint of type System.Guid?) to try and push it through via routing:

routes.MapRoute(
    "Guid",
    "{controller}/{action}/{guid}",
    new { controller = "Home", action = "Index" }, 
    new { guid = new GuidConstraint() }
);

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

And switched the action signatures to:

public ActionResult Details(Guid guid)
{
    var model = Context.GetData(guid);
    return View(model);
}

public ActionResult Details(string id)
{
    var model = Context.GetData(id);
    return View(model);
}

The constraint executes and passes, thus the argument is sent to an action, but seemingly still as a string, and thus ambiguous to the two method signatures. I expect that there's something in how the action methods are located that causes the ambiguity, and thus could be overridden by plugging in a custom module to locate methods.

The same result could be achieved by parsing out the string parameter, but would be really nice for brevity to avoid that logic in the action (not to mention to hopefully reuse someday later).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

陌伤浅笑 2024-12-13 09:52:33

首先,您必须通过给方法指定两个不同的名称来消除歧义:

public ActionResult DetailsGuid(Guid guid)
{
    var model = Context.GetData(guid);
    return View(model); 
}

public ActionResult DetailsString(string id)
{
    var model = Context.GetData(id);
    return View(model);
} 

接下来,您需要一个自定义路由处理程序来检查请求,并相应地更改方法名称:

using System.Web.Mvc; 
using System.Web.Routing; 

public class MyRouteHandler : IRouteHandler 
{ 
    public IHttpHandler GetHttpHandler(RequestContext requestContext) 
    { 
        var routeData = requestContext.RouteData; 
        var stringValue = routeData.Values["id"].ToString();
        Guid guidValue; 
        var action = routeData.Values["action"]; 
        if (Guid.TryParse(stringValue, out guidValue) && (guidValue != Guid.Empty);
            routeData.Values["action"] = action + "Guid"; 

        else
            routeData.Values["action"] = action + "String"; 

        var handler = new MvcHandler(requestContext); 
        return handler; 
    } 
} 

最后,在顶部添加一个 Details 路由您的路由,如下所示:

routes.Add("Details", 
    new Route("{controller}/Details/{id}", 
        new RouteValueDictionary( 
            new { controller = "Home", action = "Details" }), 
            new MyRouteHandler()
        )
    ); 
);

当收到详细信息请求时,Details 路由将使用您的自定义路由处理程序来检查 id 令牌。路由处理程序根据 id 令牌的形式添加到操作名称,以便将请求定向到适当的操作。

First, you must disambigute your methods by giving them two different names:

public ActionResult DetailsGuid(Guid guid)
{
    var model = Context.GetData(guid);
    return View(model); 
}

public ActionResult DetailsString(string id)
{
    var model = Context.GetData(id);
    return View(model);
} 

Next, you need a custom route handler to inspect the request, and change the method name accordingly:

using System.Web.Mvc; 
using System.Web.Routing; 

public class MyRouteHandler : IRouteHandler 
{ 
    public IHttpHandler GetHttpHandler(RequestContext requestContext) 
    { 
        var routeData = requestContext.RouteData; 
        var stringValue = routeData.Values["id"].ToString();
        Guid guidValue; 
        var action = routeData.Values["action"]; 
        if (Guid.TryParse(stringValue, out guidValue) && (guidValue != Guid.Empty);
            routeData.Values["action"] = action + "Guid"; 

        else
            routeData.Values["action"] = action + "String"; 

        var handler = new MvcHandler(requestContext); 
        return handler; 
    } 
} 

Finally, add a Details route at the top of your routes, as follows:

routes.Add("Details", 
    new Route("{controller}/Details/{id}", 
        new RouteValueDictionary( 
            new { controller = "Home", action = "Details" }), 
            new MyRouteHandler()
        )
    ); 
);

When a request comes in for details, the Details route will use your custom route handler to inspect the id token. The route handler adds to the action name based on the form of the id token, so that the request will be directed to the appropriate action.

乖乖兔^ω^ 2024-12-13 09:52:33

我的观点是,使用操作方法选择器更有用并且编码更少。

public class GuidMethodSelectorAttribute : ActionMethodSelectorAttribute
{
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        var idStr = controllerContext.RouteData.Values["id"];
        if (idStr == null)
            return false;
        Guid a;
        var result = Guid.TryParse(idStr.ToString(), out a);
        return result;
    }
}

该选择器检查 ID 参数的请求。如果是 guid,则返回 true。因此,要使用它:

public class HomeController : Controller
{
    [GuidMethodSelector]
    public ActionResult Index(Guid id)
    {
        return View();
    }
    public ActionResult Index(string id)
    {
        return View();
    }
}

My opinion is that using action method selector is more usable and less coding.

public class GuidMethodSelectorAttribute : ActionMethodSelectorAttribute
{
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        var idStr = controllerContext.RouteData.Values["id"];
        if (idStr == null)
            return false;
        Guid a;
        var result = Guid.TryParse(idStr.ToString(), out a);
        return result;
    }
}

This selector inspects request for ID parameter. If it's guid, it returns true. So, to use it:

public class HomeController : Controller
{
    [GuidMethodSelector]
    public ActionResult Index(Guid id)
    {
        return View();
    }
    public ActionResult Index(string id)
    {
        return View();
    }
}
∞梦里开花 2024-12-13 09:52:33

如果您仍然以这种方式注册路由,则 GuidRouteConstraint() 类已添加到较新版本的 MVC 中,并且应该使用它而不是自定义实现:

public override void RegisterArea(AreaRegistrationContext context)
{
    context.MapRoute(
        "Guid",
        "{controller}/{action}/{guid}",
        new { controller = "Home", action = "Index" }, 
        new { guid = new GuidRouteConstraint() }
    );
}

然后您可以简单地创建操作结果,如下所示:

public class HomeController : Controller {
    public ActionResult Index(Guid guid) {
    }
}

If you're still registering routes in this way then the GuidRouteConstraint() class was added in a newer version of MVC and should be used instead of a custom implementation:

public override void RegisterArea(AreaRegistrationContext context)
{
    context.MapRoute(
        "Guid",
        "{controller}/{action}/{guid}",
        new { controller = "Home", action = "Index" }, 
        new { guid = new GuidRouteConstraint() }
    );
}

Then you can simply create your action result as:

public class HomeController : Controller {
    public ActionResult Index(Guid guid) {
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文