2014-04-11 53 views
1

這是我的TransferController類的草圖。未找到與ASP.NET Web API中的請求URI錯誤相匹配的HTTP資源

所有這些都是Web API代碼。

public class TransferController : ApiController 
{ 
    [HttpGet, ActionName("Queue")] 
    public IEnumerable<object> GetQueue(Guid sessionId) {...} 

    [HttpDelete, ActionName("Delete")] 
    public void Delete(Guid sessionId, Guid fileId) {...} 

    [HttpGet, ActionName("Cancel")] 
    public bool Cancel(Guid sessionId, Guid fileId) {...} 

    [HttpGet, ActionName("UploadedBytes")] 
    public long GetUploadedByteCount(Guid sessionId, Guid fileId) {...} 

    [HttpGet, ActionName("DownloadUrl")] 
    public string GetDownloadUrl(string fileId) {...} 

    [HttpPost, ActionName("FileChunk")] 
    public void PostFileChunk([FromUri]Guid sessionId, [FromUri]Guid fileId) {...} 

    [HttpPost, ActionName("UploadDefinition")] 
    public Guid PostUploadItem([FromBody]UploadDefinition uploadDef) {...} 

} 

這是路由。

public static void Register(HttpConfiguration config) 
{ 
    config.Routes.MapHttpRoute(
    name: "DefaultApi", 
    routeTemplate: "api/{controller}/{action}" 
    ); 
    config.Routes.MapHttpRoute(
    name: "DefaultApiDefaultMethod", 
    routeTemplate: "api/{controller}" 
    ); 
} 

這是調用。

$.ajax({ 
    url: "api/Transfer/Queue", 
    data: { sessiondId: login.SessionId() }  
}) 
.done(function (result) { 
    history.push(new UploadItem()); 
    for (var i = 0; i < result.length; i++) { 
    var ui = new UploadItem(result[i]); 
    history.push(ui); 
    } 
}) 
.fail(function (result) { 
    app.showMessage(JSON.parse(result.responseText).Message); 
}); 

這就是結果。

No HTTP resource was found that matches the request URI 'http://localhost:54770/api/Transfer/Queue?sessiondId=0e2c47b9-e674-446d-a06c-ce16932f9580'.

這是我的UserController類的草圖。

public class UserController : ApiController 

    [HttpGet, ActionName("Authenticate")] 
    public object Authenticate(string email, string password) {...} 

    [HttpPost] 
    public void Register([FromBody]UserDefinition userDef) {...} 

    [HttpGet, ActionName("Pulse")] 
    public bool Pulse(Guid sessionId) {...} 

} 

至於原因,深不可測給我,我沒有問題要求在UserController的東西。參數以完全相同的方式進行編組,並且相同的路徑正在使用中。


下面的Darrel Miller使用單元測試來驗證路由。坦率地說,我踢自己沒有想到這一點,現在我也做了同樣的事情。

但測試,因爲他顯示他們真的測試只解析的URL。例如,此測試通過

public void TestMvc4RouteWibble() 
{ 
    var config = new HttpConfiguration(); 
    config.Routes.MapHttpRoute(
     name: "DefaultApi", 
     routeTemplate: "api/{controller}/{action}/{id}", 
     defaults: new { id = RouteParameter.Optional } 
    ); 


    var route = 
     config.Routes.GetRouteData(new HttpRequestMessage() 
     { 
     RequestUri = new Uri("http://localhost:54770/api/Transfer/Wibble?sessionId=0e2c47b9-e674-446d-a06c-ce16932f9580&fileId=0e2c47b9-e674-446d-a06c-ce16932f9581") //? 
     }); 

    Assert.IsNotNull(route); 
    Assert.AreEqual("Transfer", route.Values["controller"]); 
    Assert.AreEqual("Wibble", route.Values["action"]); 

} 

儘管在傳輸控制器上顯着缺少Wibble方法。

此外,路由對象實際上並不是一個HttpRoute對象,它是一個HttpRouteData對象。但是,這是微不足道的糾正。 HttpRoute對象可用作HttpRouteData對象的屬性。

public void TestMvc4RouteWibble() 
{ 
    var config = new HttpConfiguration(); 
    config.Routes.MapHttpRoute(
     name: "DefaultApi", 
     routeTemplate: "api/{controller}/{action}/{id}", 
     defaults: new { id = RouteParameter.Optional } 
    ); 


    var routeData = 
     config.Routes.GetRouteData(new HttpRequestMessage() 
     { 
     RequestUri = new Uri("http://localhost:54770/api/Transfer/Wibble?sessionId=0e2c47b9-e674-446d-a06c-ce16932f9580&fileId=0e2c47b9-e674-446d-a06c-ce16932f9581") //? 
     }); 

    Assert.IsNotNull(routeData); 
    Assert.AreEqual("Transfer", routeData.Values["controller"]); 
    Assert.AreEqual("Wibble", routeData.Values["action"]); 

} 

