这是我的TransferController类的草图。
所有这些都是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 :(得分: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;
}
}
答案 1 :(得分:3)
好吧那么......谢谢你把单元测试的想法放在脑子里,它极大地加速了。
这是低点:
您可以在不同的动词上使用相同的参数签名(get post put delete)。
您不能在同一动词上的不同动作名称上具有相同的参数签名。
您只需要改变一个参数名称。
所以这没关系,因为他们都在不同的动词上
[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) {...}
也许我是个笨蛋,但就我而言,在调用该方法之前它不会路由。