简体   繁体   English

创建自定义MSBuild任务时如何从C#代码获取当前项目目录?

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

Instead of running an external program with its path hardcoded, I would like to get the current Project Dir.我不想运行带有硬编码路径的外部程序,而是想获取当前的项目目录。 I'm calling an external program using a process in the custom task.我正在使用自定义任务中的进程调用外部程序。

How would I do that?我该怎么做? AppDomain.CurrentDomain.BaseDirectory just gives me the location of VS 2008. 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;

You can try one of this two methods.您可以尝试这两种方法之一。

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

string startupPath = Environment.CurrentDirectory;

Tell me, which one seems to you better告诉我,你觉得哪个更好

If a project is running on an IIS express, the Environment.CurrentDirectory could point to where IIS Express is located ( the default path would be C:\Program Files (x86)\IIS Express ), not to where your project resides.如果项目在 IIS Express 上运行,则Environment.CurrentDirectory可能指向 IIS Express 所在的位置(默认路径为C:\Program Files (x86)\IIS Express ),而不是项目所在的位置。


This is probably the most suitable directory path for various kinds of projects.这可能是各种项目最合适的目录路径。

AppDomain.CurrentDomain.BaseDirectory

This is the MSDN definition.这是 MSDN 的定义。

Gets the base directory that the assembly resolver uses to probe for assemblies.获取程序集解析器用于探测程序集的基目录。

I am amazed, literally dumbfounded, by the haphazardness of all of the solutions posted so far.到目前为止,我对所有发布的解决方案的随意性感到惊讶,简直目瞪口呆。

The proper 1 way to get the root folder of a C# project is to leverage the [CallerFilePath] attribute to obtain the full path name of a source file, and then subtract the filename plus extension from it, leaving you with the path to the project.获取 C# 项目的根文件夹的正确方法之一是利用[CallerFilePath]属性获取源文件的完整路径名,然后从中减去文件名和扩展名,留下项目的路径.

Here is how to actually do it:以下是实际操作方法:

In the root folder of your project, add file ProjectSourcePath.cs with the following content:在项目的根文件夹中,添加具有以下内容的文件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 );
    }
}

The string? string? requires a pretty late version of C# with #nullable enable ;需要带有#nullable enable的相当晚的 C# 版本; if you don't have it, then just remove the ?如果你没有它,那么只需删除? . .

The Assert() function is my own; Assert()函数是我自己的; you can replace it with your own, or omit it, if you like living your life dangerously.如果你喜欢危险地生活,你可以用你自己的代替它,或者省略它。

The function GetSourceFilePathName() is defined as follows:函数GetSourceFilePathName()定义如下:

using System.Runtime.CompilerServices

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

Once you have the above, you can use it as follows:有了以上内容后,您可以按如下方式使用它:

string projectSourcePath = ProjectSourcePath.Value;

1 'proper' as in: fool-proof; 1 “正确”如:万无一失; sure-fire;万无一失; without presumptions;没有假设; not being held together by shoestrings;不被鞋带绑在一起; not bound to work for some projects but fail for others;不一定要为某些项目工作,但不能为其他项目工作; not likely to horribly break without a warning when you change unrelated things;当您更改不相关的内容时,不太可能在没有警告的情况下可怕地中断; etc.等等

This will also give you the project directory by navigating two levels up from the current executing directory (this won't return the project directory for every build, but this is the most common).这还将通过从当前执行目录向上导航两个级别来为您提供项目目录(这不会为每个构建返回项目目录,但这是最常见的)。

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

Of course you would want to contain this inside some sort of validation/error handling logic.当然,您希望将其包含在某种验证/错误处理逻辑中。

If you want ot know what is the directory where your solution is located, you need to do this:如果你想知道你的解决方案所在的目录是什么,你需要这样做:

 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*/}
            }

If you let only with GetCurrrentDirectory() method, you get the build folder no matter if you are debugging or releasing.如果您只使用GetCurrrentDirectory()方法,无论您是在调试还是发布,您都会获得构建文件夹。 I hope this help!我希望这有帮助! If you forget about validations it would be like this:如果您忘记了验证,它将是这样的:

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

Based on Gucu112's answer , but for .NET Core Console/Window application, it should be:根据Gucu112 的回答,但对于 .NET Core Console/Window 应用程序,它应该是:

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

I'm using this in a xUnit project for a .NET Core Window Application.我在 .NET Core Window 应用程序的 xUnit 项目中使用它。

This solution works well for me, on Develop and also on TEST and PROD servers with ASP.NET MVC5 via C# :这个解决方案对我很有效,在开发服务器上以及通过 C# 使用 ASP.NET MVC5的 TEST 和 PROD 服务器上:

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

If you need project directory in project configuration file use:如果您需要项目配置文件中的项目目录,请使用:

