Get image information Cognitve Service - Bad Request ASP.NET MVC c# - c#

I am trying to write a code about reading a list of images and get the information from it using Cognitive Service MVC.NET.
I wrote this code:
public async Task<ActionResult> Index()
{
List<string> list = await ReadImages();
return View(list);
}
private async Task<List<string>> ReadImages()
{
List<string> list = new List<string>();
string[] photoEntries = Directory.GetFiles(_photoFolder);
foreach (string photo in photoEntries)
{
list.Add(await GetCaptionAsync(photo));
}
return list;
}
private async Task<string> GetCaptionAsync(string photo)
{
using (var client = new HttpClient())
{
var queryString = HttpUtility.ParseQueryString(string.Empty);
//setup HttpClient
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", _apiKey);
queryString["visualFeatures"] = "Categories";
queryString["details"] = "Celebrities";
queryString["language"] = "en";
var uri = "https://westus.api.cognitive.microsoft.com/vision/v1.0/analyze?" + queryString;
HttpResponseMessage response;
byte[] byteData = Encoding.UTF8.GetBytes(photo);
using (var content = new ByteArrayContent(byteData))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response = await client.PostAsync(uri, content);
}
return response.Content.ToString();
}
}
the View is:
#model List<string>
#foreach (var item in Model)
{
#item
}
I am receiving an Error: 400 Bad request in the line:
response = await client.PostAsync(uri, content);
I do not know what is wrong in this code, anybody please can help me and explain a little about the problem?
thank you

If you're using c#, you'll find the official client SDK a time-saver, available also in NuGet. In addition to ready-made code to call the service, it will give you concrete types so you don't have to parse the response JSON yourself.
Anyway, your code is mostly correct, but the payload needs to be the file content in binary. So you'll want instead:
byte[] byteData = File.ReadAllBytes(photo);
Also note that you'll want to wait for the response content like this:
return await response.Content.ReadAsStringAsync();

Related

Simple Post and Get C# WPF

I have two textboxes and a button. I want to put something in textBox1, send that to a server and put the results I get back in textBox2.
I can't seem to understand sockets well enough to accomplish this. I have an address and a port.
Does anyone have just a super simple setup to do this? Everything I've found includes classes I can't even find namespaces for.
Thanks!
Here is a simple solution to get data from a website:
private static HttpClient _client = new HttpClient();
public static async Task<string> GetWebsiteDataAsync(Uri fromUri)
{
using (var msg = new HttpRequestMessage(HttpMethod.Get, fromUri))
using (var resp = await _client.SendAsync(msg))
{
resp.EnsureSuccessStatusCode();
return await resp.Content.ReadAsStringAsync();
}
}
You would then call it as so:
var websiteData = await GetWebsiteDataAsync(new Uri("https://example.com"));
Your title asked for Post as well, so here's how you'd do that (requires Newtonsoft.Json nuget package):
public static async Task<TResult> PostObjectToWebsiteAsync<TResult>(
Uri site, object objToPost)
{
using (var req = new HttpRequestMessage(HttpMethod.Post, site))
{
req.Content = new StringContent(JsonConvert.SerializeObject(objToPost),
Encoding.UTF8, "application/json");
using (var resp = await _client.SendAsync(req))
{
resp.EnsureSuccessStatusCode();
using (var s = await resp.Content.ReadAsStreamAsync())
using (var sr = new StreamReader(s))
using (var jtr = new JsonTextReader(sr))
{
return new JsonSerializer().Deserialize<TResult>(jtr);
}
}
}
}
And you could call that like this:
var objToPost = new
{
hello = "world",
value = 5
}
var postResonse = await PostObjectToWebsiteAsync<object>(
new Uri("https://example.com"), objToPost);

Can't make Post requests to Web API

So I've looked around for an answer for this but nothing I've found even comes close to solving it.
I'm trying to set up a Post method on my Web API but no matter what I do it just gives me an internal server error.
I've tried adding [FromBody] (it's a simple type).
HttpClient client {get;set;}
public APICall()
{
client = new HttpClient
{
BaseAddress = new Uri("http://localhost:1472/api/")
};
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-protobuf"));
}
public void PostTimeTaken(long timeTaken)
{
var response = client.PostAsJsonAsync("Logging", timeTaken).Result;
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.ReasonPhrase);
}
}
and then my controller action looks like this:
public void Post([FromBody] long timeTaken)
{
_api.DataBuilder.NumberOfAPICalls += 1;
_api.DataBuilder.ResponseTimes.Add(timeTaken);
}
I get no error message that could actually explain what's going on, just "Internal server error"
------SOLVED-------
Just in case anyone stumbles across this looking for the same answer, the issue was I was sending the data to the server in an incorrect format, it needed to be ProtoBuf serialised first, code snippet for anyone it might help:
public void PostToAPI(int ThingToSend)
{
using (var stream = new MemoryStream())
{
// serialize to stream
Serializer.Serialize(stream, ThingToSend);
stream.Seek(0, SeekOrigin.Begin);
// send data via HTTP
StreamContent streamContent = new StreamContent(stream);
streamContent.Headers.Add("Content-Type", "application/x-protobuf");
var response = client.PostAsync("Logging", streamContent);
Console.WriteLine(response.Result.IsSuccessStatusCode);
}
}
using (var client = new HttpClient())
{
string url = "http://localhost:7936";
client.BaseAddress = new Uri(url);
var jsonString = JsonConvert.SerializeObject(contentValue);
var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
var result = await client.PostAsync("/Api/Logger/PostActionLog", content);
string resultContent = await result.Content.ReadAsStringAsync();
}
Have you tried to convert
long timeTaken to A model like;
public class TimeModel {
public long TimeTaken {get;set;}
}
public void Post([FromBody] TimeModel time){
// Do Stuff
}
Here the code of creating a simple server
baseUrl = "http://localhost:1472/"; // change based on your domain setting
using (WebApp.Start<StartUp>(url: baseUrl))
{
HttpClient client = new HttpClient();
var resp = client.GetAsync(baseUrl).Result;
}
Here some changes in your code
var requestData = new List<KeyValuePair<string, string>> // here
{
new KeyValuePair<string, string>( "Logging",timeTaken),
};
Console.WriteLine("request data : " + requestData);
FormUrlEncodedContent requestBody = newFormUrlEncodedContent(requestData);
var request = await client.PostAsync("here pass another server API", requestBody);
var response = await request.Content.ReadAsStringAsync();
Console.WriteLine("link response : " + response);
Pls add your controller
[HttpPost] // OWIN - Open Web Interface for .NET
public HttpResponseMessage Post([FromBody] long timeTaken)
{
_api.DataBuilder.NumberOfAPICalls += 1;
_api.DataBuilder.ResponseTimes.Add(timeTaken);
return Request.CreateResponse(HttpStatusCode.OK); //Using Post Method
}

How to submit a file and some other form content to Web API using C# HttpClient

