Skip to content

Instantly share code, notes, and snippets.

@TehWardy
Created April 13, 2016 09:28
Show Gist options
  • Save TehWardy/3e505abd7e22d9e9930952104136963d to your computer and use it in GitHub Desktop.
Save TehWardy/3e505abd7e22d9e9930952104136963d to your computer and use it in GitHub Desktop.
using Core.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using System.Web.Routing;
namespace Core.Api
{
public class GenericODataControllerSelector : DefaultHttpControllerSelector, IHttpControllerSelector
{
readonly HttpConfiguration config;
IDictionary<string, HttpControllerDescriptor> mappings;
/// <summary>
/// Initializes a new instance of the <see cref="GenericODataControllerSelector" /> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
public GenericODataControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
config = configuration;
}
/// <summary>
/// Gets a description of the controller to be used to handle the current web request
/// </summary>
/// <param name="request">the web request</param>
/// <returns>controller description</returns>
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
try {
var result = base.SelectController(request);
return result;
}
catch(HttpResponseException) { /* No problem, lets try something more generic */ }
var route = RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current)).Route as Route;
var controllerName = GetControllerName(request);
//var context = request.RequestUri.PathAndQuery.Split('/')[1];
return mappings[controllerName];
}
public override IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
try
{
mappings = base.GetControllerMapping();
}
catch (Exception) { /* Hmmm, ok Web Api isn't handling this very well */ }
if (mappings == null)
mappings = new Dictionary<string, HttpControllerDescriptor>();
var entities = GetEntityTypes();
var assemblies = TypeHelper.GetWebStackAssemblies().ToList();
assemblies.Add(Assembly.GetExecutingAssembly());
var baseSet = assemblies
.SelectMany(a => a.GetExportedTypes())
.Where(t => t != typeof(CoreODataController) && typeof(CoreODataController).IsAssignableFrom(t) && t.GetGenericArguments().Length == 0)
.Select(t => new { Key = t.Name.Replace("Controller", ""), Value = new HttpControllerDescriptor(config, t.Name.Replace("Controller", ""), t) })
.ToList();
baseSet.ForEach(m =>
{
if (!mappings.ContainsKey(m.Key))
mappings.Add(m.Key, m.Value);
});
foreach(var entityContext in entities)
MapContext(mappings, entityContext.Key, entityContext.Value);
return mappings;
}
/// <summary>
/// Returns all the types used in Api exposable db contexts
/// </summary>
IDictionary<Type, Type[]> GetEntityTypes()
{
var entityTypes = new Dictionary<Type, Type[]>();
foreach (var context in TypeHelper.GetContextTypes())
entityTypes.Add(context,
context.GetProperties()
.Where(p => typeof(IQueryable).IsAssignableFrom(p.PropertyType))
.Select(p => p.PropertyType.GenericTypeArguments[0])
.ToArray()
);
return entityTypes;
}
/// <summary>
/// Determines if a type is an entity type
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
bool IsEntityType(Type type)
{
return type.Namespace.Contains("Entities");
}
private void MapContext(IDictionary<string, HttpControllerDescriptor> mappings, Type context, Type[] entityTypes)
{
var dtos = DtoTypes();
var prefix = context.Name.Replace("Context", "/");
foreach (var type in entityTypes)
{
AddEntityMapping(mappings, type.Name, type);
dtos.Where(dtoType => ((ProjectionOf)dtoType.GetCustomAttributes(typeof(ProjectionOf), false).First()).EntityType == type)
.ToList()
.ForEach(dtoType => {
AddDtoMapping(mappings, dtoType.Name, dtoType);
});
}
}
void AddEntityMapping(IDictionary<string, HttpControllerDescriptor> result, string route, Type entityType)
{
if (!result.ContainsKey(route))
{
var descriptor = new HttpControllerDescriptor(config, route, typeof(EntityODataController<>).MakeGenericType(entityType));
result.Add(route, descriptor);
}
}
void AddDtoMapping(IDictionary<string, HttpControllerDescriptor> result, string route, Type dtoType)
{
if (!result.ContainsKey(route))
{
var entityType = ((ProjectionOf)dtoType.GetCustomAttributes(typeof(ProjectionOf), false).First()).EntityType;
var descriptor = new HttpControllerDescriptor(config, dtoType.Name, typeof(DtoODataController<,>).MakeGenericType(dtoType, entityType));
result.Add(route, descriptor);
}
}
Type[] DtoTypes()
{
return TypeHelper.GetWebStackAssemblies()
.SelectMany(a => a.GetTypes()).Where(t => ProjectedEntityTypeFor(t) != null)
.ToArray();
}
Type ProjectedEntityTypeFor(Type t)
{
var attribute = ((ProjectionOf)Attribute.GetCustomAttribute(t, typeof(ProjectionOf)));
if (attribute != null)
return attribute.EntityType;
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment