Prepare controller and http request to preocess request without returning value - c#

I have following method to get collection of cars:
public async Task<IEnumerable<Car>> GetCars(object car, CancellationToken ct)
{
var uri = new Uri($"{_webApiUrl}Car/GetCars");
using (var httpClient = new HttpClient())
{
HttpContent content = new StringContent(JsonConvert.SerializeObject(car), Encoding.UTF8, "application/json");
var req = await httpClient.PostAsync(uri, content, ct);
var response = await req.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<IEnumerable<Car>>(response);
}
}
In my service api in controller i have this to get it:
[HttpPost]
[Route("api/[controller]/[action]")]
public IActionResult GetBottleTypeById(Car car)
{
return Ok(_carQuery.GetCars(car));
}
Both things works great - no issues.
Now i need to save the Car and i don't need to return something (eventually i could return true or false whether it was succesfull or not). The problem is i am not sure how controller's method should look like, if i do this way it says: not all code path returns value:
[HttpPost]
[Route("api/[controller]/[action]")]
public IActionResult UpdateOperation(Car car)
{
_carRepository.UpdateOperation(car) //UpdateOperation is void with try/catch - throw;
}
Same thing with request, how this should be accomplished?
public async Task UpdateCar(Car selectedCar, CancellationToken ct)
{
var uri = new Uri($"{_webApiUrl}Car/UpdateOperation");
using (var httpClient = new HttpClient())
{
HttpContent content = new StringContent(JsonConvert.SerializeObject(selectedCar), Encoding.UTF8, "application/json");
var req = await httpClient.PostAsync(uri, content, ct);
var response = await req.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<IEnumerable<Car>>(response);
}
}
How could i prepare both things to make it work?

