Visual Studio - 生成后事件 - 引发错误

发布于 2024-09-18 14:29:51 字数 583 浏览 10 评论 0原文

我有一个很好的 power-shell 驱动的构建后脚本,它可以执行一些神奇的操作,在编译后将所有插件拉到正确的位置,并整理出与解决方案的主项目的依赖关系。

我的问题是,偶尔当我做了一些愚蠢的事情时,我最终可能会陷入脚本无法正确执行其操作的状态,并在 powershell 中抛出异常,并包含错误的详细信息。

有没有办法将这些异常拉到 Visual Studio 错误窗口,以便当我的构建后失败时,vstudio 会收到失败通知,并在窗口中将其与所有其他警告/错误一起很好地格式化?

编辑:这是对我理想的寻找内容的澄清。

删除了无效的 ImageShack 链接

注意:< em> 如果您来到这里寻找如何在 Visual Studio 中显示自定义错误消息(当您可以控制错误消息时),您可以看到 Roy Tinker 的回答,了解如何定制要显示的消息。如果您有兴趣捕获无法控制的意外错误,或寻找更完整的解决方案,请参阅已接受的答案。

I've got a nice power-shell driven post-build script that does some magic mumbo-jumbo for pulling all our plugins into the correct location after they're compiled and sorting out thier dependencies with the master-project of the solution.

My problem is, occasionally when I do something stupid, I can end up in a state where my script can't execute it's operation correctly, and throws an exception in powershell with the details of what went wrong.

Is there a way to get these exceptions to pull up to the Visual Studio Error window so that when my post-build fails, vstudio gets a failure notification and nicely formats it in the window alongside all the other warnings/errors?

Edit: This is a clarification to what I'm ideally looking for.

removed dead ImageShack link

Note: If you've landed here looking for how to make custom error messages show up in Visual Studio (when you have control of the error messages) you can see Roy Tinker's Answer to learn how to tailor your messages to show up. If you're interested in catching unexpected errors you can't control, or finding a more complete solution please see the accepted answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

锦爱 2024-09-25 14:29:51

要创建将出现在“错误列表”窗口中的错误、警告或消息,只需从由构建前或构建后事件启动的脚本以以下格式将消息记录到 stdout 或 stderr 即可。如果有官方规范,请评论或编辑;这只是我通过反复试验和观察 MSBuild 的输出得出的结论。方括号表示“可选”:

FilePath[(LineNumber[,ColumnNumber])]: MessageType[ MessageCode]: Description

例如:

E:\Projects\SampleProject\Program.cs(18,5): error CS1519: Invalid token '}' in class, struct, or interface member declaration

有关更多示例,请参阅“输出”窗口,了解在 Visual Studio 中运行生成时可能出现的任何错误/警告/消息。

To create an error, warning, or message that will appear in the Error List window, simply log a message to stdout or stderr in the following format from a script initiated by a pre- or post-build event. Please comment or edit if there is an official spec; this is only what I was able to deduce by trial-and-error and by watching the output of MSBuild. Square brackets denote "optional":

FilePath[(LineNumber[,ColumnNumber])]: MessageType[ MessageCode]: Description

As an example:

E:\Projects\SampleProject\Program.cs(18,5): error CS1519: Invalid token '}' in class, struct, or interface member declaration

For more examples, see the Output window for any error/warning/message that may occur when you run a build in Visual Studio.

够运 2024-09-25 14:29:51

以下是在 PowerShell 脚本出错时中断构建的两种方法。

使用 exit() 终止 PowerShell 进程

要从脚本返回状态代码(如果非零,将显示在错误列表中),请使用以下命令:

exit(45) # or any other non-zero number, for that matter.

这并不能精确获取错误文本到您的错误列表中,但它确实会终止脚本并在错误列表中获取一些内容以指示哪个构建前或构建后命令失败。

使用自定义 MSBuild 任务执行 PowerShell 脚本

我花了一点时间研究在 MSBuild 任务中执行 PowerShell 脚本的详细信息。我的博客上有包含示例代码的完整文章。请务必查看它,因为它包含更多讨论以及有关如何处理示例项目的一些解释。它可能不是一个完整或完美的解决方案,但我用一个非常简单的脚本在我的机器上工作TM

此方法在报告 PowerShell 错误时提供行和列精度,甚至支持我们在 Visual Studio 中习惯的双击“获取文件”行为。如果缺少,我相信您能够扩展它以满足您的需求。此外,根据您的 Visual Studio 版本,您可能需要处理程序集参考版本等详细信息。

首先,在类库项目中构建自定义 MSBuild 任务。该库应引用以下程序集以进行 MSBuild 和 PowerShell 集成。 (请注意,此示例需要 PowerShell 2.0。)

  • Microsoft.Build.Framework (GAC)
  • Microsoft.Build.Utilities.v3.5 (GAC)
  • System.Management.Automation(来自 C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\ v1.0)

构建一个任务类,并公开一个属性来指定 PowerShell 脚本的路径,如下所示:

using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

public class PsBuildTask : Task
{
    [Required]
    public string ScriptPath { get; set; }

    public override bool Execute()
    {
        // ...
    }
}

在 Execute() 方法中,启动 PowerShell 运行时,执行脚本,然后收集错误。使用Log 属性来记录错误。完成后,关闭运行空间,如果脚本没有记录任何错误,则返回 true。

