Eu tenho dois métodos de ação que são conflitantes. Basicamente, quero conseguir a mesma exibição usando duas rotas diferentes, pelo ID de um item ou pelo nome do item e do pai (os itens podem ter o mesmo nome entre pais diferentes). Um termo de pesquisa pode ser usado para filtrar a lista.
Por exemplo...
Items/{action}/ParentName/ItemName
Items/{action}/1234-4321-1234-4321
Aqui estão meus métodos de ação (também existem Remove
métodos de ação) ...
// Method #1
public ActionResult Assign(string parentName, string itemName) {
// Logic to retrieve item's ID here...
string itemId = ...;
return RedirectToAction("Assign", "Items", new { itemId });
}
// Method #2
public ActionResult Assign(string itemId, string searchTerm, int? page) { ... }
E aqui estão as rotas ...
routes.MapRoute("AssignRemove",
"Items/{action}/{itemId}",
new { controller = "Items" }
);
routes.MapRoute("AssignRemovePretty",
"Items/{action}/{parentName}/{itemName}",
new { controller = "Items" }
);
Entendo por que o erro está ocorrendo, pois o page
parâmetro pode ser nulo, mas não consigo descobrir a melhor maneira de resolvê-lo. Meu projeto é ruim para começar? Pensei em estender Method #1
a assinatura para incluir os parâmetros de pesquisa e mover a lógica Method #2
para um método privado que eles chamariam, mas não acredito que isso realmente resolva a ambiguidade.
Qualquer ajuda seria muito apreciada.
Solução real (com base na resposta de Levi)
Eu adicionei a seguinte classe ...
public class RequireRouteValuesAttribute : ActionMethodSelectorAttribute {
public RequireRouteValuesAttribute(string[] valueNames) {
ValueNames = valueNames;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
bool contains = false;
foreach (var value in ValueNames) {
contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value);
if (!contains) break;
}
return contains;
}
public string[] ValueNames { get; private set; }
}
E então decorou os métodos de ação ...
[RequireRouteValues(new[] { "parentName", "itemName" })]
public ActionResult Assign(string parentName, string itemName) { ... }
[RequireRouteValues(new[] { "itemId" })]
public ActionResult Assign(string itemId) { ... }
return ValueNames.All(v => controllerContext.RequestContext.RouteData.Values.ContainsKey(v));
contains = ...
seção por algo assim:contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value) || controllerContext.RequestContext.HttpContext.Request.Params.AllKeys.Contains(value);
ActionResult DoSomething(Person p)
onde Person
possui várias propriedades simples como Name
, e solicitações são feitas diretamente com os nomes das propriedades (por exemplo, /dosomething/?name=joe+someone&other=properties
).
controllerContext.HttpContext.Request[value] != null
vez de controllerContext.RequestContext.RouteData.Values.ContainsKey(value)
; mas um bom trabalho, no entanto.