Image blank when handling image from web api - c#

I have 2 web apiĀ“s. One that connects to the DB and get the data (webapi 2). And another that just handle this data and send to the Client side (webapi 1).
The problem is that when is a string, the handle Works. But with the image is not working. I am getting the general internal server error 500.
If i call just the WebApi 2, I get the image. If I call the WebApi 1 that calls the webapi 2, the image is blank.
My Web Api Handler:
[HttpGet]
[Route("Foto")]
public async Task<HttpResponseMessage> GetFoto(string suspid, string pk)
{
HttpClientHandler handler = new HttpClientHandler()
{
UseDefaultCredentials = true,
};
using (var client = new HttpClient(handler))
{
//QUANDO TESTAR NO SERVIDOR
client.BaseAddress = new Uri("http://192.111.56.1:1762/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("image/jpeg"));
HttpResponseMessage response = await client.GetAsync("api/Nomes/Foto?suspid="+suspid+"&pk="+pk+"");
if (response.IsSuccessStatusCode)
{
var data = response.Content.ReadAsByteArrayAsync().Result;
var stream = new MemoryStream(data);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
return response;
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
return null;
}
}
}
The Web Api that connects to the DB:
I am hiding the connect string and other stuff that doesn't matter.
cmd.InitialLONGFetchSize = -1;
var reader = cmd.ExecuteReader();
byte[] imgBytes = null;
if (reader.Read())
{
// Fetch the LONG RAW
OracleBinary imgBinary = reader.GetOracleBinary(0);
// Get the bytes from the binary obj
imgBytes = imgBinary.IsNull ? null : imgBinary.Value;
}
connection.Close();
connection.Dispose();
try
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new MemoryStream(imgBytes);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
return result;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.Gone);
}

Related

Can we send a memory stream object with web API?

