Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected System.__Canon with reflection

Tags:

c#

.net

clr

Breakdown
"System.Reflection.TargetException: Object does not match target type." when calling MethodBase.Invoke within a derivate of RealProxy. Problem appeared suddenly and without any apparent reason in the svn commit logs or the server event logs.

Scenario
Windows Server 2008 R2 Standard, 64 bit
Microsoft .NET Framework Version: 2.0.50727.4927
ASP.NET Version: 2.0.50727.4927
IIS application pool running in integrated pipeline mode.
.NET Framework 4.0 is NOT installed.

These are some compressed samples to show the code flow where this problem occurs. I've removed alot of logging, contracts, etc, just to keep the code short for this post.

// Interface structure
ICommentRepository : IRepository<Comment>  
IRepository<T> : IRepositoryWithTypedId<T, Guid>  
IRepositoryWithTypedId<T, TId>
    void Delete(T item);

// Extract from ServicesProvider which instantiates the proxies.
public class ServicesProvider {
    public T GetService<T>() where T : class {
        var proxy = WcfProxyFactory<T>.OpenChannel();
        proxy = ApplyLoggingProxy(proxy);
        return proxy;
    }

    private static T ApplyLoggingProxy<T>(T instance) where T : class {
        return (T)new LoggingProxy<T>(instance).GetTransparentProxy();
    }
}

public class LoggingProxy<T> : ProxyBase<T> where T : class {
    public LoggingProxy(T instance)
        : base(instance) {
    }

    protected override IMethodReturnMessage InvokeMethodCall(IMethodCallMessage msg) {
        var methodName = String.Format("{0}.{1}", InstanceType.Name, msg.MethodName);
        // methodName = "ICommentRepository.Delete"

        var methodCall = ReflectionHelper.GetMethodCall(msg);
        // methodCall = "IRepositoryWithTypedId<__Canon, Guid>.Delete(...)"

        Trace.WriteCategory(methodName, "Calling {0}", methodCall);

        return base.InvokeMethodCall(msg);
    }
}

public abstract class ProxyBase<T> : RealProxy where T : class {
    protected static readonly Type InstanceType = typeof(T);
    protected readonly T Instance;
    protected readonly ITraceWriter Trace = new HttpContextTraceWriter();

    protected ProxyBase(T instance) {
        Instance = instance;
    }

    public override IMessage Invoke([NotNull] IMessage msg) {
        var methodCallMessage = msg as IMethodCallMessage;
        if (methodCallMessage != null)
            return InvokeMethodCall(methodCallMessage);

        throw new NotImplementedException("Unknown message type");
    }

    protected virtual IMethodReturnMessage InvokeMethodCall([NotNull] IMethodCallMessage msg) {
        var args = msg.Args;
        var result = msg.MethodBase.Invoke(Instance, args);
        return new ReturnMessage(result, args, msg.ArgCount, msg.LogicalCallContext, msg);
    }
}

// Line causing the error.
servicesProvider.GetService<ICommentRepository>().Delete(...);

Highlights
I've added some debugging into the LoggingProxy.InvokeMethodCall, specifically writing out all properties of msg.Method (declared as MethodBase, is RuntimeMethodInfo) and msg.Method.DeclaringType. I'll provide some odd highlights.

  • method.Attributes = (PrivateScope | Public | Virtual | HideBySig | VtableLayoutMask | Abstract), PrivateScope means "Indicates that the member cannot be referenced." I am pretty sure that I have a reference to it. ;)
  • method.DeclaringType = "IRepositoryWithTypedId`2[System.__Canon,System.Guid]"
  • method.ReflectedType = "IRepositoryWithTypedId`2[System.__Canon,System.Guid]"
  • type.FullName = "IRepositoryWithTypedId`2[[System.__Canon, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
  • type.UnderlyingSystemType = "IRepositoryWithTypedId`2[System.__Canon,System.Guid]"
  • type.GenericArguments[0] = typeof(__Canon)

I have no idea how this occured, and how to solve it. Some google searches provide hints into disabling inlining of methods (MethodImplAttribute), but I am unable to find where to do this. I've placed them at all methods without being able to solve the problem.

Any thoughts or ideas?

like image 391
sisve Avatar asked Jun 24 '10 08:06

sisve


1 Answers

Could the difference be due to Debug vs Release builds? Here's a good read on why this shows up in Release builds and here are the different optimization switches available to you. Sounds like a plausible explanation, especially if the issue doesn't relate back to recent changes.

like image 163
Nariman Avatar answered Oct 26 '22 05:10

Nariman