而且它又具有Handler屬性。然而,這是比它可能提供的信息較少,因爲一個空的處理程序僅僅意味着(從MSDN)

如果爲null,默認處理程序將信息分配到IHttpController的實現。

現在,我的控制器派生自ApiController,它肯定實現了ExecuteAsync方法,它是IHttpController接口指定的唯一的東西。我想象的意思是如果我更瞭解它,我可以測試該方法的執行情況。

+0

我會避免獲取'取消' –

+0

並不是所有的動作都應該返回ActionResult?我不知道Apicontroller,但在控制器中,您必須具有返回類型的ActionResult或派生類型... –

+0

這是Web API。這應該是顯而易見的,從類繼承ApiController,但我會在適當的問題中調用它。 –

回答

2

OK,然後...謝謝把單元測試的想法放在我的腦海裏,它極大地加快了速度。

這裏的內幕:

你可以有不同的動詞相同的參數簽名(得到後把刪除)。

不能在同一個動詞上的不同動作名稱上具有相同的參數簽名。

您只需要改變一個參數名稱。

因此,這是確定的,因爲他們都在不同的動詞

[HttpDelete, ActionName("Delete")] 
public void Delete(Guid sessionId, Guid fileId) {...} 

[HttpGet, ActionName("Cancel")] 
public bool Cancel(Guid sessionId, Guid fileId) {...} 

[HttpPost, ActionName("FileChunk")] 
public void PostFileChunk(Guid sessionId, Guid fileId) {...} 

,而是因爲他們都得到

[HttpGet, ActionName("UploadedBytes")] 
public long GetUploadedByteCount(Guid sessionId, Guid fileId) {...} 

[HttpGet, ActionName("Cancel")] 
public bool Cancel(Guid sessionId, Guid fileId) {...} 

,你可以修復它像這樣

這是不是很酷
[HttpGet, ActionName("UploadedBytes")] 
public long GetUploadedByteCount(Guid sessionId, Guid uploadBytesFileId) {...} 

[HttpGet, ActionName("Cancel")] 
public bool Cancel(Guid sessionId, Guid cancelFileId) {...} 

也許我是一個硬屁股,但就我而言,它不是路由,直到該方法被調用。

3

下面是測試演示路由工作正常,

[Fact] 
public void TestRoute() 
{ 
    var config = new HttpConfiguration(); 
    config.Routes.MapHttpRoute(
     name: "DefaultApi", 
     routeTemplate: "api/{controller}/{action}" 
     ); 


    var route = 
     config.Routes.GetRouteData(new HttpRequestMessage() 
     { 
      RequestUri = new Uri("http://localhost:54770/api/Transfer/Queue?sessionId=0e2c47b9-e674-446d-a06c-ce16932f9580") //? 
     }); 

    Assert.NotNull(route); 
    Assert.Equal("Transfer",route.Values["controller"]); 
    Assert.Equal("Queue",route.Values["action"]); 

} 

和下面是該調度/動作選擇的測試也在努力,

[Fact] 
public void TestDispatch() 
{ 
    var config = new HttpConfiguration(); 
    config.Routes.MapHttpRoute(
     name: "DefaultApi", 
     routeTemplate: "api/{controller}/{action}" 
     ); 

    var server = new HttpServer(config); 

    var client = new HttpClient(server); 
    var response = 
     client.GetAsync(new Uri("http://localhost:54770/api/Transfer/Queue?sessionId=0e2c47b9-e674-446d-a06c-ce16932f9580")) // 
      .Result; 

    Assert.Equal(HttpStatusCode.OK, response.StatusCode); 
} 


public class TransferController : ApiController 
{ 
    [HttpGet] 
    [ActionName("Queue")] 
    public IEnumerable<object> Queue(Guid sessionId) 
    { 
     return null; 
    } 

} 
+0

當然,我會放棄這一點。但是叫我傻瓜先生,爲什麼它對api/User/Pulse有效? –

+0

將所有Guid更改爲字符串並在方法內解析它們。這對我(相信)路由失敗的問題沒有影響。 –

+0

@PeterWone我不知道爲什麼我以前得到錯誤,但現在它對我來說工作得很好......非常困惑。 –

相關問題