Send Http Request from Blazor Component - c#

I'm using .Net Core 3.1 and I'm having trouble sending requests from a Blazor component. I want to send a request to a controller I have, and these requests systematically end up in 400 Bad request.
In my Startup.cs, I have
if (!services.Any(x => x.ServiceType == typeof(HttpClient)))
{
services.AddScoped<HttpClient>(s =>
{
var uriHelper = s.GetRequiredService<NavigationManager>();
return new HttpClient
{
BaseAddress = new Uri(uriHelper.BaseUri)
};
});
}
In my Blazor component, I have:
var json2 = Newtonsoft.Json.JsonConvert.SerializeObject(_Model);
var stringContent2 = new StringContent(json2, System.Text.Encoding.UTF8, "application/json");
var response2 = await Http.PostAsync("/[controllerName]/[Method]", stringContent2);
if (response2.IsSuccessStatusCode)
{
var resultContent = response2.Content.ReadAsStringAsync().Result;
return resultContent;
}
else
return "failed";
And here is my Controller Method prototype:
[HttpPost]
public IActionResult Method([FromBody] Model form)
{...}
Would you happen to see what's wrong with the code?

You are passing a StringContent object in your PostAsync method, but in your action you have your Model as a parameter.
You have two options :
To change your action parameter to a StringContent.
To parse the Json as your Model to pass it to the PostAsync method content parameter.
Regards,

these requests systematically end up in 400 Bad request.
Please check you provide correct request header(s) and well-formatted data while you make request from your Blazor app to backend service.
I did a test using following code snippet with simple testing data, which work well on my side. If possible, you can create a new component and test if the code snippet can work for you.
var _Model = new Model { Id = 1, Name = "fehan" };
var json2 = Newtonsoft.Json.JsonConvert.SerializeObject(_Model);
var stringContent2 = new StringContent(json2, System.Text.Encoding.UTF8, "application/json");
var response2 = await Http.PostAsync("Home/Method", stringContent2);
if (response2.IsSuccessStatusCode)
{
var resultContent = response2.Content.ReadAsStringAsync().Result;
}
Model class
public class Model
{
public int Id { get; set; }
public string Name { get; set; }
}
Test Result
Besides, if you are making request to MVC controller action, please check if you enabled antiforgery validation on controller or action(s).

Related

Serialize async response from a database client

I have an endpoint which is used to create an item. The controller calls the service which creates the item, makes some changes on the db and db returns data based on the procedure. The db returns a json like response, but is not always the same, so I have to adjust on the backend so that I can formalize the response type.
The problem is that create item service is asynchronous and I need to be able to await the response so I can make a new response based on that. How can I await the response and that I get from db client and then return data based on that.
This is my Action and I want to be able to serialize async response from service
[HttpPost]
public IActionResult CreateItem([FromBody] InputModel item)
{
var jsonString = _itemService.CreateItem(item);
ResponseModel? response = JsonSerializer.Deserialize<ResponseModel>(jsonString);
return new ObjectResult(response.Response) { StatusCode = response.StatusCode };
}
The default response model
public class ResponseModel
{
public string Response { get; set; }
public int StatusCode { get; set; }
}
Create Item service, which makes the post request to the client and it has to be async.
Depending on the status code that is coming from the client, I want to be able to set my action status code as well.
public async Task<string> CreateItem(InputModel item)
{
if (item.VersionType != 1)
{
return new { Response = "Incorrect data", StatusCode = 400 }.ToString()!;
}
var json = JsonSerializer.Serialize(item);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, data);
var content = await response.Content.ReadAsStringAsync();
return content;
}
You can make your action method async and then await the method call _itemService.CreateItem for it :
[HttpPost]
public async Task<IActionResult> CreateItem([FromBody] InputModel item)
{
var jsonString = await _itemService.CreateItem(item);
ResponseModel? response = JsonSerializer.Deserialize<ResponseModel>(jsonString);
return new ObjectResult(response.Response) { StatusCode = response.StatusCode };
}
Now your action method would asyncrounously wait for the result from CreateItem and when it returs result, it will continue executing further and send the deserialized response back to client.

WebApi - why is my post variable always null?

I'd like to be able to read a post variable from my controller method.
I currently have the below code:
[HttpPost]
public IHttpActionResult BuildPartitions([FromBody]string PartitionBuildDate)
{
}
I'm using the below code to test:
using (HttpClient httpClient = new HttpClient())
{
var values = new Dictionary<string, string>
{
{ "PartitionBuildDate", "24-May-2017" }
};
var content = new FormUrlEncodedContent(values);
var response = httpClient.PostAsync("http://localhost:55974/api/Controller/BuildPartitions", content);
var responseString = response.Result.Content;
}
Looking online, this looks correct for both sending and receiving a post variable in C#, however the PartitionBuildDate variable is always null.
Try adding the content-type header. I have used Newtonsoft JSON.NET for JSON conversion:
string postBody = JsonConvert.SerializeObject(yourDictionary);
var response = client.PostAsync(url, new StringContent(postBody, Encoding.UTF8, "application/json"));
var responseString = response.Result.Content;
Also, on your web API side, try wrapping your POST parameters inside a class:
public class PostParameters
{
public string PartitionBuildDate {get;set;}
}
[HttpPost]
public IHttpActionResult BuildPartitions([FromBody]PostParameters parameters)
{
//you can access parameters.PartitionBuildDate
}

Httpclient consume web api via console app C#

