Vladimir Panchenko
Vladimir Panchenko

Reputation: 1193

Dependency Injection into Roslyn analyzers

I have a custom Roslyn analyzer which inherits from DiagnosticAnalyzer. It is packed in VSIX extension which contains custom Package class. I'd like to pass an instance of a class with the settings (CodeAnalysisSettings instance) from the package to my DiagnosticAnalyzer.

I've tried to use MEF for that purpose. I've registered an instance of my settings class in VS Package using the following code:

protected override void Initialize()
{
    base.Initialize();
    IComponentModel componentModel = Package.GetGlobalService(typeof(SComponentModel)) as IComponentModel;
    new CompositionContainer(componentModel.DefaultCatalog).ComposeExportedValue(
                new CodeAnalysisSettings(...));
}

Analyzer looks as follows:

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class MyAnalyzer : DiagnosticAnalyzer
{
    [Import]
    public CodeAnalysisSettings Settings { get; set; }
}

Settings class:

[Export]
public class CodeAnalysisSettings
{
    public CodeAnalysisSettings()
    {
    }

    public bool RecursiveAnalysisEnabled { get; }
}

For some reason Settings property is not imported - its value is always null.

Please help.

Upvotes: 2

Views: 926

Answers (2)

Zodman
Zodman

Reputation: 3904

The Microsoft VSIX Community Toolkit has a Dependency Injection Nuget package that adds DI to your VSIX extension. It allows you to add your own IOC container or use theirs.

VSIX Community Toolkit Package on GitHub

Upvotes: 1

Vladimir Panchenko
Vladimir Panchenko

Reputation: 1193

I've ended up using a service locator (CommonServiceLocator package) that consumes MEF container as a source.

Since VS infrastructure doesn't allow adding new registrations (IComponentModel.DefaultCatalog throws an exception which tells that this functionality is not supported anymore), I've created a new container inside Package.Initialize():

var container = new CompositionContainer(CompositionOptions.Default, componentModel.DefaultExportProvider);
container.ComposeExportedValue<CodeAnalysisSettings>(new CodeAnalysisSettings(...));
var serviceLocator = new MefServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => serviceLocator);

Roslyn diagnostic consumes this dependency:

var settings = CodeAnalysisSettings.Default;
if (ServiceLocator.IsLocationProviderSet)
    settings = ServiceLocator.GetInstance<CodeAnalysisSettings>();

Upvotes: 1

Related Questions