Visual Studio Add-In Injection

I am working on a visual studio add-in that accepts SQL queries in your project, plays the query, and generates a C # wrapper class for the results. I want to make the simplest possible dependency injection, where projects using my add-in provide a class that can provide a db project connection string, among other things.

This interface is defined in my add-in ...

[Serializable] public interface IDesignTimeQueryProcessing { public string ConnectionString { get; } ... } 

And the question is: how to define and instantiate a specific implementation, and then use it from the add-in?

Progress?

The interface above is defined in the add-in. I created a link in the target project on the add-in, wrote a specific implementation and put the name of this class in the target web.config project. Now I need to load the target project from the add-in in order to use my specific class.

If I use Assembly.Load () ...

 var userAssembly = Assembly.LoadFrom(GetAssemblyPath(userProject)); IQueryFirst_TargetProject iqftp = (IQueryFirst_TargetProject)Activator.CreateInstance(userAssembly.GetType(typeName.Value)); 

I can successfully load my class, but I am blocking the target assembly and can no longer compile the target project.

If I create a temporary application domain ...

 AppDomain ad = AppDomain.CreateDomain("tmpDomain", null, new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(targetAssembly) }); byte[] assemblyBytes = File.ReadAllBytes(targetAssembly); var userAssembly = ad.Load(assemblyBytes); 

I get an exception not found in the ad.Load () declaration, even if the bytes of my dll are in memory.

If I use CreateInstanceFromAndUnwrap () ...

 AppDomain ad = AppDomain.CreateDomain("tmpDomain", null, new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(targetAssembly) }); IQueryFirst_TargetProject iqftp = (IQueryFirst_TargetProject)ad.CreateInstanceFromAndUnwrap(targetAssembly, typeName.Value); 

I get

InvalidCastException. "Cannot pass transparent proxy for input QueryFirst.IQueryFirst_TargetProject"

Does it make me think I'm very close? Why does explicit listing work fine with Assembly.Load () but fail when the same assembly is loaded into a newly created AppDomain?

+5
source share
1 answer

I assume that your add-in will start in some way to get started with SQL queries.

I would recommend that you link a separate .exe file to the add-in and do the processing there.

That's why:

  • Personally, I had a lot of problems with AppDomains, similar to what you are working with, file locking and Temp Domains headache. Another problem that you are likely to encounter is when you load an assembly into AppDomain, you cannot unload it. Using a separate process (which dies when it is finished), you do not need to worry about the problem.
  • Depending on the type of projects you want to support, these projects will have dependencies. Managing links to dependent dlls will be much easier if you can just specify your standalone .exe in the directory (i.e. in the bin directory).
  • If you connect to Visual Studio Build Events ( DTE.Events.BuildEvents.OnBuildBegin ), you can kill your process and release locks in the dll files. Or you could make your process first by making copies.
  • Testing / debugging is much easier with a standalone file. You do not need to worry about trying to debug by connecting to Visual Studio ( How to debug a Vsix project ).

You can use the following methods to start / kill processes:

I think that you can reference the console project output directly from the VSIX Add In project through the Anatomy of the VSIX package links . Otherwise, you may need to run some custom MSBuild to get the .exe included in the VSIX file.

After inclusion, you can find the .exe file because it must match your executable VSIX ( Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location ), and I will give it the path to the loaded bin directory of the project.


As an aside, this is not Injection Dependency . If you want to use DI inside the VS extension, you can use any infrastructure you want, but I think MEF is supported. Personally, I prefer Ninject . Define your Kernel inside the Package class and use it to load the top-level class.

0
source

Source: https://habr.com/ru/post/1241593/


All Articles