ASP NET Web API中的路由 - 适用于不同版本的API

now*_*ed. 6 c# asp.net routing asp.net-web-api asp.net-mvc-5

我在阅读有关Attribute Routing in Web API 2这里

文章说,

Here are some other patterns that attribute routing makes easy.

API versioning

In this example, “/api/v1/products” would be routed to a different controller than “/api/v2/products”.

/api/v1/products
/api/v2/products
Run Code Online (Sandbox Code Playgroud)

怎么会?

编辑:我会在正常路由中执行此操作:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
         config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/v2/products",
            defaults: new { controller = V2_Products }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/v1/products",
            defaults: new { controller = V1_Products }
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释我如何做到这Attribute Routing一点?Attribute routing对于这个例子,如何使用更容易和方便(根据文章)?

Cyb*_*axs 9

有许多方法可以使用属性路由实现版本控制; 一个非常基本的方法是为每个版本的ApiController 使用RoutePrefix属性

[RoutePrefix("v1")]
public class V1_ProductsController : ApiController
{
    [Route("products")]
    public IEnumerable<string> Get()
    {
        return new string[] { "v1-product1", "v1-product2" };
    }
     //....
}


[RoutePrefix("v2")]
public class V2_ProductsController : ApiController
{
     [Route("products")]
    public IEnumerable<string> Get()
    {
        return new string[] { "v2-product1", "v2-product2" };
    }
    //....
}
Run Code Online (Sandbox Code Playgroud)

/v1/products转到第一个版本/v2/products转到第二个版本.


Vol*_*hat 9

您可以通过重写DefaultHttpControllerSelector来完成

在那里你覆盖selectcontroller的方法

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
            {
                HttpControllerDescriptor controllerDescriptor = null;
                IDictionary<string, HttpControllerDescriptor> controllers = GetControllerMapping();

                IHttpRouteData routeData = request.GetRouteData();

                if (routeData == null)
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }

                object apiVersion;
                if (!routeData.Values.TryGetValue("Version", out apiVersion))
                {
                    apiVersion = "1";
                }


                object controllerName;
                if (!routeData.Values.TryGetValue("controller", out controllerName))
                {
                    controllerName = string.Empty;
                }
                if (controllerName == null)
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }

                string newControllerName = String.Concat(controllerName.ToString(), "V", apiVersion);

                if (controllers.TryGetValue(newControllerName, out controllerDescriptor))
                {
                    return controllerDescriptor;
                }
                if (controllers.TryGetValue(controllerName.ToString(), out controllerDescriptor))
                {
                    return controllerDescriptor;
                }
                throw new HttpResponseException(HttpStatusCode.NotFound);

            }
Run Code Online (Sandbox Code Playgroud)

然后你要添加webapiconfig的路线

 config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{version}/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
Run Code Online (Sandbox Code Playgroud)

并在webapiconfig中注册控制器选择器

config.Services.Replace(typeof(IHttpControllerSelector), new ApiVersioningSelector(config));
Run Code Online (Sandbox Code Playgroud)

所以从现在起如果你命名控制器ProductsV1Controller,它将reffer/api/v1/products.另请注意,我的示例也支持没有版本的路由,因此如果找不到v1,它将尝试检查ProductsController是否存在

PS.代码更新有一个bug就在那里:(