Advertisement
Guest User

Untitled

a guest
Dec 18th, 2015
593
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.69 KB | None | 0 0
  1. public class DynamicActionSelector : ApiControllerActionSelector
  2.     {
  3.         private IUnityContainer Container { get; set; }
  4.         private ITranslationService Translator { get; set; }
  5.         private HttpConfiguration Configuration { get; set; }
  6.        
  7.         public DynamicActionSelector(IUnityContainer container, ITranslationService translator, HttpConfiguration config)
  8.         {
  9.             this.Container = container;
  10.             this.Translator = translator;
  11.             this.Configuration = config;
  12.         }
  13.        
  14.         private static readonly Lazy<ConcurrentDictionary<string, ILookup<string, HttpActionDescriptor>>> ServiceActionDescriptorMappingLazy = new Lazy<ConcurrentDictionary<string, ILookup<string, HttpActionDescriptor>>>(() => new ConcurrentDictionary<string, ILookup<string, HttpActionDescriptor>>(), LazyThreadSafetyMode.PublicationOnly);
  15.        
  16.         protected static ConcurrentDictionary<string, ILookup<string, HttpActionDescriptor>> ServiceActionDescriptorMapping
  17.         {
  18.             get { return ServiceActionDescriptorMappingLazy.Value; }
  19.         }
  20.  
  21.         public override ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor)
  22.         {
  23.             ILookup<string, HttpActionDescriptor> mapping;
  24.             if (!ServiceActionDescriptorMapping.TryGetValue(controllerDescriptor.ControllerName.ToLower(), out mapping))
  25.             {
  26.                 if (controllerDescriptor.ControllerType.GetGenericInterface(typeof(IBusinessProxyController<>)) != null)
  27.                 {
  28.                     IBusinessProxyController<IBusinessImplementation> controller = this.Container.Resolve<IHttpController>(controllerDescriptor.ControllerName.ToLower()) as IBusinessProxyController<IBusinessImplementation>;
  29.                     if (controller != null)
  30.                     {
  31.                         var methods = controller.BusinessImplementation.GetType().GetMethodsCached(BindingFlags.Public | BindingFlags.Instance);
  32.                         var interfaces = controller.BusinessImplementation.GetType().GetInterfacesCached().SelectMany(i => i.GetMethodsCached(BindingFlags.Public | BindingFlags.Instance));
  33.                         var actionServiceMethods = (from am in methods
  34.                                                     join ai in interfaces on am.Name equals ai.Name
  35.                                                     select new { Method = am, InterfaceMethod = ai, ServiceMethods = am.GetCustomAttributesCached<ServiceMethod>(true).Union(ai.GetCustomAttributesCached<ServiceMethod>(true)), Routes = am.GetCustomAttributesCached<ServiceRoute>(true).Union(ai.GetCustomAttributesCached<ServiceRoute>(true)) }
  36.                                                     ).Where(m => m.ServiceMethods.Count() > 0 && m.Routes.Any(r =>
  37.                                                         Configuration.Routes.ContainsKey(string.Format("{0}{1}", controllerDescriptor.ControllerName.ToLower(), r.Key))));
  38.                         List<HttpActionDescriptor> actionDescriptors = new List<HttpActionDescriptor>();
  39.                         foreach (var method in actionServiceMethods)
  40.                         {
  41.                             foreach (var httpMethod in method.ServiceMethods)
  42.                             {
  43.                                 actionDescriptors.Add(new ServiceMethodHttpActionDescriptor(controllerDescriptor, method.Method, method.InterfaceMethod, httpMethod, this.Translator));
  44.                             }
  45.                         }
  46.                         mapping = actionDescriptors.ToLookup(m => m.ActionName);
  47.                     }
  48.                 }
  49.                 else
  50.                     mapping = base.GetActionMapping(controllerDescriptor);
  51.                 ServiceActionDescriptorMapping.TryAdd(controllerDescriptor.ControllerName.ToLower(), mapping);
  52.             }
  53.             return mapping;
  54.         }
  55.  
  56.         public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
  57.         {
  58.             IBusinessProxyController<IBusinessImplementation> controller = controllerContext.Controller as IBusinessProxyController<IBusinessImplementation>;
  59.             if (controller != null)
  60.             {
  61.                 object actionName;
  62.                 if (controllerContext.RouteData.Values.TryGetValue("action", out actionName))
  63.                 {
  64.                     var actions = this.GetActionMapping(controllerContext.ControllerDescriptor);
  65.                     var corsRequestContext = controllerContext.Request.Properties.ContainsKey("MS_CorsRequestContextKey") ? controllerContext.Request.Properties["MS_CorsRequestContextKey"] as CorsRequestContext : null as CorsRequestContext;
  66.                     bool isOptions = (corsRequestContext != null && corsRequestContext.HttpMethod == "OPTIONS") || controllerContext.Request.Method == HttpMethod.Options;
  67.                     var actionsForRequest = actions[((string)actionName)].OfType<ServiceMethodHttpActionDescriptor>().Where(a => a.ServiceMethod.ToHttpMethod() == controllerContext.Request.Method || isOptions).ToArray();
  68.                     if(actionsForRequest.Length == 0)
  69.                         throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, this.Translator.GetErrorMessage("ACTIONS_NOT_FOUND")));
  70.                     if(actionsForRequest.Length > 1 && !isOptions)
  71.                         throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(HttpStatusCode.Ambiguous, this.Translator.GetErrorMessage("ACTIONS_MULTIPLE_FOUND")));
  72.                     var selectedAction = actionsForRequest.First();
  73.                    
  74.                     if (isOptions)
  75.                         return selectedAction.CreateOptionsActionDescriptor();
  76.                     return selectedAction;
  77.                 }
  78.             }
  79.             return base.SelectAction(controllerContext);
  80.         }
  81.     }
  82.  
  83.     public class ServiceMethodHttpActionDescriptor : HttpActionDescriptor
  84.     {
  85.         public MethodInfo BusinessMethod { get; private set; }
  86.         public ServiceMethod ServiceMethod { get; private set; }
  87.         public MethodInfo InterfaceMethod { get; private set; }
  88.         private ITranslationService Translator { get; set; }
  89.         public bool IsOptions { get; private set; }
  90.         public ServiceMethodHttpActionDescriptor(HttpControllerDescriptor controllerDescriptor, MethodInfo businessMethod, MethodInfo interfaceMethod, ServiceMethod serviceMethod, ITranslationService translator, bool isOptions = false)
  91.             : base(controllerDescriptor)
  92.         {
  93.             this.BusinessMethod = businessMethod;
  94.             this.ServiceMethod = serviceMethod;
  95.             this.Translator = translator;
  96.             this.InterfaceMethod = interfaceMethod;
  97.             this.IsOptions = isOptions;
  98.             if (serviceMethod != null)
  99.             {
  100.                 this.SupportedHttpMethods.Clear();
  101.                 if (!isOptions)
  102.                     this.SupportedHttpMethods.Add(serviceMethod.ToHttpMethod());
  103.                 else
  104.                 {
  105.                     this.SupportedHttpMethods.Add(HttpMethod.Get);
  106.                     this.SupportedHttpMethods.Add(HttpMethod.Delete);
  107.                     this.SupportedHttpMethods.Add(HttpMethod.Head);
  108.                     this.SupportedHttpMethods.Add(HttpMethod.Options);
  109.                     this.SupportedHttpMethods.Add(HttpMethod.Post);
  110.                     this.SupportedHttpMethods.Add(HttpMethod.Put);
  111.                 }
  112.             }
  113.             this.ParamatersLazy = new Lazy<Collection<HttpParameterDescriptor>>(() => this.InitializateParameters(), LazyThreadSafetyMode.PublicationOnly);
  114.             this.FiltersLazy = new Lazy<Collection<IFilter>>(() => this.InitializeFilters(), LazyThreadSafetyMode.PublicationOnly);
  115.             this.ReturnTypeLazy = new Lazy<Type>(() => this.InitializeReturnType(), LazyThreadSafetyMode.ExecutionAndPublication);
  116.         }
  117.  
  118.         public ServiceMethodHttpActionDescriptor CreateOptionsActionDescriptor()
  119.         {
  120.             return new ServiceMethodHttpActionDescriptor(this.ControllerDescriptor, this.BusinessMethod, this.InterfaceMethod, this.ServiceMethod, this.Translator, true);
  121.         }
  122.  
  123.         public override async Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken)
  124.         {
  125.             if (this.IsOptions)
  126.                 return controllerContext.Request.CreateResponse(HttpStatusCode.OK);
  127.             IBusinessProxyController<IBusinessImplementation> controller = controllerContext.Controller as IBusinessProxyController<IBusinessImplementation>;
  128.            
  129.             if (controller != null)
  130.             {
  131.                 try
  132.                 {
  133.                     if (controller.ModelState.IsValid)
  134.                     {
  135.                         var parmInfos = this.BusinessMethod.GetParametersCached();
  136.                         object[] parameters = new object[parmInfos.Length];
  137.                         for (var parmIndex = 0; parmIndex < parameters.Length; parmIndex++)
  138.                         {
  139.                             parameters[parmIndex] = Type.Missing;
  140.                         }
  141.                         int p = 0;
  142.                         foreach (var parameter in parmInfos)
  143.                         {
  144.                             object argument;
  145.                             if (arguments.TryGetValue(parameter.Name, out argument))
  146.                                 parameters[p] = argument;
  147.                             else if (parameter.ParameterType == typeof(CancellationToken))
  148.                                 parameters[p] = cancellationToken;
  149.                             p++;
  150.                         }
  151.                         var methodResult = this.BusinessMethod.Invoke(controller.BusinessImplementation, parameters);
  152.                         Task actionTask = methodResult as Task;
  153.                         if (actionTask != null)
  154.                         {
  155.                             await actionTask;
  156.                             var actionTaskType = actionTask.GetType();
  157.                             if (actionTaskType.IsGenericType)
  158.                             {
  159.                                 var result = actionTaskType.GetPropertyCached("Result").GetValue(actionTask);
  160.                                 if (result == null)
  161.                                     return controllerContext.Request.CreateErrorResponse(HttpStatusCode.NoContent, this.Translator.GetErrorMessage("REQUEST_NULL"));
  162.                                 else
  163.                                     return controllerContext.Request.CreateResponse(HttpStatusCode.OK, result);
  164.                             }
  165.                             else
  166.                                 return controllerContext.Request.CreateResponse(HttpStatusCode.OK);
  167.                         }
  168.                         if (this.BusinessMethod.ReturnType == typeof(void))
  169.                             return controllerContext.Request.CreateResponse(HttpStatusCode.OK);
  170.                         if(methodResult == null)
  171.                             return controllerContext.Request.CreateErrorResponse(HttpStatusCode.NoContent, this.Translator.GetErrorMessage("REQUEST_NULL"));
  172.                         return controllerContext.Request.CreateResponse(HttpStatusCode.OK, methodResult);
  173.                     }
  174.                     else
  175.                         throw new ValidationException(controller.ModelState.Values.SelectMany(v => v.Errors).First().ErrorMessage);
  176.                 }
  177.                 catch(GlobalizedAuthenticationException ex)
  178.                 {
  179.                     return controllerContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, this.Translator.GetErrorMessage(ex.ErrorCode), ex);
  180.                 }
  181.                 catch(GlobalizedAuthorizationException ex)
  182.                 {
  183.                     return controllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, this.Translator.GetErrorMessage(ex.ErrorCode), ex);
  184.                 }
  185.                 catch(GlobalizedValidationException ex)
  186.                 {
  187.                     return controllerContext.Request.CreateErrorResponse(HttpStatusCode.NotAcceptable, this.Translator.GetErrorMessage(ex.ErrorCode), ex);
  188.                 }
  189.                 catch(GlobalizedException ex)
  190.                 {
  191.                     return controllerContext.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, this.Translator.GetErrorMessage(ex.ErrorCode), ex);
  192.                 }
  193.                 catch(ValidationException ex)
  194.                 {
  195.                     return controllerContext.Request.CreateErrorResponse(HttpStatusCode.NotAcceptable, ex.Message, ex);
  196.                 }
  197.                 catch (OperationCanceledException)
  198.                 {
  199.                     throw;
  200.                 }
  201.                 catch (Exception ex)
  202.                 {
  203.                     return controllerContext.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
  204.                 }
  205.             }
  206.             return controllerContext.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, this.Translator.GetErrorMessage("SERVER_MISCONFIGURED"));
  207.         }
  208.  
  209.         public override string ActionName
  210.         {
  211.             get { return BusinessMethod.Name; }
  212.         }
  213.  
  214.         private readonly Lazy<Collection<HttpParameterDescriptor>> ParamatersLazy;
  215.  
  216.         public override Collection<HttpParameterDescriptor> GetParameters()
  217.         {
  218.             return this.ParamatersLazy.Value;
  219.         }
  220.  
  221.         private Collection<HttpParameterDescriptor> InitializateParameters()
  222.         {
  223.             Collection<HttpParameterDescriptor> paramaters = new Collection<HttpParameterDescriptor>();
  224.             var parms = this.BusinessMethod.GetParametersCached();
  225.             var interfaceParameters = this.InterfaceMethod.GetParametersCached();
  226.             for (var i = 0; i < parms.Length && i < interfaceParameters.Length; i++)
  227.             {
  228.                 var p = parms[i];
  229.                 if (p.ParameterType != typeof(CancellationToken))
  230.                     paramaters.Add(new ServiceMethodParameterDescriptor(this, parms[i], interfaceParameters[i]));
  231.             }
  232.             return paramaters;
  233.         }
  234.  
  235.         private readonly Lazy<Collection<IFilter>> FiltersLazy;
  236.  
  237.         public override Collection<IFilter> GetFilters()
  238.         {
  239.             return this.FiltersLazy.Value;
  240.         }
  241.  
  242.         private Collection<IFilter> InitializeFilters()
  243.         {
  244.             var filters = base.GetFilters();
  245.             if (this.ServiceMethod.AcceptSessionHeader)
  246.                 filters.Add(new SessionAttribute(this.Translator, this.ServiceMethod.RequireSessionHeader));
  247.             return filters;
  248.         }
  249.  
  250.         public override Collection<T> GetCustomAttributes<T>()
  251.         {
  252.             var attributes = base.GetCustomAttributes<T>();
  253.             if (attributes == null)
  254.                 attributes = new Collection<T>();
  255.  
  256.             if (typeof(T) == typeof(Attribute) || typeof(T) == typeof(EnableCorsAttribute) || typeof(T) == typeof(ICorsPolicyProvider))
  257.                 attributes.Add(new EnableCorsAttribute("*", "*", "*") as T);
  258.             return attributes;
  259.         }
  260.  
  261.         public override Collection<T> GetCustomAttributes<T>(bool inherit)
  262.         {
  263.             var attributes = base.GetCustomAttributes<T>(inherit);
  264.             if (attributes == null)
  265.                 attributes = new Collection<T>();
  266.  
  267.             if (typeof(T) == typeof(Attribute) || typeof(T) == typeof(EnableCorsAttribute) || typeof(T) == typeof(ICorsPolicyProvider))
  268.                 attributes.Add(new EnableCorsAttribute("*", "*", "*") as T);
  269.             return attributes;
  270.         }
  271.  
  272.         private readonly Lazy<Type> ReturnTypeLazy;
  273.  
  274.         private Type InitializeReturnType()
  275.         {
  276.             if (this.BusinessMethod.ReturnType.IsGenericType && this.BusinessMethod.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
  277.                 return this.BusinessMethod.ReturnType.GetGenericArguments().Single();
  278.             if (this.BusinessMethod.ReturnType == typeof(Task))
  279.                 return typeof(void);
  280.             return this.BusinessMethod.ReturnType;
  281.         }
  282.  
  283.         public override Type ReturnType
  284.         {
  285.             get { return ReturnTypeLazy.Value; }
  286.         }
  287.     }
  288.  
  289.     public class ServiceMethodParameterDescriptor : HttpParameterDescriptor
  290.     {
  291.         public ParameterInfo Parameter { get; private set; }
  292.         public ParameterInfo InterfaceParameter { get; private set; }
  293.         public ServiceMethodParameterDescriptor(HttpActionDescriptor actionDescriptor, ParameterInfo parameter, ParameterInfo interfaceParameter)
  294.             : base(actionDescriptor)
  295.         {
  296.             this.Parameter = parameter;
  297.             this.InterfaceParameter = interfaceParameter;
  298.         }
  299.  
  300.         public override string ParameterName
  301.         {
  302.             get { return Parameter.Name; }
  303.         }
  304.  
  305.         public override Type ParameterType
  306.         {
  307.             get { return Parameter.ParameterType; }
  308.         }
  309.  
  310.         public override Collection<T> GetCustomAttributes<T>()
  311.         {
  312.             List<Attribute> attributes = new List<Attribute>();
  313.             if ((typeof(T) == typeof(Attribute) || typeof(T) == typeof(ParameterBindingAttribute) || typeof(T) == typeof(ModelBinderAttribute)) && (Parameter.GetCustomAttributeCached<JsonEncode>(true) != null || InterfaceParameter.GetCustomAttributeCached<JsonEncode>(true) != null))
  314.                 attributes.Add(new ModelBinderAttribute(typeof(JsonParameterModelBinder)));
  315.             if ((typeof(T) == typeof(Attribute) || typeof(T) == typeof(ParameterBindingAttribute) || typeof(T) == typeof(FromBodyAttribute)) && (Parameter.GetCustomAttributeCached<Content>(true) != null || InterfaceParameter.GetCustomAttributeCached<Content>(true) != null))
  316.                 attributes.Add(new FromBodyAttribute());
  317.             attributes.AddRange(Parameter.GetCustomAttributes(typeof(T), true).OfType<Attribute>());
  318.             return new Collection<T>(attributes.Cast<T>().ToList());
  319.         }
  320.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement