【问题标题】:Dependency injection for a visual studio add-inVisual Studio 插件的依赖注入
【发布时间】:2016-01-27 11:19:22
【问题描述】:

我正在开发一个 Visual Studio 加载项,该加载项在您的项目中接受 SQL 查询、播放请求并为结果生成一个 C# 包装类。我想做一个最简单的依赖注入,其中使用我的加载项的项目提供一个可以提供项目的数据库连接字符串等的类。

这个接口是在我的插件中定义的...

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

问题是:如何定义和实例化具体实现,然后从插件中使用它?

进展?

上面的接口是在插件中定义的。我在目标项目中创建了对加载项的引用,编写了具体的实现,并将这个类的名称放在目标项目的 web.config 中。现在我需要从加载项加载目标项目以使用我的具体类。

如果我使用 Assembly.Load()...

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

我可以成功加载我的类,但是我锁定了目标程序集,无法再编译目标项目。

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。 "无法将透明代理转换为 QueryFirst.IQueryFirst_TargetProject"

这让我觉得我很亲密?为什么使用 Assembly.Load() 显式转换可以正常工作,但在新创建的 AppDomain 中加载相同的程序集时会失败?

【问题讨论】:

    标签: c# visual-studio visual-studio-addins


    【解决方案1】:

    我假设您的加载项将以某种方式被触发,以便开始使用 SQL 查询。

    我建议您将一个单独的 .exe 文件与您的加载项捆绑在一起,然后在其中进行处理。

    原因如下:

    1. 就我个人而言,AppDomain 有很多问题,类似于您遇到的文件锁定问题和临时域的头痛问题。您可能会遇到的另一个问题是,一旦将程序集加载到 AppDomain 中,就无法卸载。通过使用单独的进程(在完成时终止),您不必担心问题。
    2. 根据您要支持的项目类型,这些项目将具有依赖关系。如果您可以将独立 .exe 指向一个目录(即 bin 目录),管理对依赖 dll 的引用会容易得多。
    3. 如果您连接到 Visual Studio 的 Build Events (DTE.Events.BuildEvents.OnBuildBegin),您可以终止您的进程并释放对 dll 文件的锁定。或者您可以让您的流程先进行复制。
    4. 使用独立文件进行测试/调试要容易得多。您无需担心尝试通过附加到 Visual Studio (How to debug a Vsix project) 进行调试。

    您可以使用以下方法来启动/终止进程:

    我认为您可以通过引用 Anatomy of a VSIX Package 直接从 VSIX 插件项目中引用控制台项目的输出。否则,您可能需要执行一些自定义 MSBuild 才能将 .exe 包含在 VSIX 文件中。

    一旦包含在内,您就可以找到 .exe,因为它应该与您执行的 VSIX (Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) 位于同一路径中,我会将路径传递给已加载项目的 bin 目录。


    顺便说一句,这不是Dependency Injection。如果你想在 VS 扩展中使用 DI,你可以使用任何你喜欢的框架,但我认为 MEF 是原生支持的。就个人而言,我更喜欢Ninject。在Package 类中定义您的Kernel,并使用它来加载您的顶级类。

    【讨论】:

    • 我的加载项在 DocumentSaved 事件上执行其业务。我真的很喜欢单独的 exe 想法。我需要 EnvDTE 来处理某些事情,但处理 sql 并吐出 .cs 可能是一个独立的任务,只需在命令行上传递一个文件名即可启动。 When I see the maze you walk into with app domains,如果可以的话,我很乐意将此留给其他人。
    猜你喜欢
    • 1970-01-01
    • 2014-04-03
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    相关资源
    最近更新 更多