为什么我的Web API路由重新路由/错误路由? [英] Why is my Web API routing being re-routed / falsely routed?
问题描述
我有一个特定的控制器/存储库的两个GET方法:
I have two GET methods for a particular Controller / Repository:
public IEnumerable<InventoryItem> GetAllInventoryItems()
{
return inventoryItemsRepository.GetAll();
}
[Route("api/{controller}/{ID}/{CountToFetch}")]
public IEnumerable<InventoryItem> GetBatchOfInventoryItemsByStartingID(string ID, int CountToFetch)
{
return inventoryItemsRepository.Get(ID, CountToFetch);
}
即使我已经尝试从客户端调用所有这些方式,两个参数:
Even though I've tried calling it all these ways from the client, with two arguments:
0)
formatargready_uri = string.Format("http://localhost:28642/api/inventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH);
var webRequest = (HttpWebRequest)WebRequest.Create(formatargready_uri);
1)
formatargready_uri = string.Format("http://localhost:28642/api/inventoryItems/?ID={0}&CountToFetch={1}", lastIDFetched, RECORDS_TO_FETCH);
var webRequest = (HttpWebRequest)WebRequest.Create(formatargready_uri);
2)
formatargready_uri = string.Format("http://localhost:28642/api/inventoryItems/ID={0}&CountToFetch={1}", lastIDFetched, RECORDS_TO_FETCH);
var webRequest = (HttpWebRequest)WebRequest.Create(formatargready_uri);
...在每种情况下,它仍然是被调用的第一个方法(GetAll)。为什么?
...in each case it is still the first method (GetAll) that is being called. Why?
这是我的存储库代码:
public IEnumerable<InventoryItem> GetAll()
{
return inventoryItems;
}
public IEnumerable<InventoryItem> Get(string ID, int CountToFetch)
{
return inventoryItems.Where(i => 0 < String.Compare(i.Id, ID)).Take(CountToFetch);
}
...这里是WebApiConfig.cs中的内容:
...and here is what's in WebApiConfig.cs:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApiWithParameters",
routeTemplate: "api/{controller}/{ID}/{CountToFetch}",
defaults: new { ID = RouteParameter.Optional, CountToFetch = RouteParameter.Optional }
);
}
UPDATE
这将显示我试图路由调用到我想要运行的控制器方法:
UPDATE
This will show what I've tried as to routing calls to the Controller method I'm trying to have run:
//[HttpGet]
//[Route("api/{controller}/{ID:string}/{CountToFetch:int}")] <-- throws exception - won't run
//[Route("{controller}/{ID:string}/{CountToFetch:int}")] <-- throws exception - won't run
//[Route("inventoryItems/{ID:string}/{CountToFetch:int}")] <-- throws exception - won't run
//[Route("api/inventoryItems/{ID:string}/{CountToFetch:int}")] <-- throws exception - won't run
//[Route("api/{controller}/{ID}/{CountToFetch}")] // <-- runs, but is not called
[Route("api/InventoryItemsController/{ID}/{CountToFetch}")] // <-- runs, but is not called
//[Route("api/{controller}/{ID:string}/{CountToFetch:int}")] <-- throws exception - won't run
所以我不想调用的方法是非常强大的:无论我如何装饰另一个方法,或我如何调用它,不需要的方法运行。
So the method that I don't want to be called is extremely robust: no matter how I decorate the other method, or how I call it, the undesired one runs.
只是允许通过名称调用Controller方法更容易吗?例如,给定此Controller方法:
Wouldn't it have been easier to just allow the calling of Controller methods by name? e.g, given this Controller method:
public IEnumerable<InventoryItem> GetBatchOfInventoryItemsByStartingID(string ID, int CountToFetch)
{
return inventoryItemsRepository.Get(ID, CountToFetch); //.Where(i => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase));
}
...为什么[c,w]客户端如此:
...why [c,w]ouldn't it be called from the client like so:
formatargready_uri = string.Format("http://localhost:28642/api/InventoryItemsController.GetBatchOfInventoryItemsByStartingID/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH);
ISTM
那么它是什么呢?
可能的路由机制是由于lastIDFetched被设置为一个空字符串而变得困惑:
Possibly the routing mechanism is getting confused because of lastIDFetched being set to an empty string:
string lastIDFetched = string.Empty;
...然后formatargready_uri。
...and so then formatargready_uri. which is assigned to this way:
formatargready_uri = string.Format("http://locohost:28642/api/InventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH);
...第一个:
"http://locohost:28642/api/InventoryItems//100"
(当我希望它是:
"http://locohost:28642/api/InventoryItems/""/100"
)
可能是因为丢失的第一个参数是什么抛出了路由机制,所以,当它看到:
Could it be that the "missing" first arg is what's throwing the routing mechanism off, so that when it sees:
"http://locohost:28642/api/InventoryItems//100"
t知道是否调用这个:
...it doesn't know whether to call this:
public IEnumerable<InventoryItem> GetBatchOfInventoryItemsByStartingID(string ID, int CountToFetch)
{
return inventoryItemsRepository.Get(ID, CountToFetch); //.Where(i => string.Equals(p.Category, category,
StringComparison。 OrdinalIgnoreCase));
}
StringComparison.OrdinalIgnoreCase)); }
...或此:
public IEnumerable<InventoryItem> GetAllInventoryItems()
{
return inventoryItemsRepository.GetAll();
}
当我注释掉另一个方法时,客户端别无选择,只能看到Controller / Repository中唯一存在的方法,在这行:
When I comment out the other method, so that the client has no choice but to see the only existing method in the Controller/Repository, it does nothing on this line:
var webRequest = (HttpWebRequest)WebRequest.Create(formatargready_uri);
(控制器中的两个arg方法尚未调用)
(the two-arg method in the Controller still isn't called)
这就是控制器中的所有内容:
This is all that's in the Controller now:
public class InventoryItemsController : ApiController
{
static readonly IInventoryItemRepository inventoryItemsRepository = new InventoryItemRepository();
[Route("api/InventoryItems/{ID}/{CountToFetch:int}")] // <-- with this route decoration commented out or not, makes no difference
public IEnumerable<InventoryItem> GetBatchOfInventoryItemsByStartingID(string ID, int CountToFetch)
{
return inventoryItemsRepository.Get(ID, CountToFetch); //.Where(i => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase));
}
}
这是相应的Repository接口:
Here is the corresponding Repository interface:
interface IInventoryItemRepository
{
IEnumerable<InventoryItem> Get(string ID, int CountToFetch);
InventoryItem Add(InventoryItem item);
}
...存储库实现:
public class InventoryItemRepository : IInventoryItemRepository
{
private readonly List<InventoryItem> inventoryItems = new List<InventoryItem>();
public InventoryItemRepository()
{
// code that populates inventoryItems by calling Add() not shown - it works, though
}
public IEnumerable<InventoryItem> Get(string ID, int CountToFetch)
{
return inventoryItems.Where(i => 0 < String.Compare(i.Id, ID)).Take(CountToFetch);
}
public InventoryItem Add(InventoryItem item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
inventoryItems.Add(item);
return item;
}
}
...以及调用它的客户端代码:
...and the client code that calls it:
formatargready_uri = string.Format("http://localhost:28642/api/InventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH);
var webRequest = (HttpWebRequest)WebRequest.Create(formatargready_uri);
UPDATE 5
我会像一个有洞的袜子。它似乎是一个问题,开始与空字符串,毕竟。当我把lastIDFetched的初始值从string.Empty改为billy它工作...这是一个错误?有解决方法吗?如果我想从scratch开始,我会使用什么,而不是string.Empty?
UPDATE 5
Well, I'll be darned like a holey sock. It seems to have been a problem with starting out with the empty string, after all. When I changed the initial value of lastIDFetched from string.Empty to "billy" it worked... Is this a bug? Is there a workaround? If I want to start from "scratch," what would I use rather than string.Empty? A blank space (" ") also doesn't work.
推荐答案
首先,你为什么要拥有 {controller}
在以下属性路由?通过使用属性路由装饰,你已经指示了应该命中的控制器和动作,因此在此处删除 {controller}
并用控制器名称替换。
First, why are you having {controller}
in the following attribute route? By decorating with an attribute route here you already are indicating the controller and action which should be hit, so remove {controller}
here and replace it with the controller name.
[Route("api/{controller}/{ID}/{CountToFetch}")]
public IEnumerable<InventoryItem> GetBatchOfInventoryItemsByStartingID(string ID, int CountToFetch)
{
return inventoryItemsRepository.Get(ID, CountToFetch);
}
请求1)和2) ID和CountToFetch是必需的路由参数。
Requests 1) and 2) where you are using query string would not work because ID and CountToFetch are required route parameters.
这篇关于为什么我的Web API路由重新路由/错误路由?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!