集合被修改;枚举操作可能不会随机弹出 - HTTP?

Wil*_*iam 5 c# exception http httpclient http-headers

我有“集合已修改;枚举操作可能无法执行。” 在我的日志中随机填充的异常,它不是一个持久性错误,而是一个非常随机和烦人的错误。

它似乎源自 System.Net.Http?添加标题时,但我不确定导致此错误弹出的确切原因。我到处寻找这个错误,我理解原因的概念,但是我没有做任何可能抛出这个异常的手动循环和编辑列表(除了添加标题)?

我有一个使用 HTTPClient 与外部 API 通信的服务,这在大多数情况下都有效,但有时会因上述异常而失败,我尝试调试它,但似乎找不到解决方案!希望有人能发现问题并以正确的方式指出我。

例外

Source: System.Private.CoreLib 
 Message: Collection was modified; enumeration operation may not execute. 
 Stack trace:    at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
   at System.Net.Http.Headers.HttpHeaders.AddHeaderInfo(HeaderDescriptor descriptor, HeaderStoreItemInfo sourceInfo)
   at System.Net.Http.Headers.HttpHeaders.AddHeaders(HttpHeaders sourceHeaders)
   at System.Net.Http.Headers.HttpRequestHeaders.AddHeaders(HttpHeaders sourceHeaders)
   at System.Net.Http.HttpClient.PrepareRequestMessage(HttpRequestMessage request)
   at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.PostAsync(String requestUri, HttpContent content)
   at Hidden.Core.Service.BlaService.MyMethod(MyMethodModel model) in C:\Source\Hidden.Core\Service\BlaService.cs:line 168
   at Hidden.Web.Api.Controllers.ResourceController.MyMethod(MyMethodModel model) in C:\Source\Hidden.Web.Api\Controllers\ResourceController.cs:line 387
   at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Hidden.Web.Api.Infrastructure.ExceptionHandlerMiddleware.Invoke(HttpContext context, IActionResultExecutor`1 executor) in C:\Source\Hidden.Web.Api\Infrastructure\ExceptionHandlerMiddleware.cs:line 31 
 Inner Exception: 
Run Code Online (Sandbox Code Playgroud)

我的服务:

private static readonly HttpClient client = new HttpClient();

public async Task<HttpResponseMessage> MyMethod(MyMethodModel model)
{
    //Escape chars
    model.Location = model.Location.Replace("'", "''");
    model.DirectoryName = model.DirectoryName.Replace("'", "''");

    //Set Endpoint
    var sharePointEndpoint = $"https://{model.Hostname}/sites/{model.Site}/_api/web/folders";

    //Set default headers
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", model.SharePointToken); //Set token
    client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");

    //Pre-Body data setup
    ResourceBodyMetaDataModel metaData = new ResourceBodyMetaDataModel() { type = "SP.Folder" };

    //Body data setup
    var bodyModel = new Dictionary<string, object>();
    bodyModel.Add("__metadata", metaData);
    bodyModel.Add("ServerRelativeUrl", $"{model.Location}/{model.DirectoryName}/");

    //Set content headers
    var strContent = new StringContent(JsonConvert.SerializeObject(bodyModel));
    strContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    strContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("odata", "verbose"));

    // Send request, grab response
    var response = await client.PostAsync(sharePointEndpoint, strContent); //Exception Points HERE

    //Return response message
    return response;
}
Run Code Online (Sandbox Code Playgroud)

Wil*_*iam 6

概述:

似乎一旦我向我的 API 发送了多个请求,这些请求就会相互冲突,试图覆盖标头。我什至尝试先清除标题然后添加它们,但我仍然遇到了上述问题。该问题还开始包括以下异常:An item with the same key has already been added. Key: System.Net.Http.Headers.HeaderDescriptor.

解析度:

为了解决这个问题,我重构了我的服务以执行以下操作:

//Setup request
var request = new HttpRequestMessage(HttpMethod.Post, sharePointEndpoint)
{
    Content = strContent
};

request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", model.SharePointToken);
request.Headers.Add("Accept", "application/json;odata=verbose");
request.Headers.Add("X-HTTP-Method", "POST");
request.Headers.Add("ContentLength", bodyModelJson.Length.ToString());

// Send request, grab response
var response = await _httpClient.SendAsync(request);
Run Code Online (Sandbox Code Playgroud)

在我的情况下,标题将取决于我想要进行的操作。我删除了为HTTPClient添加默认标头的部分,而是在发出的请求中添加了它们。如您所见,我现在还使用了SendAsync()

我还将HTTPClient作为单例注入。每当我想使用HTTPClient时,我都必须开始使用我的构造函数

我的服务

private readonly HttpClient _httpClient;

public MyService(HttpClient httpClient)
{
    _httpClient = httpClient;
}
Run Code Online (Sandbox Code Playgroud)

启动.cs:

public void ConfigureServices(IServiceCollection services)
{
    /// SERVICES
    services.AddSingleton<HttpClient>();
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助其他遇到此问题的人。