2017-01-17 6 views
1

Передний план: я изучал ошибку в проекте ASP.NET Core (с таргетингом на .NET 4.6.1, используя сборки из .Net Standard 1.4), которые бросали исключение MissingMethodException, хотя это никоим образом не могло быть возможным. Изолируя метод отказа, я взял ядро ​​кода в отдельный модульный тест, который также нацелен на .NET 4.6.1.Ошибка при использовании await/async для System.Net.Http с .NET Core (.NET Standard 1.4 и .NET Framework 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() 

код в вопросе за abolve исключением:

[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.

UPDATE

Хотя проблема модульного тестирования была решена (спасибо), я все еще испытывал проблемы в веб-API ASP.NET Core. По моему мнению, .NET Standard 1.4 и .NET Framework 4.6.1 должны быть совместимы с 1-1. Вот почему я считаю, что в этой области есть редкая ошибка, хотя она кажется маловероятной.

Общий знаменатель - System.Net.Http; и это изменяется поразрядным образом из .NET Standard 1.4 и .NET Framework 4.6.1; и я, как правило, выясняю, в чем проблема, и отправляю ответ другим, которые могут столкнуться с подобной проблемой.

+1

Ну, для начала вы не «ждете» задачи. – DavidG

+0

В одном методе 'response' является' Task ', а в другом -' HttpResponseMessage', но вы, похоже, относитесь к ним одинаково. – juharr

+0

@juharr Обратите внимание на '.Result' в конце неасинхронного метода. – DavidG

ответ

2

Хорошо, чтобы решить исходную проблему, которая была MissingMethodException сообщает один из контроллеров.

Эта ошибка была ТОЛЬКО срабатывает при использовании комбинации async/await, что имеет смысл из-за кода, сгенерированного компилятором за сценой.

Оказывается, что один из узлов NuGet использует System.Net.Http от .NET Standard Library 1.6.1 и этой сборки пакет целевого .NET Standard 1.4 (который, на бумаге, которое совместимо с 1-1 .NET Framework 4.6.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.

Aha.

VISUAL STUDIO 2015

Глядя через раствор, только ссылка на встроенный Framework сборки был в project.lock.json:

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

Эта ссылка пришли от Microsoft.AspNetCore.Authentication/1.1.0 и Microsoft.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. Я просто счастлив, что нашел ошибку и смог ее исправить.

Я надеюсь, что эта довольно длинная запись может помочь другим с подобными проблемами.

Счастливое кодирование!

+0

Может быть связано: https://github.com/dotnet/ corefx/issues/9846 –

+0

Дополнительная информация по стандарту .NET: https://blogs.msdn.microsoft.com/dotnet/2016/09/26/introducing-net-standard/ –

1

Метод испытания не ожидает завершения асинхронного метода, поэтому тест заканчивается до того, как SendAsync имеет возможность вернуться.

Вы не указываете, какую среду тестирования вы используете, но я предполагаю, что она поддерживает асинхронные тесты. В этом случае измените метод испытания на:

[TestMethod] 
public async Task TestMethod1() 
{ 
    await FetchUrlAsync();  
} 

Если нет, то вам придется использовать Wait():

[TestMethod] 
public void TestMethod1() 
{ 
    FetchUrlAsync().Wait();  
}