I have one memory stream object in my server-side, this object should be accessible in another party, which I call it a client or a consumer for my API.
In server-side I have a method like this (parameters.Save is related to a third-party library)
public MemoryStream GetSerializedParameters()
{
var parameters = GetParameters();
MemoryStream memory = new MemoryStream();
parameters.Save(memory);
return memory;
}
I'm thinking about sending this memory stream to a client with web API, so my action is something like this:
[HttpGet("parameters")]
public HttpResponseMessage GetParameters()
{
var stream = _server.GetSerializedParameters();
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = stream.Length;
return result;
}
I'm not sure if it is the right way and this implementation is correct because I am in trouble to consume it:
I do not know which method of httpClient I have to use: ReadAsStreamAsync() or anything else, because I could not find anything to work
Sure you can:
[HttpGet]
public async Task Get()
{
var randomString = "thisIsCool";
var randomStringBytes = Encoding.UTF8.GetBytes(randomString);
using (var ms = new MemoryStream(randomStringBytes))
{
await ms.CopyToAsync(this.Response.Body);
}
Based on my under standing below code may help you:
WEB API:
[HttpGet]
public HttpResponseMessage ReadToStream(HttpRequestMessage requestMessage)
{
var streamObj = _server.GetSerializedParameters();
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new StreamContent(streamObj);
requestMessage.RegisterForDispose(streamObj);
response.StatusCode = HttpStatusCode.OK;
return response;
}
Client Side
public async Task<string> DownloadFile(string guid)
{
var fileInfo = new FileInfo($"{guid}.txt");
var response = await _httpClient.GetAsync($"{url}/api/fileDownloadAPI?guid={guid}");
response.EnsureSuccessStatusCode();
await using var ms = await response.Content.ReadAsStreamAsync();
await using var fs = File.Create(fileInfo.FullName);
ms.Seek(0, SeekOrigin.Begin);
ms.CopyTo(fs);
return fileInfo.FullName;
}
I found the solution like this:
here is in server side:
[HttpGet("parameters")]
public IActionResult GetParameters()
{
var stream = _server.GetSerializedParameters();
stream.Seek(0, SeekOrigin.Begin);
return File(stream, MediaTypeNames.Text.Plain, "parameters.txt");
}
and here is in client-side:
public MemoryStream StoreParameters()
{
var request =new HttpRequestMessage
{
RequestUri = new Uri("https://localhost:44316/api/parameters"),
Method = HttpMethod.Get
};
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var result = _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result;
var ms = new MemoryStream();
result.Content.CopyToAsync(ms).Wait();
return result.IsSuccessStatusCode ? ms: null;
}

Upload a list of images of type UIImage (Xamarin)

My app will retrieve a list of all images from a specific folder and attempt to upload them to a server via an API endpoint
Due to the above requirements, an image picker is not suited
Below is the method in the shared code that is passed a list of UIImages (I am trying to get it to work with just ios for now but the same scenario will eventually be applied to Android also)
The below does not work, as when I view the image on the server(AWS), it is in code format. It also says the content type is application/json on the server which I don't understand as I'm setting it to image/png
private async Task UploadImages(List<UIImage> images)
{
HttpClient client = new HttpClient();
var contentType = new MediaTypeWithQualityHeaderValue("image/png");
client.DefaultRequestHeaders.Accept.Add(contentType);
client.DefaultRequestHeaders.Add("Id-Token", Application.Current.Properties["id_token"].ToString());
foreach (var image in images)
{
try
{
string baseUrl = $"https://********/dev/ferret-test/media/team1/user1/device1/test1.png";
client.BaseAddress = new Uri(baseUrl);
//UploadModel uploadModel = new UploadModel
//{
// image_file = image.AsPNG()
//};
byte[] bArray = null;
Stream pst = image.AsPNG().AsStream();
using (MemoryStream ms = new MemoryStream())
{
ms.Position = 0;
pst.CopyTo(ms);
bArray = ms.ToArray();
}
//string stringData = JsonConvert.SerializeObject(bArray);
//var contentData = new StringContent(stringData,
//System.Text.Encoding.UTF8, "image/png");
//Byte[] myByteArray = new Byte[imageData.Length];
//System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, myByteArray, 0, Convert.ToInt32(imageData.Length));
var postRequest = new HttpRequestMessage(HttpMethod.Put, baseUrl)
{
Content = new ByteArrayContent(bArray)
};
var response = await client.SendAsync(postRequest);
response.EnsureSuccessStatusCode();
string stringJWT = response.Content.ReadAsStringAsync().Result;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
I archived uploading multiple files to the server by using the following snippet, you can give it a try...
foreach (SQLiteAccess.Tables.Image image in images.OrderByDescending(x => x.Id)) //Here is the collection of all the file at once (Documents + Images)
{
int documentId = UploadImageToServerAndroid(image).Result;
// My other code implementation
.
.
.
}
private async Task<int> UploadImageToServerAndroid(SQLiteAccess.Tables.Image image)
{
int documentId = 0;
if (!Admins.ConnectedToNetwork()) return documentId;
MyFile = FileSystem.Current.GetFileFromPathAsync(image.Path).Result;
if (MyFile == null) return documentId;
Stream stream = MyFile.OpenAsync(FileAccess.Read).Result;
byte[] byteArray;
byteArray = new byte[stream.Length];
stream.Read(byteArray, 0, (int)stream.Length);
if( !image.IsDocument )
{
try
{
byteArray = DependencyService.Get<IImageUtilities>().CompressImage(byteArray); //Its custom code to compress the Image.
}
catch (Exception ex)
{
UoW.Logs.LogMessage(new LogDTO { Message = ex.Message, Ex = ex });
}
}
string url = "Your URL";
using (HttpClient client = new HttpClient(new RetryMessageHandler(new HttpClientHandler())))
{
try
{
client.DefaultRequestHeaders.Add(Properties.Resources.Authorization, Sessions.BearerToken);
client.DefaultRequestHeaders.Add("DocumentSummary", image.Comment);
client.DefaultRequestHeaders.Add("DocumentName", Path.GetFileName(image.Path));
MultipartFormDataContent multiPartContent = new MultipartFormDataContent();
ByteArrayContent byteContent = new ByteArrayContent(byteArray);
byteContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
multiPartContent.Add(byteContent, "image", Path.GetFileName(image.Path));
HttpResponseMessage response = await client.PostAsync(url, multiPartContent);
if (response.IsSuccessStatusCode && response.Content != null)
{
string jsonString = response.Content.ReadAsStringAsync().Result;
DocumentDTO result = JsonConvert.DeserializeObject<DocumentDTO>(jsonString);
documentId = result.DocumentId;
}
}
catch(Exception ex)
{
UoW.Logs.LogMessage( new LogDTO { Message = ex.Message, Ex = ex });
return documentId;
}
}
return documentId;
}
If documentid is 0(if something went wrong, for any of reason), it's marked as not uploaded & will try to upload it again when the internet is available.
If you need some more help, you can ask...:)
You could try to use MultipartFormDataContent and set content type to application/octet-stream.
You could refer the two links one and two.

How to post file and data to api using httpclient

I am at learning phase and i want to post file and data to api using httpclient.
i have tried this.
Here is my controller code
string baseUrl = ServerConfig.server_path + "/api/Payment/AddMedicineOrder";
Dictionary parameters = new Dictionary();
parameters.Add("username",user.Username);
parameters.Add("FullName", FullName);
parameters.Add("Phone", Phone);
parameters.Add("CNIC", CNIC);
parameters.Add("address", address);
parameters.Add("Email", Email);
parameters.Add("dateofbirth", dateofbirth.ToShortDateString());
parameters.Add("Gender", Gender);
parameters.Add("PaymentMethod", PaymentMethod);
parameters.Add("Title", Title);
parameters.Add("PhramaList", medList);
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://localhost:44391/");
MultipartFormDataContent form = new MultipartFormDataContent();
HttpContent content = new StringContent("fileToUpload");
HttpContent DictionaryItems = new FormUrlEncodedContent(parameters);
form.Add(content, "fileToUpload");
form.Add(DictionaryItems, "medicineOrder");
var stream = PostedPrescription.InputStream;
content = new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "fileToUpload",
FileName = PostedPrescription.FileName
};
form.Add(content);
var response =await client.PostAsync("/api/Payment/AddMedicineOrder", form);
var k =response.Content.ReadAsStringAsync().Result;
How to pass this in Web api Method
[HttpPost]
public async Task<API> AddMedicineOrder()//string key, [FromUri]MedicineOrder medicineOrder
{
var request = HttpContext.Current.Request;
bool SubmittedFile = (request.Files.Count != 0);
this.Request.Headers.TryGetValues("medicineOrder", out IEnumerable<string> somestring);
var k = somestring;
return OK("Success");
}
catch (Exception ex)
{
return InternalServerError("Technical Error.");
}
please help me. Thanks in advance
You need to support add multipart/form-data support to your web api. For this you can add custom media type formatter which will read your json content, as well as file content and you can bind that to a concrete model directly.

Upload file to Pushbullet in Windows 10 app c#

I'm currently using Pushbullet API and need to upload a file.
I can successfully get an upload url as specified in the docs using this method:
public static async Task<Uploads> GetUploadUrl(string file_name, string file_type)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var json = new JObject
{
["file_name"] = file_name,
["file_type"] = file_type
};
var result = await client.PostAsync(new Uri(_uploadUrl, UriKind.RelativeOrAbsolute), new HttpStringContent(json.ToString(), UnicodeEncoding.Utf8, "application/json"));
if (result.IsSuccessStatusCode)
{
var textresult = await result.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Uploads>(textresult);
}
}
return null;
}
The problem is when I try to upload the file. I'm currently using this method:
public static async Task<bool> UploadFile(StorageFile file, string upload_url)
{
try
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
if (file != null)
{
var streamData = await file.OpenReadAsync();
var bytes = new byte[streamData.Size];
using (var dataReader = new DataReader(streamData))
{
await dataReader.LoadAsync((uint)streamData.Size);
dataReader.ReadBytes(bytes);
}
var streamContent = new ByteArrayContent(bytes);
content.Add(streamContent);
}
client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var response = await client.PostAsync(new Uri(upload_url, UriKind.Absolute), content);
if (response.IsSuccessStatusCode)
return true;
}
catch { return false; }
return false;
}
but I get a Http 400 error. What's the right way to upload a file using multipart/form-data in a UWP app?
HTTP 400 error indicates Bad Request, it means the request could not be understood by the server due to malformed syntax. In the other word, the request sent by the client doesn't follow server's rules.
Let's look at the document, and we can find in the example request it uses following parameter:
-F file=#cat.jpg
So in the request, we need to set the name for the uploaded file and the name should be "file". Besides, in this request, there is no need to use access token. So you can change your code like following:
public static async Task<bool> UploadFile(StorageFile file, string upload_url)
{
try
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
if (file != null)
{
var streamData = await file.OpenReadAsync();
var bytes = new byte[streamData.Size];
using (var dataReader = new DataReader(streamData))
{
await dataReader.LoadAsync((uint)streamData.Size);
dataReader.ReadBytes(bytes);
}
var streamContent = new ByteArrayContent(bytes);
content.Add(streamContent, "file");
}
//client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var response = await client.PostAsync(new Uri(upload_url, UriKind.Absolute), content);
if (response.IsSuccessStatusCode)
return true;
}
catch { return false; }
return false;
}
Then your code should be able to work. You will get a 204 No Content response and UploadFile method will return true.

