在 ASP.NET Web API 中,使用 命名空間(namespace) 來作為路由的參數

來源:互聯網
上載者:User

標籤:

這個問題來源於我想在 Web API 中使用相同的控制器名稱(Controller)在不同的命名空間下,但是 Web API 的預設 路由(Route) 機制是會忽略命名空間的不同的,如果這樣做,會看到以下提示:

找到多個與名為“XXX”的控制器匹配的類型。如果為此請求(“{namespace}/{controller}/{action}”)提供服務的路由找到多個控制器,並且這些控制器是使用相同的名稱但不同的命名空間定義的(這不受支援),則會發生這種情況。

在 ASP.NET MVC 中,可以通過建立 地區(Area) 來解決這種問題,但 Web API 並沒有地區這種東西。

 

不過官方早已給出瞭解決方案,只是並沒有作為 Web API 的一部分直接整合。不知道是出於什麼考慮。

原文連結:http://blogs.msdn.com/b/webdev/archive/2013/03/08/using-namespaces-to-version-web-apis.aspx

 

主要思路就是自己重新實現一個可以識別命名空間的路由選取器,然後替換掉系統預設的路由選取器即可。這個命名空間選取器官方也已經幫我們實現,並且提供了完整的項目示範樣本。

代碼連結:http://aspnet.codeplex.com/SourceControl/changeset/view/dd207952fa86#Samples/WebApi/NamespaceControllerSelector/NamespaceHttpControllerSelector.cs

 

將此類的實現加入到項目中,並在初始化 Web API 路由時進行替換,在設定路由模板的時候,加入相應的 {namespace} 參數即可:

public static class WebApiConfig{    public static void Register(HttpConfiguration config)    {        config.MapHttpAttributeRoutes();        config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));        config.Routes.MapHttpRoute(            name: "DefaultApi",            routeTemplate: "{namespace}/{controller}/{action}"        );    }}

 

最後,附上官方 NamespaceHttpControllerSelector 類的實現代碼(出處請見上述連結):

public class NamespaceHttpControllerSelector : IHttpControllerSelector{    private const string NamespaceKey = "namespace";    private const string ControllerKey = "controller";    private readonly HttpConfiguration _configuration;    private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controllers;    private readonly HashSet<string> _duplicates;    public NamespaceHttpControllerSelector(HttpConfiguration config)    {        _configuration = config;        _duplicates = new HashSet<string>(StringComparer.OrdinalIgnoreCase);        _controllers = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDictionary);    }    private Dictionary<string, HttpControllerDescriptor> InitializeControllerDictionary()    {        var dictionary = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);        // Create a lookup table where key is "namespace.controller". The value of "namespace" is the last        // segment of the full namespace. For example:        // MyApplication.Controllers.V1.ProductsController => "V1.Products"        IAssembliesResolver assembliesResolver = _configuration.Services.GetAssembliesResolver();        IHttpControllerTypeResolver controllersResolver = _configuration.Services.GetHttpControllerTypeResolver();        ICollection<Type> controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);        foreach (Type t in controllerTypes)        {            var segments = t.Namespace.Split(Type.Delimiter);            // For the dictionary key, strip "Controller" from the end of the type name.            // This matches the behavior of DefaultHttpControllerSelector.            var controllerName = t.Name.Remove(t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length);            var key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", segments[segments.Length - 1], controllerName);            // Check for duplicate keys.            if (dictionary.Keys.Contains(key))            {                _duplicates.Add(key);            }            else            {                dictionary[key] = new HttpControllerDescriptor(_configuration, t.Name, t);            }        }        // Remove any duplicates from the dictionary, because these create ambiguous matches.         // For example, "Foo.V1.ProductsController" and "Bar.V1.ProductsController" both map to "v1.products".        foreach (string s in _duplicates)        {            dictionary.Remove(s);        }        return dictionary;    }    // Get a value from the route data, if present.    private static T GetRouteVariable<T>(IHttpRouteData routeData, string name)    {        object result = null;        if (routeData.Values.TryGetValue(name, out result))        {            return (T)result;        }        return default(T);    }    public HttpControllerDescriptor SelectController(HttpRequestMessage request)    {        IHttpRouteData routeData = request.GetRouteData();        if (routeData == null)        {            throw new HttpResponseException(HttpStatusCode.NotFound);        }        // Get the namespace and controller variables from the route data.        string namespaceName = GetRouteVariable<string>(routeData, NamespaceKey);        if (namespaceName == null)        {            throw new HttpResponseException(HttpStatusCode.NotFound);        }        string controllerName = GetRouteVariable<string>(routeData, ControllerKey);        if (controllerName == null)        {            throw new HttpResponseException(HttpStatusCode.NotFound);        }        // Find a matching controller.        string key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", namespaceName, controllerName);        HttpControllerDescriptor controllerDescriptor;        if (_controllers.Value.TryGetValue(key, out controllerDescriptor))        {            return controllerDescriptor;        }        else if (_duplicates.Contains(key))        {            throw new HttpResponseException(                request.CreateErrorResponse(HttpStatusCode.InternalServerError,                "Multiple controllers were found that match this request."));        }        else        {            throw new HttpResponseException(HttpStatusCode.NotFound);        }    }    public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()    {        return _controllers.Value;    }}

在 ASP.NET Web API 中,使用 命名空間(namespace) 來作為路由的參數

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.