簡體   English   中英

創建自定義MSBuild任務時如何從C#代碼獲取當前項目目錄?

[英]How do you get the current project directory from C# code when creating a custom MSBuild task?

我不想運行帶有硬編碼路徑的外部程序,而是想獲取當前的項目目錄。 我正在使用自定義任務中的進程調用外部程序。

我該怎么做? AppDomain.CurrentDomain.BaseDirectory 只是給我 VS 2008 的位置。

using System;
using System.IO;

// This will get the current WORKING directory (i.e. \bin\Debug)
string workingDirectory = Environment.CurrentDirectory;
// or: Directory.GetCurrentDirectory() gives the same result

// This will get the current PROJECT bin directory (ie ../bin/)
string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName;

// This will get the current PROJECT directory
string projectDirectory = Directory.GetParent(workingDirectory).Parent.Parent.FullName;

您可以嘗試這兩種方法之一。

string startupPath = System.IO.Directory.GetCurrentDirectory();

string startupPath = Environment.CurrentDirectory;

告訴我,你覺得哪個更好

如果項目在 IIS Express 上運行,則Environment.CurrentDirectory可能指向 IIS Express 所在的位置(默認路徑為C:\Program Files (x86)\IIS Express ),而不是項目所在的位置。


這可能是各種項目最合適的目錄路徑。

AppDomain.CurrentDomain.BaseDirectory

這是 MSDN 的定義。

獲取程序集解析器用於探測程序集的基目錄。

到目前為止,我對所有發布的解決方案的隨意性感到驚訝,簡直目瞪口呆。

獲取 C# 項目的根文件夾的正確方法之一是利用[CallerFilePath]屬性獲取源文件的完整路徑名,然后從中減去文件名和擴展名,留下項目的路徑.

以下是實際操作方法:

在項目的根文件夾中,添加具有以下內容的文件ProjectSourcePath.cs

internal static class ProjectSourcePath
{
    private const  string  myRelativePath = nameof(ProjectSourcePath) + ".cs";
    private static string? lazyValue;
    public  static string  Value => lazyValue ??= calculatePath();

    private static string calculatePath()
    {
        string pathName = GetSourceFilePathName();
        Assert( pathName.EndsWith( myRelativePath, StringComparison.Ordinal ) );
        return pathName.Substring( 0, pathName.Length - myRelativePath.Length );
    }
}

string? 需要帶有#nullable enable的相當晚的 C# 版本; 如果你沒有它,那么只需刪除? .

Assert()函數是我自己的; 如果你喜歡危險地生活,你可以用你自己的代替它,或者省略它。

函數GetSourceFilePathName()定義如下:

using System.Runtime.CompilerServices

    public static string GetSourceFilePathName( [CallerFilePath] string? callerFilePath = null ) //
        => callerFilePath ?? "";

有了以上內容后,您可以按如下方式使用它:

string projectSourcePath = ProjectSourcePath.Value;

1 “正確”如:萬無一失; 萬無一失; 沒有假設; 不被鞋帶綁在一起; 不一定要為某些項目工作,但不能為其他項目工作; 當您更改不相關的內容時,不太可能在沒有警告的情況下可怕地中斷; 等等

這還將通過從當前執行目錄向上導航兩個級別來為您提供項目目錄(這不會為每個構建返回項目目錄,但這是最常見的)。

System.IO.Path.GetFullPath(@"..\..\")

當然,您希望將其包含在某種驗證/錯誤處理邏輯中。

如果你想知道你的解決方案所在的目錄是什么,你需要這樣做:

 var parent = Directory.GetParent(Directory.GetCurrentDirectory()).Parent;
            if (parent != null)
            {
                var directoryInfo = parent.Parent;
                string startDirectory = null;
                if (directoryInfo != null)
                {
                    startDirectory = directoryInfo.FullName;
                }
                if (startDirectory != null)
                { /*Do whatever you want "startDirectory" variable*/}
            }

如果您只使用GetCurrrentDirectory()方法,無論您是在調試還是發布,您都會獲得構建文件夾。 我希望這有幫助! 如果您忘記了驗證,它將是這樣的:

var startDirectory = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName;

根據Gucu112 的回答,但對於 .NET Core Console/Window 應用程序,它應該是:

string projectDir = 
    Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\.."));

我在 .NET Core Window 應用程序的 xUnit 項目中使用它。

這個解決方案對我很有效,在開發服務器上以及通過 C# 使用 ASP.NET MVC5的 TEST 和 PROD 服務器上:

var projectDir = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);

