Si está intentando descargar un archivo que requiere autenticación (como TFS Web o un servidor IIS conectado a un dominio), ni el MSBuild Extension Pack ni las tareas de comunidad de MSBuild parecen tener la capacidad de proporcionar un archivo. nombre de usuario o contraseña al servidor HTTP. En este caso, terminé escribiendo una tarea personalizada de MSBuild. Esto es lo que hice.
Seguí el consejo del usuario de Stack Overflow Doug, en su respuesta para Download a file which requires authentication using vb.net/c#?, en la que sugiere algún código para agregar a un método escrito por Tom Archer en el sitio web de Code Guru.
por lo que utiliza MS Visual Studio 2010 para crear un nuevo proyecto de C# con el siguiente código para crear un objetivo de MSBuild llamado Wget (código fuente completo se muestra):
// 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;
}
}
}
Con esto en su lugar, puedo añadir la siguiente tarea a mi proyecto de MSBuild:
<!-- Get the contents of a Url-->
<Wget
Address="http://mywebserver.com/securepage"
LocalFilename="mydownloadedfile.html"
Username="myusername"
Password="mypassword">
</Wget>
la tarea Wget descarga la página servida por mywebserver.com y lo guarda en un archivo en el directorio de trabajo actual como mydownloadedfile.html, utilizando el nombre de usuario "miusuario" y la contraseña "mi contraseña".
Sin embargo, para usar la tarea Wget MSBuild personalizada, debo decirle a MSBuild dónde encontrar el archivo de ensamblaje Wget (.dll). Esto se hace con el elemento de MSBuild:
<!-- Import your custom MSBuild task -->
<UsingTask AssemblyFile="MyCustomMSBuildTasks\Wget\bin\Release\Wget.dll" TaskName="Wget" />
Si usted desea conseguir la suposición, que incluso puede tener su proyecto MSBuild Wget antes de que se llama. Para ello, la construcción de la solución con la tarea <MSBuild Projects>
, y la importación a la tarea <UsingTaks AssemblyFile>
, algo como esto:
<!-- 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>
Si usted no ha elaborado un MSBuild objetivo personalizado antes, no es demasiado difícil - una vez usted sabe lo básico.Mire el código C arriba, eche un vistazo a la documentación oficial de MSDN y busque en la web más ejemplos. Un buen punto de partida es:
La descarga de la comunidad de communitytask ahora es compatible con la autenticación. – rasjani