我可以调用我的0-arg GET方法,它工作正常;我的双arg GET方法也是如此;但是,当我向最后一个添加第三个arg时,服务器返回“404 - not found”。为什么它可以弄清楚,大概是基于方法定义(args传递的数量和类型),前两种情况下的正确路由,但不是最后一种?
以下是服务器应用程序中的Web API Rest定义:
存储库接口:
interface IInventoryItemRepository
{
int Get();
IEnumerable<InventoryItem> Get(string ID, int CountToFetch);
IEnumerable<InventoryItem> Get(string ID, string packSize, int CountToFetch);
InventoryItem Add(InventoryItem item);
}
存储库接口实现/具体类:
public class InventoryItemRepository : IInventoryItemRepository
{
private readonly List<InventoryItem> inventoryItems = new List<InventoryItem>();
public InventoryItemRepository()
{
string lastGoodId = string.Empty;
string id = string.Empty;
try
{
using (var conn = new OleDbConnection(
@"Provider=Microsoft.Jet.OLEDB.4.0;User ID=PlatypusBrain;Password=Platydude;Data Source=C:\XLWStuff\DATA\XLWDAT03.MDB;Jet OLEDB:System database=C:\XLWWin\Data\abcd.mdw"))
{
using (var cmd = conn.CreateCommand())
{
. . .
Add(new InventoryItem
{
. . .
});
} // while
. . .
} // InventoryItemRepository (constructor)
public int Get()
{
return inventoryItems.Count;
}
public IEnumerable<InventoryItem> Get(string ID, int CountToFetch)
{
return inventoryItems.Where(i => 0 < String.Compare(i.Id, ID)).Take(CountToFetch);
}
public IEnumerable<InventoryItem> Get(string ID, string packSize, int CountToFetch)
{
return inventoryItems.Where(i => 0 < String.Compare(i.Id, ID)).Where(i => 0 < String.Compare(i.PackSize.ToString(), packSize)).Take(CountToFetch);
}
public InventoryItem Add(InventoryItem item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
inventoryItems.Add(item);
return item;
}
}
库存物品控制器:
public class InventoryItemsController : ApiController
{
static readonly IInventoryItemRepository inventoryItemsRepository = new InventoryItemRepository();
public int GetCountOfInventoryItems()
{
return inventoryItemsRepository.Get();
}
public IEnumerable<InventoryItem> GetBatchOfInventoryItemsByStartingID(string ID, int CountToFetch)
{
return inventoryItemsRepository.Get(ID, CountToFetch);
}
public IEnumerable<InventoryItem> GetBatchOfInventoryItemsByStartingID(string ID, string packSize, int CountToFetch)
{
return inventoryItemsRepository.Get(ID, packSize, CountToFetch);
}
}
...以及来自客户端应用的调用:
// 0-arg method (count)
private void buttonGetInvItemsCount_Click(object sender, EventArgs e)
{
labelInvItemsCount.Text = string.Format("== {0}", getInvItemsCount());
}
private int getInvItemsCount()
{
int recCount = 0;
const string uri = "http://localhost:28642/api/InventoryItems";
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.Method = "GET";
using (var webResponse = (HttpWebResponse)webRequest.GetResponse())
{
if (webResponse.StatusCode == HttpStatusCode.OK)
{
var reader = new StreamReader(webResponse.GetResponseStream());
string s = reader.ReadToEnd();
Int32.TryParse(s, out recCount);
}
}
return recCount;
}
// 2-arg method:
string lastIDFetched = "0";
const int RECORDS_TO_FETCH = 100;
int recordsToFetch = getInvItemsCount();
bool moreRecordsExist = recordsToFetch > 0;
int totalRecordsFetched = 0;
while (moreRecordsExist)
{
string formatargready_uri = string.Format("http://localhost:28642/api/InventoryItems/{0}/{1}", lastIDFetched, RECORDS_TO_FETCH);
var webRequest = (HttpWebRequest)WebRequest.Create(formatargready_uri);
webRequest.Method = "GET";
using (var webResponse = (HttpWebResponse)webRequest.GetResponse())
{
if (webResponse.StatusCode == HttpStatusCode.OK)
{
var reader = new StreamReader(webResponse.GetResponseStream());
string s = reader.ReadToEnd();
var arr = JsonConvert.DeserializeObject<JArray>(s);
foreach (JObject obj in arr)
{
var id = (string)obj["Id"];
lastIDFetched = id;
int packSize = (Int16)obj["PackSize"];
var description = (string)obj["Description"];
int dept = (Int16)obj["DeptSubdeptNumber"];
int subdept = (Int16)obj["InvSubdepartment"];
var vendorId = (string)obj["InventoryName"];
var vendorItem = (string)obj["VendorItemId"];
var avgCost = (Double)obj["Cost"];
var unitList = (Double)obj["ListPrice"];
inventoryItems.Add(new WebAPIClientUtils.InventoryItem
{
Id = id,
InventoryName = vendorId,
UPC_PLU = vendorId,
VendorItemId = vendorItem,
PackSize = packSize,
Description = description,
Quantity = 0.0,
Cost = avgCost,
Margin = (unitList - avgCost),
ListPrice = unitList,
DeptSubdeptNumber = dept,
InvSubdepartment = subdept
});
} // foreach
} // if ((webResponse.StatusCode == HttpStatusCode.OK) && (webResponse.ContentLength > 2))
} // using HttpWebResponse
int recordsFetched = WebAPIClientUtils.WriteRecordsToMockDatabase(inventoryItems, hs);
label1.Text += string.Format("{0} records added to mock database at {1}; ", recordsFetched, DateTime.Now.ToLongTimeString());
totalRecordsFetched += recordsFetched;
moreRecordsExist = (recordsToFetch > (totalRecordsFetched+1)); // <-- I think recordsFetched will be a max of 269, instead of 270, so will have to fix that...
} // while
if (inventoryItems.Count > 0)
{
dataGridViewGETResults.DataSource = inventoryItems;
}
}
// 3-arg method; the three differences between this and the 2-arg method above are commented.
string lastIDFetched = "0";
string lastPackSizeFetched = "1"; // <-- This is new/different from the 2-arg method
const int RECORDS_TO_FETCH = 100;
int recordsToFetch = getInvItemsCount();
bool moreRecordsExist = recordsToFetch > 0;
int totalRecordsFetched = 0;
while (moreRecordsExist)
{
// A third format arg is added, differening from the 2-arg method
string formatargready_uri = string.Format("http://localhost:28642/api/InventoryItems/{0}/{1}/{2}", lastIDFetched, lastPackSizeFetched, RECORDS_TO_FETCH);
var webRequest = (HttpWebRequest)WebRequest.Create(formatargready_uri);
webRequest.Method = "GET";
using (var webResponse = (HttpWebResponse)webRequest.GetResponse())
{
if (webResponse.StatusCode == HttpStatusCode.OK)
{
var reader = new StreamReader(webResponse.GetResponseStream());
string s = reader.ReadToEnd();
var arr = JsonConvert.DeserializeObject<JArray>(s);
foreach (JObject obj in arr)
{
var id = (string)obj["Id"];
lastIDFetched = id;
int packSize = (Int16)obj["PackSize"];
lastPackSizeFetched = packSize.ToString(); // <-- this is the final difference in this method compared to the 2-arg method
. . .
正如您所看到的,两个arg方法和三个arg方法之间的差别很小;但是前者是有效的,而后者则没有。为什么(不是)?
要回答Kiran Challa的评论/问题,请参阅RouteConfig.cs中的内容:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
...和WebApiConfig.cs:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
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 }
defaults: new { ID = RouteParameter.Optional, CountToFetch = RouteParameter.Optional }
);
}
}
我将此添加到WebApiConfig.cs:
config.Routes.MapHttpRoute(
name: "DefaultApiWith3Parameters",
routeTemplate: "api/{controller}/{ID}/{packSize}/{CountToFetch}",
defaults: new { ID = RouteParameter.Optional, packSize = RouteParameter.Optional, CountToFetch = RouteParameter.Optional }
);
......它现在有效。去搞清楚;没有所需方法的装饰 - 也许这就是让我搞砸的原因,是我试图将装饰/注释/属性添加到方法和WebApiConfig中。
我不知道,但在被证明是错误之前,我将避开这些大肆宣传的属性装饰。
现在我将测试Tim S.关于86的可选位的建议......只是花花公子。
我认为WebApiConfig.cs中每个MapHttpRoute的“name”成员只是一个ID,并且与项目中的任何其他内容都没有关联?我的意思是,我可以用一个新名称(例如“ DuckbilledPlatypiOfThePondsUnite ”)证明当前名为“ DefaultApiWith3Parameters ”的那个,它没有任何区别。
答案 0 :(得分:1)
您的路线配置指出api/InventoryItems/{0}/{1}
映射到ID
和CountToFetch
,但没有任何说法api/InventoryItems/{0}/{1}/{2}
应映射到ID, packSize, CountToFetch
。此外,您可能不希望任何这些参数完全可选。试试这个:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApiWith2Parameters",
routeTemplate: "api/{controller}/{ID}/{CountToFetch}"
);
config.Routes.MapHttpRoute(
name: "DefaultApiWith3Parameters",
routeTemplate: "api/{controller}/{ID}/{packSize}/{CountToFetch}"
);