2015-05-13 3 views
0

Я провел несколько дней, пытаясь улучшить управление версиями заголовков веб-API C#; и получил далеко, поскольку теперь он вызывает другое пространство имен, например. v1, v2, но когда я пытаюсь сделать запрос с таким параметром, как id, он не работает, вместо этого он просто вызывает метод контроллера api по умолчанию.C# Web API Versioning

Весь код показан ниже, так что действительно оцените некоторую помощь в понимании того, как заставить его вызывать метод с помощью guid, а не только пустым методом по умолчанию.

Ниже приведено Пространство именСистема контроля, которую я использую. Я добавляю его через файл WebApi.Config.cs и добавляя вызов метода «Заменить», как показано ниже.

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

Селектор контроллер

public class NamespaceControllerSelector : 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 NamespaceControllerSelector(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 = "v" + GetVersionFromHttpHeader(request);//GetRouteVariable<string>(routeData, NamespaceKey); 
      if (namespaceName == null) 
      { 
       throw new HttpResponseException(HttpStatusCode.NotFound); 
      } 

      string controllerName = GetControllerName(request);//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; 
     } 

     private string GetVersionFromHttpHeader(HttpRequestMessage request) 
     { 
      const string headerName = "version"; 

      if (request.Headers.Contains(headerName)) 
      { 
       var versionHeader = request.Headers.GetValues(headerName).FirstOrDefault(); 
       if (versionHeader != null) 
       { 
        return versionHeader; 
       } 
      } 

      return string.Empty; 
     } 


     public virtual string GetControllerName(HttpRequestMessage request) 
     { 

      IHttpRouteData routeData = request.GetRouteData(); 
      if (routeData == null) 
      { 
       return null; 
      } 

      // Look up controller in route data 
      object controllerName = null; 
      routeData.Values.TryGetValue(ControllerKey, out controllerName); 
      return (string)controllerName; 
     } 

    } 

UsersController, что я называю

namespace Api.Controllers.v1 
{ 
    //[Authorize] 
    /// <summary> 
    /// User controller 
    /// </summary> 
    //[RoutePrefix("api")] 
    public class UsersController : ApiController 
    { 
     /// <summary> 
     /// Get all the users in the system 
     /// </summary> 
     /// <returns>A list of User objects</returns> 
     //[Route("users")] 
     [HttpGet] 
     public HttpResponseMessage GetUsers() 
     { 
      return Request.CreateResponse(HttpStatusCode.OK, DummyUsers.GetAllUsers()); 
     } 

     /// <summary> 
     /// Get a user by there id 
     /// </summary> 
     /// <param name="userId">The users id</param> 
     /// <returns>A User object, will return 404 (Not Found) if unable to find</returns> 
     //[Route("users/{userId:guid}")] 
     [HttpGet] 
     public HttpResponseMessage GetUsers(Guid userId) 
     { 
      User user = DummyUsers.GetAllUsers().FirstOrDefault(x => x.Id == userId); 
      if (user != null) 
      { 
       return Request.CreateResponse(HttpStatusCode.OK, user); 
      } 
      return Request.CreateResponse(HttpStatusCode.NotFound); 
     } 

    } 
} 

просьбе я делаю, как вы можете видеть, я передаю в Guid после API/пользователей, поэтому wuld ожидает, что он вызовет метод GetUsers (Guid guid), но его просто вызывает метод GetUsers(). Нужна помощь?

GET http://localhost:62249/api/users/d4eb9dd9-571a-406b-9b6d-07154293c21d 
Host: localhost:62249 
Connection: keep-alive 
Version: 1 
Accept: application/json 
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36 
Accept-Encoding: gzip, deflate, sdch 
Accept-Language: en-US,en;q=0.8 

Большое спасибо Andrew

ответ

0

Проблема заключалась в том, что

GetUsers(Guid guid) 

должен был

GetUsers(Guid id) 

Возможно любителем ошибка, но новичок в этом, как предполагается, это было достаточно тесак знать. Маршрутизация, похоже, немного беспокоит некоторых методов получения дополнительных параметров.