Category Archives: .net

Roslyn analyzer with external references

I was creating a Roslyn powered analyzer to detect proper usage of WinForms components that are not added to a form through designer. When you add control through designer it is properly disposed when the form itself is disposed. The designer also adds field components of type System.ComponentModel.IContainer that is disposed in Dispose method:

protected override void Dispose(bool disposing)
{
  if (disposing && (components != null))
  {
    components.Dispose();
  }
  base.Dispose(disposing);
} 

But if you create, for example a timer, manually, you will have to dispose it manually later. Instead of handling the disposal of that timer this way, it is easier to add it to that container where it will be disposed along with all other controls.

The analyzer worked fine when a new instance of VS.NET was triggered and the debugger was actually debugging the code running in that instance. But this process is somewhat slow and you spend some time waiting for the new instance of VS.NET to be open.

When you create new Roslyn analyzer project using the project template, a test project is created as well with ready-to-run code. Because it is much easier to do it TDD way, I created new test based on the test classes already available. But my tests were failing.

I quickly discovered the problem – in the analyzer code, there is some type checking when I do not want to carry on with the analysis when the class being analyzed is not inherited from System.Windows.Forms class:

var formType = context.SemanticModel.Compilation.GetTypeByMetadataName("System.Windows.Forms.Form");

and the reason the test was failing was that formType is null and that’s because there is no metadata available when the test is executed. But it does not fail in the second instance of VS.NET, because the project is fully loaded with all references there.

So I went straight to Roslyn GitHub repository and searched for mscorlib, System.Linq, etc. and found out that the tests there are adding references through properties like this one:

private static MetadataReference s_systemWindowsFormsRef;
public static MetadataReference SystemWindowsFormsRef
{
  get
  {
    if (s_systemWindowsFormsRef == null)
    {
      s_systemWindowsFormsRef = AssemblyMetadata.CreateFromImage(TestResources.NetFX.v4_0_30319.System_Windows_Forms).GetReference(display: "System.Windows.Forms.v4_0_30319.dll");
    }

    return s_systemWindowsFormsRef;
  }
}

And the most important code here is AssemblyMetadata.CreateFromImage(TestResources.NetFX.v4_0_30319.System_Windows_Forms) which creates the assembly metadata object for System.Windows.Forms assembly. After cloning the solution I discovered that the TestResources namespace comes from external assembly Microsoft.CodeAnalysis.Test.Resources.Proprietary that was added as a Nuget package.

This library contains assembly metadata images for selected .NET framework versions and assemblies (System, System.Data, System.Drawing, …). Note that the only version of that library available is prerelease version.

What was left was to change the code generated by project template to propagate the references

VerifyCSharpDiagnostic(test, new[]
{
  AssemblyMetadata.CreateFromImage(TestResources.NetFX.v4_0_30319.System_Windows_Forms)
    .GetReference(display: "System.Windows.Forms.v4_0_30319.dll"),
  AssemblyMetadata.CreateFromImage(TestResources.NetFX.v4_0_30319.System)
    .GetReference(display: "System.v4_0_30319.dll")
}, expected); 

deeper to where the Compilation is created and change the code there:

var compilation = CSharpCompilation.Create(
   "MyName",
   documents.Select(d => d.GetSyntaxTreeAsync().Result),
   references, // there are those references
   new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug));
// and pass the analyzer 
var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer));

And then my unit tests worked! I recommend you to check the unit testing part of Roslyn project for some guidelines on how to test the analyzers and also how to write reusable test components (and rewrite is something my code needs right now).

NInject problem with remote proxies

I have run into following issue while working with NInject:

System.TypeInitializationException: The type initializer for 'ClassA' threw an exception. --->    
System.Runtime.Remoting.RemotingException: Attempted to call a method declared on type 'Ninject.IInitializable' on an object which exposes 'ClassB'.
Server stack trace:
  at System.Runtime.Remoting.Messaging.StackBuilderSink.VerifyIsOkToCallMethod(Object server, IMethodMessage msg)
  at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msg)

Exception rethrown at [0]: 
  at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
  at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
  at Ninject.IInitializable.Initialize()
  at Ninject.Activation.Strategies.InitializableStrategy.b__0(IInitializable x) in InitializableStrategy.cs:line 28

The problem is that NInject tries to call Ninject.IInitializable.Initialize() on remoting proxy (ClassB) and that fails since that class does not implement that interface. This call is made by one of the activation strategies in the pipeline.

The workaround is (inspired by Ydie’s blog post) to create new kernel class derived StandardKernel, remove all instances of IActivationStrategy from Components collection, return some of the default strategies back and add my own strategy that does not try to invoke Initialize method when the object being activated is instance of MarshalByRef class.

I don’t have any class implementing IStartable interface, so I’m not re-adding the StartableStrategy, but for complete fix that strategy should also be modified. Or the pipeline can be changed to completely ignore remoting proxies …

public class MyStandardKernel : StandardKernel
{
    protected override void AddComponents()
    {
        base.AddComponents();
        // remove the all activation strategies
        Components.RemoveAll(typeof(IActivationStrategy));
        // add some of the default strategies back (code copied from NInject sources)
        if(!Settings.ActivationCacheDisabled)
        {
            Components.Add<IActivationStrategy, ActivationCacheStrategy>();
        }

        Components.Add<IActivationStrategy, PropertyInjectionStrategy>();
        Components.Add<IActivationStrategy, MethodInjectionStrategy>();
        // I don't need this
        // Components.Add<IActivationStrategy, StartableStrategy>();
        Components.Add<IActivationStrategy, BindingActionStrategy>();
        Components.Add<IActivationStrategy, DisposableStrategy>();
        // this is the new strategy
        Components.Add<IActivationStrategy, RemotingProxyAwareStrategy>();
    }
}

public class RemotingProxyAwareInitializableStrategy : ActivationStrategy
{
    /// <summary>
    /// Initializes the specified instance.
    /// </summary>
    /// <param name="context">The context.
    /// <param name="reference">A reference to the instance being activated.
    public override void Activate(IContext context, InstanceReference reference)
    {
        if(reference.Is<MarshalByRefObject>()) 
        {
            return;
        }

        reference.IfInstanceIs<IInitializable>(x => x.Initialize());
    }
}

NInject modularity let’s you to replace different core components and that’s really great. I’m looking forward to another problem 🙂