PageRenderTime 44ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/SignalR/Hubs/DefaultJavaScriptProxyGenerator.cs

https://github.com/kpmrafeeq/SignalR
C# | 199 lines | 169 code | 29 blank | 1 comment | 16 complexity | 7cea447e18eb881a0aa344ec06ce2bf4 MD5 | raw file
Possible License(s): MIT
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. using SignalR.Infrastructure;
  9. namespace SignalR.Hubs
  10. {
  11. public class DefaultJavaScriptProxyGenerator : IJavaScriptProxyGenerator
  12. {
  13. private static readonly Lazy<string> _template = new Lazy<string>(GetTemplate);
  14. private static readonly ConcurrentDictionary<string, string> _scriptCache = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
  15. private static readonly Type[] _numberTypes = new[] { typeof(byte), typeof(short), typeof(int), typeof(long), typeof(float), typeof(decimal), typeof(double) };
  16. private static readonly Type[] _dateTypes = new[] { typeof(DateTime), typeof(DateTimeOffset) };
  17. private const string ScriptResource = "SignalR.Scripts.hubs.js";
  18. private readonly IHubManager _manager;
  19. private readonly IJavaScriptMinifier _javascriptMinifier;
  20. public DefaultJavaScriptProxyGenerator(IDependencyResolver resolver) :
  21. this(resolver.Resolve<IHubManager>(),
  22. resolver.Resolve<IJavaScriptMinifier>())
  23. {
  24. }
  25. public DefaultJavaScriptProxyGenerator(IHubManager manager, IJavaScriptMinifier javascriptMinifier)
  26. {
  27. _manager = manager;
  28. _javascriptMinifier = javascriptMinifier ?? NullJavaScriptMinifier.Instance;
  29. }
  30. public bool IsDebuggingEnabled { get; set; }
  31. public string GenerateProxy(string serviceUrl, bool includeDocComments = false)
  32. {
  33. string script;
  34. if (_scriptCache.TryGetValue(serviceUrl, out script))
  35. {
  36. return script;
  37. }
  38. var template = _template.Value;
  39. script = template.Replace("{serviceUrl}", serviceUrl);
  40. var hubs = new StringBuilder();
  41. var first = true;
  42. foreach (var descriptor in _manager.GetHubs().OrderBy(h => h.Name))
  43. {
  44. if (!first)
  45. {
  46. hubs.AppendLine(";");
  47. hubs.AppendLine();
  48. hubs.Append(" ");
  49. }
  50. GenerateType(hubs, descriptor, includeDocComments);
  51. first = false;
  52. }
  53. if (hubs.Length > 0)
  54. {
  55. hubs.Append(";");
  56. }
  57. script = script.Replace("/*hubs*/", hubs.ToString());
  58. if (!IsDebuggingEnabled)
  59. {
  60. script = _javascriptMinifier.Minify(script);
  61. }
  62. _scriptCache.TryAdd(serviceUrl, script);
  63. return script;
  64. }
  65. private void GenerateType(StringBuilder sb, HubDescriptor descriptor, bool includeDocComments)
  66. {
  67. // Get only actions with minimum number of parameters.
  68. var methods = GetMethods(descriptor);
  69. var members = methods.Select(m => m.Name).OrderBy(name => name).ToList();
  70. sb.AppendFormat("signalR.{0} = {{", GetHubName(descriptor)).AppendLine();
  71. sb.AppendFormat(" _: {{").AppendLine();
  72. sb.AppendFormat(" hubName: '{0}',", descriptor.Name ?? "null").AppendLine();
  73. sb.AppendFormat(" ignoreMembers: [{0}],", Commas(members, m => "'" + Json.CamelCase(m) + "'")).AppendLine();
  74. sb.AppendLine(" connection: function () { return signalR.hub; }");
  75. sb.AppendFormat(" }}");
  76. if (methods.Any())
  77. {
  78. sb.Append(",").AppendLine();
  79. }
  80. bool first = true;
  81. foreach (var method in methods)
  82. {
  83. if (!first)
  84. {
  85. sb.Append(",").AppendLine();
  86. }
  87. this.GenerateMethod(sb, method, includeDocComments);
  88. first = false;
  89. }
  90. sb.AppendLine();
  91. sb.Append(" }");
  92. }
  93. protected virtual string GetHubName(HubDescriptor descriptor)
  94. {
  95. return Json.CamelCase(descriptor.Name);
  96. }
  97. private IEnumerable<MethodDescriptor> GetMethods(HubDescriptor descriptor)
  98. {
  99. return from method in _manager.GetHubMethods(descriptor.Name)
  100. group method by method.Name into overloads
  101. let oload = (from overload in overloads
  102. orderby overload.Parameters.Count
  103. select overload).FirstOrDefault()
  104. select oload;
  105. }
  106. private void GenerateMethod(StringBuilder sb, MethodDescriptor method, bool includeDocComments)
  107. {
  108. var parameterNames = method.Parameters.Select(p => p.Name).ToList();
  109. sb.AppendLine();
  110. sb.AppendFormat(" {0}: function ({1}) {{", GetMethodName(method), Commas(parameterNames)).AppendLine();
  111. if (includeDocComments)
  112. {
  113. sb.AppendFormat(" /// <summary>Calls the {0} method on the server-side {1} hub.&#10;Returns a jQuery.Deferred() promise.</summary>", method.Name, method.Hub.Name).AppendLine();
  114. var parameterDoc = method.Parameters.Select(p => String.Format(" /// <param name=\"{0}\" type=\"{1}\">Server side type is {2}</param>", p.Name, MapToJavaScriptType(p.Type), p.Type)).ToList();
  115. if (parameterDoc.Any())
  116. {
  117. sb.AppendLine(String.Join(Environment.NewLine, parameterDoc));
  118. }
  119. }
  120. sb.AppendFormat(" return invoke(this, \"{0}\", $.makeArray(arguments));", method.Name).AppendLine();
  121. sb.Append(" }");
  122. }
  123. private string MapToJavaScriptType(Type type)
  124. {
  125. if (!type.IsPrimitive && !(type == typeof(string)))
  126. {
  127. return "Object";
  128. }
  129. if (type == typeof(string))
  130. {
  131. return "String";
  132. }
  133. if (_numberTypes.Contains(type))
  134. {
  135. return "Number";
  136. }
  137. if (typeof(IEnumerable).IsAssignableFrom(type))
  138. {
  139. return "Array";
  140. }
  141. if (_dateTypes.Contains(type))
  142. {
  143. return "Date";
  144. }
  145. return String.Empty;
  146. }
  147. private static string GetMethodName(MethodDescriptor method)
  148. {
  149. return Json.CamelCase(method.Name);
  150. }
  151. private static string Commas(IEnumerable<string> values)
  152. {
  153. return Commas(values, v => v);
  154. }
  155. private static string Commas<T>(IEnumerable<T> values, Func<T, string> selector)
  156. {
  157. return String.Join(", ", values.Select(selector));
  158. }
  159. private static string GetTemplate()
  160. {
  161. using (Stream resourceStream = typeof(DefaultJavaScriptProxyGenerator).Assembly.GetManifestResourceStream(ScriptResource))
  162. {
  163. using (var reader = new StreamReader(resourceStream))
  164. {
  165. return reader.ReadToEnd();
  166. }
  167. }
  168. }
  169. }
  170. }