I am trying to download a zip archive from Azure via REST API using this Request Url and the C# code below. The response StatusCode is 200 so I assume it is working. But the zip file does not get downloaded to my computer. What am I doing wrong?
GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repositoryId}/items?path={path}&scopePath={scopePath}&recursionLevel={recursionLevel}&includeContentMetadata={includeContentMetadata}&latestProcessedChange={latestProcessedChange}&download={download}&$format={$format}&versionDescriptor.version={versionDescriptor.version}&versionDescriptor.versionOptions={versionDescriptor.versionOptions}&versionDescriptor.versionType={versionDescriptor.versionType}&includeContent={includeContent}&resolveLfs={resolveLfs}&sanitize={sanitize}&api-version=6.0
public static void DownloadTest()
{
var repository = "myrepository";
var branch = "main";
var url = $"https://dev.azure.com/{Constants.ORGANIZATION}/{Constants.PROJECT}/_apis/git/repositories/{repository}/items?path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=0&versionDescriptor[version]={branch}&resolveLfs=true&$format=zip&api-version=6.0&download=true";
try
{
using (HttpClient httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/zip"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "", Constants.PAT))));
var response = httpClient.GetAsync(url).Result;
response.EnsureSuccessStatusCode();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Related
I am facing en enconding issue when downloading a file from Sharepoint Online by an Azure function. So I have an Azure HTTP triggered function that calls Sharepoint Online to retrieve a file and download it. Here is how I call Sharepoint:
public dynamic DownloadFile(Guid fileUniqueId)
{
const string apiUrl = "{0}/_api/web/GetFileById('{1}')/$value";
try
{
var fileInfo = GetFileInfo(fileUniqueId);
if (string.IsNullOrEmpty(_sharepointSiteUrl)) return null;
string api = string.Format(apiUrl, _sharepointSiteUrl, fileUniqueId.ToString());
string response = new TokenHelper().GetAPIResponse(api);
if (string.IsNullOrEmpty(response)) return null;
return new {
fileInfo.FileName,
Bytes = Encoding.UTF8.GetBytes(response)
};
}
catch (Exception ex)
{
throw ex;
}
}
And Here is the Azure App function that is called:
string guidString = req.Query["id"];
if (!Guid.TryParse(guidString, out var fileId))
return new BadRequestResult();
var fileManager = new FileManager();
dynamic fileData = fileManager.DownloadFile(fileId);
if (null == fileData) return new NotFoundResult();
var contentType = (((string)fileData.FileName).ToUpper().EndsWith(".PNG") || ((string)fileData.FileName).ToUpper().EndsWith(".JPEG") || ((string)fileData.FileName).ToUpper().EndsWith(".JPG")) ? "image/jpeg" : "application/octet-stream";
return new FileContentResult(fileData.Bytes, contentType)
{
FileDownloadName = fileData.FileName
};
The file is succesfully downloaded but it seems corrupted as it says that the file type is not recognised. I think that it's an issue related to encoding. Does somebody sees what I'm doing wrong ?
Your code is using UTF8.GetBytes() to try and get the file content from SharePoint Online. You should instead use the CSOM method OpenBinaryDirect() like this:
var fileRef = file.ServerRelativeUrl;
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef);
using (var fileStream = System.IO.File.Create(fileName))
{
fileInfo.Stream.CopyTo(fileStream);
}
I have an Azure Function App which is triggered by the task Invoke Azure Function in DevOps Pipeline, because the Function App is taking so long I´m using the async mode in the function and the task is configured in callback mode. That all is working fine. The issue I´m having is that when an exception is occouring in my function app, I want to send a callback to my pipeline so it fails. So it doesn´t stay in waiting for response mode. Is there a way to fail a DevOps Pipeline with a callback?
I have been using this documentation from Microsoft.
Here is some code I tried:
var body = JsonConvert.SerializeObject(new
{
status = "Cancelling",
name = "Taskfailed",
taskId = taskInstanceId.ToString(),
jobId = jobId.ToString(),
result = "failed", // also tryed fail
}) ;
PostEvent(callbackUrl, body, authToken)
The function which is sending the callback
public static void PostEvent(String callbackUrl, String body, String authToken)
{
try
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
var requestContent = new StringContent(body, Encoding.UTF8, "application/json");
var response = client.PostAsync(new Uri(callbackUrl), requestContent).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
log.LogInformation(response.StatusCode.ToString());
log.LogInformation(responseContent);
}
catch (Exception ex)
{
log.LogInformation("failed to cancel pipeline");
}
}
I have a python azure function I'm trying to integrate with a C# backend. I'm trying to upload a file from an angular front end using a c# back end to post the data.
However, I'm getting a 401 error unauthorized. My function isnt anonymous level authentication and I'm attaching the keys to the headers, but is there something I'm missing that I need to include?
I've tried adding all the authentication to the headers and the form data headers but no luck.
public HttpResponseMessage UploadPartsTemplate()
{
MultipartFormDataContent form = new MultipartFormDataContent();
Dictionary<string, string> parameters = new Dictionary<string, string>();
string baseUrl = ConfigurationManager.AppSettings["PartsProjectAPIURL"];
try
{
var fileBytes = Request.Content.ReadAsStreamAsync().Result;
client.BaseAddress = new Uri(baseUrl);
HttpContent content = new StringContent("");
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "file",
FileName = "template.xlsx"
};
content = new StreamContent(fileBytes);
form.Add(content, "template.xlsx");
form.Headers.Add("x-functions-key", ConfigurationManager.AppSettings["XFunctionsKey"]);
form.Headers.Add("Ocp-Apim-Subscription-Key", ConfigurationManager.AppSettings["OcmAPISubscriptionKey"]);
form.Headers.Add("Ocp-Apim-Trace", "true");
form.Headers.Add("command", "validate");
form.Headers.Add("code", ConfigurationManager.AppSettings["XFunctionsKey"]);
client.DefaultRequestHeaders.Add("x-functions-key", ConfigurationManager.AppSettings["XFunctionsKey"]);
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", ConfigurationManager.AppSettings["OcmAPISubscriptionKey"]);
client.DefaultRequestHeaders.Add("Ocp-Apim-Trace", "true");
client.DefaultRequestHeaders.Add("command", "validate");
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var response = client.PostAsync(baseUrl, form).Result;
return result;
}
catch(Exception ex)
{
throw;
}
}
And the POST Request in Postman works just fine. Any help would be appreciated!
Thank you!
I have a project in Azure Devops with underlying repository as git. I have a automatically created database documentation which is stored in the project repository. To keep this documentation up-to date I want to schedule an application to push the generated documentation to azure on daily basis.
Basically, check out the file, write new content & check-in. Can we do this using Azure devops rest APIs? Is there any example code that I can follow?
You can have a scheduled build using Azure Pipelines, and in the build definition you define a Powershell script that run git related git commands as ShaykiAbramczyk suggested.
Need pay attention with below if you want to run Git commands in a script:
Grant version control permissions to the build service
Allow scripts to access the system token
Merge a feature branch to master
More details please refer our official doc here-- Run Git commands in a script
Script snippet:
#Config Set
git config user.email "$(Build.RequestedForEmail)"
git config user.name "$(Build.RequestedFor)"
#Push new Branch
git -c http.extraheader="AUTHORIZATION: bearer $(System.AccessToken)" push origin master:refs/heads/my-branch
#Other command
......
This is how I have implemented the a solution to check-in content in Azure Devops Git Repo.
Below is the generic class & caller method.
class AzureDevops
{
private readonly Uri uri;
private readonly string personalAccessToken;
public AzureDevops(string orgName, string personalAccessToken)
{
this.uri = new Uri("https://dev.azure.com/" + orgName);
this.personalAccessToken = personalAccessToken;
}
public T Post<T>(dynamic body, string path)
{
if (body == null)
throw new ArgumentNullException("body");
if (path == null)
throw new ArgumentNullException("path");
T output = default(T);
using (var client = new HttpClient())
{
client.BaseAddress = uri;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", personalAccessToken);
string serl_body = JsonConvert.SerializeObject(body);
var content = new StringContent(serl_body, Encoding.UTF8, "application/json");
using (HttpResponseMessage response = client.PostAsync(path, content).Result)
{
response.EnsureSuccessStatusCode();
output = response.Content.ReadAsAsync<T>().Result;
}
}
return output;
}
public T Get<T>(string path)
{
if (path == null)
throw new ArgumentNullException("path");
T output = default(T);
using (var client = new HttpClient())
{
client.BaseAddress = uri;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", personalAccessToken);
HttpResponseMessage response = client.GetAsync(path).Result;
if (response.IsSuccessStatusCode)
output = response.Content.ReadAsAsync<T>().Result;
else
throw new ApplicationException(string.Format("Response message is not OK. Issues in action: {0}", path));
}
return output;
}
}
public class Main
{
AzureDevops azureDevops = new AzureDevops("OrgName", "PAT");
private void AddNewContent()
{
ListOfRefResponse.Root listOfRefResponse = azureDevops.Get<ListOfRefResponse.Root>(string.Format("{0}/_apis/git/repositories/{1}/refs? api-version=6.0-preview.1&filter=heads/master", "projectId", "repositoryId"));
ArrayList contentArray = new ArrayList();
contentArray.Add(new ChangesBO
{
changeType = "add",
item = new ChangeItemBO { path = string.Concat("/", Constants.BaseAzureFolder, "/", "projedctName" + "/" + "filename.md") },
newContent = new ChangeContent { content = "new text content", contentType = "rawtext" }
});
dynamic body = new
{
refUpdates = new[] { new { name = Constants.Branch, oldObjectId = listOfRefResponse.value.First().objectId } },
commits = new[] {
new {
comment = Constants.AppKeysUpdateComment,
changes = contentArray.ToArray()
}}
};
CommitSuccessBO.Root commitSuccess = azureDevops.Post<CommitSuccessBO.Root>(body, string.Format("_apis/git/repositories/{0}/pushes?api-version=5.0", "RepositoryId"));
}
}
i'm trying to download file from azure blob storage, but it returns only part of file. What i'm doing wrong ? File in storage is not corrupted
public async Task<byte[]> GetFile(string fileName)
{
var blobClient = BlobContainerClient.GetBlobClient(fileName);
var downloadInfo = await blobClient.DownloadAsync();
byte[] b = new byte[downloadInfo.Value.ContentLength];
await downloadInfo.Value.Content.ReadAsync(b, 0, (int)downloadInfo.Value.ContentLength);
return b;
}
I'm using Azure.Storage.Blobs 12.4.2 package. I tried this code and it works for me
public async Task<byte[]> GetFile(string fileName)
{
var blobClient = BlobContainerClient.GetBlobClient(fileName);
using (var memorystream = new MemoryStream())
{
await blobClient.DownloadToAsync(memorystream);
return memorystream.ToArray();
}
}
I am not able to full understand your code as the current BlobClient as of v11.1.1 does not expose any download methods. As #Guarav Mantri-AIS mentioned the readAsync can behave in that manner.
Consider an alternative using the DownloadToByteArrayAsync() which is part of the API. I have include the code required to connect but of course this is just for the purpose of demonstrating a full example.
Your method would be condensed as follows:
public async Task<byte[]> GetFile(string containerName, string fileName)
{
//i am getting the container here, not sure where or how you are doing this
var container = GetContainer("//your connection string", containerName);
//Get the blob first
ICloudBlob blob = container.GetBlockBlobReference(fileName);
//and now download it straight to a byte array
return await blobClient.DownloadAsync();
}
public CloudBlobContainer GetContainer(string connectionString, string containerName)
{
//1. connect to the account
var account = CloudStorageAccount.Parse(connectionString);
//2. create a client
var blobClient = _account.CreateCloudBlobClient();
//3. i am getting the container here, not sure where or how you are doing this
return = _blobClient.GetContainerReference(containerName);
}