WebApi file download has frozen the browser for the first time

I am using WebAPI for downloading a .pdf file like this:
[HttpGet]
public async Task<HttpResponseMessage> DownloadFile(string id, bool attachment = true)
{
HttpResponseMessage result = null;
try
{
MyService service = new MyService();
var bytes = await service.DownloadFileAsync(id);
if (bytes != null)
{
result = GetBinaryFile(personalDocument, string.Format("{0}.pdf", id), attachment);
}
else
{
result = new HttpResponseMessage(HttpStatusCode.NotFound);
}
}
catch (Exception ex)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = "ServerError" });
}
return result;
}
private HttpResponseMessage GetBinaryFile(byte[] bytes, string fileName, bool attachment)
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
// result.Content = new ByteArrayContent(bytes);
result.Content = new StreamContent(new System.IO.MemoryStream(bytes));
//result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline");
if (attachment)
{
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
}
result.Content.Headers.ContentDisposition.FileName = fileName;
result.Content.Headers.ContentLength = bytes.Length;
return result;
}
The issue is: when I download file for the first time it freezes the browser, and cannot perform anything. But after a refresh of the page, every time the file download is successful.
I tried to use ByteArrayContent or StreamContent but same thing happens. I also tried to use MediaTypeHeaderValue("application/octet-stream") or MediaTypeHeaderValue("application/pdf"), but again - the same issue occurred.
So I find that the problem is
if (attachment)
{
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
}
If I set attachment to be true it set ContentDisposition to be ContentDispositionHeaderValue("attachment") (it is for download only)
If I set attachment to be false it open the file immediately and doesn't freeze the browser..
Any idea? Thanks!

Categories