AutoFixture无法创建Claim(使用.NET Framework 4.6)

6
我刚安装了VS2015,它同时安装了.NET Framework 4.6,突然之间AutoFixture 3.30.8无法创建Claim对象。我猜测新的.NET Framework版本4.6在AutoFixture内部引起了一些问题。
我在VS2013中创建了一个测试项目(针对.NET Framework 4.5.1),包含以下代码:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ploeh.AutoFixture;

namespace AutoFixtureTester
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void CanCreateClaim()
        {
            var fixture = new Fixture();
            fixture.Behaviors.Add(new OmitOnRecursionBehavior());

            var claim = fixture.Create<System.Security.Claims.Claim>(); // exception here

            Assert.IsNotNull(claim);
        }
    }
}

错误信息如下:
Ploeh.AutoFixture.ObjectCreationException: AutoFixture was unable to create an instance from System.IO.Stream, most likely because it has no public constructor, is an abstract or non-public type.

Request path:
         System.Security.Claims.Claim --> 
          System.IO.BinaryReader reader --> 
           System.IO.BinaryReader --> 
            System.IO.Stream input --> 
             System.IO.Stream
   at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.BehaviorRoot.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Fixture.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.SpecimenContext.Resolve(Object request)
   at Ploeh.AutoFixture.Kernel.SeedIgnoringRelay.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.AutoPropertiesTarget.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.BehaviorRoot.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Fixture.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.SpecimenContext.Resolve(Object request)
   at Ploeh.AutoFixture.Kernel.ParameterRequestRelay.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.AutoPropertiesTarget.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.BehaviorRoot.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Fixture.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.SpecimenContext.Resolve(Object request)
   at Ploeh.AutoFixture.Kernel.MethodInvoker.<>c__DisplayClass2.<Create>b__0(ParameterInfo pi)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Ploeh.AutoFixture.Kernel.MethodInvoker.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.AutoPropertiesTarget.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.BehaviorRoot.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Fixture.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.SpecimenContext.Resolve(Object request)
   at Ploeh.AutoFixture.Kernel.SeedIgnoringRelay.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.AutoPropertiesTarget.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.BehaviorRoot.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Fixture.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.SpecimenContext.Resolve(Object request)
   at Ploeh.AutoFixture.Kernel.ParameterRequestRelay.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.AutoPropertiesTarget.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.BehaviorRoot.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Fixture.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.SpecimenContext.Resolve(Object request)
   at Ploeh.AutoFixture.Kernel.MethodInvoker.<>c__DisplayClass2.<Create>b__0(ParameterInfo pi)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Ploeh.AutoFixture.Kernel.MethodInvoker.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.AutoPropertiesTarget.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.BehaviorRoot.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Fixture.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.SpecimenContext.Resolve(Object request)
   at Ploeh.AutoFixture.Kernel.SeedIgnoringRelay.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.AutoPropertiesTarget.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.BehaviorRoot.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Fixture.Create(Object request, ISpecimenContext context)
   at Ploeh.AutoFixture.Kernel.SpecimenContext.Resolve(Object request)
   at Ploeh.AutoFixture.SpecimenFactory.Create[T](ISpecimenContext context, T seed)
   at Ploeh.AutoFixture.SpecimenFactory.Create[T](ISpecimenContext context)
   at Ploeh.AutoFixture.SpecimenFactory.Create[T](ISpecimenBuilder builder)
   at AutoFixtureTester.UnitTest1.CanCreateClaim() in D:\Sandbox\AutoFixtureTester\AutoFixtureTester\UnitTest1.cs:line 16

在安装VS2015之前,创建Claim对象的方法是有效的。实际上,我将这个解决方案发送给了只安装了VS2013的同事,对他而言也是有效的。
我注意到,在F12导航到Claim代码时,显示来自4.5.1 DLL的元数据。这是VS2015安装程序搞砸了4.5.1 DLL的问题吗?还是AutoFixture中可能存在的一个bug导致安装4.6后才浮出水面?
我比较了我和同事机器上的System.Security.Claims.Claim的DotPeek输出。他的输出显示:
// Assembly location: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\mscorlib.dll

我的显示如下:
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll

他的有5个构造函数,接受stringClaimsIdentity类型的参数。
我的有7个构造函数,其中包括2个新的构造函数,看起来像这样:

public Claim(BinaryReader reader) { ... }

并且

public Claim(BinaryReader reader, ClaimsIdentity subject) { ... }

我猜这种情况的解决方法是强制 AutoFixture 使用特定构造函数。但是这个变化没有被微软注意到,让我有些紧张。是否还有其他类似的变化?


根据文档,Stream 可能在 System.IO.dll 中适用于 4.6 版本。但是这非常不清楚。 - leppie
1
相关:https://dev59.com/0Gcs5IYBdhLWcg3wmlEK - leppie
1个回答

6

为了解决AutoFixture无法像以前一样工作的问题,我对其创建Claim的方式进行了自定义,选择了参数最多的构造函数。

fixture.Customize<System.Security.Claims.Claim>(
    c => c.FromFactory(new MethodInvoker(new GreedyConstructorQuery())));

这个问题的原因似乎是由于安装了4.6影响了4.5.1 DLL。现在,Claim有7个构造函数,其中2个新的构造函数需要一个依赖于StreamBinaryReader参数,而BinaryReader无法被AutoFixture构造。不过,幸运的是,AutoFixture相当友好且可配置。
正如上面提到的,这种重大变化令我感到紧张,因为它已经溜过了微软的检查。此外,如果他们决定在未来的4.7框架中添加另一个构造函数,包括一个BinaryReader参数和20个参数,那么我们将再次陷入困境。

2
我相信 Microsoft 不认为这是一个破坏性的变化。以前使用 claim 的正常代码将继续编译并像以前一样工作; 向类添加新成员并不构成破坏性变化。AutoFixture 出错的原因是因为它从来没有学会如何创建一个 Claim 实例。除了少数几个着名的 BCL 类型之外,AutoFixture 不知道如何创建各种类型的对象,而是使用尽力而为的启发式方法来创建对象。当框架发生变化时,偶尔会出现此类问题;有时,它也可能朝另一个方向发展。 - Mark Seemann
谢谢Mark。我想我同意添加这些构造函数不应该导致任何问题。让我困惑的是安装4.6改变了4.5.1的行为。但我猜这可能随时发生在Windows更新中,这只是我们需要注意的事情。 - demoncodemonkey
@demoncodemonkey,我知道已经有一段时间了,这个问题给你带来了什么困扰吗? - Brent Schmaltz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接