I am using TFS2018 api and I am trying to to retrieve the zip file of a solution but I always get an internal server error.
internal async Task<bool> GetSourceZipFile(string sourceVersionId)
{
using (var handler = new HttpClientHandler { Credentials = new NetworkCredential(tfsUser, tfsPass) })
using (var client = new HttpClient(handler))
{
try
{
client.BaseAddress = new Uri(tfsServer);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
var tempFolder = "c:\\temp\\test";
tempFolder = HttpUtility.UrlEncode(tempFolder);
var url = $"DefaultCollection/_api/_versioncontrol/itemContentZipped?path={tempFolder}&version={sourceVersionId}";
using (var file = await client.GetStreamAsync(url).ConfigureAwait(false))
using (var memoryStream = new MemoryStream())
{
await file.CopyToAsync(memoryStream);
var s = memoryStream.ToArray();
var f = s;
};
}
catch (Exception ex)
{
// LOGGING
}
return true;
}
}
I am not sure if the zip file is generated by the TFS server. Do I need to set it specifically? Any idea why this is not working?
You're passing in a local folder to the path parameter in the REST API. The path should be to the item in source control (ex: $/MyTeamProject/DEV/SomeCode), not to the local file system.
Related
Let me preface by stating that I' somewhat new to dealing with zipping/unzipping/reading/reading files. That being said, I'm doing a PoC that will retrieve data via api and write the responses to a database. The response is a zip file and inside this zip is the json data I will be reading and writing to the database.
I'm having some trouble unzipping and reading the information. Please find the code below:
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(baseUrl),
Headers =
{
{ "X-API-TOKEN", apiKey },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
// here is where I am stuck - not sure how I would unzip and read the contents
}
Thanks
Assuming you actually have a .zip file, you don't need a MemoryStream, you just need to pass the existing stream to ZipArchive
static HttpClient client = new HttpClient(); // always keep static client
async Task GetZip()
{
using var request = new HttpRequestMessage(HttpMethod.Get, new Uri(baseUrl))
{
Headers = {
{ "X-API-TOKEN", apiKey },
},
};
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using var stream = await response.Content.ReadAsStreamAsync();
await ProcessZip(stream);
}
async Task ProcessZip(Stream zipStream)
{
using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);
foreach (var file in zip.Entries)
{
using var entryStream = file.Open();
await ....; // do stuff here
}
}
You can convert body to a byte array and then unzip it using MemoryStream.
byte[] bytes = Encoding.ASCII.GetBytes(body);
using (var mso = new MemoryStream(bytes)) {
using (var gs = new GZipStream(msi, CompressionMode.Decompress)) {
CopyTo(gs, mso);
}
return Encoding.UTF8.GetString(mso.ToArray());
}
I am building an C# Console Application for GET file which will automatically download the file when I run the console application.
These are my codes:
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace WebAPIConsoleNEW
{
class Program
{
static void Main(string[] args)
{
RunAsync().Wait();
}
static async Task RunAsync()
{
string bookPath_Pdf = #"D:\VisualStudio\randomfile.pdf";
string bookPath_xls = #"D:\VisualStudio\randomfile.xls";
string bookPath_doc = #"D:\VisualStudio\randomfile.docx";
string bookPath_zip = #"D:\VisualStudio\randomfile.zip";
string format = "pdf";
string reqBook = format.ToLower() == "pdf" ? bookPath_Pdf : (format.ToLower() == "xls" ? bookPath_xls : (format.ToLower() == "doc" ? bookPath_doc : bookPath_zip));
string fileName = "sample." + format.ToLower();
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:49209/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("applicaiton/json"));
Console.WriteLine("GET");
//converting Pdf file into bytes array
var dataBytes = File.ReadAllBytes(reqBook);
//adding bytes to memory stream
var dataStream = new MemoryStream(dataBytes);
//send request asynchronously
HttpResponseMessage response = await client.GetAsync("api/person");
response.Content = new StreamContent(dataStream);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = fileName;
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
//Check that response was successful or throw exception
//response.EnsureSuccessStatusCode();
//Read response asynchronously and save asynchronously to file
if (response.IsSuccessStatusCode)
{
using (var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:49209/api"))
{
using (
Stream contentStream = await (await client.SendAsync(request)).Content.ReadAsStreamAsync(),
fileStream = new FileStream("D:\\VisualStudio\\randomfile.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
//copy the content from response to filestream
await response.Content.CopyToAsync(fileStream);
//Console.WriteLine();
}
}
}
}
catch (HttpRequestException rex)
{
Console.WriteLine(rex.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
When I run another ASP.NET application which is my localhost, it only return the default which is value1 and value2 in the Controller. However, I do not have Controller in C# Console Application. I think I just one step away, I had successfully obtain the file and CopyToAsync the file I wanted to download.
Conclusion:
I want when user runs the application it would straight download the file in a place (or can I use SaveFileDialog to let user decide where to save the file).
Please help thanks
Update:
At first, I created a ASP.NET Web Application and Create a PersonController and I run the Project. After that I created a console C# Application and then I want to achieve the result of when user runs the console C# Application it would straight download the file to a specific place.
In the first get I uses api/person, and I convert the file int o bytes array and add the bytes array to memory stream. After that, I don't really know what I'm doing is right or wrong. I saw something like CopyToAsync is working then I tried it and implement it but it won't works. My goal is simple I just want to acheive once I run the C# Console application it would straight download the file from a specific localhost address
Well I think your problem is that you are sending two GET requests, in case you just want to call api/student then save the response into a file then no need for the second request
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:49209/api")//no need for it
So your code should be like this:
static async Task RunAsync()
{
string bookPath_Pdf = #"D:\VisualStudio\randomfile.pdf";
string bookPath_xls = #"D:\VisualStudio\randomfile.xls";
string bookPath_doc = #"D:\VisualStudio\randomfile.docx";
string bookPath_zip = #"D:\VisualStudio\randomfile.zip";
string format = "pdf";
string reqBook = format.ToLower() == "pdf" ? bookPath_Pdf : (format.ToLower() == "xls" ? bookPath_xls : (format.ToLower() == "doc" ? bookPath_doc : bookPath_zip));
string fileName = "sample." + format.ToLower();
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:49209/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("applicaiton/json"));
Console.WriteLine("GET");
//converting Pdf file into bytes array
var dataBytes = File.ReadAllBytes(reqBook);
//adding bytes to memory stream
var dataStream = new MemoryStream(dataBytes);
//send request asynchronously
HttpResponseMessage response = await client.GetAsync("api/person");
response.Content = new StreamContent(dataStream);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = fileName;
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
//Check that response was successful or throw exception
//response.EnsureSuccessStatusCode();
//Read response asynchronously and save asynchronously to file
if (response.IsSuccessStatusCode)
{
using (Stream contentStream = await response.Content.ReadAsStreamAsync())
{
using (fileStream = new FileStream("D:\\VisualStudio\\randomfile.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
//copy the content from response to filestream
await response.Content.CopyToAsync(fileStream);
//Console.WriteLine();
}
}
}
}
}
catch (HttpRequestException rex)
{
Console.WriteLine(rex.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Also it would be good to print a message for the user telling him that logging data from server into file(File path) is in progress:
static void Main(string[] args)
{
Console.WriteLine("Logging data from server into file (D:\\VisualStudio\\randomfile.pdf");
RunAsync().Wait();
}
Bot Builder SDK 4 (dotnet) How to work with attachments ? I tried to use the example of BotBuilder-Samples 15.handling-attachments, but got 401 Unauthorized error with Skype channel.
foreach (var file in activity.Attachments)
{
// Determine where the file is hosted.
var remoteFileUrl = file.ContentUrl;
// Save the attachment to the system temp directory.
var localFileName = Path.Combine(Path.GetTempPath(), file.Name)
// Download the actual attachment
using (var webClient = new WebClient())
{
webClient.DownloadFile(remoteFileUrl, localFileName); <-- 401 here
}
I have discovered solution at github.com discussion Skype Can not receive attachment? #3623 which I also have just tested with success.
I see minimal modification to your code sample as follows:
string channelToken = null;
if ((activity.ChannelId.Equals("skype", StringComparison.InvariantCultureIgnoreCase))
{
var credentials = new MicrosoftAppCredentials(youBotAppId, yourBotAppPassword);
channelToken = await credentials.GetTokenAsync();
}
foreach (var file in activity.Attachments)
{
// Determine where the file is hosted.
var remoteFileUrl = file.ContentUrl;
// Save the attachment to the system temp directory.
var localFileName = Path.Combine(Path.GetTempPath(), file.Name)
// Download the actual attachment
using (var webClient = new WebClient())
{
if (!string.IsNullOrWhiteSpace(channelToken))
{
webClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", channelToken);
}
webClient.DownloadFile(remoteFileUrl, localFileName);
}
I am doing kind of a proxy. A client uploads file to Web API method, this web API method sends file to some other HTTP location. I have this code:
[HttpPost]
public async Task mPost(string id)
{
var provider = new MultipartMemoryStreamProvider();
var r = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(async t =>
{
var file = provider.Contents.First();
var buffer = await file.ReadAsByteArrayAsync();
var stream = new MemoryStream(buffer);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.ExpectContinue = false;
using (var content = new StreamContent(stream))
{
using (var req = new HttpRequestMessage(HttpMethod.Put, "target_url"))
{
req.Content = content;
using (HttpResponseMessage resp = client.SendAsync(req).Result)
{
resp.EnsureSuccessStatusCode();
}
}
}
}
});
It works, but what i don't like is that at some point (var buffer = await file.ReadAsByteArrayAsync();) I have all file data in server's memory.
How to transfer data directly from input stream to output without keeping it in memory buffer?
I have a WebApi application whose intent is to serve up audio files, located within the application. They are stored in the app_data/audio folder.
Here is my method of retrieval:
public HttpResponseMessage Get(string file)
{
var path = String.Format("{0}{1}", HttpContext.Current.Server.MapPath(#"~/App_Data/Audio/"), file);
try
{
var responseStream = new MemoryStream();
using (Stream fileStream = File.Open(path, FileMode.Open))
{
fileStream.CopyTo(responseStream);
fileStream.Close();
responseStream.Position = 0;
}
var response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StreamContent(responseStream)
};
response.Content.Headers.Add("content-type", "audio/basic");
response.Headers.CacheControl = new CacheControlHeaderValue()
{
Private = true
};
response.Content.Headers.Expires = null;
response.Headers.Pragma.Clear();
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = file
};
return response;
}
catch (Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, e.Message);
}
}
Unfortunately, I get this error:
"Access to the path 'F:\Apps\AudioServeup\App_Data\Audio\test.pcm' is denied."
I can resolve this by setting the AppPool identity to NetworkService, then giving NetworkService Write Access. Huh? Not sure why I would require that, because NetworkService has read access by default.
Any ideas?
Thanks!
Try File.OpenRead( instead of File.Open( as that will ensure it only requests read access when opening the file.