在带有.NET Core(.NET Standard 1.4和.NET Framework 4.6.1)的System.Net.Http中使用await/async时出现错误? [英] Bug when using await/async for System.Net.Http with .NET Core (.NET Standard 1.4 and .NET Framework 4.6.1)?

查看:102
本文介绍了在带有.NET Core(.NET Standard 1.4和.NET Framework 4.6.1)的System.Net.Http中使用await/async时出现错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前景:我正在调查ASP.NET Core项目(使用.Net Standard 1.4中的程序集定位到.NET 4.6.1)中的错误,尽管该错误是不可能的,但该错误引发了MissingMethodException.隔离故障方法后,我将代码的核心带到了另一个针对.NET 4.6.1的单元测试中.

我从单元测试中收到的异常ThreadAbortException或多或少是这种情况(有时是不同的):

   at System.Net.Http.WinHttpHandler.SetRequestHandleDecompressionOptions(SafeWinHttpHandle requestHandle)
   at System.Net.Http.WinHttpHandler.SetRequestHandleOptions(WinHttpRequestState state)
   at System.Net.Http.WinHttpHandler.<StartRequest>d__103.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.Http.HttpClient.<FinishSendAsync>d__58.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Hub.Test.UnitTest1.<FetchUrlAsync>d__2.MoveNext() 

有关上述异常的代码:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        //FetchUrl(); // works
        var task = FetchUrlAsync(); // does not work
    }

    private void FetchUrl()
    {
        var handler = new HttpClientHandler();
        handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
        using (var client = new HttpClient(handler, true))
        {
            var response = client.SendAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("https://github.com/dotnet/core"))).Result;
            Trace.WriteLine("FetchUrl:" + response.StatusCode);
        }
    }

    private async Task FetchUrlAsync()
    {
        try
        {
            var handler = new HttpClientHandler();
            handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
            using (var client = new HttpClient(handler, true))
            {
                var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("https://github.com/dotnet/core")));
                Trace.WriteLine("FetchUrlAsync: " + response.StatusCode);
            }
        }
        catch (Exception e)
        {
            Trace.WriteLine(e);
            throw;
        }
    }
}

请注意,如果我调用FetchUrl(),代码将起作用.是的,我知道在我调用结果的那一刻,这已成为一种同步方法,但这仅是出于演示目的.

但是,故障方法FetchUrlAsync()始终引发ThreadAbortException.

SendAsync的原因是,原始实现是使用该方法进行所有Http *工作的通用实现.可以使用GetAsync等触发相同的错误.

我无法弄清楚我在做什么错,但我怀疑此错误是.NET CLR中的某个错误.

更新

尽管已解决了单元测试问题(谢谢),但我仍然在ASP.NET Core Web-api中遇到问题.据我了解,.NET Standard 1.4和.NET Framework 4.6.1应该是1-1兼容的.这就是为什么我认为框架中有一个罕见的错误,尽管似乎不太可能.

共同点是System.Net.Http;与.NET Standard 1.4和.NET Framework 4.6.1有所不同;而且我倾向于找出问题所在,并将答案发布给可能会遇到类似问题的其他人.

解决方案

好的,要解决最初的问题,这是一个控制器报告的MissingMethodException.

仅当使用async/await组合时才触发此错误,这是有道理的,因为编译器在后台生成了代码.

事实证明,其中一个Nuget程序集正在使用.NET Standard Library 1.6.1中的System.Net.Http,并且该程序包目标是.NET Standard 1.4(在纸上与.NET Framework 4.6.1 1-1兼容).

然后我将其与解决方案混合在一起,并能够生成FileNotFoundException: Could not load file or assembly 'System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.

到目前为止一切都很好.

当查看bin/debug文件夹时,问题变得很明显.没有找到System.Net.Http.dll,因为它使用的是内置Framework程序集.

啊哈.

VISUAL STUDIO 2015

在解决方案中,仅对内置Framework程序集的引用在project.lock.json中:

    "frameworkAssemblies": [
      "System.Net.Http"
    ]

此引用来自Microsoft.AspNetCore.Authentication/1.1.0Microsoft.IdentityModel.Protocols/2.1.0.

删除这两个frameworkAssemblies条目使解决方案起作用,因为真实的" System.Net.Http.dll现在已复制到bin/debug文件夹中.

VISUAL STUDIO 2017

几乎相同的问题;但是由于Microsoft已弃用project.json,因此此处的解决方案是修改(或添加)具有以下内容的app.config文件:

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

