.NETStandard 1.1库中的接口没有.NET 4.61中的实现

cas*_*One 6 .net c# .net-core .net-standard

我在.NETStandard库中定义了一个接口,它是HttpClient实例的工厂:

namespace Ofl.Net.Http
{
    public interface IHttpClientFactory
    {
        Task<HttpClient> CreateAsync(HttpMessageHandler handler, 
            bool disposeHandler, CancellationToken cancellationToken);
    }
}
Run Code Online (Sandbox Code Playgroud)

<FrameworkTarget>.csproj文件中的元素设置为netstandard1.1(HttpClient需要1.1).

默认情况下引用.NETStandard.Library 1.6.1(尽管未在.csproj文件中明确指定).

在同一个解决方案中,我从.NET Standard项目开始,并将<FrameworkTargets>元素设置为netcoreapp1.1;net461.

我有一些测试来测试只是创建一个接口的实现(我通常不会测试它,但这将它减少到最小的自包含可重现的例子).

为此,我有一个私人实施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
}
Run Code Online (Sandbox Code Playgroud)

然后测试:

[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);
}
Run Code Online (Sandbox Code Playgroud)

基本上,通过具有接口实现类型的变量进行调用,并使用实现类的类型进行调用(尽管无关紧要).

dotnet test在.NETCoreApp 1.1框架中运行测试(通过Resharper或)时,所有测试都通过了.但是,在.NET Framework 4.6.1上运行时,我得到一个System.TypeLoadException声明:没有实现:

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()
Run Code Online (Sandbox Code Playgroud)

为什么在.NET Framework 4.6.1上运行时测试没有通过?肯定有一个实现.

我认为这可能是因为System.Net.Http没有在测试项目中引用(因为引用了.NETStandard 1.6.1而没有在接口定义中引用System.Net.Http)所以我确保添加它,但测试仍然在.NET下失败框架4.6.1.

完整的设置可以在这里找到:

https://github.com/OneFrameLink/Ofl.Net.Http.Abstractions/tree/c2bc5499b86e29c2e0a91282ca7dabcc1acc1176

信息

VS.NET 2017 .NET CLI:1.1.0 .NET桌面框架:4.61 .NET Core:1.1

Mar*_*ich 7

这是因为没有.dll.config为程序集生成具有正确绑定重定向的文件,并且Test SDK未设置自动执行此操作所需的属性.

您可以通过将其添加到测试.csproj文件来解决此问题:

  <PropertyGroup Condition=" '$(TargetFramework)' == 'net461' ">
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
  </PropertyGroup>
Run Code Online (Sandbox Code Playgroud)

您将看到这会导致bin\Debug\net461\Ofl.Net.Http.Abstractions.Tests.dll.config生成包含绑定重定向的文件,System.Net.Http并且您的测试应该正常运行.

即将推出的.net core/cli 2.0工具和测试sdk将包含一些应该修复此问题的更改,但这可能被认为是当前工具中的一个错误.