ASP.NET MVC暧昧动作方法 [英] ASP.NET MVC ambiguous action methods

查看:163
本文介绍了ASP.NET MVC暧昧动作方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有相互矛盾两项行动的方法。基本上,我希望能够去使用两种不同的路线相同的观点,无论是由一个项目的ID或按项目的名称和它的母公司(项目可以有不同的父母相同的名称)。一个搜索词可以用来过滤列表。

例如...

 产品/ {}动作/ ParentName / ITEMNAME
项目/ {}动作/ 1234-4321-1234-4321

下面是我的操作方法(也有删除操作方法)...

  //方法#1
公众的ActionResult分配(字符串parentName,ItemName字符串){
    //逻辑在这里找回物品的ID ...
    字符串的itemId = ...;
    返回RedirectToAction(分配,项目,新的{}的itemId);
}//方法#2
公众的ActionResult分配(字符串的itemId,字符串搜索关键词,诠释?页){...}

和这里的路...

  routes.MapRoute(AssignRemove
                项目/ {行动} / {}的itemId,
                新{控制器=项目}
                );routes.MapRoute(AssignRemove pretty
                项目/ {行动} / {parentName} / {} ITEMNAME
                新{控制器=项目}
                );

我明白了为什么错误发生,因为参数可以为空,但我想不出解决它的最好办法。是我设计的穷人开始?我已经考虑过延长方法1 的签名,包括搜索参数,并在方法2 到一个私有方法,他们将两个电话,但我不认为会真正解决歧义。

任何帮助将大大AP preciated。


实际的解决方案(根据李维斯的答案)

我添加下面的类...

 公共类RequireRouteValues​​Attribute:ActionMethodSelectorAttribute {
    公共RequireRouteValues​​Attribute(字符串[] valueNames){
        ValueNames = valueNames;
    }    公众覆盖布尔IsValidForRequest(ControllerContext controllerContext,MethodInfo的MethodInfo的){
        布尔包含= FALSE;
        的foreach(在ValueNames VAR值){
            包含= controllerContext.RequestContext.RouteData.Values​​.ContainsKey(值);
            如果(包含!)破;
        }
        返回包含;
    }    公共字符串[] {ValueNames获得;私人集; }
}

再点缀的动作方法......

  [RequireRouteValues​​(新[] {parentName,ITEMNAME})]
公众的ActionResult分配(字符串parentName,ItemName字符串){...}[RequireRouteValues​​(新[] {的itemId})]
公众的ActionResult分配(字符串的itemId){...}


解决方案

MVC不支持方法重载的签名完全根据,所以这将会失败:

 公众的ActionResult的MyMethod(INT someInt){/ * ... * /}
公众的ActionResult的MyMethod(字符串someString){/ * ... * /}

然而,它的确实的基于属性的支持方法重载:

  [RequireRequestValue(someInt)]
公众的ActionResult的MyMethod(INT someInt){/ * ... * /}[RequireRequestValue(someString)]
公众的ActionResult的MyMethod(字符串someString){/ * ... * /}公共类RequireRequestValueAttribute:ActionMethodSelectorAttribute {
    公共RequireRequestValueAttribute(字符串VALUENAME){
        ValueName的= VALUENAME;
    }
    公众覆盖布尔IsValidForRequest(ControllerContext controllerContext,MethodInfo的MethodInfo的){
        回报(controllerContext.HttpContext.Request [ValueName的]!= NULL);
    }
    公共字符串ValueName的{搞定;私人集; }
}

在上面的例子中,属性简单地说这种方法相匹配,如果键的 XXX 的是$ P $在请求psent。您还可以通过,如果是更适合您的目的包含在路线(controllerContext.RequestContext)中的信息进行过滤。

I have two action methods that are conflicting. Basically, I want to be able to get to the same view using two different routes, either by an item's ID or by the item's name and its parent's (items can have the same name across different parents). A search term can be used to filter the list.

For example...

Items/{action}/ParentName/ItemName
Items/{action}/1234-4321-1234-4321

Here are my action methods (there are also Remove action methods)...

// 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) { ... }

And here are the routes...

routes.MapRoute("AssignRemove",
                "Items/{action}/{itemId}",
                new { controller = "Items" }
                );

routes.MapRoute("AssignRemovePretty",
                "Items/{action}/{parentName}/{itemName}",
                new { controller = "Items" }
                );

I understand why the error is occurring, since the page parameter can be null, but I can't figure out the best way to resolve it. Is my design poor to begin with? I've thought about extending Method #1's signature to include the search parameters and moving the logic in Method #2 out to a private method they would both call, but I don't believe that will actually resolve the ambiguity.

Any help would be greatly appreciated.


Actual Solution (based on Levi's answer)

I added the following class...

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

And then decorated the action methods...

[RequireRouteValues(new[] { "parentName", "itemName" })]
public ActionResult Assign(string parentName, string itemName) { ... }

[RequireRouteValues(new[] { "itemId" })]
public ActionResult Assign(string itemId) { ... }

解决方案

MVC doesn't support method overloading based solely on signature, so this will fail:

public ActionResult MyMethod(int someInt) { /* ... */ }
public ActionResult MyMethod(string someString) { /* ... */ }

However, it does support method overloading based on attribute:

[RequireRequestValue("someInt")]
public ActionResult MyMethod(int someInt) { /* ... */ }

[RequireRequestValue("someString")]
public ActionResult MyMethod(string someString) { /* ... */ }

public class RequireRequestValueAttribute : ActionMethodSelectorAttribute {
    public RequireRequestValueAttribute(string valueName) {
        ValueName = valueName;
    }
    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
        return (controllerContext.HttpContext.Request[ValueName] != null);
    }
    public string ValueName { get; private set; }
}

In the above example, the attribute simply says "this method matches if the key xxx was present in the request." You can also filter by information contained within the route (controllerContext.RequestContext) if that better suits your purposes.

这篇关于ASP.NET MVC暧昧动作方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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