如果您需要項目配置文件中的項目目錄,請使用:

$(ProjectDir)
using System;
using System.IO;

// Get the current directory and make it a DirectoryInfo object.
// Do not use Environment.CurrentDirectory, vistual studio 
// and visual studio code will return different result:
// Visual studio will return @"projectDir\bin\Release\netcoreapp2.0\", yet 
// vs code will return @"projectDir\"
var currentDirectory = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);

// On windows, the current directory is the compiled binary sits,
// so string like @"bin\Release\netcoreapp2.0\" will follow the project directory. 
// Hense, the project directory is the great grand-father of the current directory.
string projectDirectory = currentDirectory.Parent.Parent.Parent.FullName;

我也在找這個。 我有一個運行 HWC 的項目,我想將網站保留在應用程序樹之外,但我不想將其保留在調試(或發布)目錄中。 FWIW,公認的解決方案(以及這個解決方案)僅標識可執行文件正在運行的目錄。

為了找到那個目錄,我一直在使用

string startupPath = System.IO.Path.GetFullPath(".\\").

另一種方法來做到這一點

string startupPath = System.IO.Directory.GetParent(@"./").FullName;

如果要獲取 bin 文件夾的路徑

string startupPath = System.IO.Directory.GetParent(@"../").FullName;

也許有更好的方法=)

