What I am using
- .NET 4.5.2
- Web API 2
I am using a few examples ASP.NET API working with Areas - I am not actually doing areas but trying to do versioning. So now for the code...
This is my Application_Start in my Global.asax:
namespace WebApiVersioning
{
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new VersionedHttpControllerSelector(GlobalConfiguration.Configuration));
}
}
}
This is the custom HttpControllerSelector:
namespace WebApiVersioning.PipeLine
{
public class VersionedHttpControllerSelector : DefaultHttpControllerSelector
{
private const string VersionHeaderName = "API-Version";
private readonly HttpConfiguration _configuration;
private readonly Lazy<ConcurrentDictionary<string, Type>> _apiControllerTypes;
public VersionedHttpControllerSelector(HttpConfiguration configuration) : base(configuration)
{
_configuration = configuration;
_apiControllerTypes = new Lazy<ConcurrentDictionary<string, Type>>(GetControllerTypes);
}
private static string GetVersionHeader(HttpRequestMessage request)
{
IEnumerable<string> headerValues;
if (request.Headers.TryGetValues(VersionHeaderName, out headerValues) && headerValues.Count() == 1)
{
return headerValues.First();
}
throw new Exception($"{VersionHeaderName} not found.");
}
private static ConcurrentDictionary<string, Type> GetControllerTypes()
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var types = assemblies
.SelectMany(a =>
a.GetTypes().Where(t =>
!t.IsAbstract &&
t.Name.EndsWith(ControllerSuffix) &&
typeof(IHttpController).IsAssignableFrom(t)))
.ToDictionary(t => t.FullName, t => t);
return new ConcurrentDictionary<string, Type>(types);
}
private HttpControllerDescriptor GetApiController(HttpRequestMessage request)
{
var controllerName = GetControllerName(request);
var version = GetVersionHeader(request);
if (string.IsNullOrEmpty(version))
{
return null;
}
if (version.Contains("."))
{
version = version.Replace(".", "");
}
var type = GetControllerTypeByVersion(version, controllerName);
return type == null ? null : new HttpControllerDescriptor(_configuration, controllerName, type);
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
return GetApiController(request) ?? base.SelectController(request);
}
private Type GetControllerTypeByVersion(string version, string controllerName)
{
var versionNameToFind = $".Version{version.ToLower()}.";
var controllerNameToFind = $".{controllerName}{ControllerSuffix}";
var query = _apiControllerTypes.Value.AsEnumerable();
var controller =
query.Where(
t =>
t.Key.ToLower().Contains(versionNameToFind.ToLower()) &&
t.Key.EndsWith(controllerNameToFind, StringComparison.OrdinalIgnoreCase))
.Select(t => t.Value).FirstOrDefault();
return controller;
}
}
}
Here is the issue. I originally had the VersionedHttpControllerSelector in a separate libary and was referencing it in the WebAPI Project. When I was try to access it I was given an error that I was missing a method. It said I was missing the constructor method on VersionedHttpControllerSelector. I checked to make sure both where using the same .NET version, I cleared my bins and made sure the latest version of all libraries where being use. I recycled IIS. I tried to put a break-point in (which never hit) and ran in debug mode. I even tried turning my computer off and on again...NOTHING!
I removed the reference in the Web API Project and compied the VersionedHttpControllerSelector.cs to the Web API Project. Fixed the reference in the Global.asax.cs file. BAM!!! Everything is working.
I have tried googling this and asked several other senior developers at my office. None of us have a clue why I cannot use this if its a reference verse directly in the project.
Anyone??