Hosting 292 B

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. commit f6cda4fab73ff5d4594741cc5b34b58fa3d0e579
  2. Author: Chris Ross (ASP.NET) <[email protected]>
  3. Date: Fri Nov 16 16:39:50 2018 -0800
  4. Make TestServer handle exceptions from OnStarting #1594
  5. diff --git a/src/Microsoft.AspNetCore.TestHost/HttpContextBuilder.cs b/src/Microsoft.AspNetCore.TestHost/HttpContextBuilder.cs
  6. index 6886b1aac45..c576628b65c 100644
  7. --- a/src/Microsoft.AspNetCore.TestHost/HttpContextBuilder.cs
  8. +++ b/src/Microsoft.AspNetCore.TestHost/HttpContextBuilder.cs
  9. @@ -109,7 +109,16 @@ namespace Microsoft.AspNetCore.TestHost
  10. if (!_responseFeature.HasStarted)
  11. {
  12. // Sets HasStarted
  13. - await _responseFeature.FireOnSendingHeadersAsync();
  14. + try
  15. + {
  16. + await _responseFeature.FireOnSendingHeadersAsync();
  17. + }
  18. + catch (Exception ex)
  19. + {
  20. + Abort(ex);
  21. + return;
  22. + }
  23. +
  24. // Copy the feature collection so we're not multi-threading on the same collection.
  25. var newFeatures = new FeatureCollection();
  26. foreach (var pair in _httpContext.Features)
  27. diff --git a/test/Microsoft.AspNetCore.TestHost.Tests/ClientHandlerTests.cs b/test/Microsoft.AspNetCore.TestHost.Tests/ClientHandlerTests.cs
  28. index e90a79e97bd..7187f493dc5 100644
  29. --- a/test/Microsoft.AspNetCore.TestHost.Tests/ClientHandlerTests.cs
  30. +++ b/test/Microsoft.AspNetCore.TestHost.Tests/ClientHandlerTests.cs
  31. @@ -272,6 +272,63 @@ namespace Microsoft.AspNetCore.TestHost
  32. Assert.IsType<InvalidOperationException>(ex.GetBaseException());
  33. }
  34. + [Fact]
  35. + public Task ExceptionFromOnStartingFirstWriteIsReported()
  36. + {
  37. + var handler = new ClientHandler(PathString.Empty, new DummyApplication(context =>
  38. + {
  39. + context.Response.OnStarting(() =>
  40. + {
  41. + throw new InvalidOperationException(new string('a', 1024 * 32));
  42. + });
  43. + return context.Response.WriteAsync("Hello World");
  44. + }));
  45. + var httpClient = new HttpClient(handler);
  46. + return Assert.ThrowsAsync<InvalidOperationException>(() => httpClient.GetAsync("https://example.com/",
  47. + HttpCompletionOption.ResponseHeadersRead));
  48. + }
  49. +
  50. + [Fact]
  51. + public Task ExceptionFromOnStartingWithNoWriteIsReported()
  52. + {
  53. + var handler = new ClientHandler(PathString.Empty, new DummyApplication(context =>
  54. + {
  55. + context.Response.OnStarting(() =>
  56. + {
  57. + throw new InvalidOperationException(new string('a', 1024 * 32));
  58. + });
  59. + return Task.CompletedTask;
  60. + }));
  61. + var httpClient = new HttpClient(handler);
  62. + return Assert.ThrowsAsync<InvalidOperationException>(() => httpClient.GetAsync("https://example.com/",
  63. + HttpCompletionOption.ResponseHeadersRead));
  64. + }
  65. +
  66. + [Fact]
  67. + public Task ExceptionFromOnStartingWithErrorHandlerIsReported()
  68. + {
  69. + var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context =>
  70. + {
  71. + context.Response.OnStarting(() =>
  72. + {
  73. + throw new InvalidOperationException(new string('a', 1024 * 32));
  74. + });
  75. + try
  76. + {
  77. + await context.Response.WriteAsync("Hello World");
  78. + }
  79. + catch (Exception ex)
  80. + {
  81. + // This is no longer the first write, so it doesn't trigger OnStarting again.
  82. + // The exception is large enough that it fills the pipe and stalls.
  83. + await context.Response.WriteAsync(ex.ToString());
  84. + }
  85. + }));
  86. + var httpClient = new HttpClient(handler);
  87. + return Assert.ThrowsAsync<InvalidOperationException>(() => httpClient.GetAsync("https://example.com/",
  88. + HttpCompletionOption.ResponseHeadersRead));
  89. + }
  90. +
  91. private class DummyApplication : IHttpApplication<Context>
  92. {
  93. RequestDelegate _application;