Just change your code to return void. ASP.NET is smart enough to just send 200 OK if no exceptions were thrown out of a void method.
[HttpPost]
[Route("api/[controller]/[action]")]
public void UpdateOperation(Car car)
{
_carRepository.UpdateOperation(car) //UpdateOperation is void with try/catch - throw;
}
To make your calling code work, you don't need to receive anything but the HTTP response message from the server. Even if your method returns void, HTTP servers still send a status code (200, 500, etc.) and some headers for you to inspect.
Try this:
public async Task UpdateCar(Car selectedCar, CancellationToken ct)
{
var uri = new Uri($"{_webApiUrl}Car/UpdateOperation");
using (var httpClient = new HttpClient())
{
HttpContent content = new StringContent(JsonConvert.SerializeObject(selectedCar), Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(uri, content, ct);
if (response.IsSuccessStatusCode)
{
return;
}
else
{
// handle error
}
}
}

Related

C# async - creating a task properly

I'm creating a Task in C# but I'm not sure what I do is correct. I'm using Restsharp and in Restsharp there are two methods: Execute and ExecuteAsync. I want to do an Async call but I also need to return data to the client without blocking the execution.
Therefore I created a task which will use Execute instead of ExecuteAsync. The reason why is because I have to wait until I get a response back and then return it in the right data structure. So I thought there is no use in using ExecuteAsync if I have to await it in a Task...
My code looks as follows:
public Task<Response> ExecuteAsync()
{
return new Task<Response>(() =>
{
var client = new RestClient(URL);
if (_useBasicAuth)
{
client.Authenticator = new HttpBasicAuthenticator(_username, _password);
}
var request = RequestBuilder(_method);
var response = client.Execute(request);
return new Response()
{
HttpStatusCode = response.StatusCode,
HttpStatusDescription = response.StatusDescription,
Content = response.Content,
Cookies = ExtractCookies(response.Cookies),
Headers = ExtractHeaders(response.Headers)
};
});
}
Is this correct? The client should be able to call ExecuteAsync without blocking the execution.
I strongly suspect you should really just use ExecuteAsync and write an async method:
public async Task<Response> ExecuteAsync()
{
var client = new RestClient(URL);
if (_useBasicAuth)
{
client.Authenticator = new HttpBasicAuthenticator(_username, _password);
}
var request = RequestBuilder(_method);
var response = await client.ExecuteAsync(request).ConfigureAwait(false);
return new Response
{
HttpStatusCode = response.StatusCode,
HttpStatusDescription = response.StatusDescription,
Content = response.Content,
Cookies = ExtractCookies(response.Cookies),
Headers = ExtractHeaders(response.Headers)
};
}

SendAsync() returning 422 Unprocessable Entity

I wrote a function using GetAsync() which works fine, but now i'd like to expand on it using SendAsync() instead [for POSTing and sofourth]; however my SendAsync() version is not working as expected, it returns a 422 unprocessible entity. (no IDE atm; sorry for minor typos)
init
var Client = new HttpClient{
BaseAddress = "https://example.com"
}
Client.DefaultRequestHeaders.UserAgent.ParseAdd("Project/1.0 (blah blah)");
...
Working GetAsync()
public async Task<string> GetResponse(string user, string pass){
var uri = $"/user/login.json?name={user}&password={pass}";
var req = await Client.GetAsync(uri);
return req.Content.Request.Content.ReasStringAsync();
}
non working SendAsync()
public async Task<string> GetResponse(string page, Dictionary<string, string> args){
//assume page = "/user/login.json" and args == {"username", "user"},{"password", "pass"}
try{
var req = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(page),
Content = new FormUrlEncodedContent(args),
}
var response = await Client.SendAsync(req);
if(response.IsSuccessStatusCode){
return await response.Content.ReasStringAsync();
return null;
}
catch{ return null }
}
note: along with the 422, the response still contains json which states "invalid Auth Token!"
What is GetAsync() doing that SendAsync() is not?
Your Send included content in the BODY of a HTTP GET request.
HTTP GET requests should not have a BODY and there are servers that wont process such requests.
Convert the dictionary to a QueryString and include it in the URI.
public async Task<string> GetResponse(string page, Dictionary<string, string> args) {
//assume page = "/user/login.json" and args == {"username", "user"},{"password", "pass"}
try {
QueryString queryString = QueryString.Create(args);
var uri = new Uri(page + queryString.ToString());
var request = new HttpRequestMessage(HttpMethod.Get, uri);
var response = await Client.SendAsync(request);
if(response.IsSuccessStatusCode){
return await response.Content.ReadAsStringAsync();
return string.Empty;
} catch { return string.Empty; }
}
Your code snippets don't show it, but are you sure the second query's URL has
$"/user/login.json?name={user}&password={pass}"
and not
$"/user/login.json"
?

How to pass request content with HttpClient GetAsync method in c#

How do I pass request content in the HttpClient.GetAsync method? I need to fetch data depending upon request content.
[HttpGet]
public async Task<HttpResponseMessage> QuickSearch()
{
try
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
HttpResponseMessage response =await client.GetAsync("http://localhost:8080/document/quicksearch");
if (response.IsSuccessStatusCode)
{
Console.Write("Success");
}
If you are using .NET Core, the standard HttpClient can do this out-of-the-box. For example, to send a GET request with a JSON body:
HttpClient client = ...
...
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("some url"),
Content = new StringContent("some json", Encoding.UTF8, ContentType.Json),
};
var response = await client.SendAsync(request).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
If you want to send content, then you need to send it as query string (According to your API route)
HttpResponseMessage response =await client.GetAsync("http://localhost:8080/document/quicksearch/paramname=<dynamicName>&paramValue=<dynamicValue>");
And in API check for "paramName" and "paramValue"
this works for me:
using (var httpClient = new HttpClient())
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("your url"),
Content = new StringContent("your json", Encoding.UTF8, ContentType.Json),
};
using (var response = await httpClient.SendAsync(request))
{
string apiResponse = await response.Content.ReadAsStringAsync();
}
}
EDITED:
This is minor different then #SonaliJain answer above:
MediaTypeNames.Application.Json instead of ContentType.Json
I'm assuming that your "request content" would be POST data, no?
If you're sending it using the standard form content way of doing it, you would first have to build the content:
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("username", "theperplexedone"),
new KeyValuePair<string, string>("password", "mypassword123"),
});
And then submit it using PostAsync instead:
var response = await client.PostAsync("http://localhost:8080/document/quicksearch", content);
Hi all thank you for your comments, i got the solution
[HttpGet]
public async Task<HttpResponseMessage> QuickSearch(HttpRequestMessage Query)
{
Debugger.Launch();
try
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
Console.WriteLine(Query);
HttpResponseMessage response = await client.GetAsync("http://localhost:8080/document/quicksearch/"+ Query.RequestUri.Query);
if (response.IsSuccessStatusCode)
{
Console.Write("Success");
}
else
{
Console.Write("Failure");
}
return response;
}
}
catch (Exception e)
{
throw e;
}

