So I am working on writing an extension class for my project using HttpClient since I am moving over from HttpWebRequest.
When doing the POST request, how do I send a normal string as a parameter? No json or anything just a simple string.
And this is what it looks like so far.
static class HttpClientExtension
{
static HttpClient client = new HttpClient();
public static string GetHttpResponse(string URL)
{
string fail = "Fail";
client.BaseAddress = new Uri(URL);
HttpResponseMessage Response = client.GetAsync(URL).GetAwaiter().GetResult();
if (Response.IsSuccessStatusCode)
return Response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
else
return fail;
}
public static string PostRequest(string URI, string PostParams)
{
client.PostAsync(URI, new StringContent(PostParams));
HttpResponseMessage response = client.GetAsync(URI).GetAwaiter().GetResult();
string content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
return content;
}
}
If you look at this like
client.PostAsync(URI, new StringContent(PostParams));
You can see that I just tried creating new StringContent and passing a string into it and the response returned 404 page not found.
How do I properly use Post.Async(); do I send a string or byte array? Because with HttpWebRequest you would do it like this
public static void SetPost(this HttpWebRequest request, string postdata)
{
request.Method = "POST";
byte[] bytes = Encoding.UTF8.GetBytes(postdata);
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(bytes, 0, bytes.Length);
}
In the PostRequest the following is done..
client.PostAsync(URI, new StringContent(PostParams));
HttpResponseMessage response = client.GetAsync(URI).GetAwaiter().GetResult();
Which does not capture the response of the POST.
Refactor to
public static string PostRequest(string URI, string PostParams) {
var response = client.PostAsync(URI, new StringContent(PostParams)).GetAwaiter().GetResult();
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
return content;
}
HttpClient is primarily meant to be used async so consider refactoring to
public static async Task<string> PostRequestAsync(string URI, string PostParams) {
var response = await client.PostAsync(URI, new StringContent(PostParams));
var content = await response.Content.ReadAsStringAsync();
return content;
}
You need prepare object and then you will serialize the object using Newtonsoft.Json. After that you will prepare byte content from the buffer. We are using api url api/auth/login and it is not full api url as we used dependency injection and configure base address in startup, see the second code.
public async void Login(string username, string password)
{
LoginDTO login = new LoginDTO();
login.Email = username;
login.Password = password;
var myContent = JsonConvert.SerializeObject(login);
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await httpClient.PostAsync("api/auth/login", byteContent);
var contents = await response.Content.ReadAsStringAsync();
}
services.AddHttpClient<IAuthService, AuthService>(client =>
{
client.BaseAddress = new Uri("https://localhost:44354/");
});
.NET 5 Solution
In .NET 5, There is new class JsonContent and you can implement this easily
LoginDTO login = new LoginDTO();
login.Email = username;
login.Password = password;
JsonContent content = JsonContent.Create(login);
var url = "http://...";
HttpResponseMessage response = await httpClient.PostAsync(url, content);
I have worked the following (using the package Ngonzalez.ImageProcessorCore).
Query (ASP.NET Core 2 Controller):
async Task<byte[]> CreateImage(IFormFile file)
{
using (var memoryStream = new MemoryStream())
{
await file.CopyToAsync(memoryStream);
var image = new Image(memoryStream);
var height = image.Height < 150 ? image.Height : 150;
image.Resize((int)(image.Width * height / image.Height), height).Save(memoryStream);
return memoryStream.ToArray();
}
}
[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> ImageAdd(ImageAddVm vm)
{
byte[] image = null;
if (vm.File != null && vm.File.Length > 0)
image = await CreateImage(vm.File);
if (image != null)
{
var json = JsonConvert.SerializeObject(new { vm.ObjectId, image });
var content = new StringContent(json, Encoding.UTF8, "application/json");
var client= new HttpClient();
await client.PostAsync($"{ApiUrl}/SaveImage", content);
}
return RedirectToAction("ReturnAction");
}
Api (ASP.NET Core 2 Controller):
public class ObjectImage
{
public int ObjectId { get; set; }
public byte[] Image { get; set; }
}
[HttpPost("SaveImage")]
public void SaveImage([FromBody]object content)
{
var obj = JsonConvert.DeserializeObject<ObjectImage>(content.ToString());
_db.Images.Find(obj.ObjectId).Image = obj.Image;
_db.SaveChanges();
}
Related
I'd like to call a Web API in .NET 6 with httpclient. The code works fine when I return OK(result), I get the right result. The problem is when I return a BadRequest, I'd like to have access to the properties EN, FR, NL. In the HttpRequestException, I just receive the message "500 internal exception error", not the properties EN, FR, NL.
How can I do to get these values ?
[HttpPost(nameof(Testing), Name = "Testing")]
public async Task<ActionResult<MyResponseDto>> Testing(ParameterDto parameter)
{
var res = new MyResponseDto
{
//Few properties her
};
//return Ok(res);
return BadRequest(new { FR = "My Error FR", NL = "My Error NL", EN = "My Error EN" });
}
I call web api from console application doe testing purpose with this code :
in program.cs
var result = await Api.Testing();
public static class Api
{
public static async Task<string> Testing()
{
string response = await HttpRequests.Post(
"/api/Testing",
new { /* few parameter here */ });
var result = JsonConvert.DeserializeObject<MyResponseDto>(response);
}
}
public static class MyHttpRequests
{
private static readonly HttpClient client = new HttpClient();
private const string url = "myURL";
public static async Task<string> Post(string entryPoint, Object dto)
{
string url = $"{url}{entryPoint}";
string dto = JsonConvert.SerializeObject(dto);
HttpContent httpContent = new StringContent(dto, Encoding.UTF8, "application/json");
try
{
using(HttpResponseMessage response = await client.PostAsync(url, httpContent))
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
}
}
catch(HttpRequestException e)
{
Console.WriteLine($"Message :{e.Message} ");
}
return await Task.FromResult(string.Empty);
}
}
This line is throwing the exception:
response.EnsureSuccessStatusCode();
Without it, you would continue to return the response body which will contain a json representation of your error variables.
So instead of throwing an exception like this, you can manually check the response status code and parse the json. EG:
public static async Task<string> Post(string entryPoint, Object dto)
{
string url = $"{url}{entryPoint}";
string dto = JsonConvert.SerializeObject(dto);
HttpContent httpContent = new StringContent(dto, Encoding.UTF8, "application/json");
using(HttpResponseMessage response = await client.PostAsync(url, httpContent))
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string responseBody = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
return responseBody;
Console.WriteLine($"Error: {responseBody}");
}
return await Task.FromResult(string.Empty);
}
I need to post data with files but I face this problem - all data is null.
It works when I use postman:
My post function in ASP.NET Core Web API:
public async Task<ActionResult<Category>> PostCategory([FromForm]CategoryViewModel model)
{
Category category = new Category()
{
Brief = model.Brief,
Color = model.Color,
IsDraft = model.IsDraft,
Name = model.Name,
Priority = model.Priority,
Update = DateTime.Now
};
if (model.Files != null)
{
category.IconUrl = ApplicationManager.UploadFiles(model.Files, "content/category")[0];
}
_context.Categories.Add(category);
await _context.SaveChangesAsync();
return CreatedAtAction("GetCategory", new { id = category.Id }, category);
}
My post function in ASP.NET Core MVC:
private ApiClient _client;
_client = new ApiClient(new Uri("https:localhost:55436/api/"));
public async Task<IActionResult> Create([FromForm]CategoryViewModel category)
{
var uri = new Uri(_appSettings.WebApiBaseUrl + "Categories");
var response = await _client.PostAsync<Category, CategoryViewModel>(uri, category);
return RedirectToAction("index");
}
My ApiClient class:
public partial class ApiClient
{
private readonly HttpClient _httpClient;
private Uri BaseEndpoint { get; set; }
public ApiClient(Uri baseEndpoint)
{
if (baseEndpoint == null)
{
throw new ArgumentNullException("baseEndpoint");
}
BaseEndpoint = baseEndpoint;
_httpClient = new HttpClient();
}
/// <summary>
/// Common method for making GET calls
/// </summary>
public async Task<T> GetAsync<T>(Uri requestUrl)
{
addHeaders();
var response = await _httpClient.GetAsync(requestUrl, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
var data = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(data);
}
public async Task<HttpResponseMessage> PostStreamAsync(Uri requestUrl, object content)
{
using (var client = new HttpClient())
using (var request = new HttpRequestMessage(HttpMethod.Post, requestUrl))
using (var httpContent = CreateHttpContentForStream(content))
{
request.Content = httpContent;
using (var response = await client
.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)
.ConfigureAwait(false))
{
response.EnsureSuccessStatusCode();
return response;
}
}
}
public async Task<HttpResponseMessage> PostBasicAsync(Uri requestUrl, object content)
{
using (var client = new HttpClient())
using (var request = new HttpRequestMessage(HttpMethod.Post, requestUrl))
{
var json = JsonConvert.SerializeObject(content);
using (var stringContent = new StringContent(json, Encoding.UTF8, "application/json"))
{
request.Content = stringContent;
using (var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)
.ConfigureAwait(false))
{
response.EnsureSuccessStatusCode();
return response;
}
}
}
}
public static void SerializeJsonIntoStream(object value, Stream stream)
{
using (var sw = new StreamWriter(stream, new UTF8Encoding(false), 1024, true))
using (var jtw = new JsonTextWriter(sw) { Formatting = Formatting.None })
{
var js = new JsonSerializer();
js.Serialize(jtw, value);
jtw.Flush();
}
}
private static HttpContent CreateHttpContentForStream<T>(T content)
{
HttpContent httpContent = null;
if (content != null)
{
var ms = new MemoryStream();
SerializeJsonIntoStream(content, ms);
ms.Seek(0, SeekOrigin.Begin);
httpContent = new StreamContent(ms);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
return httpContent;
}
/// <summary>
/// Common method for making POST calls
/// </summary>
public async Task<T> PostAsync<T>(Uri requestUrl, T content)
{
addHeaders();
var response = await _httpClient.PostAsync(requestUrl.ToString(), CreateHttpContent<T>(content));
response.EnsureSuccessStatusCode();
var data = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(data);
}
public async Task<T1> PostAsync<T1, T2>(Uri requestUrl, T2 content)
{
addHeaders();
var response = await _httpClient.PostAsync(requestUrl.ToString(), CreateHttpContent<T2>(content));
response.EnsureSuccessStatusCode();
var data = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T1>(data);
}
public Uri CreateRequestUri(string relativePath, string queryString = "")
{
var endpoint = new Uri(BaseEndpoint, relativePath);
var uriBuilder = new UriBuilder(endpoint);
uriBuilder.Query = queryString;
return uriBuilder.Uri;
}
public HttpContent CreateHttpContent<T>(T content)
{
var json = JsonConvert.SerializeObject(content, MicrosoftDateFormatSettings);
var value = new StringContent(json, Encoding.UTF8, "application/json");
return value;
}
public static JsonSerializerSettings MicrosoftDateFormatSettings
{
get
{
return new JsonSerializerSettings
{
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
};
}
}
public void addHeaders()
{
_httpClient.DefaultRequestHeaders.Remove("userIP");
_httpClient.DefaultRequestHeaders.Add("userIP", "192.168.1.1");
}
}
If you want to post the multipart/form-data using HttpClient, you should write a separate post method using MultipartFormDataContent as HttpContent type as shown:
PostCategoryAsync
public async Task<Category> PostCategoryAsync(Uri requestUrl, CategoryViewModel content)
{
addHeaders();
var response = new HttpResponseMessage();
var fileContent = new StreamContent(content.Files.OpenReadStream())
{
Headers =
{
ContentLength = content.Files.Length,
ContentType = new MediaTypeHeaderValue(content.Files.ContentType)
}
};
var formDataContent = new MultipartFormDataContent();
formDataContent.Add(fileContent, "Files", content.Files.FileName); // file
//other form inputs
formDataContent.Add(new StringContent(content.Name), "Name");
formDataContent.Add(new StringContent(content.Brief), "Brief");
formDataContent.Add(new StringContent(content.IsDraft.ToString()), "IsDraft");
formDataContent.Add(new StringContent(content.Color), "Color");
formDataContent.Add(new StringContent(content.Priority), "Priority");
response = await _httpClient.PostAsync(requestUrl.ToString(), formDataContent);
var data = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
return JsonConvert.DeserializeObject<Category>(data);
}
MVC controller
var response = await _client.PostCategoryAsync(uri, category);
Web API
I am looking for how to cache a request in ASP.NET Core 2.x?
I have API proxy which always return a different response using the same request (synonyms composition using an AI, hence that's why I am not looking for caching the response).
And I would like to cache the request since it's always the same (always the same basic auth and parameters to poke the other API that I am proxy-ing).
Since the request use a file input.xml for the parameters, I am wondering where I can cache that one as well
My controller:
[Route("api/v1/[controller]")]
public class CompositionController : Controller
{
[HttpGet]
public async Task<string> Get(string transformation = "xml")
{
var httpClient = new HttpClient();
const string authScheme = #"Basic";
const string name = #"myUserName";
const string password = #"myPassword";
var authBytes = Encoding.ASCII.GetBytes($#"{name}:{password}");
var auth64BaseString = Convert.ToBase64String(authBytes);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, auth64BaseString);
const string fileName = #"input.xml";
var inputBytes = File.ReadAllBytes(fileName);
var byteArrayContent = new ByteArrayContent(inputBytes);
const string formDataKey = #"""file""";
const string formDataValue = #"""input.xml""";
var multipartFormDataContent = new MultipartFormDataContent()
{
{ byteArrayContent, formDataKey, formDataValue }
};
const string url = #"http://baseurl:port/my/resource/is/there.do?transformation=" + transformation;
var response = await httpClient.PostAsync(url, multipartFormDataContent);
return await response.Content.ReadAsStringAsync();
}
}
You really shouldn't be constructing an HttpClient every time the endpoint is called.
This is what I would do:
//create a service that caches HttpClient based on url
public interface IHttpClientService
{
IHttpClient GetClient(string baseHref);
void AddClient(HttpClient client, string baseHref);
}
//implement your interface
public class HttpClientService : IHttpClientService
{
private readonly ConcurrentDictionary<string, IHttpClient> _httpClients;
public HttpClientService()
{
_httpClients = new ConcurrentDictionary<string, IHttpClient>();
}
public void AddClient(HttpClient client, string baseHref)
{
_httpClients.
.AddOrUpdate(baseHref, client, (key, existingHttpClient) => existingHttpClient);
}
public IHttpClient GetClient(string baseHref)
{
if (_httpClients.TryGetValue(baseHref, out var client))
return client;
return null;
}
}
//register as singleton Startup.cs
services.AddSingleton<IHttpClientService, HttpClientService>();
//inject into Controller
[HttpGet]
public async Task<string> Get(string transformation = "xml")
{
const string url = #"http://baseurl:port/my/resource/is/there.do?transformation=" + transformation;
var httpClient = _httpService.GetClient(url);
if(httpClient == null)
{
httpClient = new HttpClient(url);
const string authScheme = #"Basic";
const string name = #"myUserName";
const string password = #"myPassword";
var authBytes = Encoding.ASCII.GetBytes($#"{name}:{password}");
var auth64BaseString = Convert.ToBase64String(authBytes);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, auth64BaseString);
const string fileName = #"input.xml";
var inputBytes = File.ReadAllBytes(fileName);
var byteArrayContent = new ByteArrayContent(inputBytes);
const string formDataKey = #"""file""";
const string formDataValue = #"""input.xml""";
var multipartFormDataContent = new MultipartFormDataContent()
{
{ byteArrayContent, formDataKey, formDataValue }
};
_httpClient.AddClient(httpClient, url);
}
else
{
//You can cache your MultipartFormDataContent in MemoryCache or same cache as HttpClient
//Get MultipartFormDataContent from cache and
}
var response = await httpClient.PostAsync(url, multipartFormDataContent);
return await response.Content.ReadAsStringAsync();
}
I am trying to move change some methods from httpwebrequest to httpclient. I have done most of the work but stuck with this one. Can someone help to achieve this.
string url = someurl;
HttpWebRequest request = CreateRequest(url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
request.ServicePoint.Expect100Continue = false;
string body = #"somestring here.";
byte[] postBytes = Encoding.UTF8.GetBytes(body);
request.ContentLength = postBytes.Length;
Stream stream = request.GetRequestStream();
stream.Write(postBytes, 0, postBytes.Length);
stream.Close();
response = (HttpWebResponse)request.GetResponse();
I need to convert this method using HttpClient.
This is what I have tried.
string url = someurl;
var client = new HttpClient();;
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));//ACCEPT header
//request.ContentType = "application/x-www-form-urlencoded";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post,url);
string body = #"somestring here...";
var content = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");
request.Content = content;
var ss = client.PostAsync(url,content).Result;
string str2 = await ss.Content.ReadAsStringAsync();
and I am not getting this part to work.
string body = #"somestring here.";
byte[] postBytes = Encoding.UTF8.GetBytes(body);
request.ContentLength = postBytes.Length;
Stream stream = request.GetRequestStream();
stream.Write(postBytes, 0, postBytes.Length);
stream.Close();
This is the sample client class which I use most of the time. You can use either PostAsync or SendAsync
public class RestClient
{
public bool IsDisposed { get; private set; }
public HttpClient BaseClient { get; private set; }
private readonly string jsonMediaType = "application/json";
public RestClient(string hostName, string token, HttpClient client)
{
BaseClient = client;
BaseClient.BaseAddress = new Uri(hostName);
BaseClient.DefaultRequestHeaders.Add("Authorization", token);
}
public async Task<string> PostAsync(string resource, string postData)
{
StringContent strContent = new StringContent(postData, Encoding.UTF8, jsonMediaType);
HttpResponseMessage responseMessage = await BaseClient.PostAsync(resource, strContent).ConfigureAwait(false);
responseMessage.RaiseExceptionIfFailed();
return await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
}
public async Task<string> SendAsync(HttpMethod method, string resource, string token, string postData)
{
var resourceUri = new Uri(resource, UriKind.Relative);
var uri = new Uri(BaseClient.BaseAddress, resourceUri);
HttpRequestMessage request = new HttpRequestMessage(method, uri);
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
if (!string.IsNullOrEmpty(postData))
{
request.Content = new StringContent(postData, Encoding.UTF8, jsonMediaType);
}
HttpResponseMessage response = BaseClient.SendAsync(request).Result;
response.RaiseExceptionIfFailed();
return await response.Content.ReadAsStringAsync();
}
protected virtual void Dispose(bool isDisposing)
{
if (IsDisposed)
{
return;
}
if (isDisposing)
{
BaseClient.Dispose();
}
IsDisposed = true;
}
public virtual void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~RestClient()
{
Dispose(false);
}
}
I am using ASP.NET Web API. I want to download a PDF with C# from the API (that the API generates).
Can I just have the API return a byte[]? and for the C# application can I just do:
byte[] pdf = client.DownloadData("urlToAPI");?
and
File.WriteAllBytes()?
Better to return HttpResponseMessage with StreamContent inside of it.
Here is example:
public HttpResponseMessage GetFile(string id)
{
if (String.IsNullOrEmpty(id))
return Request.CreateResponse(HttpStatusCode.BadRequest);
string fileName;
string localFilePath;
int fileSize;
localFilePath = getFileFromID(id, out fileName, out fileSize);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = fileName;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return response;
}
UPDATE from comment by patridge:
Should anyone else get here looking to send out a response from a byte array instead of an actual file, you're going to want to use new ByteArrayContent(someData) instead of StreamContent (see here).
I made the follow action:
[HttpGet]
[Route("api/DownloadPdfFile/{id}")]
public HttpResponseMessage DownloadPdfFile(long id)
{
HttpResponseMessage result = null;
try
{
SQL.File file = db.Files.Where(b => b.ID == id).SingleOrDefault();
if (file == null)
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{
// sendo file to client
byte[] bytes = Convert.FromBase64String(file.pdfBase64);
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new ByteArrayContent(bytes);
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = file.name + ".pdf";
}
return result;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.Gone);
}
}
Just a note for .Net Core: We can use the FileContentResult and set the contentType to application/octet-stream if we want to send the raw bytes. Example:
[HttpGet("{id}")]
public IActionResult GetDocumentBytes(int id)
{
byte[] byteArray = GetDocumentByteArray(id);
return new FileContentResult(byteArray, "application/octet-stream");
}
Example with IHttpActionResult in ApiController.
[HttpGet]
[Route("file/{id}/")]
public IHttpActionResult GetFileForCustomer(int id)
{
if (id == 0)
return BadRequest();
var file = GetFile(id);
IHttpActionResult response;
HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.OK);
responseMsg.Content = new ByteArrayContent(file.SomeData);
responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;
responseMsg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response = ResponseMessage(responseMsg);
return response;
}
If you don't want to download the PDF and use a browsers built in PDF viewer instead remove the following two lines:
responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;
You Can try , HttpClient for Download file from another side and same time you can pass as File Result
[HttpGet]
[Route("api/getFile")]
public async Task<FileResult> GetFile(string Param1,string Param2)
{
try
{
Stream stream = null;
string strURL = #"File URL";
HttpClient client = new HttpClient();
HttpResponseMessage httpResponse = await client.GetAsync(strURL);
Stream streamToReadFrom = await httpResponse.Content.ReadAsStreamAsync();
return File(streamToReadFrom, "{MIME TYPE}");
}
catch (Exception ex)
{
throw ex;
}
finally
{
}
}
I've been wondering if there was a simple way to download a file in a more ... "generic" way. I came up with this.
It's a simple ActionResult that will allow you to download a file from a controller call that returns an IHttpActionResult.
The file is stored in the byte[] Content. You can turn it into a stream if needs be.
I used this to return files stored in a database's varbinary column.
public class FileHttpActionResult : IHttpActionResult
{
public HttpRequestMessage Request { get; set; }
public string FileName { get; set; }
public string MediaType { get; set; }
public HttpStatusCode StatusCode { get; set; }
public byte[] Content { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = new HttpResponseMessage(StatusCode);
response.StatusCode = StatusCode;
response.Content = new StreamContent(new MemoryStream(Content));
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = FileName;
response.Content.Headers.ContentType = new MediaTypeHeaderValue(MediaType);
return Task.FromResult(response);
}
}
Another way to download file is to write the stream content to the response's body directly:
[HttpGet("pdfstream/{id}")]
public async Task GetFile(long id)
{
var stream = GetStream(id);
Response.StatusCode = (int)HttpStatusCode.OK;
Response.Headers.Add( HeaderNames.ContentDisposition, $"attachment; filename=\"{Guid.NewGuid()}.pdf\"" );
Response.Headers.Add( HeaderNames.ContentType, "application/pdf" );
await stream.CopyToAsync(Response.Body);
await Response.Body.FlushAsync();
}