【问题标题】:How do you get the solution directory in C# (VS 2008) in code?如何在代码中获取 C#(VS 2008)中的解决方案目录?
【发布时间】:2010-06-16 22:56:45
【问题描述】:

这里有一个烦人的问题。我有一个通过 SVN 工作的 NHibernate/Forms 应用程序。我制作了一些我自己的控件,但是当我将这些(或查看我已经拖放的一些表单编辑器)拖放到我的其他一些控件上时,Visual Studio 决定它需要执行我编写的一些代码,包括查找 hibernate.cfg.xml 的部分。

我不知道为什么会这样,但是(有时!)当它在我的表单加载或拖放期间执行代码时,它会将当前目录切换到 C:\program files\vs 9.0\common7\ide,然后nhibernate 抛出一个找不到 hibernate.cfg.xml 的异常,因为我是在相对路径中搜索的。

现在,我不想硬编码 hibernate.cfg.xml 的位置,或者只是将 hibernate.cfg.xml 复制到 ide 目录(这将起作用)。我想要一个在当前目录为 common7\ide 时获取解决方案目录的解决方案。可以让某人在设计器中查看我的表单,以便在任意机器上的任意目录中重新结帐。不,我不打算在代码中加载控件。我在控件中有这么多控件,如果没有它,将所有东西都排列起来简直是一场噩梦。

我尝试了一个预构建事件,该事件生成了一个包含解决方案目录的文件,但是我当然如何从 common7\ide 中找到它?由于svn,所有项目文件都需要在解决方案目录中。

感谢你们的帮助,我已经花了几个小时徒劳地摆弄这个。

更新:我将 hibernate.cfg 设置为嵌入式资源。对于每个配置,我只是简单地创建一个新的构建配置、调试、发布、XYZ。在大多数情况下,我建议您嵌入运行程序所依赖的任何文件。它使构建安装程序变得更加简单。

【问题讨论】:

  • 你在VS的时候能把hbm的配置放到App.config里吗?
  • 我不知道,如果我将 xml 文件放入 xml 文件中,xml 解析器是否能够找到所有标签?

标签: c# visual-studio winforms nhibernate


【解决方案1】:

这可能来得有点晚,但我在http://www.tek-tips.com/viewthread.cfm?qid=1226891&page=164 找到了解决方案。由于我使用的是 Visual Studio 2010,因此我做了一些小改动。您必须参考EnvDTE和EnvDTE100(VS2008的EnvDTE90),

string solutionDirectory = ((EnvDTE.DTE)System.Runtime
                                              .InteropServices
                                              .Marshal
                                              .GetActiveObject("VisualStudio.DTE.10.0"))
                                   .Solution
                                   .FullName;
solutionDirectory = System.IO.Path.GetDirectoryName(solutionDirectory);

当然我用的是VisualStudio.DTE.10.0,你应该用VisualStudio.DTE.9.0。

祝你好运!

【讨论】:

  • 这确实找到了解决方案目录,但我的问题更具体一些。在加载表单设计器期间的某个时间,当前目录更改为 program files\common7\ide。我需要在这段时间内找到原始解决方案目录的代码,而这段代码不这样做。不过,它确实可以工作!
  • 是否可以在进入表单设计器之前将此解决方案目录设置在静态变量中?应用程序加载 -> 设置目录 -> 表单设计器 -> 从静态变量中提取。或者这会不会太过分了?
  • 哦,我没有想到这个!我不确定它是否会在 common7/ide 之前进入常规解决方案目录,但如果确实如此,那么这将不是一个 hack,而是一个解决方案!我会检查一下。跨度>
  • 在 VS2013 中也可以使用,只需将上面类似的行更改为。 .GetActiveObject("VisualStudio.DTE.12.0");
  • 我发现的一个问题是你不能指望它在打开多个 Visual Studio 实例的情况下工作(使用不同的解决方案)
【解决方案2】:

我终于想通了。这适用于任何 Visual Studio 版本,不依赖于 EnvDTE,并解决了此处提出的原始问题。

  1. 在您的项目设置中,在“构建事件”下,添加以下“预构建事件命令行”:

    echo $(SolutionDir) > ..\..\solutionpath.txt
    
  2. 构建项目一次。该文件将在您的项目根目录中创建。

  3. 在解决方案资源管理器中,单击“显示所有文件”和“刷新”

  4. 将 solutionpath.txt 添加到您的解决方案中

  5. 右键单击 solutionpath.txt,单击属性。将构建操作更改为“嵌入式资源”

  6. 使用以下代码获取您的解决方案路径。

        string assemblyname = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
        string path = "";
        using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(assemblyname + ".solutionpath.txt"))
        {
            using (var sr = new StreamReader(stream))
            {
                path = sr.ReadToEnd().Trim();
            }
        }
    