I am trying to consume the below web api via console app using Httpclient. I am stuck as in how to pass the parameter. The paramter is coming as a command line argument.
This is my Rest api
[HttpPost, Route("Test")]
public IHttpActionResult Test(bool sample = false)
{
return Ok();
}
The parameter comes in this was as command line argument
/Parameters:sample=true.
Here is how I am parsing out the parameter in the console app
static int Main(string[] args)
{
if (args.Length == 0)
{
Console.Error.WriteLine("No action provided.");
return -1;
}
foreach (string param in args)
{
switch (param.Substring(0, param.IndexOf(":")))
{
case "/Action":
action = param.Substring(param.IndexOf(":") + 1);
break;
case "/Parameters":
parameter = param.Substring(param.IndexOf(":") + 1);
break;
}
}
return 0;
}
Once I get my parameter which is in this format
parameter = "sample=true"
I am trying to invoke the web api call but unable to pass the parameter value. can anybody pin point what I am doing wrong
client.BaseAddress = new Uri(ConfigurationManager.AppSettings.Get("BaseWebApiUrl"));
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var apiUrl = GetApiURL();
var Context = new StringContent(JsonConvert.SerializeObject(parameter), Encoding.UTF8, "application/json");
var respFeed = await client.PostAsync(apiUrl, Context);
By default in Web Api basic type parameters are never bound to the body of the request.
If you want to forcefully bind your bool parameter with the request body you need to decorate it with FromBodyAttribute:
[HttpPost, Route("Test")]
public IHttpActionResult Test([FromBody] bool sample = false)
{
return Ok();
}
Be aware that even if you do this your request is not valid for Web Api. A single basic type parameter must be passed with a specific format. In your case your request body must be the following:
=true
A better approach is to turn your Action parameter into a class:
public class TestModel
{
public bool Sample { get; set; }
}
[HttpPost, Route("Test")]
public IHttpActionResult Test(TestModel model)
{
return Ok();
}
This way you will be able to send a Json object as request body, like:
{
"sample": true
}
This is a small example of how you could achieve such a result:
var parameterDictionary = parameter.Split("=").ToDictionary(s => s[0], s => bool.Parse(s[1]));
var json = JsonConvert.SerializeObject(parameterDictionary);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var respFeed = await client.PostAsync(apiUrl, content);
You should pass it as a part of the url.
private void CallService(bool sample)
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings.Get("BaseWebApiUrl"));
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var apiUrl = $"http://yourserver:port/api/somecontroller/?sample={sample}";
var Context = new StringContent(JsonConvert.SerializeObject(parameter), Encoding.UTF8, "application/json");
var respFeed = await client.PostAsync(apiUrl, Context);
}
First, change your method signature to
public IHttpActionResult Test([FromBody]bool sample = false)
since primitive types are resolved from URL/Query String and not body. By adding FromBody attribute will force it to resolve from the body.
Next, since you said you have parameter value as var parameter = "sample=true";, change your parameter construction to
var jsonParam = new { sample = parameter.split('=')[1]}; // I'm leaving null checks and validation for simplicity
var Context = new StringContent(JsonConvert.SerializeObject(jsonParam), Encoding.UTF8, "application/json");

POSTing to WebApi2 from C#

I can't for the life of me get this to work. I keep getting 404.
Here's the WebApi2 code:
[HttpPost]
public IHttpActionResult Post(string testString)
{
if(!string.IsNullOrEmpty(testString))
{
return Ok(testString);
}
else
{
return BadRequest();
}
}
Here's the WebClient code:
public async Task PostingToWebServiceShouldWork()
{
var apiEndPoint = new Uri(String.Format("{0}/Paging", ConfigurationManager.AppSettings["ApiEndpoint"].ToString()));
var apiRoot = new Uri(apiEndPoint.GetLeftPart(UriPartial.Authority));
var apiCall = apiEndPoint.PathAndQuery.Substring(1, apiEndPoint.PathAndQuery.Length - 1);
using (var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
{
client.BaseAddress = apiRoot;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpContent content = new StringContent("testSTring");
HttpResponseMessage response = await client.PostAsync(apiCall, content);
if(response.IsSuccessStatusCode)
{
}
}
}
I just want to post a simple string to the web service. This should be dead simple, and it's giving me a migraine, lol. I've tried everything I can think of, and I have to be missing some tiny detail...
Thanks!
Because your API endpoint is simply a string instead of an object, WebAPI is looking for that string as a query string parameter. You have two options:
Use the [FromBody] attribute in your action's definition
public IHttpActionResult Post([FromBody] string testString)
Send the string on the URL instead of in the body (works, but if you're going for security over HTTPS this exposes what you were posting)
See http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api for a deeper explanation and examples

How to pass model object to Web API Post method

I want to save data to database in MVC application. I have below class which calls the webapi1 service post method. Here Sample is a model object. I have a view which uses the Sample object. I want to inert the Sample Object data to db using the service call.
public SampleTestCreate(Sample)
{
string uri = baseUri + "Test";
using (HttpClient httpClient = new HttpClient())
{
Task<HttpResponseMessage> response = httpClient.PostAsJsonAsync(uri, new StringContent(JsonConvert.SerializeObject(Test)));
// Task<HttpResponseMessage> response = httpClient.PostAsJsonAsync(uri, Test);
var data = response.Result.Content.ReadAsStringAsync().Result;
return JsonConvert.DeserializeObjectAsync<Test>(response.Result.Content.ReadAsStringAsync().Result).Result;
}
}
// POST api/Sample
public HttpResponseMessage PostSample(Sample Sample)
{
if (ModelState.IsValid)
{
db.Samples.Add(Sample);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, Sample);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = Sample.SampleID }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
Here my service post method is getting called , but the "Sample" objects all the properties values are coming null. The model object binding is not happening.

Categories

Resources