Url.Link无法在WebAPI中使用

ash*_*ina 4 c# url-helper asp.net-mvc-4 asp.net-web-api

使用下面的单元测试..我试图测试我的webapi.

[Test]
public void CheckControllerForCreate()
{
    var config = new HttpConfiguration();
    config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
    var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/product");
    var route = config.Routes.MapHttpRoute("Foo", "api/{controller}/{id}");
    var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", "products" } });
    var controller = new ProductController
    {
        ControllerContext = new HttpControllerContext(config, routeData, request),
        Request = request,
        Url = new UrlHelper(request)
    };

    controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;

    var result = controller.Create(new Product {Id = 4, Name = "Tomato Soup", Category = "Groceries", Price = 1});
}

[HttpPost]
public HttpResponseMessage Create(Product product)
{
    var url = Url;
    if (product == null)
        throw new HttpResponseException(new HttpResponseMessage{StatusCode = HttpStatusCode.BadRequest,ReasonPhrase = "Product is not specified"});
    products.Add(product);
    var response = Request.CreateResponse(HttpStatusCode.Created, product);
    string uri = Url.Link("Foo", product.Id);
    response.Headers.Location = new Uri(uri);
    return response;
}
Run Code Online (Sandbox Code Playgroud)

因为创建操作抛出异常urinull.现在,Url助手正在正确地拾取RouteName,否则会出现RouteName not found异常.我假设我的配置有些错误.

我提到了http://www.peterprovost.org/blog/2012/06/16/unit-testing-asp-dot-net-web-api以及其他一些用于对控制器进行单元测试的帖子.

WebAPI方法在这里是codeplex

http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/1acb241299a8#src/System.Web.Http/Routing/UrlHelper.cs

编辑

我把它缩小到vpd为空(UrlHelper)

IHttpVirtualPathData vpd = configuration.Routes.GetVirtualPath(
                request: request,
                name: routeName,
                values: routeValues);
Run Code Online (Sandbox Code Playgroud)

似乎无法弄清楚为什么?

Dar*_*rov 9

您需要将routeData设置为请求,方法与配置相同:

controller.Request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData;
Run Code Online (Sandbox Code Playgroud)

您也错误地使用了Url.Link帮助程序.您尚未指定控制器,也未指明ID.

控制器中的代码应如下所示:

string uri = Url.Link("Foo", new { id = product.Id, controller = "product" });
Run Code Online (Sandbox Code Playgroud)

更新:

这是一个完整的例子.

控制器:

public class ProductController : ApiController
{
    public HttpResponseMessage Create(int id)
    {
        var uri = Url.Link("Foo", new { id = id, controller = "product" });
        return Request.CreateResponse(HttpStatusCode.OK, uri);
    }
}
Run Code Online (Sandbox Code Playgroud)

测试:

// arrange
var config = new HttpConfiguration();
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/product");
var route = config.Routes.MapHttpRoute("Foo", "api/{controller}/{id}");
var routeData = new HttpRouteData(route, new HttpRouteValueDictionary(new { controller = "product" }));
var controller = new ProductController
{
    ControllerContext = new HttpControllerContext(config, routeData, request),
    Request = request,
    Url = new UrlHelper(request)
};
controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
controller.Request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData;

// act
var result = controller.Create(4);

// assert
...
Run Code Online (Sandbox Code Playgroud)