visual studio 加载项的依赖注入
Dependency injection for a visual studio add-in
我正在开发一个 visual studio 加载项,它在您的项目中接受 SQL 查询,播放请求并为结果生成一个 C# 包装器 class。我想做一个尽可能简单的依赖注入,其中使用我的加载项的项目提供一个 class,它可以提供项目的数据库连接字符串,等等。
这个接口在我的加载项中定义...
[Serializable]
public interface IDesignTimeQueryProcessing
{
public string ConnectionString { get; }
...
}
还有问题:如何定义和实例化具体实现,然后从加载项中使用它?
有进展吗?
上面的接口是在加载项中定义的。我已经在目标项目中创建了对加载项的引用,编写了具体实现,并将这个class的名称放在了目标项目web.config中。现在我需要从加载项加载目标项目以使用我的具体 class.
如果我使用 Assembly.Load()...
var userAssembly = Assembly.LoadFrom(GetAssemblyPath(userProject));
IQueryFirst_TargetProject iqftp = (IQueryFirst_TargetProject)Activator.CreateInstance(userAssembly.GetType(typeName.Value));
我可以成功加载我的 class,但是我锁定了目标程序集,无法再编译目标项目。
If I create a temporary app domain...
AppDomain ad = AppDomain.CreateDomain("tmpDomain", null, new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(targetAssembly) });
byte[] assemblyBytes = File.ReadAllBytes(targetAssembly);
var userAssembly = ad.Load(assemblyBytes);
我在调用 ad.Load() 时遇到找不到文件的异常,即使我的 dll 的字节在内存中也是如此。
如果我使用 CreateInstanceFromAndUnwrap()...
AppDomain ad = AppDomain.CreateDomain("tmpDomain", null, new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(targetAssembly) });
IQueryFirst_TargetProject iqftp = (IQueryFirst_TargetProject)ad.CreateInstanceFromAndUnwrap(targetAssembly, typeName.Value);
我得到一个
InvalidCastException. "Unable to cast transparent proxy to type QueryFirst.IQueryFirst_TargetProject"
这让我觉得我很亲近?为什么显式转换在 Assembly.Load() 中可以正常工作,但在新创建的 AppDomain 中加载相同的程序集时会失败?
我假设您的 add-in 将以某种方式被触发,以便开始使用 SQL 查询。
我建议您将一个单独的 .exe 文件与您的 add-in 捆绑在一起,然后在其中进行处理。
原因如下:
- 就我个人而言,我遇到过很多关于 AppDomains 的问题,这些问题与您 运行 遇到的文件锁定和临时域的头痛问题类似。您可能 运行 遇到的另一个问题是,一旦将程序集加载到 AppDomain 中,就无法卸载。通过使用一个单独的进程(它在完成时死亡)你不必担心这个问题。
- 根据您要支持的项目类型,这些项目将具有依赖性。如果您可以将独立的 .exe 指向一个目录(即 bin 目录),那么管理对相关 dll 的引用将会容易得多。
- 如果挂接到 Visual Studio 的 Build Events (
DTE.Events.BuildEvents.OnBuildBegin
),您可以终止进程并释放对 dll 文件的锁定。或者您可以让您的流程先制作副本。
- Testing/debugging 使用独立文件要容易得多。您无需担心通过附加到 Visual Studio (How to debug a Vsix project).
来尝试调试
您可以使用以下方法start/kill处理:
我认为您可以通过参考 Anatomy of a VSIX Package 直接从您的 VSIX 加载项项目中引用控制台项目的输出。否则,您可能需要执行一些自定义 MSBuild 操作才能将 .exe 包含在 VSIX 文件中。
包含后,您可以找到 .exe,因为它应该与您正在执行的 VSIX (Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location
) 在同一路径中,我会将它传递给已加载项目的 bin 目录的路径。
顺便说一句,这不是 Dependency Injection. If you want to use DI inside a VS Extension, you can use whatever framework you'd like, but I think MEF is natively supported. Personally, I prefer Ninject。在 Package
class 中定义你的 Kernel
并用它来加载你的顶层 class.
我正在开发一个 visual studio 加载项,它在您的项目中接受 SQL 查询,播放请求并为结果生成一个 C# 包装器 class。我想做一个尽可能简单的依赖注入,其中使用我的加载项的项目提供一个 class,它可以提供项目的数据库连接字符串,等等。
这个接口在我的加载项中定义...
[Serializable]
public interface IDesignTimeQueryProcessing
{
public string ConnectionString { get; }
...
}
还有问题:如何定义和实例化具体实现,然后从加载项中使用它?
有进展吗?
上面的接口是在加载项中定义的。我已经在目标项目中创建了对加载项的引用,编写了具体实现,并将这个class的名称放在了目标项目web.config中。现在我需要从加载项加载目标项目以使用我的具体 class.
如果我使用 Assembly.Load()...
var userAssembly = Assembly.LoadFrom(GetAssemblyPath(userProject));
IQueryFirst_TargetProject iqftp = (IQueryFirst_TargetProject)Activator.CreateInstance(userAssembly.GetType(typeName.Value));
我可以成功加载我的 class,但是我锁定了目标程序集,无法再编译目标项目。
If I create a temporary app domain...
AppDomain ad = AppDomain.CreateDomain("tmpDomain", null, new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(targetAssembly) });
byte[] assemblyBytes = File.ReadAllBytes(targetAssembly);
var userAssembly = ad.Load(assemblyBytes);
我在调用 ad.Load() 时遇到找不到文件的异常,即使我的 dll 的字节在内存中也是如此。
如果我使用 CreateInstanceFromAndUnwrap()...
AppDomain ad = AppDomain.CreateDomain("tmpDomain", null, new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(targetAssembly) });
IQueryFirst_TargetProject iqftp = (IQueryFirst_TargetProject)ad.CreateInstanceFromAndUnwrap(targetAssembly, typeName.Value);
我得到一个
InvalidCastException. "Unable to cast transparent proxy to type QueryFirst.IQueryFirst_TargetProject"
这让我觉得我很亲近?为什么显式转换在 Assembly.Load() 中可以正常工作,但在新创建的 AppDomain 中加载相同的程序集时会失败?
我假设您的 add-in 将以某种方式被触发,以便开始使用 SQL 查询。
我建议您将一个单独的 .exe 文件与您的 add-in 捆绑在一起,然后在其中进行处理。
原因如下:
- 就我个人而言,我遇到过很多关于 AppDomains 的问题,这些问题与您 运行 遇到的文件锁定和临时域的头痛问题类似。您可能 运行 遇到的另一个问题是,一旦将程序集加载到 AppDomain 中,就无法卸载。通过使用一个单独的进程(它在完成时死亡)你不必担心这个问题。
- 根据您要支持的项目类型,这些项目将具有依赖性。如果您可以将独立的 .exe 指向一个目录(即 bin 目录),那么管理对相关 dll 的引用将会容易得多。
- 如果挂接到 Visual Studio 的 Build Events (
DTE.Events.BuildEvents.OnBuildBegin
),您可以终止进程并释放对 dll 文件的锁定。或者您可以让您的流程先制作副本。 - Testing/debugging 使用独立文件要容易得多。您无需担心通过附加到 Visual Studio (How to debug a Vsix project). 来尝试调试
您可以使用以下方法start/kill处理:
我认为您可以通过参考 Anatomy of a VSIX Package 直接从您的 VSIX 加载项项目中引用控制台项目的输出。否则,您可能需要执行一些自定义 MSBuild 操作才能将 .exe 包含在 VSIX 文件中。
包含后,您可以找到 .exe,因为它应该与您正在执行的 VSIX (Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location
) 在同一路径中,我会将它传递给已加载项目的 bin 目录的路径。
顺便说一句,这不是 Dependency Injection. If you want to use DI inside a VS Extension, you can use whatever framework you'd like, but I think MEF is natively supported. Personally, I prefer Ninject。在 Package
class 中定义你的 Kernel
并用它来加载你的顶层 class.