2014-02-13 49 views
0

我已經在之前的位置完成了這一點,但我不記得如何。WebAPI:自定義路由到異步加載ApiController

我有一個基於插件的WebAPI應用程序。每個插件組件具有實現IApiServiceEntryPoint它類似於這樣的類:

public interface IApiServiceEntryPoint : IDisposable 
{ 
    /// <summary> 
    /// Gets the name of the API Plugin 
    /// </summary> 
    string Name { get; } 

    /// <summary> 
    /// Registers the assembly in the application, sets up the routes, and enables invocation of API requests 
    /// </summary> 
    void Register(RouteCollection routes); 

    /// <summary> 
    /// Gets the routing namespace of the plugin 
    /// </summary> 
    string UrlNameSpace { get; } 
} 

Register(RouteCollection routes),除其他外,採取路由集合從主Web應用程序(MVC4),並補充說,這個插件組件將支持自定義路線。

假設我在我的新MyApi.Plugins.Foo組件中的MyApi.Plugins.Foo.FooServiceEntryPoint類中實現了此接口。 Name的值將是「Foo」,UrlNameSpace將是「Foo」,我們假設api控制器類將是MyApi.Plugins.Foo.FooController。意圖是當消費者點擊http://myapi.something.com/Foo/GiveMeRecords時,將調用MyApi.Plugins.Foo.FooController.GiveMeRecords方法。

我的MyApi.Plugins.Foo.FooServiceEntryPoint.Register(RouteCollection routes)應該是什麼樣子?

回答

0

好的,我明白了這一點。這是一個有點複雜,比我原來想象,但這裏需要做些什麼:

Register方法,我把下面的代碼在一個抽象類,實現IApiServiceEntryPoint

​​

我再有實現我自己IHttpControllerSelector(我無恥地從一個博客帖子修改,我發現here):

public class ApiHttpControllerSelector : 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; 
    private static readonly List<Type> _pluginControllers = new List<Type>(); 

    public ApiHttpControllerSelector(HttpConfiguration config) 
    { 
     _configuration = config; 
     _duplicates = new HashSet<string>(StringComparer.OrdinalIgnoreCase); 
     _controllers = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDictionary); 
     _pluginControllers.AddRange(ApiFramework.PluginHelper.Controllers); 
    } 

    private Dictionary<string, HttpControllerDescriptor> InitializeControllerDictionary() 
    { 
     var dictionary = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase); 

     var assembliesResolver = _configuration.Services.GetAssembliesResolver(); 
     var controllersResolver = _configuration.Services.GetHttpControllerTypeResolver(); 

     var controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver) 
      .Concat(_pluginControllers).ToList();    

     foreach (var t in controllerTypes) 
     { 
      var key = string.Format("{0}.{1}", t.Namespace, t.Name); 
      dictionary[key] = new HttpControllerDescriptor(_configuration, t.Name, t); 
     } 
     return dictionary; 
    } 

    public System.Web.Http.Controllers.HttpControllerDescriptor SelectController(System.Net.Http.HttpRequestMessage request) 
    { 
     var routeData = request.GetRouteData(); 
     if (routeData == null) 
     { 
      throw new HttpResponseException(new HttpResponseMessage(System.Net.HttpStatusCode.NotFound)); 
     } 

     string namespaceName = GetRouteVariable<string>(routeData, "namespace"); 
     if (namespaceName == null) 
     { 
      throw new HttpResponseException(new HttpResponseMessage(System.Net.HttpStatusCode.NotFound)); 
     } 

     string controllerName = GetRouteVariable<string>(routeData, "controller"); 
     if (controllerName == null) 
     { 
      throw new HttpResponseException(new HttpResponseMessage(System.Net.HttpStatusCode.NotFound)); 
     } 

     // Find a matching controller. 
     var baseKey = String.Format(CultureInfo.InvariantCulture, "{0}.{1}Controller", namespaceName, controllerName); 
     var key = String.Format("{0}Controller", baseKey); 
     HttpControllerDescriptor controllerDescriptor; 
     if (_controllers.Value.TryGetValue(key, out controllerDescriptor)) // the default should include the "Controller" at the end of the class name 
     { 
      return controllerDescriptor; 
     } 
     else if (_controllers.Value.TryGetValue(baseKey, out controllerDescriptor)) //explicit class name, sans "Controller" 
     { 
      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); 
     } 

    } 

    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 IDictionary<string, HttpControllerDescriptor> GetControllerMapping() 
    { 
     return _controllers.Value; 
    } 
} 

然後我不得不更換默認IHttpControllerSelector在我的Global.asax.cs像這樣:

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), 
      new ApiHttpControllerSelector(GlobalConfiguration.Configuration)); 

...然後一切正常。