I am trying work out the correct & best way to deserialize the response from a Asp.Net Web Api method that returns byte[].
The Web Api method looks like this
public IHttpActionResult Get()
{
byte[] content = GetContent();
return Ok(content);
}
I am calling the endpoint
string content;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
HttpResponseMessage response = await client.GetAsync("api/v1/thecorrectpath");
if (response.IsSuccessStatusCode)
{
content = await response.Content.ReadAsStringAsync();
}
}
When I read the response into content it is in the format below
<base64Binary xmlns="http://schemas.microsoft.com/2003/10/Serialization/">SfSEjEyNzE9MNgMCD2a8i0xLjcNJeLjzC...R4Cg==</base64Binary>
What would be a best practice way to convert this response into a byte[]?
I would use json.net for this.
Web API:
public string Get()
{
byte[] content = GetContent();
var data = JsonConvert.SerializeObject(content);
return data;
}
Client:
private static async Task GetData()
{
string content;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:23306/");
client.DefaultRequestHeaders.Accept.Clear();
HttpResponseMessage response = await client.GetAsync("home/get");
if (response.IsSuccessStatusCode)
{
content = await response.Content.ReadAsStringAsync();
var data = JsonConvert.DeserializeObject<byte[]>(content);
}
}
}
You can return binary data from a Web Api method.
The ms object is a memory stream
You might want to set a more specific ContentType
On the server:
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(ms.ToArray());
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;
Then on the client:
response.Content.ReadAsByteArrayAsync();
First, install nuget package Microsoft.AspNet.WebApi.Client ;
Then use the generic extension method of http content:
c#
var result = await response.Content.ReadAsAsync<byte[]>();
It should works!
Related
I am not getting any response - no error, no bad request status, etc. - when I send a post request to this API route. postData is simply a JSON object. The funny thing here is this: When i send post data as a string instead of an object, I can get a response.
View the code below:
[HttpPost]
[Route("api/updateStaffs/")]
public async Task<object> UpdateStaff([FromBody] object postData)
{
string _apiUrl = "http://localhost:5000/system/getToken";
string _baseAddress = "http://localhost:5000/system/getToken";
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var responseMessage = await client.PostAsync(_apiUrl, new StringContent(postData.ToString(), Encoding.UTF8, "application/json"));
if (responseMessage.IsSuccessStatusCode)
{
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = responseMessage.Content;
return ResponseMessage(response);
}
}
return NotFound();
}
No response:
var postData = new {
user = "test"
pass = "hey"
};
var responseMessage = await client.PostAsync(_apiUrl, new StringContent(postData.ToString(), Encoding.UTF8, "application/json"));
OR
var responseMessage = await client.PostAsync(_apiUrl, new StringContent("{}", Encoding.UTF8, "application/json"));
Will get response:
var responseMessage = await client.PostAsync(_apiUrl, new StringContent("blahblah", Encoding.UTF8, "application/json"));
The receiving API is a third-party application so I am unable to verify if this error is on the other end.
Thanks.
If you dont want to use PostAsJsonAsync
You need to serialize your anonymous type to JSON, the most common tool for this is Json.NET
var jsonData = JsonConvert.SerializeObject(postData);
Then you need to construct a content object to send this data, here we can use ByteArrayContent but you can use a different type
var buffer = System.Text.Encoding.UTF8.GetBytes(jsonData);
var byteContent = new ByteArrayContent(buffer);
Then send the request
var responseMessage = await client.PostAsync(_apiUrl, byteContent);
Figured out the issue. Have to use HttpVersion10 instead of HttpVersion11.
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;
}
I'm trying to access a rest endpoint, https://api.planet.com/auth/v1/experimental/public/users/authenticate. It is expecting json in the request body.
I can get the request to work in Postman but not using c#. Using postman I get the expected invalid email or password message but with my code I get "Bad Request" no matter I try.
Here is the code that makes the request
private void Login()
{
try
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://api.planet.com/");
client.DefaultRequestHeaders.Accept.Clear();
//ClientDefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
Data.User user = new Data.User
{
email = "myemail#company.com",
password = "sdosadf"
};
var requestMessage = JsonConvert.SerializeObject(user);
var content = new StringContent(requestMessage, Encoding.UTF8, "application/json");
var response = client.PostAsync("auth/v1/experimental/public/users/authenticate", content).Result;
Console.WriteLine(response.ToString());
}
catch (WebException wex )
{
MessageBox.Show(wex.Message) ;
}
}
class User
{
public string email;
public string password;
}
Here are screen grabs form Postman that are working
The way to get this to work was to alter the content header "content-type". By default HTTPClient was creating content-type: application/json;characterset= UTF8. I dropped and recreated the content header without the characterset section and it worked.
content.Headers.Remove("Content-Type");
content.Headers.Add("Content-Type", "application/json");
The issue is you are trying to call an async method without waiting for the response using await method or var task = method; task.Wait() Therefore, when you end up doing response.ToString() it returns the text you are seeing.
One way to handle this within a non-async method would be to do the following:
var task = client.PostAsync("auth/v1/experimental/public/users/authenticate", content);
task.Wait();
var responseTask = task.Content.ReadAsStringAsync();
responseTask.Wait();
Console.WriteLine(responseTask.Result);
Another way is to make the current method async by doing private async void Login() and then do:
var postResp = await client.PostAsync("auth/v1/experimental/public/users/authenticate", content);
var response = await postResp.Content.ReadAsStringAsync();
Console.WriteLine(response);
Create a Method Like this...
static async Task<string> PostURI(Uri u, HttpContent c)
{
var response = string.Empty;
var msg = "";
using (var client = new HttpClient())
{
HttpResponseMessage result = await client.PostAsync(u, c);
msg = await result.Content.ReadAsStringAsync();
if (result.IsSuccessStatusCode)
{
response = result.StatusCode.ToString();
}
}
return response;
}
call In your Method
public void Login()
{
string postData ="{\"email\":\"your_email\",\"password\":\"your_password\"}";
Uri u = new Uri("yoururl");
var payload = postData;
HttpContent c = new StringContent(payload, Encoding.UTF8,"application/json");
var t = Task.Run(() => PostURI(u, c));
t.Wait();
Response.Write(t.Result);
}
I am trying to call the webapi using httpclient. but it's not recognizing method and always throw 404 error.
My api Action method is like this.
[Route("AddEmployee")]
[HttpPost]
public async Task<IActionResult> PostTEmployee([FromBody]Employee emp)
{ // doing something here}
And the calling method is like below
using (var httpClient = new HttpClient())
{i
String BaseUrl = "http://ip:port/";
httpClient.BaseAddress = new Uri(BaseUrl);
AuthenticationHeaderValue parsedAuthToken = null;
bool authParsed = AuthenticationHeaderValue.TryParse(authToken, out parsedAuthToken);
if (authParsed)
{
httpClient.DefaultRequestHeaders.Authorization = parsedAuthToken;
}
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string serialisedData = JsonConvert.SerializeObject(emp);
HttpContent content = new StringContent(serialisedData, Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
response = await httpClient.PostAsync("AddEmployee", content);
if (response.IsSuccessStatusCode)
{
}
}
I am stuck with this issue from 2 days. Not sure what is the mistake? please help me.
Totally a wild guess but is your endpoint /api/AddEmployee not /AddEmployee?
try changing
response = await httpClient.PostAsync("AddEmployee", content);
To
response = await httpClient.PostAsync("api/AddEmployee", content);
I have the following WebAPI client code in an MVC 6 project:
public async Task<Blog> GetData()
{
Blog result = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:55792/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// New code:
HttpResponseMessage response = await client.GetAsync("api/values/1");
if (response.IsSuccessStatusCode)
{
result = await response.Content.???;
return result;
}
}
return result;
}
I can't use it, as the DNX core does not support WebAPI.Client NuGet package (which contains ReadAsync<MyClass>()) so I have to use System.Net.Http.
It has only 3 reading functions:
ReadAsByteArrayAsync
ReadAsStreamAsync
ReadAsStringAsync
None of them can read an arbitrary typed object.
What should I use now?
You can deserialize the JSON, Newtonsoft is one popular library:
...
string payload = await response.Content.ReadAsStringAsync();
var obj = JsonConvert.DeserializeObject<MyClass>(payload);
...
Not tested code, but completed code here with download option
public ActionResult Part2()
{
List<Employee> list = new List<Employee>();
HttpClient client = new HttpClient();
var result = client.GetAsync("http://localhost:1963/api/Example").Result;
if (result.IsSuccessStatusCode)
{
list = result.Content.ReadAsAsync<List<Employee>>().Result;
}
return View(list);
}