program tip

Castle DynamicProxy-GTR로 사용되는 GTP와 관련된 프록시를 만들 때 실패

radiobox 2020. 11. 9. 08:00
반응형

Castle DynamicProxy-GTR로 사용되는 GTP와 관련된 프록시를 만들 때 실패


좋아, 이제 정말 혼란스러워.

저는 원래이 문제 가있었습니다. 포스터에 따르면 최신 Rhino.Mocks 라이브러리에 ILMerge 된 Castle.DynamicProxy 버전의 문제입니다. 주제에 대한 여러 당국에 따르면 최신 Castle에서 수정되었지만 해당 라이브러리는 새로운 Rhino.Mocks로 만들지 않았습니다. 대부분의 사람들은 "Rhino 소스와 최신 Castle을 다운로드하고 자신 만의 버전을 만드세요"라고 말합니다.

그래서 저는 정확히 그렇게했습니다. Ayende의 GitHub에서 Rhino 트렁크 소스의 ZIP을 가져 와서 열고 빌드했습니다. 그런 다음 좋은 작은 TDDer처럼 변경 사항이 작동하는지 확인하기 위해 단위 테스트를 만들었습니다 (최신 Castle은 DynamicProxy를 Core로 접어 몇 가지 중요한 참조 변경이 필요하기 때문입니다).

    [Test]
    public void MockOfInterfaceMethodWithInterfaceGTR()
    {
        var mock = mocks.DynamicMock<ITestRestrictedInterface>();
        Assert.NotNull(mock);
        Expect.Call(mock.TestMethod(new Object2())).IgnoreArguments().Return(5);
        mocks.ReplayAll();
        Assert.AreEqual(5, mock.TestMethod(new Object2()));
    }

...

internal interface ITestGenericInterface<TRest> where TRest:IObject1
{
    int TestMethod<T>(T input) where T : TRest;
}

internal interface ITestRestrictedInterface:ITestGenericInterface<IObject2> { }

internal interface IObject1 { }
internal interface IObject2:IObject1 { }

internal class Object2:IObject2 { } 

그 결과, 최근에 출시 된 Rhino를 사용하여 내 프로덕션 코드로 실행할 때? 다음 메시지와 함께 실패 :

System.TypeLoadException : 'DynamicProxyGenAssembly2, Version = 0.0.0.0, Culture = neutral, PublicKeyToken = null'어셈블리의 'ITestRestrictedInterfaceProxy83ad369cdf41472c857f61561d434436'형식에 대한 'TestMethod'메서드가 더 약한 형식 매개 변수 제약 조건을 사용하여 암시 적으로 인터페이스 메서드를 구현하려고했습니다.

...하지만이 테스트를 복사하여 Rhino.Mocks.Tests 프로젝트의 픽스쳐에 붙여 넣으면 참조 된 라이브러리를 변경하지 않고 테스트가 통과됩니다. 다운로드 한 소스를 전혀 변경하지 않았습니다. 테스트 방법 및 관련 인터페이스 / 개체를 양쪽에서 ZERO 변경했습니다. 새로운 Rhino.Mocks DLL을 빌드하고 (Castle 라이브러리를 IL 병합하지 않고) Castle 라이브러리와 함께 내 프로덕션 솔루션으로 다시 복사하고 테스트를 다시 실행했지만 여전히 동일한 메시지와 함께 실패합니다.

WTF?


저는 Castle 전문가 나 컴파일러 전문가는 아니지만이 문제는 RhinoMocks.Tests 어셈블리 내부에 숨겨져있는 약간의 마법이라고 생각합니다.

에서 https://github.com/ayende/rhino-mocks/blob/master/Rhino.Mocks.Tests/TestInfo.cs

using System.Runtime.CompilerServices;
using Rhino.Mocks;

[assembly: InternalsVisibleTo(RhinoMocks.StrongName)]

완전성을 위해 RhinoMocks.StrongName은 다음과 같이 정의됩니다.

/// <summary>
/// Used for [assembly: InternalsVisibleTo(RhinoMocks.StrongName)]
/// Used for [assembly: InternalsVisibleTo(RhinoMocks.NormalName)]
/// </summary>
public static class RhinoMocks
{
    /// <summary>
    /// Strong name for the Dynamic Proxy assemblies. Used for InternalsVisibleTo specification.
    /// </summary>
    public const string StrongName =
        "DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7";

    /// <summary>
    /// Normal name for dynamic proxy assemblies. Used for InternalsVisibleTo specification.
    /// </summary>
    public const string NormalName = "DynamicProxyGenAssembly2";

    /// <summary>
    /// Logs all method calls for methods
    /// </summary>
    public static IExpectationLogger Logger = new NullLogger();
}

I've seen a similar issue when using Moq, which has this issue documented.

The problem is that DynamicProxy in Castle needs to dynamically derive a new type but does not have visibility to see your interface which is internal to your assembly. Simply adding the InternalsVisibleTo to the DynamicProxyGenAssembly2 to your test library should solve the problem.

참고URL : https://stackoverflow.com/questions/9186087/castle-dynamicproxy-failure-when-creating-proxy-involving-a-gtp-used-as-a-gtr

반응형