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

而不是运行其路径硬编码的外部程序,我想获得当前的项目目录。我正在使用自定义任务中的进程调用外部程序。

我该怎么做呢?AppDomain.CurrentDomain.BaseDirectory只是给了我VS 2008的位置。

443711 次浏览

您可以尝试这两种方法中的一种。

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


string startupPath = Environment.CurrentDirectory;

告诉我,你觉得哪个更好

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

会给你项目目录。

我也在找这个。我有一个运行HWC的项目,我想让网站远离应用程序树,但我不想让它在调试(或发布)目录。FWIW是公认的解决方案(这个也是),它只标识可执行文件所在的目录。

找到我一直在用的那个目录

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

我也遇到过类似的情况,在google搜索无果之后,我声明了一个公共字符串,它修改调试/发布路径的字符串值以获得项目路径。使用这种方法的一个好处是,因为它使用了当前项目的目录,所以不管你是从调试目录还是发布目录工作:

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

这应该在大多数情况下工作。

在我最终完成了关于公共字符串的us的第一个答案以获得答案后,我突然意识到您可能可以从注册表中读取一个值以获得您想要的结果。事实证明,这条路线甚至更短:

首先,你必须包括微软。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;等等),那么你可能必须修改子密钥字符串的'version'部分(即8.0,7.0;等等)。

如果你使用了我的答案之一,如果这不是一个过分的要求,那么我想知道你使用了我的方法,为什么。祝你好运。

  • dm
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;

如果你想知道你的解决方案所在的目录是什么,你需要这样做:

 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;

另一种方法

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

如果你想获取bin文件夹的路径

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

也许有更好的方法=)

使用这个来获得项目目录(为我工作):

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

这还将通过从当前执行目录向上导航两级来为您提供项目目录(这不会为每次构建返回项目目录,但这是最常见的)。

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

当然,您希望将其包含在某种验证/错误处理逻辑中。

还有另一个不完美的解决方案(但可能比其他一些更接近完美):

    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/");

如果项目在IIS express上运行,Environment.CurrentDirectory可以指向IIS express所在的位置(默认路径是C:\Program Files (x86)\IIS快递),而不是指向项目所在的位置。


这可能是各种项目最适合的目录路径。

AppDomain.CurrentDomain.BaseDirectory

这就是MSDN的定义。

获取程序集解析器用于探测程序集的基目录。

最好的解决方案

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

我使用以下解决方案来完成这项工作:

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

基于Gucu112的回答,但对于.NET核心控制台/窗口应用程序,它应该是:

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

我在一个xUnit项目中使用这个。net核心窗口应用程序。

这适用于VS2017 w/ SDK核心MSBuild配置。

您需要在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);
}
}

试一试:

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

这是不同于其他的解决方案,也考虑到可能的x86或x64构建。

如果你真的想确保你得到源项目目录,不管bin输出路径设置为什么:

  1. 添加一个预构建事件命令行(Visual Studio:项目属性->构建事件):

    echo $(MSBuildProjectDirectory) > $(MSBuildProjectDirectory)\Resources\ProjectDirectory.txt < / p >

  2. ProjectDirectory.txt文件添加到“资源”。resx项目(如果它还不存在,右键单击项目->添加新项目->资源文件)

  3. 从带有Resources.ProjectDirectory的代码中访问。
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;

这个解决方案对我来说很好,在开发和测试和PROD服务器上使用ASP。NET MVC5通过c#:

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

如果你需要项目配置文件中的项目目录,使用:

$(ProjectDir)

<强>的< /强>1获取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?需要一个相当后期的c#版本,包含#nullable enable;如果你没有它,那么只需删除?

Assert()函数是我自己的;如果你喜欢过危险的生活,你可以用你自己的代替它,或者省略它。

函数GetSourceFilePathName()的定义如下:

using System.Runtime.CompilerServices


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

一旦你有了以上这些,你可以这样使用它:

string projectSourcePath = ProjectSourcePath.Value;

1“正确的”,如:万无一失的;可靠;没有假设;不牢靠的:不牢靠的;不一定在某些项目上成功,但在另一些项目上失败;当你改变不相关的东西时,不太可能毫无征兆地坏掉;等。

(因为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 /调试
  • bin / x86 /调试
  • bin /调试/ 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 projPath = Path.GetFullPath(@"..\..\..\");
Console.WriteLine(projPath);

这对我来说一直都很有效。试一试。

试一试:

            {
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上传目录的代码