PostAsync parameter is always null

I am calling an API Post method, however, I am not sure what I am doing wrong but the value in the API is always null. The method I am calling the API from is below. When I hit this I can see Ids is list of ints with 5 values for example.
private void Save(List<int> Ids)
{
var myAPI = ConfigurationManager.AppSettings["MyAPI"];
string myIds = string.Join(",", Ids);
using (var client = new HttpClient())
{
int result = client.PostAsync(myAPI, new { test = myIds }, new JsonMediaTypeFormatter())
.Result
.Content
.ReadAsAsync<int>()
.Result;
}
}
My API signature is like below - with a breakpoint on I can see it is getting hit but test the parameter I am trying to pass is always null
[HttpPost]
[Route("api/MyController/SaveData")]
public HttpResponseMessage SaveData([FromBody]List<string> test)
{
try
{
//Rest of method removed for brevity
I have tried removing the [FromBody] Annotation from the WebAPI controller but test still is getting null with breakpoint in the SaveData API method
Try this:
private void Save(List<int> Ids)
{
var myAPI = ConfigurationManager.AppSettings["MyAPI"];
using (var client = new HttpClient())
{
var requestBody = JsonConvert.SerializeObject(Ids);
var postRequest = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = client.PostAsync(myAPI, postRequest).GetAwaiter().GetResult();
var rawResponse = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
// Do something with the answer
}
}
I also suggest to make the method private Task Save and replace .GetAwaiter().GetResult(); with await in front of that calls.
In my case i used System.Web.Http.ApiController instead of System.Web.Mvc.Controller. So over all code looks like
public class YourAppController : ApiController
{
[System.Web.Http.Route("publish-message")]
public HttpResponseMessage Post([System.Web.Http.FromBody] string msges)
{
//Your Code
return Request.CreateResponse(HttpStatusCode.OK, "");
}
}
public async Task<string> PublishMessageCall(string publishMessage){
var returnval = "";
string httpWebRqst = "http://localhost:543134535/publish-message";
using (HttpClient myClient = new HttpClient())
{
var jsonString = JsonConvert.SerializeObject(publishMessage);
var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
var response = await myClient.PostAsync(httpWebRqst, content);
var responseString = await response.Content.ReadAsStringAsync();
}
return await Task.FromResult(returnval);}

Accessing contents of HttpResponseMessage

I'd like to print the contents of a HTTPResponseMessage.
class Requests
{
public static async Task SendRequest(int port, string path, KVPairs kvPairs)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(BASE_ADDRESS + port);
var request = new HttpRequestMessage(HttpMethod.Put, path);
request.Content = new FormUrlEncodedContent(kvPairs);
ProcessResponse(await client.SendAsync(request));
}
}
public static void ProcessResponse (HttpResponseMessage response)
{
Console.WriteLine(response.Content.ReadAsStringAsync());
}
}
SendRequest works perfectly. But ProcessResponse() prints System.Threading.Tasks.Task\`1[System.String]
How can I access and print the contents of the response? Thank you!
You need to await the task returned by response.Content.ReadAsStringAsync(), which in turn means you need to make ProcessResponse an async method, and await on that too. Otherwise, you are printing out the task object itself, which is not what you want.
Notice the 3 changes below (see comments):
public static async Task SendRequest(int port, string path, KVPairs kvPairs)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(BASE_ADDRESS + port);
var request = new HttpRequestMessage(HttpMethod.Put, path);
request.Content = new FormUrlEncodedContent(kvPairs);
await ProcessResponse(await client.SendAsync(request)); // added await here
}
}
public static async Task ProcessResponse (HttpResponseMessage response) // added async Task here
{
Console.WriteLine(await response.Content.ReadAsStringAsync()); // added await here
}
This solution should work for you. Deserialize JSON to Array or List with HTTPClient .ReadAsAsync using .NET 4.0 Task pattern
You should use await or wait() to get the response and then process it like this:
var jsonString = response.Content.ReadAsStringAsync();
jsonString.Wait();
model = JsonConvert.DeserializeObject<List<Job>>(jsonString.Result);

Categories

Resources