// create Powershell runspace
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();

// create a pipeline and feed it the script text
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(". " + ScriptPath);

// execute the script and extract errors
pipeline.Invoke();
var errors = pipeline.Error;

// log an MSBuild error for each error.
foreach (PSObject error in errors.Read(errors.Count))
{
    var invocationInfo = ((ErrorRecord)(error.BaseObject)).InvocationInfo;
    Log.LogError(
        "Script",
        string.Empty,
        string.Empty,
        new FileInfo(ScriptPath).FullName,
        invocationInfo.ScriptLineNumber,
        invocationInfo.OffsetInLine,
        0,
        0,
        error.ToString());
}

// close the runspace
runspace.Close();

return !Log.HasLoggedErrors;

就是这样。有了这个程序集,我们就可以配置另一个项目来使用 MSBuild 任务。

例如,考虑一个基于 C# 的类库项目 (.csproj)。将任务集成到构建后事件中只需要做一些事情。

首先,在 .csproj 文件的 节点内注册任务,如下所示:

<UsingTask TaskName="PsBuildTask"
           AssemblyFile="..\Noc.PsBuild\bin\Debug\Noc.PsBuild.dll" />

TaskName 应该是任务类的名称,尽管命名空间似乎不是必需的。 AssemblyFile 是自定义 MSBuild 任务程序集的绝对路径,或相对于 .csproj 文件的相对路径。对于 GAC 中的程序集,您可以改用 AssemblyName 属性。

注册后,该任务可以在构建前和构建后事件中使用。在 .csproj 文件的 元素中配置构建事件,如下所示:

<Target Name="AfterBuild">
    <PsBuildTask ScriptPath=".\script.ps1" />
</Target>

就是这样。当 Visual Studio 编译项目时,它会加载自定义程序集和任务对象并执行任务。检索并报告管道引发的错误。

屏幕截图

Here are two approaches for interrupting the build when a PowerShell script errors.

Use exit() to terminate the PowerShell process

To return a status code from the script which, if non-zero, will show up in the error list, use the following:

exit(45) # or any other non-zero number, for that matter.

This doesn't precisely get the error text onto your error list, but it does terminate the script and get a little something in your error list to indicate which pre- or post-build command failed.

Use a custom MSBuild task to execute the PowerShell script

I spent a little time working out the details of executing a PowerShell script within an MSBuild task. I have a full article with sample code on my blog. Do check it out, as it includes more discussion, and some explanation of how to handle the sample projects. It's probably not a complete or perfect solution, but I got it Working on My MachineTM with a very simple script.

This approach provides line and column precision when reporting PowerShell errors, and even supports the double-click-takes-me-to-the-file behavior we're accustomed to in Visual Studio. If it's lacking, I'm sure you'll be able to extend it to meet your needs. Also, depending on your version of Visual Studio, you may need to massage details like assembly reference versions.

First off, build a custom MSBuild Task in a class library project. The library should reference the following assemblies for MSBuild and PowerShell integration. (Note that this example requires PowerShell 2.0.)

  • Microsoft.Build.Framework (GAC)
  • Microsoft.Build.Utilities.v3.5 (GAC)
  • System.Management.Automation (from C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0)

Build a task class, and expose a property to specify the path to the PowerShell script, like so:

using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

public class PsBuildTask : Task
{
    [Required]
    public string ScriptPath { get; set; }

    public override bool Execute()
    {
        // ...
    }
}

Within the Execute() method, start the PowerShell run time, execute the script, and collect errors. Use the Log property to log the errors. When finished, close the runspace and return true if the script logged no errors.

// create Powershell runspace
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();

// create a pipeline and feed it the script text
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(". " + ScriptPath);

// execute the script and extract errors
pipeline.Invoke();
var errors = pipeline.Error;

// log an MSBuild error for each error.
foreach (PSObject error in errors.Read(errors.Count))
{
    var invocationInfo = ((ErrorRecord)(error.BaseObject)).InvocationInfo;
    Log.LogError(
        "Script",
        string.Empty,
        string.Empty,
        new FileInfo(ScriptPath).FullName,
        invocationInfo.ScriptLineNumber,
        invocationInfo.OffsetInLine,
        0,
        0,
        error.ToString());
}

// close the runspace
runspace.Close();

return !Log.HasLoggedErrors;

And that's it. With this assembly in hand, we can configure another project to consume the MSBuild task.

Consider, for example, a C#-based class library project (.csproj). Integrating the task in a post build event requires just a few things.

First, register the task just inside the <Project> node of the .csproj file like so:

<UsingTask TaskName="PsBuildTask"
           AssemblyFile="..\Noc.PsBuild\bin\Debug\Noc.PsBuild.dll" />

TaskName should be the name of the task class, though it would seem the namespace is not required. AssemblyFile is an absolute path to the custom MSBuild task assembly, or relative path with respect to the .csproj file. For assemblies in the GAC, you can use the AssemblyName attribute instead.

Once registered, the task can be used within pre- and post-build events. Configure a build event within the <Project> element of the .csproj file like so:

<Target Name="AfterBuild">
    <PsBuildTask ScriptPath=".\script.ps1" />
</Target>

And that's it. When Visual Studio compiles the project, it loads the custom assembly and task object and executes the task. Errors raised by the pipeline are retrieved and reported.

Screenshot

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文