C# RuntimeMiddleware目标数组不够长错误
我在asp.net core 2.1中有一个写运行时中间件服务,它工作正常,但有时会出错 错误: 目标数组不够长。检查目标索引、长度和数组的下限 代码:C# RuntimeMiddleware目标数组不够长错误,c#,asp.net-core,C#,Asp.net Core,我在asp.net core 2.1中有一个写运行时中间件服务,它工作正常,但有时会出错 错误: 目标数组不够长。检查目标索引、长度和数组的下限 代码: 公共类运行时中间件服务 { 私有Func中间件; 私有IApplicationBuilder appBuilder; 内部无效使用(IApplicationBuilder应用程序) =>appBuilder=app.Use(next=>context=>middleware==null?next(上下文):middleware(next)(co
公共类运行时中间件服务
{
私有Func中间件;
私有IApplicationBuilder appBuilder;
内部无效使用(IApplicationBuilder应用程序)
=>appBuilder=app.Use(next=>context=>middleware==null?next(上下文):middleware(next)(context));
公共无效配置(操作)
{
var app=appBuilder.New();
行动(app);
middleware=next=>app.Use(=>next.Build();//行获取错误
}
}
我也使用了来自
堆栈跟踪
需要注意的是:
foreach (var component in _components.Reverse())
Reverse
调用ReverseIterator
集合是通过引用传递的。似乎在获取集合计数和创建相同大小的新数组之间的某个地方,集合的大小增加超过TElement
数组的大小,导致错误“目标数组不够长。请检查目标索引、长度和数组的下限。(参数'destinationArray')。“这将提示线程安全问题,并解释间歇性错误
下一个问题是,线程安全问题的根源在哪里
这对我个人来说还是一个谜。RuntimeMiddlewareService
在我的应用程序中是在启动时创建的一个单例。它的Configure
函数肯定会被调用,但调用频率不够(据我所知)因此,\u中间件
Func
可能在其他地方被调用。也就是说,在调用Use和Build时添加一个锁对象解决了这个问题,可能是因为线程1调用了Build
,线程2刚刚调用了Use
(这会将新项目添加到集合
)
公共类RuntimeMiddlewareService:IRuntimeMiddlewareService
{
私有静态只读对象_middlewareLock=新对象();
私有函数中间件;
私有IApplicationBuilder\u appBuilder;
公共作废使用(IApplicationBuilder应用程序)
=>\u appBuilder=app.Use(next=>context=>\u middleware==null?next(context):\u middleware(next)(context));
公共无效配置(操作)
{
var app=_appBuilder.New();
行动(app);
_中间件=下一步=>
{
锁(_middlewareLock)
{
返回app.Use(=>next.Build();
}
};
}
}
我也使用了来自
堆栈跟踪
需要注意的是:
foreach (var component in _components.Reverse())
Reverse
调用ReverseIterator
集合是通过引用传递的。似乎在获取集合的计数和创建相同大小的新数组之间的某个地方,集合的大小增加超过TElement
数组的大小,从而导致错误“目标数组不够长。请检查目标索引、长度和数组的下限。(参数'destinationArray')。”这将提示线程安全问题并解释间歇性错误
下一个问题是,线程安全问题的根源在哪里
这对我个人来说还是一个谜。RuntimeMiddlewareService
在我的应用程序中是在启动时创建的一个单例。它的Configure
函数肯定会被调用,但调用频率不够(据我所知)因此,\u中间件
Func
可能在其他地方被调用。也就是说,在调用Use和Build时添加一个锁对象解决了这个问题,可能是因为线程1调用了Build
,线程2刚刚调用了Use
(这会将新项目添加到集合
)
公共类RuntimeMiddlewareService:IRuntimeMiddlewareService
{
私有静态只读对象_middlewareLock=新对象();
私有函数中间件;
私有IApplicationBuilder\u appBuilder;
公共作废使用(IApplicationBuilder应用程序)
=>\u appBuilder=app.Use(next=>context=>\u middleware==null?next(context):\u middleware(next)(context));
公共无效配置(操作)
{
var app=_appBuilder.New();
行动(app);
_中间件=下一步=>
{
锁(_middlewareLock)
{
返回app.Use(=>next.Build();
}
};
}
}
发生此错误时,您可以与我们共享堆栈跟踪。发生此错误时,您可以与我们共享堆栈跟踪。
private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();
public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
{
_components.Add(middleware);
return this;
}
public RequestDelegate Build()
{
RequestDelegate app = context =>
{
// If we reach the end of the pipeline, but we have an endpoint, then something unexpected has happened.
// This could happen if user code sets an endpoint, but they forgot to add the UseEndpoint middleware.
var endpoint = context.GetEndpoint();
var endpointRequestDelegate = endpoint?.RequestDelegate;
if (endpointRequestDelegate != null)
{
var message =
$"The request reached the end of the pipeline without executing the endpoint: '{endpoint.DisplayName}'. " +
$"Please register the EndpointMiddleware using '{nameof(IApplicationBuilder)}.UseEndpoints(...)' if using " +
$"routing.";
throw new InvalidOperationException(message);
}
context.Response.StatusCode = 404;
return Task.CompletedTask;
};
foreach (var component in _components.Reverse())
{
app = component(app);
}
return app;
}
foreach (var component in _components.Reverse())
public static IEnumerable<TSource> Reverse<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
return ReverseIterator<TSource>(source);
}
static IEnumerable<TSource> ReverseIterator<TSource>(IEnumerable<TSource> source) {
Buffer<TSource> buffer = new Buffer<TSource>(source);
for (int i = buffer.count - 1; i >= 0; i--) yield return buffer.items[i];
}
struct Buffer<TElement>
{
internal TElement[] items;
internal int count;
internal Buffer(IEnumerable<TElement> source) {
TElement[] items = null;
int count = 0;
ICollection<TElement> collection = source as ICollection<TElement>;
if (collection != null) {
count = collection.Count;
if (count > 0) {
items = new TElement[count];
collection.CopyTo(items, 0);
}
}
else {
foreach (TElement item in source) {
if (items == null) {
items = new TElement[4];
}
else if (items.Length == count) {
TElement[] newItems = new TElement[checked(count * 2)];
Array.Copy(items, 0, newItems, 0, count);
items = newItems;
}
items[count] = item;
count++;
}
}
this.items = items;
this.count = count;
}
internal TElement[] ToArray() {
if (count == 0) return new TElement[0];
if (items.Length == count) return items;
TElement[] result = new TElement[count];
Array.Copy(items, 0, result, 0, count);
return result;
}
}
if (collection != null) {
count = collection.Count;
if (count > 0) {
items = new TElement[count];
collection.CopyTo(items, 0);
}
}
public class RuntimeMiddlewareService : IRuntimeMiddlewareService
{
private static readonly object _middlewareLock = new object();
private Func<RequestDelegate, RequestDelegate> _middleware;
private IApplicationBuilder _appBuilder;
public void Use(IApplicationBuilder app)
=> _appBuilder = app.Use(next => context => _middleware == null ? next(context) : _middleware(next)(context));
public void Configure(Action<IApplicationBuilder> action)
{
var app = _appBuilder.New();
action(app);
_middleware = next =>
{
lock (_middlewareLock)
{
return app.Use(_ => next).Build();
}
};
}
}