RestService.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.ServiceModel;
  5. using System.ServiceModel.Web;
  6. using System.Text;
  7. using FrameworkBench;
  8. using Revenj.Api;
  9. using Revenj.DomainPatterns;
  10. using Revenj.Serialization;
  11. using Revenj.Utility;
  12. namespace Revenj.Bench
  13. {
  14. [ServiceContract(Namespace = "https://github.com/ngs-doo/revenj")]
  15. public interface IRestService
  16. {
  17. [OperationContract]
  18. [WebGet(UriTemplate = "/plaintext")]
  19. Stream PlainText();
  20. [OperationContract]
  21. [WebGet(UriTemplate = "/json")]
  22. Stream JSON();
  23. [OperationContract]
  24. [WebGet(UriTemplate = "/db")]
  25. Stream SingleQuery();
  26. [OperationContract]
  27. [WebGet(UriTemplate = "/queries/{count}")]
  28. Stream MultipleQueries(string count);
  29. [OperationContract]
  30. [WebGet(UriTemplate = "/updates/{count}")]
  31. Stream Updates(string count);
  32. [OperationContract]
  33. [WebGet(UriTemplate = "/fortunes")]
  34. Stream Fortunes();
  35. }
  36. public class RestService : IRestService
  37. {
  38. private static readonly ChunkedMemoryStream HelloWorld = ChunkedMemoryStream.Static();
  39. private static readonly string[] IDs = new string[10001];
  40. [ThreadStatic]
  41. private static Context Context;
  42. private static Context GetContext(IServiceProvider services)
  43. {
  44. if (Context == null)
  45. Context = new Context(services);
  46. Context.Stream.Reset();
  47. return Context;
  48. }
  49. static RestService()
  50. {
  51. var hwText = Encoding.UTF8.GetBytes("Hello, World!");
  52. HelloWorld.Write(hwText, 0, hwText.Length);
  53. HelloWorld.Position = 0;
  54. for (int i = 0; i < IDs.Length; i++)
  55. IDs[i] = i.ToString();
  56. }
  57. private Random Random = new Random(0);
  58. private readonly IServiceProvider Services;
  59. public RestService(IServiceProvider services)
  60. {
  61. this.Services = services;
  62. }
  63. public Stream PlainText()
  64. {
  65. ThreadContext.Response.ContentType = "text/plain";
  66. return HelloWorld;
  67. }
  68. private Stream ReturnJSON(IJsonObject value, ChunkedMemoryStream cms)
  69. {
  70. value.Serialize(cms);
  71. ThreadContext.Response.ContentType = "application/json";
  72. return cms;
  73. }
  74. public Stream JSON()
  75. {
  76. var ctx = GetContext(Services);
  77. return ReturnJSON(new Message { message = "Hello, World!" }, ctx.Stream);
  78. }
  79. public Stream SingleQuery()
  80. {
  81. var id = Random.Next(10000) + 1;
  82. var ctx = GetContext(Services);
  83. var world = ctx.WorldRepository.Find(IDs[id]);
  84. return ReturnJSON(world, ctx.Stream);
  85. }
  86. /* bulk loading of worlds. use such pattern for production code */
  87. private void LoadWorldsFast(int repeat, Context ctx)
  88. {
  89. var reader = ctx.BulkReader;
  90. var lazyResult = ctx.LazyWorlds;
  91. var worlds = ctx.Worlds;
  92. reader.Reset(true);
  93. for (int i = 0; i < repeat; i++)
  94. {
  95. var id = Random.Next(10000) + 1;
  96. lazyResult[i] = reader.Find<World>(IDs[id]);
  97. }
  98. reader.Execute();
  99. for (int i = 0; i < repeat; i++)
  100. worlds[i] = lazyResult[i].Value;
  101. }
  102. /* multiple roundtrips loading of worlds. don't write such production code */
  103. private void LoadWorldsSlow(int repeat, Context ctx)
  104. {
  105. var worlds = ctx.Worlds;
  106. var repository = ctx.WorldRepository;
  107. for (int i = 0; i < repeat; i++)
  108. {
  109. var id = Random.Next(10000) + 1;
  110. worlds[i] = repository.Find(IDs[id]);
  111. }
  112. }
  113. public Stream MultipleQueries(string count)
  114. {
  115. int repeat;
  116. int.TryParse(count, out repeat);
  117. if (repeat < 1) repeat = 1;
  118. else if (repeat > 500) repeat = 500;
  119. var ctx = GetContext(Services);
  120. LoadWorldsSlow(repeat, ctx);
  121. var cms = ctx.Stream;
  122. ctx.Worlds.Serialize(cms, repeat);
  123. ThreadContext.Response.ContentType = "application/json";
  124. return cms;
  125. }
  126. private static readonly Comparison<World> ASC = (l, r) => l.id - r.id;
  127. public Stream Updates(string count)
  128. {
  129. int repeat;
  130. int.TryParse(count, out repeat);
  131. if (repeat < 1) repeat = 1;
  132. else if (repeat > 500) repeat = 500;
  133. var ctx = GetContext(Services);
  134. LoadWorldsSlow(repeat, ctx);
  135. var result = new World[repeat];
  136. Array.Copy(ctx.Worlds, result, repeat);
  137. for (int i = 0; i < result.Length; i++)
  138. result[i].randomNumber = Random.Next(10000) + 1;
  139. Array.Sort(result, ASC);
  140. ctx.WorldRepository.Update(result);
  141. var cms = ctx.Stream;
  142. result.Serialize(cms);
  143. ThreadContext.Response.ContentType = "application/json";
  144. return cms;
  145. }
  146. private static readonly Comparison<KeyValuePair<int, string>> Comparison = (l, r) => string.Compare(l.Value, r.Value, StringComparison.Ordinal);
  147. public Stream Fortunes()
  148. {
  149. var ctx = GetContext(Services);
  150. var fortunes = ctx.FortuneRepository.Search();
  151. var list = new List<KeyValuePair<int, string>>(fortunes.Length + 1);
  152. foreach (var f in fortunes)
  153. list.Add(new KeyValuePair<int, string>(f.id, f.message));
  154. list.Add(new KeyValuePair<int, string>(0, "Additional fortune added at request time."));
  155. list.Sort(Comparison);
  156. var cms = ctx.Stream;
  157. var writer = cms.GetWriter();
  158. var template = new Fortunes(list, writer);
  159. template.TransformText();
  160. writer.Flush();
  161. cms.Position = 0;
  162. ThreadContext.Response.ContentType = "text/html; charset=UTF-8";
  163. return cms;
  164. }
  165. }
  166. }