From 6848dc0a852580106602322c53a44d4c105a0f86 Mon Sep 17 00:00:00 2001 From: Rafiki Assumani Date: Wed, 14 Jul 2021 20:23:06 -0500 Subject: [PATCH 1/4] add helper method to set the content type for string return values --- .../src/RequestDelegateFactory.cs | 29 +++++++++++++++++-- .../test/RequestDelegateFactoryTests.cs | 17 ++++++++++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index 083f5318044c..a53002186b12 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -32,7 +32,7 @@ public static partial class RequestDelegateFactory private static readonly MethodInfo ExecuteObjectReturnMethod = typeof(RequestDelegateFactory).GetMethod(nameof(ExecuteObjectReturn), BindingFlags.NonPublic | BindingFlags.Static)!; private static readonly MethodInfo GetRequiredServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethod(nameof(ServiceProviderServiceExtensions.GetRequiredService), BindingFlags.Public | BindingFlags.Static, new Type[] { typeof(IServiceProvider) })!; private static readonly MethodInfo ResultWriteResponseAsyncMethod = typeof(RequestDelegateFactory).GetMethod(nameof(ExecuteResultWriteResponse), BindingFlags.NonPublic | BindingFlags.Static)!; - private static readonly MethodInfo StringResultWriteResponseAsyncMethod = GetMethodInfo>((response, text) => HttpResponseWritingExtensions.WriteAsync(response, text, default)); + private static readonly MethodInfo StringResultWriteResponseAsyncMethod = typeof(RequestDelegateFactory).GetMethod(nameof(ExecuteWriteStringResponseAsync), BindingFlags.NonPublic | BindingFlags.Static)!; private static readonly MethodInfo JsonResultWriteResponseAsyncMethod = GetMethodInfo>((response, value) => HttpResponseJsonExtensions.WriteAsJsonAsync(response, value, default)); private static readonly MethodInfo LogParameterBindingFailureMethod = GetMethodInfo>((httpContext, parameterType, parameterName, sourceValue) => Log.ParameterBindingFailed(httpContext, parameterType, parameterName, sourceValue)); @@ -56,6 +56,8 @@ public static partial class RequestDelegateFactory private static readonly BinaryExpression TempSourceStringNotNullExpr = Expression.NotEqual(TempSourceStringExpr, Expression.Constant(null)); + private const string PlainTextContentTypeWithCharset = "text/plain; charset=utf-8"; + /// /// Creates a implementation for . /// @@ -434,7 +436,7 @@ private static Expression AddResponseWritingToMethodCall(Expression methodCall, } else if (returnType == typeof(string)) { - return Expression.Call(StringResultWriteResponseAsyncMethod, HttpResponseExpr, methodCall, Expression.Constant(CancellationToken.None)); + return Expression.Call(StringResultWriteResponseAsyncMethod, HttpContextExpr, methodCall); } else if (returnType.IsValueType) { @@ -694,6 +696,7 @@ private static async Task ExecuteObjectReturn(object? obj, HttpContext httpConte } else if (obj is string stringValue) { + SetContentType(httpContext); await httpContext.Response.WriteAsync(stringValue); } else @@ -722,8 +725,10 @@ static async Task ExecuteAwaited(Task task, HttpContext httpContext) private static Task ExecuteTaskOfString(Task task, HttpContext httpContext) { - EnsureRequestTaskNotNull(task); + SetContentType(httpContext); + EnsureRequestTaskNotNull(task); + static async Task ExecuteAwaited(Task task, HttpContext httpContext) { await httpContext.Response.WriteAsync(await task); @@ -737,6 +742,14 @@ static async Task ExecuteAwaited(Task task, HttpContext httpContext) return ExecuteAwaited(task!, httpContext); } + private static Task ExecuteWriteStringResponseAsync(HttpContext httpContext, string text) + { + + SetContentType(httpContext); + return httpContext.Response.WriteAsync(text); + + } + private static Task ExecuteValueTask(ValueTask task) { static async Task ExecuteAwaited(ValueTask task) @@ -769,6 +782,8 @@ static async Task ExecuteAwaited(ValueTask task, HttpContext httpContext) private static Task ExecuteValueTaskOfString(ValueTask task, HttpContext httpContext) { + SetContentType(httpContext); + static async Task ExecuteAwaited(ValueTask task, HttpContext httpContext) { await httpContext.Response.WriteAsync(await task); @@ -873,5 +888,13 @@ private static IResult EnsureRequestResultNotNull(IResult? result) return result; } + + private static void SetContentType(HttpContext httpContext) + { + if (httpContext.Response.ContentType == null) + { + httpContext.Response.ContentType = PlainTextContentTypeWithCharset; + } + } } } diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs index d782fbca43f5..3d4fe4123812 100644 --- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs @@ -1127,7 +1127,7 @@ public static IEnumerable StringResult [Theory] [MemberData(nameof(StringResult))] - public async Task RequestDelegateWritesStringReturnValueAsJsonResponseBody(Delegate @delegate) + public async Task RequestDelegateWritesStringReturnValueAndSetContentTypeWhenNull(Delegate @delegate) { var httpContext = new DefaultHttpContext(); var responseBodyStream = new MemoryStream(); @@ -1140,6 +1140,21 @@ public async Task RequestDelegateWritesStringReturnValueAsJsonResponseBody(Deleg var responseBody = Encoding.UTF8.GetString(responseBodyStream.ToArray()); Assert.Equal("String Test", responseBody); + Assert.Equal("text/plain; charset=utf-8", httpContext.Response.ContentType); + } + + [Theory] + [MemberData(nameof(StringResult))] + public async Task RequestDelegateWritesStringReturnDoNotChangeContentType(Delegate @delegate) + { + var httpContext = new DefaultHttpContext(); + httpContext.Response.ContentType = "application/json; charset=utf-8"; + + var requestDelegate = RequestDelegateFactory.Create(@delegate, new EmptyServiceProvider()); + + await requestDelegate(httpContext); + + Assert.NotEqual("text/plain; charset=utf-8", httpContext.Response.ContentType); } public static IEnumerable IntResult From 8fa9ab2ae24e0a00bdfddbfa4d2ef54370d2a4b2 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 15 Jul 2021 10:55:30 -0700 Subject: [PATCH 2/4] Apply suggestions from code review Co-authored-by: Stephen Halter --- src/Http/Http.Extensions/src/RequestDelegateFactory.cs | 9 +-------- .../Http.Extensions/test/RequestDelegateFactoryTests.cs | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index a53002186b12..101ecdca0a33 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -56,8 +56,6 @@ public static partial class RequestDelegateFactory private static readonly BinaryExpression TempSourceStringNotNullExpr = Expression.NotEqual(TempSourceStringExpr, Expression.Constant(null)); - private const string PlainTextContentTypeWithCharset = "text/plain; charset=utf-8"; - /// /// Creates a implementation for . /// @@ -744,10 +742,8 @@ static async Task ExecuteAwaited(Task task, HttpContext httpContext) private static Task ExecuteWriteStringResponseAsync(HttpContext httpContext, string text) { - SetContentType(httpContext); return httpContext.Response.WriteAsync(text); - } private static Task ExecuteValueTask(ValueTask task) @@ -891,10 +887,7 @@ private static IResult EnsureRequestResultNotNull(IResult? result) private static void SetContentType(HttpContext httpContext) { - if (httpContext.Response.ContentType == null) - { - httpContext.Response.ContentType = PlainTextContentTypeWithCharset; - } + httpContext.Response.ContentType ??= "text/plain; charset=utf-8"; } } } diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs index 3d4fe4123812..6e80b8f20ea2 100644 --- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs @@ -1154,7 +1154,7 @@ public async Task RequestDelegateWritesStringReturnDoNotChangeContentType(Delega await requestDelegate(httpContext); - Assert.NotEqual("text/plain; charset=utf-8", httpContext.Response.ContentType); + Assert.Equal("application/json; charset=utf-8", httpContext.Response.ContentType); } public static IEnumerable IntResult From f61d57f245b8f7ad4e8a81a29d9199a518a51978 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Thu, 15 Jul 2021 11:11:07 -0700 Subject: [PATCH 3/4] Apply suggestions from code review --- src/Http/Http.Extensions/src/RequestDelegateFactory.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs index 101ecdca0a33..3349239e6232 100644 --- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs +++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs @@ -694,7 +694,7 @@ private static async Task ExecuteObjectReturn(object? obj, HttpContext httpConte } else if (obj is string stringValue) { - SetContentType(httpContext); + SetPlaintextContentType(httpContext); await httpContext.Response.WriteAsync(stringValue); } else @@ -724,7 +724,7 @@ static async Task ExecuteAwaited(Task task, HttpContext httpContext) private static Task ExecuteTaskOfString(Task task, HttpContext httpContext) { - SetContentType(httpContext); + SetPlaintextContentType(httpContext); EnsureRequestTaskNotNull(task); static async Task ExecuteAwaited(Task task, HttpContext httpContext) @@ -742,7 +742,7 @@ static async Task ExecuteAwaited(Task task, HttpContext httpContext) private static Task ExecuteWriteStringResponseAsync(HttpContext httpContext, string text) { - SetContentType(httpContext); + SetPlaintextContentType(httpContext); return httpContext.Response.WriteAsync(text); } @@ -778,7 +778,7 @@ static async Task ExecuteAwaited(ValueTask task, HttpContext httpContext) private static Task ExecuteValueTaskOfString(ValueTask task, HttpContext httpContext) { - SetContentType(httpContext); + SetPlaintextContentType(httpContext); static async Task ExecuteAwaited(ValueTask task, HttpContext httpContext) { @@ -885,7 +885,7 @@ private static IResult EnsureRequestResultNotNull(IResult? result) return result; } - private static void SetContentType(HttpContext httpContext) + private static void SetPlaintextContentType(HttpContext httpContext) { httpContext.Response.ContentType ??= "text/plain; charset=utf-8"; } From 41efb12f67f0889ff4152686ece975c71e6f1dd5 Mon Sep 17 00:00:00 2001 From: Rafiki Assumani Date: Thu, 15 Jul 2021 12:33:58 -0700 Subject: [PATCH 4/4] fix test failure --- src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs index 731fdb18f3dc..eaf0c96a8bfb 100644 --- a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs +++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs @@ -1197,7 +1197,7 @@ public async Task RequestDelegateWritesStringReturnDoNotChangeContentType(Delega var httpContext = new DefaultHttpContext(); httpContext.Response.ContentType = "application/json; charset=utf-8"; - var requestDelegate = RequestDelegateFactory.Create(@delegate, new EmptyServiceProvider()); + var requestDelegate = RequestDelegateFactory.Create(@delegate); await requestDelegate(httpContext);