因为这是一个预构建事件,所以文件在构建开始之前不需要存在,因此它与源代码控制兼容并且没有任何明显的问题。

【讨论】:

  • 它有效:只有我的 50 个硬币:echo $(SolutionDir) > $(ProjectDir)\solutionpath.txtstring assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name
  • 好把戏。我实际上用它来输出一个部分类,其中有一个保持这个路径的常量。这是在测试套件中运行 IIS express,您需要知道 applicationHost.config 文件的路径,该文件位于解决方案目录中。
  • @naasking 谢谢,我自己偶尔也会使用这个技巧。
【解决方案3】:

更新:不幸的是,我不知道如何在设计时获取您的解决方案文件夹。所以,从技术上讲,我不是在回答你的问题,只是提供一个潜在的解决方法。

您可以检查您的控件是否在DesignMode 中,如果是,您可以使用Assembly.GetExecutingAssembly() 为您的控件获取Assembly 并确定它的加载位置。

请注意,DesignTime 属性值有一些注意事项,即如果您设计您的控件或如果您正在设计一个包含您的控件的表单,它将正确返回 true,但如果您正在设计一个表单包含一个包含您的控件的控件,它将返回 false。

因此,您可能希望跳过整个 DesignTime 检查并始终在程序集的基本路径中查找 NHibernate 配置,如果您查找该配置文件的标准方法失败。

【讨论】:

  • 'C:\Users\Administrator\AppData\Local\Microsoft\VisualStudio\9.0\ProjectAssemblies\raa4j4oa01\dllname.dll' 这是我从 Assembly.Location 得到的,除非有组装方法得到原始的dll位置?你知道一个吗?
  • 啊。因此 VS 使用您的控件创建一个临时程序集。 :-( 不幸的是,我不确定如何解决这个特定问题。
  • 感谢您的帮助!感谢您抽出宝贵时间。
【解决方案4】:

听起来你只需要编写一个更好的配置文件路径。

如果你这样做:

configPath =  Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "\\PathToCFG");

当 Windows 更改你的当前目录时,你不应该搞砸。

编辑:您可能遇到了 Visual Studio 托管进程的问题。你能禁用这个吗?项目属性\调试下有一个复选框。

【讨论】:

  • 这不起作用,它只是给了我 C:\program files\vs9\common7\ide\PathToCFG 我也从 NHibernate 常见问题解答中尝试过。
  • 我添加了一个提示来禁用托管进程。也许这将为您提供解决方法?
  • 这个答案对我来说很棒,因为我需要获取项目基目录中的目录路径!只是将相对路径与基目录结合起来!而且效果很好!!!谢谢!
【解决方案5】:

我最终嵌入了配置文件。由于程序自动更新独立于配置文件,我可以放弃向用户公开它。

【讨论】:

  • +1 因为在这种特定情况下(但不是我的情况),嵌入配置文件将是一个更简单的解决方案
【解决方案6】:

我来晚了,我不知道这是否适用于 VS2008,但对于 VS2015,我能想到的最简单的事情就是创建一个 t4 模板。内容如下:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".generated.cs" #>
namespace MyNamespace
{
    public static class BuildVariables
    {
        public static readonly string SolutionDir = <#= QuotedString(Host.ResolveAssemblyReference(@"$(SolutionDir)")) #>;
    }
}
<#+
public string QuotedString(string value)
{
    if (value == null)
    {
        return "null";
    }

    return "@\"" + value.Replace("\"", "\"\"") + "\"";
}
#>

这会生成一个完全符合需要的类。我对此提出的两个警告是确保从版本控制中忽略它,并注意是否将解决方案复制到其他地方。不幸的是,在 2018 年构建 t4 模板作为自动化构建过程的一部分仍然是一个复杂的问题。

【讨论】:

  • 这对我来说效果最好,因为当我们的 CI 服务器构建单元测试而不是本地构建时,我需要将 solutiondir 更改为正确的值。
  • 这在 VS2019 中对我有用。我需要它是因为我的单元测试运行者有不同的目录。非常酷的技术。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多