aboutsummaryrefslogtreecommitdiff
path: root/ServiceStack/Host/ServiceExec.cs
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2016-11-11 14:55:12 -0500
committerLuke Pulverenti <luke.pulverenti@gmail.com>2016-11-11 14:55:12 -0500
commit406e6cb8132c1b8ade2872d44d7183267dd51ca8 (patch)
treef9088ce1219351cee1976ba9fa57ed6341eeed9a /ServiceStack/Host/ServiceExec.cs
parentf8b8de13b752c49360bbe10502cc067be89937ae (diff)
update portable projects
Diffstat (limited to 'ServiceStack/Host/ServiceExec.cs')
-rw-r--r--ServiceStack/Host/ServiceExec.cs156
1 files changed, 156 insertions, 0 deletions
diff --git a/ServiceStack/Host/ServiceExec.cs b/ServiceStack/Host/ServiceExec.cs
new file mode 100644
index 000000000..cb501a3ad
--- /dev/null
+++ b/ServiceStack/Host/ServiceExec.cs
@@ -0,0 +1,156 @@
+//Copyright (c) Service Stack LLC. All Rights Reserved.
+//License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Services;
+
+namespace ServiceStack.Host
+{
+ public static class ServiceExecExtensions
+ {
+ public static IEnumerable<MethodInfo> GetActions(this Type serviceType)
+ {
+ foreach (var mi in serviceType.GetRuntimeMethods().Where(i => i.IsPublic && !i.IsStatic))
+ {
+ if (mi.GetParameters().Length != 1)
+ continue;
+
+ var actionName = mi.Name.ToUpper();
+ if (!HttpMethods.AllVerbs.Contains(actionName) && actionName != ActionContext.AnyAction)
+ continue;
+
+ yield return mi;
+ }
+ }
+ }
+
+ internal static class ServiceExecGeneral
+ {
+ public static Dictionary<string, ActionContext> execMap = new Dictionary<string, ActionContext>();
+
+ public static void CreateServiceRunnersFor(Type requestType, List<ActionContext> actions)
+ {
+ foreach (var actionCtx in actions)
+ {
+ if (execMap.ContainsKey(actionCtx.Id)) continue;
+
+ execMap[actionCtx.Id] = actionCtx;
+ }
+ }
+
+ public static async Task<object> Execute(Type serviceType, IRequest request, object instance, object requestDto, string requestName)
+ {
+ var actionName = request.Verb
+ ?? HttpMethods.Post; //MQ Services
+
+ ActionContext actionContext;
+ if (ServiceExecGeneral.execMap.TryGetValue(ActionContext.Key(serviceType, actionName, requestName), out actionContext)
+ || ServiceExecGeneral.execMap.TryGetValue(ActionContext.AnyKey(serviceType, requestName), out actionContext))
+ {
+ if (actionContext.RequestFilters != null)
+ {
+ foreach (var requestFilter in actionContext.RequestFilters)
+ {
+ requestFilter.RequestFilter(request, request.Response, requestDto);
+ if (request.Response.IsClosed) return null;
+ }
+ }
+
+ var response = actionContext.ServiceAction(instance, requestDto);
+
+ var taskResponse = response as Task;
+ if (taskResponse != null)
+ {
+ await taskResponse.ConfigureAwait(false);
+ response = ServiceStackHost.Instance.GetTaskResult(taskResponse, requestName);
+ }
+
+ return response;
+ }
+
+ var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLower();
+ throw new NotImplementedException(string.Format("Could not find method named {1}({0}) or Any({0}) on Service {2}", requestDto.GetType().GetOperationName(), expectedMethodName, serviceType.GetOperationName()));
+ }
+
+ public static List<ActionContext> Reset(Type serviceType)
+ {
+ var actions = new List<ActionContext>();
+
+ foreach (var mi in serviceType.GetActions())
+ {
+ var actionName = mi.Name.ToUpper();
+ var args = mi.GetParameters();
+
+ var requestType = args[0].ParameterType;
+ var actionCtx = new ActionContext
+ {
+ Id = ActionContext.Key(serviceType, actionName, requestType.GetOperationName())
+ };
+
+ try
+ {
+ actionCtx.ServiceAction = CreateExecFn(serviceType, requestType, mi);
+ }
+ catch
+ {
+ //Potential problems with MONO, using reflection for fallback
+ actionCtx.ServiceAction = (service, request) =>
+ mi.Invoke(service, new[] { request });
+ }
+
+ var reqFilters = new List<IHasRequestFilter>();
+
+ foreach (var attr in mi.GetCustomAttributes(true))
+ {
+ var hasReqFilter = attr as IHasRequestFilter;
+
+ if (hasReqFilter != null)
+ reqFilters.Add(hasReqFilter);
+ }
+
+ if (reqFilters.Count > 0)
+ actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray();
+
+ actions.Add(actionCtx);
+ }
+
+ return actions;
+ }
+
+ private static ActionInvokerFn CreateExecFn(Type serviceType, Type requestType, MethodInfo mi)
+ {
+ var serviceParam = Expression.Parameter(typeof(object), "serviceObj");
+ var serviceStrong = Expression.Convert(serviceParam, serviceType);
+
+ var requestDtoParam = Expression.Parameter(typeof(object), "requestDto");
+ var requestDtoStrong = Expression.Convert(requestDtoParam, requestType);
+
+ Expression callExecute = Expression.Call(
+ serviceStrong, mi, requestDtoStrong);
+
+ if (mi.ReturnType != typeof(void))
+ {
+ var executeFunc = Expression.Lambda<ActionInvokerFn>
+ (callExecute, serviceParam, requestDtoParam).Compile();
+
+ return executeFunc;
+ }
+ else
+ {
+ var executeFunc = Expression.Lambda<VoidActionInvokerFn>
+ (callExecute, serviceParam, requestDtoParam).Compile();
+
+ return (service, request) =>
+ {
+ executeFunc(service, request);
+ return null;
+ };
+ }
+ }
+ }
+} \ No newline at end of file