ServiceExec.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. //Copyright (c) Service Stack LLC. All Rights Reserved.
  2. //License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Reflection;
  8. using System.Threading.Tasks;
  9. using MediaBrowser.Model.Services;
  10. namespace ServiceStack.Host
  11. {
  12. public static class ServiceExecExtensions
  13. {
  14. public static IEnumerable<MethodInfo> GetActions(this Type serviceType)
  15. {
  16. foreach (var mi in serviceType.GetRuntimeMethods().Where(i => i.IsPublic && !i.IsStatic))
  17. {
  18. if (mi.GetParameters().Length != 1)
  19. continue;
  20. var actionName = mi.Name.ToUpper();
  21. if (!HttpMethods.AllVerbs.Contains(actionName) && actionName != ActionContext.AnyAction)
  22. continue;
  23. yield return mi;
  24. }
  25. }
  26. }
  27. internal static class ServiceExecGeneral
  28. {
  29. public static Dictionary<string, ActionContext> execMap = new Dictionary<string, ActionContext>();
  30. public static void CreateServiceRunnersFor(Type requestType, List<ActionContext> actions)
  31. {
  32. foreach (var actionCtx in actions)
  33. {
  34. if (execMap.ContainsKey(actionCtx.Id)) continue;
  35. execMap[actionCtx.Id] = actionCtx;
  36. }
  37. }
  38. public static async Task<object> Execute(Type serviceType, IRequest request, object instance, object requestDto, string requestName)
  39. {
  40. var actionName = request.Verb
  41. ?? HttpMethods.Post; //MQ Services
  42. ActionContext actionContext;
  43. if (ServiceExecGeneral.execMap.TryGetValue(ActionContext.Key(serviceType, actionName, requestName), out actionContext)
  44. || ServiceExecGeneral.execMap.TryGetValue(ActionContext.AnyKey(serviceType, requestName), out actionContext))
  45. {
  46. if (actionContext.RequestFilters != null)
  47. {
  48. foreach (var requestFilter in actionContext.RequestFilters)
  49. {
  50. requestFilter.RequestFilter(request, request.Response, requestDto);
  51. if (request.Response.IsClosed) return null;
  52. }
  53. }
  54. var response = actionContext.ServiceAction(instance, requestDto);
  55. var taskResponse = response as Task;
  56. if (taskResponse != null)
  57. {
  58. await taskResponse.ConfigureAwait(false);
  59. response = ServiceStackHost.Instance.GetTaskResult(taskResponse, requestName);
  60. }
  61. return response;
  62. }
  63. var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLower();
  64. throw new NotImplementedException(string.Format("Could not find method named {1}({0}) or Any({0}) on Service {2}", requestDto.GetType().GetOperationName(), expectedMethodName, serviceType.GetOperationName()));
  65. }
  66. public static List<ActionContext> Reset(Type serviceType)
  67. {
  68. var actions = new List<ActionContext>();
  69. foreach (var mi in serviceType.GetActions())
  70. {
  71. var actionName = mi.Name.ToUpper();
  72. var args = mi.GetParameters();
  73. var requestType = args[0].ParameterType;
  74. var actionCtx = new ActionContext
  75. {
  76. Id = ActionContext.Key(serviceType, actionName, requestType.GetOperationName())
  77. };
  78. try
  79. {
  80. actionCtx.ServiceAction = CreateExecFn(serviceType, requestType, mi);
  81. }
  82. catch
  83. {
  84. //Potential problems with MONO, using reflection for fallback
  85. actionCtx.ServiceAction = (service, request) =>
  86. mi.Invoke(service, new[] { request });
  87. }
  88. var reqFilters = new List<IHasRequestFilter>();
  89. foreach (var attr in mi.GetCustomAttributes(true))
  90. {
  91. var hasReqFilter = attr as IHasRequestFilter;
  92. if (hasReqFilter != null)
  93. reqFilters.Add(hasReqFilter);
  94. }
  95. if (reqFilters.Count > 0)
  96. actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray();
  97. actions.Add(actionCtx);
  98. }
  99. return actions;
  100. }
  101. private static ActionInvokerFn CreateExecFn(Type serviceType, Type requestType, MethodInfo mi)
  102. {
  103. var serviceParam = Expression.Parameter(typeof(object), "serviceObj");
  104. var serviceStrong = Expression.Convert(serviceParam, serviceType);
  105. var requestDtoParam = Expression.Parameter(typeof(object), "requestDto");
  106. var requestDtoStrong = Expression.Convert(requestDtoParam, requestType);
  107. Expression callExecute = Expression.Call(
  108. serviceStrong, mi, requestDtoStrong);
  109. if (mi.ReturnType != typeof(void))
  110. {
  111. var executeFunc = Expression.Lambda<ActionInvokerFn>
  112. (callExecute, serviceParam, requestDtoParam).Compile();
  113. return executeFunc;
  114. }
  115. else
  116. {
  117. var executeFunc = Expression.Lambda<VoidActionInvokerFn>
  118. (callExecute, serviceParam, requestDtoParam).Compile();
  119. return (service, request) =>
  120. {
  121. executeFunc(service, request);
  122. return null;
  123. };
  124. }
  125. }
  126. }
  127. }