I am trying to submit a file with some KeyValuePairs.(which is id in this case) using HttpClient in C#. the File is being submitted but i cannot read the KeyValuePairs
This is my controller.
[HttpPost]
public async Task<ActionResult> Index(HttpPostedFileBase File)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:65211/");
MultipartFormDataContent form = new MultipartFormDataContent();
//Here I am adding a file to a form
HttpContent content = new StringContent("fileToUpload");
form.Add(content, "fileToUpload");
var stream = File.InputStream;
content = new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "fileToUpload",
FileName = File.FileName
};
form.Add(content);
// and here i am adding a dictionary with one keyvaluepair
Dictionary<string, string> Parameters = new Dictionary<string, string>();
Parameters.Add("id", "3");
form.Add(new FormUrlEncodedContent(Parameters));
//this will hit the api
var response = await client.PostAsync("/api/Upload", form);
var k = response.Content.ReadAsStringAsync().Result;
return View();
}
This is the Api Code
[Route("api/Upload")]
[HttpPost]
// i have tested public async Task<HttpResponseMessage> Upload(string id) <= giving parameters. the api doesnt hit if i give any
public async Task<HttpResponseMessage> Upload()
{
var request = HttpContext.Current.Request;
HttpResponseMessage result = null;
if (request.Files.Count == 0)
{
result = Request.CreateResponse(HttpStatusCode.OK, "Ok");;
}
var postedFile = request.Files[0];
return Request.CreateResponse(HttpStatusCode.OK, "Ok");
}
I am able to read the file. It gets submitted to the API. the problem is the "id" that i submitted as a keyvaluepair. I don't know how to read it. If i pass parameters to the Api. client returns the error "Not Found".
I finally was able to read both the file and the parameters I sent to the Web API. It was a simple implimentation with HttpContext.Current.Request
This is how i modified the API code.
[Route("api/Upload")]
[HttpPost]
// i have tested public async Task<HttpResponseMessage> Upload(string id) <= giving parameters. the api doesnt hit if i give any
public async Task<HttpResponseMessage> Upload()
{
var request = HttpContext.Current.Request;
var key = Request.Params["key"]; // **<- LOOK AT THIS HERE**
HttpResponseMessage result = null;
if (request.Files.Count == 0)
{
result = Request.CreateResponse(HttpStatusCode.OK, "Ok");;
}
var postedFile = request.Files[0];
return Request.CreateResponse(HttpStatusCode.OK, "Ok");
}
By using HttpContext.Current.Request.Params, I was able to read the other values from the api. Request.Files contains all the files and Request.Params contains all string parameters.

Streaming large Files using Web Api

I got a little question: I would like to stream an large array from my web API to my client. But I got a System.OutOfMemory Exception or an AggregateException.
My Api looks like this:
public List<MyLittlePony> Get()
{ return GetLittlePonys();}
And my Client looks like:
public string GetRequest(string URL)
{
using (var client = new System.Net.Http.HttpClient())
{
// HTTP POST
client.BaseAddress = new Uri(URL);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync("").Result;
string res = "";
using (HttpContent content = response.Content)
{
// ... Read the string.
Task<string> result = content.ReadAsStringAsync();
return result.Result;
}
}
If I'm dealing with a small size of Objects, everything works fine.
But the large one does not work.
I don't want to work with creating files or things like this.
I solved it by using this (Web API):
public HttpResponseMessage Get()
{
var result = GetLittlePonys();
var response = Request.CreateResponse();
response.Content =
new PushStreamContent((stream, content, context) =>
{
var serializer = new JsonSerializer();
using (var writer = new StreamWriter(stream))
{
serializer.Serialize(writer, result);
stream.Flush();
}
});
return response;
}
But now I have the Problem that it takes over 1 minute to transfer about 60000 elements. And this is too long for my client. Can Someone help?

C#: Error when HttpClient reponse

I am doing HTTP get request using HttpClient in C# console app . I am not getting expected response with one get request.
Get Request is like
http://example.com/xyz/SearchProduct?productNo=11210&1d6rstc9xc=5jyi27htzk
I am getting some vague response but when i do same get request with fiddler it is giving expected response.
How can I get expected response from httpClient.GetAsync(url)?
code is :-
var httpClient = new HttpClient();
var url = "http://example.com/xyz/SearchProduct?productNo=11210&1d6rstc9xc=5jyi27htzk";
HttpResponseMessage response1 = await httpClient.GetAsync(url);
if (response1.IsSuccessStatusCode)
{
HttpContent stream = response1.Content;
Task<string> data = stream.ReadAsStringAsync();
}
You should read as string that way:
string result = await stream.ReadAsStringAsync();
instead of that:
Task<string> data = stream.ReadAsStringAsync();
Here full code example and another example
This is a full method using async/await approach.
private static async Task<string> GetRequestContentAsString(string url)
{
var data = string.Empty;
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var stream = response.Content;
data = await stream.ReadAsStringAsync();
}
}
return data;
}
This method is called this way:
var content = await GetRequestContentAsString("http://www.bing.com");

Categories

Resources