UseMiddlewareTest.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. // Copyright (c) .NET Foundation. All rights reserved.
  2. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Threading.Tasks;
  6. using Microsoft.AspNetCore.Builder;
  7. using Microsoft.AspNetCore.Builder.Internal;
  8. using Microsoft.AspNetCore.Http.Abstractions;
  9. using Xunit;
  10. namespace Microsoft.AspNetCore.Http
  11. {
  12. public class UseMiddlewareTest
  13. {
  14. [Fact]
  15. public void UseMiddleware_WithNoParameters_ThrowsException()
  16. {
  17. var builder = new ApplicationBuilder(new DummyServiceProvider());
  18. builder.UseMiddleware(typeof(MiddlewareNoParametersStub));
  19. var exception = Assert.Throws<InvalidOperationException>(() => builder.Build());
  20. Assert.Equal(
  21. Resources.FormatException_UseMiddlewareNoParameters(
  22. UseMiddlewareExtensions.InvokeMethodName,
  23. UseMiddlewareExtensions.InvokeAsyncMethodName,
  24. nameof(HttpContext)),
  25. exception.Message);
  26. }
  27. [Fact]
  28. public void UseMiddleware_AsyncWithNoParameters_ThrowsException()
  29. {
  30. var builder = new ApplicationBuilder(new DummyServiceProvider());
  31. builder.UseMiddleware(typeof(MiddlewareAsyncNoParametersStub));
  32. var exception = Assert.Throws<InvalidOperationException>(() => builder.Build());
  33. Assert.Equal(
  34. Resources.FormatException_UseMiddlewareNoParameters(
  35. UseMiddlewareExtensions.InvokeMethodName,
  36. UseMiddlewareExtensions.InvokeAsyncMethodName,
  37. nameof(HttpContext)),
  38. exception.Message);
  39. }
  40. [Fact]
  41. public void UseMiddleware_NonTaskReturnType_ThrowsException()
  42. {
  43. var builder = new ApplicationBuilder(new DummyServiceProvider());
  44. builder.UseMiddleware(typeof(MiddlewareNonTaskReturnStub));
  45. var exception = Assert.Throws<InvalidOperationException>(() => builder.Build());
  46. Assert.Equal(
  47. Resources.FormatException_UseMiddlewareNonTaskReturnType(
  48. UseMiddlewareExtensions.InvokeMethodName,
  49. UseMiddlewareExtensions.InvokeAsyncMethodName,
  50. nameof(Task)),
  51. exception.Message);
  52. }
  53. [Fact]
  54. public void UseMiddleware_AsyncNonTaskReturnType_ThrowsException()
  55. {
  56. var builder = new ApplicationBuilder(new DummyServiceProvider());
  57. builder.UseMiddleware(typeof(MiddlewareAsyncNonTaskReturnStub));
  58. var exception = Assert.Throws<InvalidOperationException>(() => builder.Build());
  59. Assert.Equal(
  60. Resources.FormatException_UseMiddlewareNonTaskReturnType(
  61. UseMiddlewareExtensions.InvokeMethodName,
  62. UseMiddlewareExtensions.InvokeAsyncMethodName,
  63. nameof(Task)),
  64. exception.Message);
  65. }
  66. [Fact]
  67. public void UseMiddleware_NoInvokeOrInvokeAsyncMethod_ThrowsException()
  68. {
  69. var builder = new ApplicationBuilder(new DummyServiceProvider());
  70. builder.UseMiddleware(typeof(MiddlewareNoInvokeStub));
  71. var exception = Assert.Throws<InvalidOperationException>(() => builder.Build());
  72. Assert.Equal(
  73. Resources.FormatException_UseMiddlewareNoInvokeMethod(
  74. UseMiddlewareExtensions.InvokeMethodName,
  75. UseMiddlewareExtensions.InvokeAsyncMethodName, typeof(MiddlewareNoInvokeStub)),
  76. exception.Message);
  77. }
  78. [Fact]
  79. public void UseMiddleware_MultipleInvokeMethods_ThrowsException()
  80. {
  81. var builder = new ApplicationBuilder(new DummyServiceProvider());
  82. builder.UseMiddleware(typeof(MiddlewareMultipleInvokesStub));
  83. var exception = Assert.Throws<InvalidOperationException>(() => builder.Build());
  84. Assert.Equal(
  85. Resources.FormatException_UseMiddleMutlipleInvokes(
  86. UseMiddlewareExtensions.InvokeMethodName,
  87. UseMiddlewareExtensions.InvokeAsyncMethodName),
  88. exception.Message);
  89. }
  90. [Fact]
  91. public void UseMiddleware_MultipleInvokeAsyncMethods_ThrowsException()
  92. {
  93. var builder = new ApplicationBuilder(new DummyServiceProvider());
  94. builder.UseMiddleware(typeof(MiddlewareMultipleInvokeAsyncStub));
  95. var exception = Assert.Throws<InvalidOperationException>(() => builder.Build());
  96. Assert.Equal(
  97. Resources.FormatException_UseMiddleMutlipleInvokes(
  98. UseMiddlewareExtensions.InvokeMethodName,
  99. UseMiddlewareExtensions.InvokeAsyncMethodName),
  100. exception.Message);
  101. }
  102. [Fact]
  103. public void UseMiddleware_MultipleInvokeAndInvokeAsyncMethods_ThrowsException()
  104. {
  105. var builder = new ApplicationBuilder(new DummyServiceProvider());
  106. builder.UseMiddleware(typeof(MiddlewareMultipleInvokeAndInvokeAsyncStub));
  107. var exception = Assert.Throws<InvalidOperationException>(() => builder.Build());
  108. Assert.Equal(
  109. Resources.FormatException_UseMiddleMutlipleInvokes(
  110. UseMiddlewareExtensions.InvokeMethodName,
  111. UseMiddlewareExtensions.InvokeAsyncMethodName),
  112. exception.Message);
  113. }
  114. [Fact]
  115. public async Task UseMiddleware_ThrowsIfArgCantBeResolvedFromContainer()
  116. {
  117. var builder = new ApplicationBuilder(new DummyServiceProvider());
  118. builder.UseMiddleware(typeof(MiddlewareInjectInvokeNoService));
  119. var app = builder.Build();
  120. var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => app(new DefaultHttpContext()));
  121. Assert.Equal(
  122. Resources.FormatException_InvokeMiddlewareNoService(
  123. typeof(object),
  124. typeof(MiddlewareInjectInvokeNoService)),
  125. exception.Message);
  126. }
  127. [Fact]
  128. public void UseMiddlewareWithInvokeArg()
  129. {
  130. var builder = new ApplicationBuilder(new DummyServiceProvider());
  131. builder.UseMiddleware(typeof(MiddlewareInjectInvoke));
  132. var app = builder.Build();
  133. app(new DefaultHttpContext());
  134. }
  135. [Fact]
  136. public void UseMiddlewareWithInvokeWithOutAndRefThrows()
  137. {
  138. var mockServiceProvider = new DummyServiceProvider();
  139. var builder = new ApplicationBuilder(mockServiceProvider);
  140. builder.UseMiddleware(typeof(MiddlewareInjectWithOutAndRefParams));
  141. var exception = Assert.Throws<NotSupportedException>(() => builder.Build());
  142. }
  143. [Fact]
  144. public void UseMiddlewareWithIMiddlewareThrowsIfParametersSpecified()
  145. {
  146. var mockServiceProvider = new DummyServiceProvider();
  147. var builder = new ApplicationBuilder(mockServiceProvider);
  148. var exception = Assert.Throws<NotSupportedException>(() => builder.UseMiddleware(typeof(Middleware), "arg"));
  149. Assert.Equal(Resources.FormatException_UseMiddlewareExplicitArgumentsNotSupported(typeof(IMiddleware)), exception.Message);
  150. }
  151. [Fact]
  152. public async Task UseMiddlewareWithIMiddlewareThrowsIfNoIMiddlewareFactoryRegistered()
  153. {
  154. var mockServiceProvider = new DummyServiceProvider();
  155. var builder = new ApplicationBuilder(mockServiceProvider);
  156. builder.UseMiddleware(typeof(Middleware));
  157. var app = builder.Build();
  158. var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
  159. {
  160. var context = new DefaultHttpContext();
  161. var sp = new DummyServiceProvider();
  162. context.RequestServices = sp;
  163. await app(context);
  164. });
  165. Assert.Equal(Resources.FormatException_UseMiddlewareNoMiddlewareFactory(typeof(IMiddlewareFactory)), exception.Message);
  166. }
  167. [Fact]
  168. public async Task UseMiddlewareWithIMiddlewareThrowsIfMiddlewareFactoryCreateReturnsNull()
  169. {
  170. var mockServiceProvider = new DummyServiceProvider();
  171. var builder = new ApplicationBuilder(mockServiceProvider);
  172. builder.UseMiddleware(typeof(Middleware));
  173. var app = builder.Build();
  174. var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
  175. {
  176. var context = new DefaultHttpContext();
  177. var sp = new DummyServiceProvider();
  178. sp.AddService(typeof(IMiddlewareFactory), new BadMiddlewareFactory());
  179. context.RequestServices = sp;
  180. await app(context);
  181. });
  182. Assert.Equal(
  183. Resources.FormatException_UseMiddlewareUnableToCreateMiddleware(
  184. typeof(BadMiddlewareFactory),
  185. typeof(Middleware)),
  186. exception.Message);
  187. }
  188. [Fact]
  189. public async Task UseMiddlewareWithIMiddlewareWorks()
  190. {
  191. var mockServiceProvider = new DummyServiceProvider();
  192. var builder = new ApplicationBuilder(mockServiceProvider);
  193. builder.UseMiddleware(typeof(Middleware));
  194. var app = builder.Build();
  195. var context = new DefaultHttpContext();
  196. var sp = new DummyServiceProvider();
  197. var middlewareFactory = new BasicMiddlewareFactory();
  198. sp.AddService(typeof(IMiddlewareFactory), middlewareFactory);
  199. context.RequestServices = sp;
  200. await app(context);
  201. Assert.True(Assert.IsType<bool>(context.Items["before"]));
  202. Assert.True(Assert.IsType<bool>(context.Items["after"]));
  203. Assert.NotNull(middlewareFactory.Created);
  204. Assert.NotNull(middlewareFactory.Released);
  205. Assert.IsType<Middleware>(middlewareFactory.Created);
  206. Assert.IsType<Middleware>(middlewareFactory.Released);
  207. Assert.Same(middlewareFactory.Created, middlewareFactory.Released);
  208. }
  209. public class Middleware : IMiddleware
  210. {
  211. public async Task InvokeAsync(HttpContext context, RequestDelegate next)
  212. {
  213. context.Items["before"] = true;
  214. await next(context);
  215. context.Items["after"] = true;
  216. }
  217. }
  218. public class BasicMiddlewareFactory : IMiddlewareFactory
  219. {
  220. public IMiddleware? Created { get; private set; }
  221. public IMiddleware? Released { get; private set; }
  222. public IMiddleware? Create(Type middlewareType)
  223. {
  224. Created = Activator.CreateInstance(middlewareType) as IMiddleware;
  225. return Created;
  226. }
  227. public void Release(IMiddleware middleware)
  228. {
  229. Released = middleware;
  230. }
  231. }
  232. public class BadMiddlewareFactory : IMiddlewareFactory
  233. {
  234. public IMiddleware? Create(Type middlewareType) => null;
  235. public void Release(IMiddleware middleware) { }
  236. }
  237. private class DummyServiceProvider : IServiceProvider
  238. {
  239. private readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
  240. public void AddService(Type type, object value) => _services[type] = value;
  241. public object? GetService(Type serviceType)
  242. {
  243. if (serviceType == typeof(IServiceProvider))
  244. {
  245. return this;
  246. }
  247. if (_services.TryGetValue(serviceType, out var value))
  248. {
  249. return value;
  250. }
  251. return null;
  252. }
  253. }
  254. public class MiddlewareInjectWithOutAndRefParams
  255. {
  256. public MiddlewareInjectWithOutAndRefParams(RequestDelegate next) { }
  257. public Task Invoke(HttpContext context, ref IServiceProvider? sp1, out IServiceProvider? sp2)
  258. {
  259. sp1 = null;
  260. sp2 = null;
  261. return Task.FromResult(0);
  262. }
  263. }
  264. private class MiddlewareInjectInvokeNoService
  265. {
  266. public MiddlewareInjectInvokeNoService(RequestDelegate next) { }
  267. public Task Invoke(HttpContext context, object value) => Task.CompletedTask;
  268. }
  269. private class MiddlewareInjectInvoke
  270. {
  271. public MiddlewareInjectInvoke(RequestDelegate next) { }
  272. public Task Invoke(HttpContext context, IServiceProvider provider) => Task.CompletedTask;
  273. }
  274. private class MiddlewareNoParametersStub
  275. {
  276. public MiddlewareNoParametersStub(RequestDelegate next) { }
  277. public Task Invoke() => Task.CompletedTask;
  278. }
  279. private class MiddlewareAsyncNoParametersStub
  280. {
  281. public MiddlewareAsyncNoParametersStub(RequestDelegate next) { }
  282. public Task InvokeAsync() => Task.CompletedTask;
  283. }
  284. private class MiddlewareNonTaskReturnStub
  285. {
  286. public MiddlewareNonTaskReturnStub(RequestDelegate next) { }
  287. public int Invoke() => 0;
  288. }
  289. private class MiddlewareAsyncNonTaskReturnStub
  290. {
  291. public MiddlewareAsyncNonTaskReturnStub(RequestDelegate next) { }
  292. public int InvokeAsync() => 0;
  293. }
  294. private class MiddlewareNoInvokeStub
  295. {
  296. public MiddlewareNoInvokeStub(RequestDelegate next) { }
  297. }
  298. private class MiddlewareMultipleInvokesStub
  299. {
  300. public MiddlewareMultipleInvokesStub(RequestDelegate next) { }
  301. public Task Invoke(HttpContext context) => Task.CompletedTask;
  302. public Task Invoke(HttpContext context, int i) => Task.CompletedTask;
  303. }
  304. private class MiddlewareMultipleInvokeAsyncStub
  305. {
  306. public MiddlewareMultipleInvokeAsyncStub(RequestDelegate next) { }
  307. public Task InvokeAsync(HttpContext context) => Task.CompletedTask;
  308. public Task InvokeAsync(HttpContext context, int i) => Task.CompletedTask;
  309. }
  310. private class MiddlewareMultipleInvokeAndInvokeAsyncStub
  311. {
  312. public MiddlewareMultipleInvokeAndInvokeAsyncStub(RequestDelegate next) { }
  313. public Task Invoke(HttpContext context) => Task.CompletedTask;
  314. public Task InvokeAsync(HttpContext context) => Task.CompletedTask;
  315. }
  316. }
  317. }