HttpControllerSelector Replacement doesnt work with reference library

134 Views Asked by At

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??

0

There are 0 best solutions below