另一個不完美的解決方案(但可能比其他一些更接近完美):

    protected static string GetSolutionFSPath() {
        return System.IO.Directory.GetParent(System.IO.Directory.GetCurrentDirectory()).Parent.Parent.FullName;
    }
    protected static string GetProjectFSPath() {
        return String.Format("{0}\\{1}", GetSolutionFSPath(), System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
    }

即使當前項目不是解決方案的Startup Project ,此版本也會返回當前項目的文件夾。

第一個缺陷是我跳過了所有的錯誤檢查。 這可以很容易地解決,但只有當您將項目存儲在驅動器的根目錄中或在路徑中使用結點(並且該結點是解決方案文件夾的后代)時才會出現問題,因此這種情況不太可能出現. 我不完全確定 Visual Studio 是否可以處理這些設置中的任何一個。

您可能遇到的另一個(更有可能)問題是項目名稱必須與項目的文件夾名稱匹配才能找到它。

您可能遇到的另一個問題是項目必須位於解決方案文件夾中。 這通常不是問題,但如果您使用“ Add Existing Project to Solution ”選項將項目添加到解決方案,那么這可能不是您的解決方案的組織方式。

最后,如果您的應用程序將修改工作目錄,您應該在這樣做之前存儲此值,因為此值是相對於當前工作目錄確定的。

當然,這也意味着您不能在項目屬性對話框中更改項目的Build -> Output pathDebug -> Working directory選項的默認值。

試試這個,很簡單

HttpContext.Current.Server.MapPath("~/FolderName/");

如果您真的想確保獲得源項目目錄,則無論 bin 輸出路徑設置為:

  1. 添加預構建事件命令行(Visual Studio:項目屬性 -> 構建事件):

    echo $(MSBuildProjectDirectory) > $(MSBuildProjectDirectory)\Resources\ProjectDirectory.txt

  2. ProjectDirectory.txt文件添加到項目的 Resources.resx 中(如果還不存在,請右鍵單擊項目 -> 添加新項目 -> 資源文件)

  3. 使用Resources.ProjectDirectory從代碼訪問。

我也遇到過類似的情況,在谷歌無果之后,我聲明了一個公共字符串,它修改了調試/發布路徑的字符串值來獲取項目路徑。 使用此方法的一個好處是,由於它使用當前項目的目錄,因此無論您是從調試目錄還是發布目錄工作都無關緊要:

public string DirProject()
{
    string DirDebug = System.IO.Directory.GetCurrentDirectory();
    string DirProject = DirDebug;

    for (int counter_slash = 0; counter_slash < 4; counter_slash++)
    {
        DirProject = DirProject.Substring(0, DirProject.LastIndexOf(@"\"));
    }

    return DirProject;
}

然后,您可以隨時調用它,只需使用一行:

string MyProjectDir = DirProject();

這在大多數情況下應該有效。

使用它來獲取項目目錄(為我工作):

string projectPath = 
    Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;

我使用以下解決方案來完成工作:

string projectDir =
    Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\.."));

嘗試:

var pathRegex = new Regex(@"\\bin(\\x86|\\x64)?\\(Debug|Release)$", RegexOptions.Compiled);
var directory = pathRegex.Replace(Directory.GetCurrentDirectory(), String.Empty);

這是與其他解決方案不同的解決方案,它也考慮了可能的 x86 或 x64 構建。

在我終於完成了關於公共字符串的我們的第一個答案以得出答案之后,我突然意識到您可能可以從注冊表中讀取一個值以獲得您想要的結果。 事實證明,這條路線甚至更短:

首先,您必須包含 Microsoft.Win32 命名空間,以便您可以使用注冊表:

using Microsoft.Win32;    // required for reading and / or writing the registry

這是主要代碼:

RegistryKey Projects_Key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\9.0", false);
string DirProject = (string)Projects_Key.GetValue(@"DefaultNewProjectLocation");

關於這個答案的注釋:

我正在使用 Visual Studio 2008 專業版。 如果您使用的是其他版本(即 2003、2005、2010 等),那么您可能不必修改 SubKey 字符串的“版本”部分(即 8.0、7.0 等)。

如果您使用我的答案之一,並且問的不是太多,那么我想知道您使用了我的哪種方法以及為什么。 祝你好運。

  • 分米
string projPath = Path.GetFullPath(@"..\..\..\");
Console.WriteLine(projPath);

這對我來說一直很有效。 搏一搏。

(因為 22 個答案還不夠……這里還有一個……)

Mike Nakis 發布了一個很好的答案,我添加了一些增強功能。 這只是他非常好的代碼的一個稍微改進的版本。

正如 Mike 指出的,這個類文件必須在項目的根目錄中。

我沒有遇到以下任何問題,但也許有一些我不知道的細微差別。 YMMV。

using System.IO;
using System.Runtime.CompilerServices;

namespace Whatever
{
  internal static class ProjectPathInfo
  {
    public static string CSharpClassFileName = nameof(ProjectPathInfo) + ".cs";
    public static string CSharpClassPath;
    public static string ProjectPath;
    public static string SolutionPath;

    static ProjectPathInfo() {
      CSharpClassPath = GetSourceFilePathName();
      ProjectPath = Directory.GetParent(CSharpClassPath)!.FullName;
      SolutionPath = Directory.GetParent(ProjectPath)!.FullName;
    }

    private static string GetSourceFilePathName( [CallerFilePath] string? callerFilePath = null ) => callerFilePath ?? "";
  }
}

好的,2021 年,派對有點晚了……但我對我在許多項目中發現的所有可能性感到非常惱火:

  • 垃圾箱/調試
  • bin/x86/調試
  • bin/Debug/net5.0-windows
  • ...

來吧...我只需要一個(或幾乎)一行來解決測試單元中的一些文件; 我需要在所有過去、現在、(也許將來)的項目中使用它。

因此,如果項目名稱與其所在的相對文件夾相同

  1. 使用程序集名稱選擇項目根文件夾名稱;
  2. 返回直到找到該名稱。

代碼示例:

string appName = Assembly.GetExecutingAssembly().GetName().Name;
var dir = new DirectoryInfo(Environment.CurrentDirectory);
while (dir.Name != appName) {
  dir = Directory.GetParent(dir.FullName);
}
return dir.FullName;

最佳解決方案

string PjFolder1 =
    Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).
        Parent.Parent.FullName;

其他解決方案

string pjFolder2 = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(
                System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)));

測試它,AppDomain.CurrentDomain.BaseDirectory 在過去的項目中為我工作,現在我得到調試文件夾....所選的好答案只是不工作!。

//Project DEBUG folder, but STILL PROJECT FOLDER
string pjDebugFolder = AppDomain.CurrentDomain.BaseDirectory;

//Visual studio folder, NOT PROJECT FOLDER
//This solutions just not work
string vsFolder = Directory.GetCurrentDirectory();
string vsFolder2 = Environment.CurrentDirectory;
string vsFolder3 = Path.GetFullPath(".\\");   

//Current PROJECT FOLDER
string ProjectFolder = 
    //Get Debug Folder object from BaseDirectory ( the same with end slash)
    Directory.GetParent(pjDebugFolder).
    Parent.//Bin Folder object
    Parent. //Project Folder object
    FullName;//Project Folder complete path

這適用於帶有 SDK Core MSBuild 配置的 VS2017。

您需要在 EnvDTE / EnvDTE80 包中進行 NuGet。

不要使用 COM 或互操作。 什么……垃圾!!

 internal class Program {
    private static readonly DTE2 _dte2;

    // Static Constructor
    static Program() {
      _dte2 = (DTE2)Marshal.GetActiveObject("VisualStudio.DTE.15.0");
    }


    private static void FindProjectsIn(ProjectItem item, List<Project> results) {
      if (item.Object is Project) {
        var proj = (Project) item.Object;
        if (new Guid(proj.Kind) != new Guid(Constants.vsProjectItemKindPhysicalFolder))
          results.Add((Project) item.Object);
        else
          foreach (ProjectItem innerItem in proj.ProjectItems)
            FindProjectsIn(innerItem, results);
      }

      if (item.ProjectItems != null)
        foreach (ProjectItem innerItem in item.ProjectItems)
          FindProjectsIn(innerItem, results);
    }


    private static void FindProjectsIn(UIHierarchyItem item, List<Project> results) {
      if (item.Object is Project) {
        var proj = (Project) item.Object;
        if (new Guid(proj.Kind) != new Guid(Constants.vsProjectItemKindPhysicalFolder))
          results.Add((Project) item.Object);
        else
          foreach (ProjectItem innerItem in proj.ProjectItems)
            FindProjectsIn(innerItem, results);
      }

      foreach (UIHierarchyItem innerItem in item.UIHierarchyItems)
        FindProjectsIn(innerItem, results);
    }


    private static IEnumerable<Project> GetEnvDTEProjectsInSolution() {
      var ret = new List<Project>();
      var hierarchy = _dte2.ToolWindows.SolutionExplorer;
      foreach (UIHierarchyItem innerItem in hierarchy.UIHierarchyItems)
        FindProjectsIn(innerItem, ret);
      return ret;
    }


    private static void Main() {
      var projects = GetEnvDTEProjectsInSolution();
      var solutiondir = Path.GetDirectoryName(_dte2.Solution.FullName);

      // TODO
      ...

      var project = projects.FirstOrDefault(p => p.Name == <current project>);
      Console.WriteLine(project.FullName);
    }
  }

我沒有看到使用 string.Join 和 string.Split + SkipLast 4 個元素的解決方案,所以在這里。

            string projectDir = 
            string.Join('/', AppDomain.CurrentDomain.BaseDirectory
                .Split(new char[] { '/' })
                .SkipLast(4));

我想運行當前的Project Dir,而不是運行路徑經過硬編碼的外部程序。 我正在使用自定義任務中的進程來調用外部程序。

我該怎么做? AppDomain.CurrentDomain.BaseDirectory只是給了我VS 2008的位置。

嘗試:

            {
                OpenFileDialog fd = new OpenFileDialog();
                fd.Multiselect = false;
                fd.Filter = "Image files (*.bmp, *.jpg)|*.bmp;*.jpg|All files (*.*)|*.*";
                if (fd.ShowDialog() == true)
                {
                    if (fd.CheckFileExists)
                    {
                        var fileNameToSave = GetTimestamp(DateTime.Now) + Path.GetExtension(fd.FileName);
                        var pathRegex = new Regex(@"\\bin(\\x86|\\x64)?\\(Debug|Release)$", RegexOptions.Compiled);
                        var directory = pathRegex.Replace(Directory.GetCurrentDirectory(), String.Empty);
                        var imagePath = Path.Combine(directory + @"\Uploads\" + fileNameToSave);
                        File.Copy(fd.FileName, imagePath);

                    }
                }
            }
            catch (Exception ex)
            {

                throw ex;
            }

這是將圖像上傳到 wpf 上傳目錄的代碼

Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.Parent.FullName

會給你項目目錄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM