Skip to content

Commit dc3c6e8

Browse files
committed
修正在未正常响应时Accept包含通配符会导致异常的问题;
1 parent b188465 commit dc3c6e8

File tree

3 files changed

+65
-13
lines changed

3 files changed

+65
-13
lines changed

src/Cuture.AspNetCore.ResponseAutoWrapper/Cuture.AspNetCore.ResponseAutoWrapper.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<IsPackable>true</IsPackable>
99
<GenerateDocumentationFile>true</GenerateDocumentationFile>
1010

11-
<Version>1.1.0</Version>
11+
<Version>1.1.1</Version>
1212
<Description>用于`asp.net core`的响应和异常自动包装器,使`Action`提供一致的响应内容格式</Description>
1313

1414
<PackageIdPrefix>Cuture.AspNetCore.ResponseAutoWrapper</PackageIdPrefix>
@@ -19,7 +19,7 @@
1919
<RepositoryType>git</RepositoryType>
2020
<RepositoryUrl>$(PackageProjectUrl)</RepositoryUrl>
2121

22-
<PackageTags>response-wrapper autowrap autowrapper auto-wrapper response-auto-wrapper asp-net-core</PackageTags>
22+
<PackageTags>response-wrapper responsewrapper response-wrap responsewrap autowrap auto-wrapper autowrapper response-auto-wrapper responseautowrapper asp-net-core</PackageTags>
2323
</PropertyGroup>
2424

2525
<PropertyGroup Condition="'$(Configuration)' == 'Release'">

src/Cuture.AspNetCore.ResponseAutoWrapper/ResponseAutoWrapMiddleware.cs

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Runtime.CompilerServices;
34
using System.Threading.Tasks;
45

56
using Microsoft.AspNetCore.Http;
@@ -9,6 +10,7 @@
910
using Microsoft.Extensions.DependencyInjection;
1011
using Microsoft.Extensions.Logging;
1112
using Microsoft.Extensions.Options;
13+
using Microsoft.Extensions.Primitives;
1214
using Microsoft.Net.Http.Headers;
1315

1416
namespace Cuture.AspNetCore.ResponseAutoWrapper;
@@ -172,11 +174,61 @@ public async Task InvokeAsync(HttpContext context)
172174

173175
private Task WriteResponseWithFormatterAsync(HttpContext context, object response)
174176
{
175-
var formatterContext = new OutputFormatterWriteContext(context,
176-
_httpResponseStreamWriterFactory.CreateWriter,
177-
response.GetType(),
178-
response);
177+
var formatterWriteContext = new OutputFormatterWriteContext(context,
178+
_httpResponseStreamWriterFactory.CreateWriter,
179+
response.GetType(),
180+
response);
181+
182+
if (context.Request.Headers.TryGetValue(HeaderNames.Accept, out var acceptValues)
183+
&& acceptValues.Count > 0
184+
&& !EmptyOrHasWildcard(acceptValues))
185+
{
186+
return WriteResponseWithSelectFormatterAsync(context, formatterWriteContext);
187+
}
188+
189+
// 有通配符,直接使用默认Formatter
190+
return _defaultOutputFormatter.WriteAsync(formatterWriteContext);
191+
192+
static bool EmptyOrHasWildcard(in StringValues acceptValues)
193+
{
194+
// 检查通配符
195+
return acceptValues.Count switch
196+
{
197+
1 => NullOrHasWildcard(acceptValues, 0),
198+
2 => NullOrHasWildcard(acceptValues, 0) && NullOrHasWildcard(acceptValues, 1),
199+
{ } count => HasAnyWildcard(acceptValues, count),
200+
};
201+
}
179202

203+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
204+
static bool HasAnyWildcard(in StringValues acceptValues, int count)
205+
{
206+
for (int i = 0; i < count; i++)
207+
{
208+
if (NullOrHasWildcard(acceptValues, i))
209+
{
210+
return true;
211+
}
212+
}
213+
return false;
214+
}
215+
216+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
217+
static bool NullOrHasWildcard(in StringValues acceptValues, in int index)
218+
{
219+
var value = acceptValues[index];
220+
return value is null || value.Contains("*/*", StringComparison.Ordinal);
221+
}
222+
}
223+
224+
/// <summary>
225+
/// 选择Formatter进行响应
226+
/// </summary>
227+
/// <param name="context"></param>
228+
/// <param name="formatterWriteContext"></param>
229+
/// <returns></returns>
230+
private Task WriteResponseWithSelectFormatterAsync(HttpContext context, OutputFormatterWriteContext formatterWriteContext)
231+
{
180232
var accepts = context.Request.Headers.TryGetValue(HeaderNames.Accept, out var acceptValue)
181233
? MediaTypeHeaderValue.TryParseList(acceptValue, out var parsedAcceptValues)
182234
? CreateMediaTypeCollection(parsedAcceptValues)
@@ -185,12 +237,12 @@ private Task WriteResponseWithFormatterAsync(HttpContext context, object respons
185237

186238
var selectedFormatter = accepts is null
187239
? _defaultOutputFormatter
188-
: _outputFormatterSelector.SelectFormatter(formatterContext,
189-
Array.Empty<IOutputFormatter>(),
190-
accepts)
191-
?? _defaultOutputFormatter;
240+
: _outputFormatterSelector.SelectFormatter(formatterWriteContext,
241+
Array.Empty<IOutputFormatter>(),
242+
accepts)
243+
?? _defaultOutputFormatter;
192244

193-
return selectedFormatter.WriteAsync(formatterContext);
245+
return selectedFormatter.WriteAsync(formatterWriteContext);
194246
}
195247

196248
#endregion Internal

src/Cuture.AspNetCore.ResponseAutoWrapper/ResponseAutoWrapMiddlewareOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class ResponseAutoWrapMiddlewareOptions
1414

1515
/// <summary>
1616
/// 是否捕获异常<para/>
17-
/// default is "true"
17+
/// default is <see langword="true"/>
1818
/// </summary>
1919
public bool CatchExceptions { get; set; } = true;
2020

@@ -29,7 +29,7 @@ public class ResponseAutoWrapMiddlewareOptions
2929

3030
/// <summary>
3131
/// 是否将捕获到的异常抛出给上层中间件<para/>
32-
/// default is "fasle"
32+
/// default is <see langword="false"/>
3333
/// </summary>
3434
public bool ThrowCaughtExceptions { get; set; } = false;
3535

0 commit comments

Comments
 (0)