很抱歉你们这么长的帖子;但是有一个错误-它可能不在框架中..证据可能指向msbuild和/或其他IDE.我很高兴我发现了错误并能够纠正它.

我希望这篇较长的文章能对其他遇到类似问题的人有所帮助.

祝您编程愉快!

Foreground: I was investigating a bug in an ASP.NET Core project (targeting .NET 4.6.1, using assemblies from .Net Standard 1.4), that threw a MissingMethodException, although this in no way could be possible. Isolating the faulting method, I took the core of the code out to a separate unit test which also targets .NET 4.6.1.

The exception I receive, ThreadAbortException, from the unit test is more or less this (it sometime various):

   at System.Net.Http.WinHttpHandler.SetRequestHandleDecompressionOptions(SafeWinHttpHandle requestHandle)
   at System.Net.Http.WinHttpHandler.SetRequestHandleOptions(WinHttpRequestState state)
   at System.Net.Http.WinHttpHandler.<StartRequest>d__103.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.Http.HttpClient.<FinishSendAsync>d__58.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Hub.Test.UnitTest1.<FetchUrlAsync>d__2.MoveNext() 

The code in question for the abolve exception:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        //FetchUrl(); // works
        var task = FetchUrlAsync(); // does not work
    }

    private void FetchUrl()
    {
        var handler = new HttpClientHandler();
        handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
        using (var client = new HttpClient(handler, true))
        {
            var response = client.SendAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("https://github.com/dotnet/core"))).Result;
            Trace.WriteLine("FetchUrl:" + response.StatusCode);
        }
    }

    private async Task FetchUrlAsync()
    {
        try
        {
            var handler = new HttpClientHandler();
            handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
            using (var client = new HttpClient(handler, true))
            {
                var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("https://github.com/dotnet/core")));
                Trace.WriteLine("FetchUrlAsync: " + response.StatusCode);
            }
        }
        catch (Exception e)
        {
            Trace.WriteLine(e);
            throw;
        }
    }
}

Notice, that if I call FetchUrl() the code works. Yes, I know this became a sync method the moment i invoked result, but it is for demonstration purpose only.

However, the faulting method, FetchUrlAsync(), keeps throwing a ThreadAbortException.

Reason for SendAsync is, that the original implementation is a generic one using this one method for all the Http* work. The same error can be triggered with GetAsync and so forth.

I cannot figure out what I am doing wrong here, but I suspect this error to be a bug somewhere in the .NET CLR.

UPDATE

Although the unit test problem was solved (thank you), I still experienced issue in the ASP.NET Core web-api. From my understanding, .NET Standard 1.4 and .NET Framework 4.6.1 should be 1-1 compatible. This is why i believe there is a rare bug in the framework, although it seems unlikely.

The common denominator is System.Net.Http; and this varies bitwise from .NET Standard 1.4 and .NET Framework 4.6.1; and I tend to find out what the problem is and post the answer to others that might struggle with a similar problem.

解决方案

Okay, to solve the original issue which was a MissingMethodException reported by one of the controllers.

This error was ONLY triggered when using the async/await combination, which make sense because of the compiler generated code behind the scene.

Turns out, that one of the Nuget assemblies was using System.Net.Http from .NET Standard Library 1.6.1 and this assembly package targeted .NET Standard 1.4 (which, on paper, is 1-1 compatible with .NET Framework 4.6.1).

I then mingled with the solution, and was able to produce a FileNotFoundException: Could not load file or assembly 'System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.

So far so good.

The problem became apparent when looking the bin/debug folder. There was no System.Net.Http.dll to be found, as it was using the built-in Framework assembly.

Aha.

VISUAL STUDIO 2015

Looking through the solution, only reference to the built-in Framework assembly was in the project.lock.json:

    "frameworkAssemblies": [
      "System.Net.Http"
    ]

This reference came from Microsoft.AspNetCore.Authentication/1.1.0 and Microsoft.IdentityModel.Protocols/2.1.0.

Removing these two frameworkAssemblies entries made the solution work, as the "real" System.Net.Http.dll was now copied to the bin/debug folder.

VISUAL STUDIO 2017

Almost the same problem; but since Microsoft has deprecated the use of project.json, the solution here is to modify (or add) an app.config file with the following content:

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

I am sorry guys for this long post; but there is a bug - and it might not be in the framework .. evidence might point to msbuild and/or different IDE's. I am just happy i found the error and was able to correct it.

I hope this rather long entry can help others with similar issues.

Happy coding!

这篇关于在带有.NET Core(.NET Standard 1.4和.NET Framework 4.6.1)的System.Net.Http中使用await/async时出现错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