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

fal*_*uan 7 asp.net-mvc guid asp.net-mvc-routing

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

用法示例适用于URL

HTTP:// [域] /客户/信息/ F325A917-04F4-4562-B104-AF193C41FA78

执行

public ActionResult Details(Guid guid)
Run Code Online (Sandbox Code Playgroud)

方法,和

HTTP:// [域] /客户/信息/账单门

执行

public ActionResult Details(string id)
Run Code Online (Sandbox Code Playgroud)

方法.

没有任何变化,显然这些方法含糊不清,如下:

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);
}
Run Code Online (Sandbox Code Playgroud)

导致错误:

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 
Run Code Online (Sandbox Code Playgroud)

我尝试使用自定义约束(基于如何创建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 }
);
Run Code Online (Sandbox Code Playgroud)

并将动作签名切换为:

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);
}
Run Code Online (Sandbox Code Playgroud)

约束执行并传递,因此参数被发送到动作,但看起来仍然是一个字符串,因此对两个方法签名不明确.我希望动作方法的位置会导致模糊,因此可以通过插入自定义模块来定位方法来覆盖.

通过解析出字符串参数可以获得相同的结果,但为了简洁起见,在行动中避免使用该逻辑(更不用说希望有一天后再使用),这样做非常好.

cou*_*ben 11

首先,您必须通过给出两个不同的名称来消除歧义.

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);
} 
Run Code Online (Sandbox Code Playgroud)

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

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; 
    } 
} 
Run Code Online (Sandbox Code Playgroud)

最后,在Details路线顶部添加路线,如下所示:

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

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


Nic*_*ich 8

我的观点是使用动作方法选择器更有用,编码更少.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

此选择器检查ID参数的请求.如果是guid,则返回true.所以,使用它:

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


Lau*_*e C 7

如果你仍然以这种方式注册路由,那么GuidRouteConstraint()类被添加到更新版本的MVC中,应该用来代替自定义实现:

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

然后,您可以简单地创建您的操作结果:

public class HomeController : Controller {
    public ActionResult Index(Guid guid) {
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 做了一个款待,只是确保你使用正确的`using`语句 - 你可能想要`使用System.Web.Mvc.Routing.Constraints;`而不是System.Web.Http.Routing.Constraints (3认同)