2016-10-10 3 views
0

2 개의 다른 어셈블리 (두 개의 서로 다른 프로젝트에 있음)에서 동일한 이름의 컨트롤러가 두 개 있습니다 (이 두 컨트롤러는 XController).런타임에 실행할 API 컨트롤러를 지정하십시오.

하나는 모의 데이터를 반환하고 두 번째는 실제 거래입니다.

http(s)://.../api/X 컨트롤러에 액세스하려고하면 uri와 일치하는 이름의 컨트롤러가 두 개 발견되므로 물론 예외입니다.

내 목표는 도달 한 하나 또는 다른 컨트롤러로 쉽게 웹 API를 실행할 수 있습니다.

은 내가 #if <symbol> ... #endif에서 그 클래스를 래핑 수 있습니다 알고 있지만 나는 다른 한 XController 전환 할 때마다 두 프로젝트에 대한 변경을해야합니다.

나는 IHttpControllerSelector에서 뭔가를 할 수 있다고 생각하지만 어쩌면 그렇게 멀리 가져 왔을 수도 있습니다.

어떻게하면됩니까?

답변

1

구현 suggested by Microsoft은 "네임 스페이스"가 포함 된 사용자 지정 경로를 사용하고 사용자 지정 구성을 IHttpControllerSelector (사용자가 제안한 것처럼)으로 사용합니다.

// used in your WebApiConfig class 
    config.Routes.MapHttpRoute(
     name: "DefaultApi", 
     routeTemplate: "api/{namespace}/{controller}/{id}", 
     defaults: new { id = RouteParameter.Optional } 
    ); 

    config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config)); 

그리고 NamespaceHttControllerSelector의 구현 :

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; 
    } 
} 
0

내가 함께 한이 코드를 직접적으로 링크 된 소스 코드에서 파생, 난 그냥 앞으로 passerbys에 대한 직접 참조 여기에 넣어 이 토양이지만 어쩌면 내가 무시한 현기증 나는 측세가있다. 누군가 그게 잘못이라면 저에게 말해 줄 수 있습니까?

protected void Application_Start() 
    { 
     var specificControllerTypes = new[] 
     { 
      typeof(Mocks.XController) 
     }; 
     var config = GlobalConfiguration.Configuration; 
     config.Services.Replace(
      typeof(IHttpControllerTypeResolver), 
      new DefaultHttpControllerTypeResolver(type => 
       type.IsVisible && 
       !type.IsAbstract && 
       typeof(IHttpController).IsAssignableFrom(type) && 
       type.Name.EndsWith(DefaultHttpControllerSelector.ControllerSuffix) && 
       !specificControllerTypes.Any(t => t != type && t.Name == type.Name) 
      ) 
     ); 
관련 문제