Различить Guid и строковые параметры в MVC 3 - PullRequest
7 голосов
/ 27 сентября 2011

Используя готовые локаторы методов в ASP.NET MVC (3 или 4DP), существует ли способ заставить инфраструктуру MVC различать строку и Guid без необходимости разбора параметра в действии контроллера

Примеры использования будут для URL

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

выполнить

public ActionResult Details(Guid guid)

метод и

http://[domain]/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 }
);

И переключил подписи действий на:

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

Ограничение выполняется и проходит, таким образом, аргумент отправляется действию, но, по-видимому, все еще в виде строки, и, следовательно, неоднозначно для двух сигнатур методов. Я ожидаю, что в методах действия есть что-то, что вызывает неоднозначность и, следовательно, может быть переопределено путем подключения пользовательского модуля для поиска методов.

Тот же результат может быть достигнут при разборе строкового параметра, но для краткости было бы неплохо избежать этой логики в действии (не говоря уже о том, чтобы, надеюсь, использовать его когда-нибудь позже).

Ответы [ 3 ]

11 голосов
/ 27 сентября 2011

Во-первых, вы должны устранить неоднозначность своих методов, дав им два разных имени:

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, чтобы запрос был направлен на соответствующее действие.

8 голосов
/ 26 мая 2012

Мое мнение таково: использование селектора метода действия более удобно и требует меньше кодирования.

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, он возвращает истину.Итак, чтобы использовать это:

public class HomeController : Controller
{
    [GuidMethodSelector]
    public ActionResult Index(Guid id)
    {
        return View();
    }
    public ActionResult Index(string id)
    {
        return View();
    }
}
7 голосов
/ 06 июля 2015

Если вы все еще регистрируете маршруты таким образом, тогда класс 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) {
    }
}
...