ServiceController.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using MediaBrowser.Model.Logging;
  9. using MediaBrowser.Model.Services;
  10. namespace ServiceStack.Host
  11. {
  12. public delegate Task<object> InstanceExecFn(IRequest requestContext, object intance, object request);
  13. public delegate object ActionInvokerFn(object intance, object request);
  14. public delegate void VoidActionInvokerFn(object intance, object request);
  15. public class ServiceController
  16. {
  17. private readonly Func<IEnumerable<Type>> _resolveServicesFn;
  18. public ServiceController(Func<IEnumerable<Type>> resolveServicesFn)
  19. {
  20. _resolveServicesFn = resolveServicesFn;
  21. this.RequestTypeFactoryMap = new Dictionary<Type, Func<IRequest, object>>();
  22. }
  23. public Dictionary<Type, Func<IRequest, object>> RequestTypeFactoryMap { get; set; }
  24. public void Init()
  25. {
  26. foreach (var serviceType in _resolveServicesFn())
  27. {
  28. RegisterService(serviceType);
  29. }
  30. }
  31. private Type[] GetGenericArguments(Type type)
  32. {
  33. return type.GetTypeInfo().IsGenericTypeDefinition
  34. ? type.GetTypeInfo().GenericTypeParameters
  35. : type.GetTypeInfo().GenericTypeArguments;
  36. }
  37. public void RegisterService(Type serviceType)
  38. {
  39. var processedReqs = new HashSet<Type>();
  40. var actions = ServiceExecGeneral.Reset(serviceType);
  41. var requiresRequestStreamTypeInfo = typeof(IRequiresRequestStream).GetTypeInfo();
  42. var appHost = ServiceStackHost.Instance;
  43. foreach (var mi in serviceType.GetActions())
  44. {
  45. var requestType = mi.GetParameters()[0].ParameterType;
  46. if (processedReqs.Contains(requestType)) continue;
  47. processedReqs.Add(requestType);
  48. ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions);
  49. var returnMarker = requestType.GetTypeWithGenericTypeDefinitionOf(typeof(IReturn<>));
  50. var responseType = returnMarker != null ?
  51. GetGenericArguments(returnMarker)[0]
  52. : mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ?
  53. mi.ReturnType
  54. : Type.GetType(requestType.FullName + "Response");
  55. RegisterRestPaths(requestType);
  56. appHost.Metadata.Add(serviceType, requestType, responseType);
  57. if (requiresRequestStreamTypeInfo.IsAssignableFrom(requestType.GetTypeInfo()))
  58. {
  59. this.RequestTypeFactoryMap[requestType] = req =>
  60. {
  61. var restPath = req.GetRoute();
  62. var request = RestHandler.CreateRequest(req, restPath, req.GetRequestParams(), ServiceStackHost.Instance.CreateInstance(requestType));
  63. var rawReq = (IRequiresRequestStream)request;
  64. rawReq.RequestStream = req.InputStream;
  65. return rawReq;
  66. };
  67. }
  68. }
  69. }
  70. public readonly Dictionary<string, List<RestPath>> RestPathMap = new Dictionary<string, List<RestPath>>(StringComparer.OrdinalIgnoreCase);
  71. public void RegisterRestPaths(Type requestType)
  72. {
  73. var appHost = ServiceStackHost.Instance;
  74. var attrs = appHost.GetRouteAttributes(requestType);
  75. foreach (MediaBrowser.Model.Services.RouteAttribute attr in attrs)
  76. {
  77. var restPath = new RestPath(requestType, attr.Path, attr.Verbs, attr.Summary, attr.Notes);
  78. if (!restPath.IsValid)
  79. throw new NotSupportedException(string.Format(
  80. "RestPath '{0}' on Type '{1}' is not Valid", attr.Path, requestType.GetOperationName()));
  81. RegisterRestPath(restPath);
  82. }
  83. }
  84. private static readonly char[] InvalidRouteChars = new[] { '?', '&' };
  85. public void RegisterRestPath(RestPath restPath)
  86. {
  87. if (!restPath.Path.StartsWith("/"))
  88. throw new ArgumentException(string.Format("Route '{0}' on '{1}' must start with a '/'", restPath.Path, restPath.RequestType.GetOperationName()));
  89. if (restPath.Path.IndexOfAny(InvalidRouteChars) != -1)
  90. throw new ArgumentException(string.Format("Route '{0}' on '{1}' contains invalid chars. " +
  91. "See https://github.com/ServiceStack/ServiceStack/wiki/Routing for info on valid routes.", restPath.Path, restPath.RequestType.GetOperationName()));
  92. List<RestPath> pathsAtFirstMatch;
  93. if (!RestPathMap.TryGetValue(restPath.FirstMatchHashKey, out pathsAtFirstMatch))
  94. {
  95. pathsAtFirstMatch = new List<RestPath>();
  96. RestPathMap[restPath.FirstMatchHashKey] = pathsAtFirstMatch;
  97. }
  98. pathsAtFirstMatch.Add(restPath);
  99. }
  100. public void AfterInit()
  101. {
  102. var appHost = ServiceStackHost.Instance;
  103. //Register any routes configured on Metadata.Routes
  104. foreach (var restPath in appHost.RestPaths)
  105. {
  106. RegisterRestPath(restPath);
  107. }
  108. //Sync the RestPaths collections
  109. appHost.RestPaths.Clear();
  110. appHost.RestPaths.AddRange(RestPathMap.Values.SelectMany(x => x));
  111. }
  112. public RestPath GetRestPathForRequest(string httpMethod, string pathInfo, ILogger logger)
  113. {
  114. var matchUsingPathParts = RestPath.GetPathPartsForMatching(pathInfo);
  115. List<RestPath> firstMatches;
  116. var yieldedHashMatches = RestPath.GetFirstMatchHashKeys(matchUsingPathParts);
  117. foreach (var potentialHashMatch in yieldedHashMatches)
  118. {
  119. if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches))
  120. {
  121. continue;
  122. }
  123. var bestScore = -1;
  124. foreach (var restPath in firstMatches)
  125. {
  126. var score = restPath.MatchScore(httpMethod, matchUsingPathParts, logger);
  127. if (score > bestScore) bestScore = score;
  128. }
  129. if (bestScore > 0)
  130. {
  131. foreach (var restPath in firstMatches)
  132. {
  133. if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts, logger))
  134. return restPath;
  135. }
  136. }
  137. }
  138. var yieldedWildcardMatches = RestPath.GetFirstMatchWildCardHashKeys(matchUsingPathParts);
  139. foreach (var potentialHashMatch in yieldedWildcardMatches)
  140. {
  141. if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) continue;
  142. var bestScore = -1;
  143. foreach (var restPath in firstMatches)
  144. {
  145. var score = restPath.MatchScore(httpMethod, matchUsingPathParts, logger);
  146. if (score > bestScore) bestScore = score;
  147. }
  148. if (bestScore > 0)
  149. {
  150. foreach (var restPath in firstMatches)
  151. {
  152. if (bestScore == restPath.MatchScore(httpMethod, matchUsingPathParts, logger))
  153. return restPath;
  154. }
  155. }
  156. }
  157. return null;
  158. }
  159. public async Task<object> Execute(object requestDto, IRequest req)
  160. {
  161. req.Dto = requestDto;
  162. var requestType = requestDto.GetType();
  163. req.OperationName = requestType.Name;
  164. var serviceType = ServiceStackHost.Instance.Metadata.GetServiceTypeByRequest(requestType);
  165. var service = ServiceStackHost.Instance.CreateInstance(serviceType);
  166. //var service = typeFactory.CreateInstance(serviceType);
  167. var serviceRequiresContext = service as IRequiresRequest;
  168. if (serviceRequiresContext != null)
  169. {
  170. serviceRequiresContext.Request = req;
  171. }
  172. if (req.Dto == null) // Don't override existing batched DTO[]
  173. req.Dto = requestDto;
  174. //Executes the service and returns the result
  175. var response = await ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetOperationName()).ConfigureAwait(false);
  176. return response;
  177. }
  178. }
  179. }