如何使用msbuild下载文件?

时间:2022-02-21 21:13:59

Is there a built in way to download a file to a local directory using HTTP?

是否有内置的方法使用HTTP将文件下载到本地目录?

I can shell out to wget or write a custom task, but I wanted to make sure there wasn't an existing way to accomplish this.

我可以打算忘记或编写自定义任务,但我想确保没有现成的方法来实现这一点。

Thanks in advance!

提前致谢!

5 个解决方案

#1


MSBuild Community Tasks has a task WebDownload which seems to be what you require.

MSBuild社区任务有一个任务WebDownload,它似乎是你需要的。

#2


In MSBuild 4.0 you can use inline tasks to avoid needing to compile and deploy a custom task in a separate assembly.

在MSBuild 4.0中,您可以使用内联任务来避免需要在单独的程序集中编译和部署自定义任务。

  <UsingTask TaskName="DownloadFile" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <Address ParameterType="System.String" Required="true"/>
      <FileName ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Reference Include="System" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
            new System.Net.WebClient().DownloadFile(Address, FileName);
        ]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="DownloadSomething">
    <DownloadFile Address="http://somewebsite/remotefile" FileName="localfilepath" />
  </Target>

#3


If you're trying to download a file that requires authentication (such as TFS Web, or an IIS server attached to a domain), neither the MSBuild Extension Pack nor the MSBuild Community Tasks seem to have the ability to give a username or password to the HTTP server. In this case, I ended up writing a custom MSBuild task. Here's what I did.

如果您尝试下载需要身份验证的文件(例如TFS Web或连接到域的IIS服务器),则MSBuild扩展包和MSBuild社区任务似乎都无法提供用户名或密码。 HTTP服务器。在这种情况下,我最终编写了一个自定义的MSBuild任务。这就是我做的。

I followed the advice of Stack Overflow user Doug, in his answer for Download a file which requires authentication using vb.net/c#?, in which he suggests some code to add to a method written by Tom Archer on the Code Guru web site.

我按照Stack Overflow用户Doug的建议,在他的回答中找到了一个需要使用vb.net/c#?进行身份验证的文件,其中他建议添加一些代码添加到Tom Archer在Code Guru网站上编写的方法中。

So I used MS Visual Studio 2010 to create a new C# project with the following code to create an MSBuild target named Wget (full source code shown):

因此,我使用MS Visual Studio 2010创建了一个新的C#项目,其中包含以下代码,用于创建名为Wget的MSBuild目标(显示完整的源代码):

// Include references to the following frameworks in your solution:
// - Microsoft.Build.Framework
// - Microsoft.Build.Utilities.v4.0
// - System
// - System.Net

using System;
using System.Net;
using System.IO;

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace Wget
{
    public class Wget: Task
    {
        [Required]
        public String Address // HTTP address to access
        { get; set; }

        [Required]
        public String LocalFilename // Local file to which the downloaded page will be saved
        { get; set; }

        public String Username // Credential for HTTP authentication
        { get; set; }

        public String Password // Credential for HTTP authentication
        { get; set; }

        public override bool Execute()
        {
            int read = DownloadFile(Address, LocalFilename, Username, Password);

            Console.WriteLine("{0} bytes written", read);

            return true;
        }

        public static int DownloadFile(String remoteFilename, String localFilename, String httpUsername, String httpPassword)
        {
            // Function will return the number of bytes processed
            // to the caller. Initialize to 0 here.
            int bytesProcessed = 0;

            // Assign values to these objects here so that they can
            // be referenced in the finally block
            Stream remoteStream = null;
            Stream localStream = null;
            WebResponse response = null;

            // Use a try/catch/finally block as both the WebRequest and Stream
            // classes throw exceptions upon error
            try
            {
                // Create a request for the specified remote file name
                WebRequest request = WebRequest.Create(remoteFilename);
                if (request != null)
                {
                    // If a username or password have been given, use them
                    if (httpUsername.Length > 0 || httpPassword.Length > 0)
                    {
                        string username = httpUsername;
                        string password = httpPassword;
                        request.Credentials = new System.Net.NetworkCredential(username, password);
                    }

                    // Send the request to the server and retrieve the
                    // WebResponse object 
                    response = request.GetResponse();
                    if (response != null)
                    {
                        // Once the WebResponse object has been retrieved,
                        // get the stream object associated with the response's data
                        remoteStream = response.GetResponseStream();

                        // Create the local file
                        localStream = File.Create(localFilename);

                        // Allocate a 1k buffer
                        byte[] buffer = new byte[1024];
                        int bytesRead;

                        // Simple do/while loop to read from stream until
                        // no bytes are returned
                        do
                        {
                            // Read data (up to 1k) from the stream
                            bytesRead = remoteStream.Read(buffer, 0, buffer.Length);

                            // Write the data to the local file
                            localStream.Write(buffer, 0, bytesRead);

                            // Increment total bytes processed
                            bytesProcessed += bytesRead;
                        } while (bytesRead > 0);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                // Close the response and streams objects here 
                // to make sure they're closed even if an exception
                // is thrown at some point
                if (response != null) response.Close();
                if (remoteStream != null) remoteStream.Close();
                if (localStream != null) localStream.Close();
            }

            // Return total bytes processed to caller.
            return bytesProcessed;
        }
    }
}

With that in place, I can add the following task to my MSBuild project:

有了这个,我可以将以下任务添加到我的MSBuild项目:

<!-- Get the contents of a Url-->
<Wget
    Address="http://mywebserver.com/securepage"
    LocalFilename="mydownloadedfile.html"
    Username="myusername"
    Password="mypassword">
</Wget>

The Wget task downloads the page served by mywebserver.com and saves it to a file in the current working directory as mydownloadedfile.html, using the username "myusername" and password "mypassword".

Wget任务下载mywebserver.com提供的页面,并使用用户名“myusername”和密码“mypassword”将其保存到当前工作目录中的文件mydownloadedfile.html。

However, in order to use the custom Wget MSBuild task, I must tell MSBuild where to find the Wget assembly file (.dll). This is done with MSBuild's element:

但是,为了使用自定义Wget MSBuild任务,我必须告诉MSBuild在哪里找到Wget程序集文件(.dll)。这是通过MSBuild的元素完成的:

<!-- Import your custom MSBuild task -->
<UsingTask AssemblyFile="MyCustomMSBuildTasks\Wget\bin\Release\Wget.dll" TaskName="Wget" />

If you want to get fancy, you can even have your MSBuild project build Wget before it's called. To do that, build the solution with the <MSBuild Projects> task, and import it with the <UsingTaks AssemblyFile> task, something like this:

如果你想获得想象力,你甚至可以让你的MSBuild项目在调用之前构建Wget。为此,使用 任务构建解决方案,并使用 任务导入它,如下所示:

<!-- Build the custom MSBuild target solution-->
<MSBuild Projects="MyCustomMSBuildTasks\CustomBuildTasks.sln" Properties="Configuration=Release" />

<!-- Import your custom MSBuild task -->
<UsingTask AssemblyFile="MyCustomMSBuildTasks\Wget\bin\Release\Wget.dll" TaskName="Wget" />

<!-- Get the contents of a Url-->
<Wget
    Address="http://mywebserver.com/securepage"
    LocalFilename="mydownloadedfile.html"
    Username="myusername"
    Password="mypassword">
</Wget>

If you've never created a custom MSBuild target before, it's not too difficult -- once you know the basics. Look at the C# code above, take a look at the official MSDN documentation, and search around on the web for more examples. A good place to start is:

如果您之前从未创建过自定义MSBuild目标,那么一旦您了解了基础知识,就不会太困难。查看上面的C#代码,查看官方MSDN文档,并在网上搜索更多示例。一个好的开始是:

#4


The DownloadFile task is available in MSBuild 15.8 and above (since August 14, 2018)

DownloadFile任务在MSBuild 15.8及更高版本中可用(自2018年8月14日起)

example:

    <PropertyGroup>  
      <LicenceUrl>https://raw.githubusercontent.com/Microsoft/msbuild/master/LICENSE</LicenceUrl>
    </PropertyGroup>  

    <Target Name="DownloadContentFiles" BeforeTargets="Build">
        <DownloadFile
            SourceUrl="$(LicenceUrl)"
            DestinationFolder="$(MSBuildProjectDirectory)">
        <Output TaskParameter="DownloadedFile" ItemName="Content" />
      </DownloadFile>
    </Target>

For more details: DownloadFile task

有关更多详细信息:DownloadFile任务

#5


In addition to the the WebDownload task in the MSBuild Community Tasks project, the MSBuild Extension pack (current version: 4.x) has a WebClient class that can be used to download a file. You can download the MSBuild extension pack here:

除了MSBuild社区任务项目中的WebDownload任务之外,MSBuild扩展包(当前版本:4.x)还有一个可用于下载文件的WebClient类。您可以在此处下载MSBuild扩展包:

Here is an example of using the MSBuild Extension Pack 4 to download a file:

以下是使用MSBuild Extension Pack 4下载文件的示例:

<Project ToolsVersion="4.0" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
    <TPath>$(MSBuildProjectDirectory)\..\MSBuild.ExtensionPack.tasks</TPath>
    <TPath Condition="Exists('$(MSBuildProjectDirectory)\..\..\Common\MSBuild.ExtensionPack.tasks')">$(MSBuildProjectDirectory)\..\..\Common\MSBuild.ExtensionPack.tasks</TPath>
</PropertyGroup>
<Import Project="$(TPath)"/>
<Target Name="Default">
    <!-- Download a File-->
    <MSBuild.ExtensionPack.Web.WebClient TaskAction="DownloadFile" Url="http://hlstiw.bay.livefilestore.com/y1p7GhsJWeF4ig_Yb-8QXeA1bL0nY_MdOGaRQ3opRZS0YVvfshMfoZYe_cb1wSzPhx4nL_yidkG8Ji9msjRcTt0ew/Team%20Build%202008%20DeskSheet%202.0.pdf?download" FileName="C:\TFS Build 2008 DeskSheet.pdf"/>
    <!-- Get the contents of a Url-->
    <MSBuild.ExtensionPack.Web.WebClient TaskAction="OpenRead" Url="http://www.msbuildextensionpack.com">
        <Output TaskParameter="Data" PropertyName="Out"/>
    </MSBuild.ExtensionPack.Web.WebClient>
    <Message Text="$(Out)"/>
</Target>

As mentioned in a different answer, WebClient does not appear to have the capability to download from a secure (password protected) web server.

正如其他答案所述,WebClient似乎无法从安全(受密码保护的)Web服务器下载。

#1


MSBuild Community Tasks has a task WebDownload which seems to be what you require.

MSBuild社区任务有一个任务WebDownload,它似乎是你需要的。

#2


In MSBuild 4.0 you can use inline tasks to avoid needing to compile and deploy a custom task in a separate assembly.

在MSBuild 4.0中,您可以使用内联任务来避免需要在单独的程序集中编译和部署自定义任务。

  <UsingTask TaskName="DownloadFile" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <Address ParameterType="System.String" Required="true"/>
      <FileName ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Reference Include="System" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
            new System.Net.WebClient().DownloadFile(Address, FileName);
        ]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="DownloadSomething">
    <DownloadFile Address="http://somewebsite/remotefile" FileName="localfilepath" />
  </Target>

#3


If you're trying to download a file that requires authentication (such as TFS Web, or an IIS server attached to a domain), neither the MSBuild Extension Pack nor the MSBuild Community Tasks seem to have the ability to give a username or password to the HTTP server. In this case, I ended up writing a custom MSBuild task. Here's what I did.

如果您尝试下载需要身份验证的文件(例如TFS Web或连接到域的IIS服务器),则MSBuild扩展包和MSBuild社区任务似乎都无法提供用户名或密码。 HTTP服务器。在这种情况下,我最终编写了一个自定义的MSBuild任务。这就是我做的。

I followed the advice of Stack Overflow user Doug, in his answer for Download a file which requires authentication using vb.net/c#?, in which he suggests some code to add to a method written by Tom Archer on the Code Guru web site.

我按照Stack Overflow用户Doug的建议,在他的回答中找到了一个需要使用vb.net/c#?进行身份验证的文件,其中他建议添加一些代码添加到Tom Archer在Code Guru网站上编写的方法中。

So I used MS Visual Studio 2010 to create a new C# project with the following code to create an MSBuild target named Wget (full source code shown):

因此,我使用MS Visual Studio 2010创建了一个新的C#项目,其中包含以下代码,用于创建名为Wget的MSBuild目标(显示完整的源代码):

// Include references to the following frameworks in your solution:
// - Microsoft.Build.Framework
// - Microsoft.Build.Utilities.v4.0
// - System
// - System.Net

using System;
using System.Net;
using System.IO;

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace Wget
{
    public class Wget: Task
    {
        [Required]
        public String Address // HTTP address to access
        { get; set; }

        [Required]
        public String LocalFilename // Local file to which the downloaded page will be saved
        { get; set; }

        public String Username // Credential for HTTP authentication
        { get; set; }

        public String Password // Credential for HTTP authentication
        { get; set; }

        public override bool Execute()
        {
            int read = DownloadFile(Address, LocalFilename, Username, Password);

            Console.WriteLine("{0} bytes written", read);

            return true;
        }

        public static int DownloadFile(String remoteFilename, String localFilename, String httpUsername, String httpPassword)
        {
            // Function will return the number of bytes processed
            // to the caller. Initialize to 0 here.
            int bytesProcessed = 0;

            // Assign values to these objects here so that they can
            // be referenced in the finally block
            Stream remoteStream = null;
            Stream localStream = null;
            WebResponse response = null;

            // Use a try/catch/finally block as both the WebRequest and Stream
            // classes throw exceptions upon error
            try
            {
                // Create a request for the specified remote file name
                WebRequest request = WebRequest.Create(remoteFilename);
                if (request != null)
                {
                    // If a username or password have been given, use them
                    if (httpUsername.Length > 0 || httpPassword.Length > 0)
                    {
                        string username = httpUsername;
                        string password = httpPassword;
                        request.Credentials = new System.Net.NetworkCredential(username, password);
                    }

                    // Send the request to the server and retrieve the
                    // WebResponse object 
                    response = request.GetResponse();
                    if (response != null)
                    {
                        // Once the WebResponse object has been retrieved,
                        // get the stream object associated with the response's data
                        remoteStream = response.GetResponseStream();

                        // Create the local file
                        localStream = File.Create(localFilename);

                        // Allocate a 1k buffer
                        byte[] buffer = new byte[1024];
                        int bytesRead;

                        // Simple do/while loop to read from stream until
                        // no bytes are returned
                        do
                        {
                            // Read data (up to 1k) from the stream
                            bytesRead = remoteStream.Read(buffer, 0, buffer.Length);

                            // Write the data to the local file
                            localStream.Write(buffer, 0, bytesRead);

                            // Increment total bytes processed
                            bytesProcessed += bytesRead;
                        } while (bytesRead > 0);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                // Close the response and streams objects here 
                // to make sure they're closed even if an exception
                // is thrown at some point
                if (response != null) response.Close();
                if (remoteStream != null) remoteStream.Close();
                if (localStream != null) localStream.Close();
            }

            // Return total bytes processed to caller.
            return bytesProcessed;
        }
    }
}

With that in place, I can add the following task to my MSBuild project:

有了这个,我可以将以下任务添加到我的MSBuild项目:

<!-- Get the contents of a Url-->
<Wget
    Address="http://mywebserver.com/securepage"
    LocalFilename="mydownloadedfile.html"
    Username="myusername"
    Password="mypassword">
</Wget>

The Wget task downloads the page served by mywebserver.com and saves it to a file in the current working directory as mydownloadedfile.html, using the username "myusername" and password "mypassword".

Wget任务下载mywebserver.com提供的页面,并使用用户名“myusername”和密码“mypassword”将其保存到当前工作目录中的文件mydownloadedfile.html。

However, in order to use the custom Wget MSBuild task, I must tell MSBuild where to find the Wget assembly file (.dll). This is done with MSBuild's element:

但是,为了使用自定义Wget MSBuild任务,我必须告诉MSBuild在哪里找到Wget程序集文件(.dll)。这是通过MSBuild的元素完成的:

<!-- Import your custom MSBuild task -->
<UsingTask AssemblyFile="MyCustomMSBuildTasks\Wget\bin\Release\Wget.dll" TaskName="Wget" />

If you want to get fancy, you can even have your MSBuild project build Wget before it's called. To do that, build the solution with the <MSBuild Projects> task, and import it with the <UsingTaks AssemblyFile> task, something like this:

如果你想获得想象力,你甚至可以让你的MSBuild项目在调用之前构建Wget。为此,使用 任务构建解决方案,并使用 任务导入它,如下所示:

<!-- Build the custom MSBuild target solution-->
<MSBuild Projects="MyCustomMSBuildTasks\CustomBuildTasks.sln" Properties="Configuration=Release" />

<!-- Import your custom MSBuild task -->
<UsingTask AssemblyFile="MyCustomMSBuildTasks\Wget\bin\Release\Wget.dll" TaskName="Wget" />

<!-- Get the contents of a Url-->
<Wget
    Address="http://mywebserver.com/securepage"
    LocalFilename="mydownloadedfile.html"
    Username="myusername"
    Password="mypassword">
</Wget>

If you've never created a custom MSBuild target before, it's not too difficult -- once you know the basics. Look at the C# code above, take a look at the official MSDN documentation, and search around on the web for more examples. A good place to start is:

如果您之前从未创建过自定义MSBuild目标,那么一旦您了解了基础知识,就不会太困难。查看上面的C#代码,查看官方MSDN文档,并在网上搜索更多示例。一个好的开始是:

#4


The DownloadFile task is available in MSBuild 15.8 and above (since August 14, 2018)

DownloadFile任务在MSBuild 15.8及更高版本中可用(自2018年8月14日起)

example:

    <PropertyGroup>  
      <LicenceUrl>https://raw.githubusercontent.com/Microsoft/msbuild/master/LICENSE</LicenceUrl>
    </PropertyGroup>  

    <Target Name="DownloadContentFiles" BeforeTargets="Build">
        <DownloadFile
            SourceUrl="$(LicenceUrl)"
            DestinationFolder="$(MSBuildProjectDirectory)">
        <Output TaskParameter="DownloadedFile" ItemName="Content" />
      </DownloadFile>
    </Target>

For more details: DownloadFile task

有关更多详细信息:DownloadFile任务

#5


In addition to the the WebDownload task in the MSBuild Community Tasks project, the MSBuild Extension pack (current version: 4.x) has a WebClient class that can be used to download a file. You can download the MSBuild extension pack here:

除了MSBuild社区任务项目中的WebDownload任务之外,MSBuild扩展包(当前版本:4.x)还有一个可用于下载文件的WebClient类。您可以在此处下载MSBuild扩展包:

Here is an example of using the MSBuild Extension Pack 4 to download a file:

以下是使用MSBuild Extension Pack 4下载文件的示例:

<Project ToolsVersion="4.0" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
    <TPath>$(MSBuildProjectDirectory)\..\MSBuild.ExtensionPack.tasks</TPath>
    <TPath Condition="Exists('$(MSBuildProjectDirectory)\..\..\Common\MSBuild.ExtensionPack.tasks')">$(MSBuildProjectDirectory)\..\..\Common\MSBuild.ExtensionPack.tasks</TPath>
</PropertyGroup>
<Import Project="$(TPath)"/>
<Target Name="Default">
    <!-- Download a File-->
    <MSBuild.ExtensionPack.Web.WebClient TaskAction="DownloadFile" Url="http://hlstiw.bay.livefilestore.com/y1p7GhsJWeF4ig_Yb-8QXeA1bL0nY_MdOGaRQ3opRZS0YVvfshMfoZYe_cb1wSzPhx4nL_yidkG8Ji9msjRcTt0ew/Team%20Build%202008%20DeskSheet%202.0.pdf?download" FileName="C:\TFS Build 2008 DeskSheet.pdf"/>
    <!-- Get the contents of a Url-->
    <MSBuild.ExtensionPack.Web.WebClient TaskAction="OpenRead" Url="http://www.msbuildextensionpack.com">
        <Output TaskParameter="Data" PropertyName="Out"/>
    </MSBuild.ExtensionPack.Web.WebClient>
    <Message Text="$(Out)"/>
</Target>

As mentioned in a different answer, WebClient does not appear to have the capability to download from a secure (password protected) web server.

正如其他答案所述,WebClient似乎无法从安全(受密码保护的)Web服务器下载。