I'm defining an interface in a .NETStandard library that is a factory for a HttpClient
instances:
namespace Ofl.Net.Http
{
public interface IHttpClientFactory
{
Task<HttpClient> CreateAsync(HttpMessageHandler handler,
bool disposeHandler, CancellationToken cancellationToken);
}
}
The <FrameworkTarget>
element in the .csproj file is set to netstandard1.1
(HttpClient
requires 1.1).
.NETStandard.Library 1.6.1 is referenced by default (although not explicitly specified in the .csproj file).
In the same solution, I start with a .NET Standard project and set the <FrameworkTargets>
element to netcoreapp1.1;net461
.
I have some tests to test just creating an implementation of the interface (I wouldn't normally test this, but this reduces it to the smallest self contained reproducible example).
To aid in this, I have a private implementation of IHttpClientFactory
:
private class HttpClientFactory : IHttpClientFactory
{
#region Implementation of IHttpClientFactory
public Task<HttpClient> CreateAsync(HttpMessageHandler handler,
bool disposeHandler, CancellationToken cancellationToken)
{
// Return a new client.
return Task.FromResult(new HttpClient());
}
#endregion
}
Then the tests:
[Fact]
public async Task Test_CreateAsync_Interface_Async()
{
// Cancellation token.
CancellationToken cancellationToken = CancellationToken.None;
// The client factory.
IHttpClientFactory factory = new HttpClientFactory();
// Not null.
Assert.NotNull(factory);
// Create client.
HttpClient client = await factory.CreateAsync(null, true,
cancellationToken).ConfigureAwait(false);
// Not null.
Assert.NotNull(client);
}
[Fact]
public async Task Test_CreateAsync_Concrete_Async()
{
// Cancellation token.
CancellationToken cancellationToken = CancellationToken.None;
// The client factory.
var factory = new HttpClientFactory();
// Not null.
Assert.NotNull(factory);
// Create client.
HttpClient client = await factory.CreateAsync(null, true,
cancellationToken).ConfigureAwait(false);
// Not null.
Assert.NotNull(client);
}
Basically, making a call through a variable with a type of the interface implementation, and a variable with a type of the implementing class (that doesn't matter though).
When running the tests (through Resharper, or dotnet test
) in .NETCoreApp 1.1 framework has all tests passing. However, when running on the .NET Framework 4.6.1, I get a System.TypeLoadException
stating that there is no implementation:
System.TypeLoadException : Method 'CreateAsync' in type 'HttpClientFactory' from assembly 'Ofl.Net.Http.Abstractions.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
at Ofl.Net.Http.Abstractions.Tests.HttpClientFactoryTests.<Test_CreateAsync_Interface_Async>d__1.MoveNext()
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine](TStateMachine& stateMachine)
at Ofl.Net.Http.Abstractions.Tests.HttpClientFactoryTests.Test_CreateAsync_Interface_Async()
Why doesn't the test pass when running on the .NET Framework 4.6.1? There's most certainly an implementation.
I thought it could be because System.Net.Http
wasn't referenced in the test project (not necessary in the interface definition because .NETStandard 1.6.1 is referenced, which references System.Net.Http
) so I made sure to add that, but the test still fails under the .NET Framework 4.6.1.
The full setup can be found here:
https://github.com/OneFrameLink/Ofl.Net.Http.Abstractions/tree/c2bc5499b86e29c2e0a91282ca7dabcc1acc1176
Info
VS.NET 2017 .NET CLI: 1.1.0 .NET Desktop Framework: 4.61 .NET Core: 1.1
This is because no .dll.config
file with the correct binding redirects is generated for your assembly and the Test SDK doesn't set the required properties to do this automatically.
You can work around this by adding this to your test's .csproj
file:
<PropertyGroup Condition=" '$(TargetFramework)' == 'net461' ">
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
You'll see that this causes a bin\Debug\net461\Ofl.Net.Http.Abstractions.Tests.dll.config
file to be generated that includes binding redirects for System.Net.Http
and your tests should run properly.
The upcoming tooling for .net core / cli 2.0 and the test sdk will include a few changes that should fix this but this may be considered a bug in the current tooling.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With