$(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;

I was looking for this too.我也在找这个。 I've got a project that runs HWC, and I'd like to keep the web site out of the app tree, but I don't want to keep it in the debug (or release) directory.我有一个运行 HWC 的项目,我想将网站保留在应用程序树之外,但我不想将其保留在调试(或发布)目录中。 FWIW, the accepted solution (and this one as well) only identifies the directory the executable is running in. FWIW,公认的解决方案(以及这个解决方案)仅标识可执行文件正在运行的目录。

To find that directory, I've been using为了找到那个目录,我一直在使用

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

Another way to do this另一种方法来做到这一点

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

If you want to get path to bin folder如果要获取 bin 文件夹的路径

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

Maybe there are better way =)也许有更好的方法=)

Yet another imperfect solution (but perhaps a little closer to perfect than some of the others):另一个不完美的解决方案(但可能比其他一些更接近完美):

    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);
    }

This version will return the current projects' folder even if the current project is not the Startup Project for the solution.即使当前项目不是解决方案的Startup Project ,此版本也会返回当前项目的文件夹。

The first flaw with this is that I've skipped all error checking.第一个缺陷是我跳过了所有的错误检查。 That can be fixed easy enough but should only be a problem if you're storing your project in the root directory for the drive or using a junction in your path (and that junction is a descendant of the solution folder) so this scenario is unlikely.这可以很容易地解决,但只有当您将项目存储在驱动器的根目录中或在路径中使用结点(并且该结点是解决方案文件夹的后代)时才会出现问题,因此这种情况不太可能出现. I'm not entirely sure that Visual Studio could handle either of these setups anyway.我不完全确定 Visual Studio 是否可以处理这些设置中的任何一个。

Another (more likely) problem that you may run into is that the project name must match the folder name for the project for it to be found.您可能遇到的另一个(更有可能)问题是项目名称必须与项目的文件夹名称匹配才能找到它。

Another problem you may have is that the project must be inside the solution folder.您可能遇到的另一个问题是项目必须位于解决方案文件夹中。 This usually isn't a problem but if you've used the Add Existing Project to Solution option to add the project to the solution then this may not be the way your solution is organized.这通常不是问题,但如果您使用“ Add Existing Project to Solution ”选项将项目添加到解决方案,那么这可能不是您的解决方案的组织方式。

Lastly, if you're application will be modifying the working directory, you should store this value before you do that because this value is determined relative to the current working directory.最后,如果您的应用程序将修改工作目录,您应该在这样做之前存储此值,因为此值是相对于当前工作目录确定的。

Of course, this all also means that you must not alter the default values for your projects' Build -> Output path or Debug -> Working directory options in the project properties dialog.当然,这也意味着您不能在项目属性对话框中更改项目的Build -> Output pathDebug -> Working directory选项的默认值。

试试这个,很简单

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

If you really want to ensure you get the source project directory, no matter what the bin output path is set to:如果您真的想确保获得源项目目录,则无论 bin 输出路径设置为:

  1. Add a pre-build event command line (Visual Studio: Project properties -> Build Events):添加预构建事件命令行(Visual Studio:项目属性 -> 构建事件):

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

  2. Add the ProjectDirectory.txt file to the Resources.resx of the project (If it doesn't exist yet, right click project -> Add new item -> Resources file)ProjectDirectory.txt文件添加到项目的 Resources.resx 中(如果还不存在,请右键单击项目 -> 添加新项目 -> 资源文件)

  3. Access from code with Resources.ProjectDirectory .使用Resources.ProjectDirectory从代码访问。

I had a similar situation, and after fruitless Googles, I declared a public string, which mods a string value of the debug / release path to get the project path.我也遇到过类似的情况,在谷歌无果之后,我声明了一个公共字符串,它修改了调试/发布路径的字符串值来获取项目路径。 A benefit of using this method is that since it uses the currect project's directory, it matters not if you are working from a debug directory or a release directory:使用此方法的一个好处是,由于它使用当前项目的目录,因此无论您是从调试目录还是发布目录工作都无关紧要:

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;
}

You would then be able to call it whenever you want, using only one line:然后,您可以随时调用它,只需使用一行:

string MyProjectDir = DirProject();

This should work in most cases.这在大多数情况下应该有效。

Use this to get the Project directory (worked for me):使用它来获取项目目录(为我工作):

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

I have used following solution to get the job done:我使用以下解决方案来完成工作:

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

Try:尝试:

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

This is solution different from the others does also take into account possible x86 or x64 build.这是与其他解决方案不同的解决方案,它也考虑了可能的 x86 或 x64 构建。

After I had finally finished polishing my first answer regarding the us of public strings to derive an answer, it dawned on me that you could probably read a value from the registry to get your desired result.在我终于完成了关于公共字符串的我们的第一个答案以得出答案之后,我突然意识到您可能可以从注册表中读取一个值以获得您想要的结果。 As it turns out, that route was even shorter:事实证明,这条路线甚至更短:

First, you must include the Microsoft.Win32 namespace so you can work with the registry:首先,您必须包含 Microsoft.Win32 命名空间,以便您可以使用注册表:

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

Here is the main code:这是主要代码:

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

A note on this answer:关于这个答案的注释:

I am using Visual Studio 2008 Professional Edition.我正在使用 Visual Studio 2008 专业版。 If you are using another version, (ie 2003, 2005, 2010; etc.), then you mayt have to modify the 'version' part of the SubKey string (ie 8.0, 7.0; etc.).如果您使用的是其他版本(即 2003、2005、2010 等),那么您可能不必修改 SubKey 字符串的“版本”部分(即 8.0、7.0 等)。

If you use one of my answers, and if it is not too much to ask, then I would like to know which of my methods you used and why.如果您使用我的答案之一,并且问的不是太多,那么我想知道您使用了我的哪种方法以及为什么。 Good luck.祝你好运。

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

This consistently works well for me.这对我来说一直很有效。 Give it a go.搏一搏。

(Because 22 answers are not enough... here's one more....) (因为 22 个答案还不够……这里还有一个……)

Mike Nakis posted a great answer, to which I added a few enhancements. Mike Nakis 发布了一个很好的答案,我添加了一些增强功能。 This is just a slightly spiffed up version of his very nice code.这只是他非常好的代码的一个稍微改进的版本。

As Mike pointed out, this class file must be in the root of the project.正如 Mike 指出的,这个类文件必须在项目的根目录中。

I did not run into any problems with the below, but perhaps there are nuances I'm not aware of.我没有遇到以下任何问题,但也许有一些我不知道的细微差别。 YMMV. 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 ?? "";
  }
}

Ok, 2021, a bit late to the party... but very annoyed by all possibilities I found in many projects:好的,2021 年,派对有点晚了……但我对我在许多项目中发现的所有可能性感到非常恼火:

  • bin/Debug垃圾箱/调试
  • bin/x86/Debug bin/x86/调试
  • bin/Debug/net5.0-windows bin/Debug/net5.0-windows
  • ... ...

Come on... I just need a one-liner (or almost) to address some files in test units;来吧...我只需要一个(或几乎)一行来解决测试单元中的一些文件; I need to use it on all past, current, (maybe future) projects.我需要在所有过去、现在、(也许将来)的项目中使用它。

So, if the project name is the same of relative folder which it lies in :因此,如果项目名称与其所在的相对文件夹相同

  1. use the assembly name to pick project root folder name;使用程序集名称选择项目根文件夹名称;
  2. go back until that name is found.返回直到找到该名称。

Code sample:代码示例:

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

The best solution最佳解决方案

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

Other solution其他解决方案

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

Test it, AppDomain.CurrentDomain.BaseDirectory worked for me on past project, now I get debug folder .... the selected GOOD answer just NOT WORK!.测试它,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

This works on VS2017 w/ SDK Core MSBuild configurations.这适用于带有 SDK Core MSBuild 配置的 VS2017。

You need to NuGet in the EnvDTE / EnvDTE80 packages.您需要在 EnvDTE / EnvDTE80 包中进行 NuGet。

Do not use COM or interop.不要使用 COM 或互操作。 anything.... garbage!!什么……垃圾!!

 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);
    }
  }

I didn't see a solution by using string.Join and string.Split + SkipLast 4 elements, so here it is.我没有看到使用 string.Join 和 string.Split + SkipLast 4 个元素的解决方案,所以在这里。

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

Instead of running an external program with its path hardcoded, I would like to get the current Project Dir.我想运行当前的Project Dir,而不是运行路径经过硬编码的外部程序。 I'm calling an external program using a process in the custom task.我正在使用自定义任务中的进程来调用外部程序。

How would I do that?我该怎么做? AppDomain.CurrentDomain.BaseDirectory just gives me the location of VS 2008. AppDomain.CurrentDomain.BaseDirectory只是给了我VS 2008的位置。

Try:尝试:

            {
                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;
            }

this is the code for uploading image into wpf upload directory这是将图像上传到 wpf 上传目录的代码

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

Will give you the project directory.会给你项目目录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从编辑器分类器项目(c#)获取当前的解决方案目录? - How do you get the current solution directory from a Editor Classifier Project (c#)? 创建MSBuild自定义任务以在* compile之前修改C#代码* - Create MSBuild custom task to modify C# code *before* compile 如何使用 C# 获取当前项目目录路径 - How to get Current Project Directory path using C# 自定义MSBuild任务无法从App.config中读取[C#] - Custom MSBuild Task not reading from App.config [C#] 从Powershell / MSBuild中的现有模板创建C#项目模板 - Creating C# project template from existing one in Powershell/MSBuild 你如何在代码中获得C#(VS 2008)中的解决方案目录? - How do you get the solution directory in C# (VS 2008) in code? 如何从VSPackage获取当前解决方案目录? - How do you get the current solution directory from a VSPackage? 你如何在C#中获得Random的当前种子? - How do you get the current seed of Random in C#? C#代码中如何获取当前项目名称? - How to get the current project name in C# code? 在Visual Studio C#中使用自定义DLL时,如何显示自定义的intellisense注释? - How do you get custom intellisense comments to appear when using a custom DLL in Visual Studio C#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM