Calling Put method in Web API with asp.net MVC as client - asp.net

I have created a Web-api with following put method
public HttpResponseMessage Put(int id, [FromBody]DataModel model)
in the put method i pass the object and it get updated in the database. Its working i have checked it with fiddler.
Now in My MVC Application i call it using the following code
[HttpPost]
public JsonResult OrderSearch(DataModel model)
{
UpdateOrder(model).Wait();
if (putresult != null && putresult != string.Empty)
{
return Json(putresult);
}
else
{
return Json("Error in getting result");
}
}
private async Task UpdateOrder(DataModel model)
{
string json = JsonConvert.SerializeObject(model);
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.PutAsync("api/values/"+ model.OrderNo,new StringContent(json)).Result;
if (response.IsSuccessStatusCode)
{
putresult = await response.Content.ReadAsAsync<string>();
}
}
}
But the code does not hit my Put method on the service and putresult remains blank. I try to search about PutAsync usage but could not find anything so please help.

Using .Wait in any ASP.NET runtime application is likely to result in a deadlock. I'm not sure how you are supposed to handle async methods in MVC.

Related

Web API PUT,DELETE, POST methods via URI

I am very new to the whole consept of API's. So far, I managed to build a web api that has GET,POST,PUT and DELETE methods.
Now, from an ASP.NET project, I try to finally use my web api.
Here's what I do for GET method:
string info = new WebClient() { }.DownloadString("https://mywebapisite.com/item/" + id);
Item item = JsonConvert.DeserializeObject<Item>(info);
This functions all fine. As you can see, all the GET method needs is an id.
However, for the POST method, I have no clue what to do.
I can create a new Item instance, but don't know what to do with it.
By the way, I also used ASP.NET to make my web.api.
There is a built-in feature in ASP.NET 5 called Swagger. It can perform all the tasks very succesfully. Is there like a code-behind for what Swagger does.
PS: I know that this question must be very common and basic. If you could refer me to another question in stackoverflow or simply tell me what to search on google I would appreciate it. (As you may guess, I don't even know what to search for)
pseudo code to consume post request in C#
var requestObj = GetDummyDataTable();
using (var client = new HttpClient())
{
// Setting Base address.
client.BaseAddress = new Uri("https://localhost:8080/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = new HttpResponseMessage();
// HTTP POST
response = await client.PostAsJsonAsync("api/product", requestObj).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
// Reading Response.
string result = response.Content.ReadAsStringAsync().Result;
var responseObj = JsonConvert.DeserializeObject<DataTable>(result);
}
}
You can refer the following code to call the API using HttpClient:
////using System.Net.Http.Headers;
////using System.Text;
using (var client = new HttpClient())
{
var requesturi = "https://localhost:7110/api/ToDo/relativeAddress";
var item = new TestUserViewModel()
{
Name = "John Doe",
Age = 33
};
////using System.Text.Json; // use JsonSerializer.Serialize method to convert the object to Json string.
StringContent content = new StringContent(JsonSerializer.Serialize(item), Encoding.UTF8, "application/json");
//HTTP POST
var postTask = client.PostAsync(requesturi, content);
postTask.Wait();
var result = postTask.Result;
if (result.IsSuccessStatusCode)
{
var Content = await postTask.Result.Content.ReadAsStringAsync();
return RedirectToAction("Privacy");
}
}
The API method like this:
[Route("api/[controller]")]
[ApiController]
public class TodoController : ControllerBase
{
[HttpPost]
[Route("relativeAddress")]
public string GetAddress([FromBody] TestUserViewModel testUser)
{
return "Address A";
}
And the result like this:
You can also refer this link to set the Content-Type.
You seem a little bit lost, and I get it. Api learning path is kinda weird, I recommend you watch a tutorial (My favorite https://www.youtube.com/playlist?list=PLLWMQd6PeGY0bEMxObA6dtYXuJOGfxSPx)
But if you need code asap, you could refer the following code.
Ps: The others answers are really good!
using System.Net.Http;
using System.Net.Http.Headers;
public class ApiHelper
{
public HttpClient ApiClient { get; set; }
public void InitializeClient()
{
ApiClient = new HttpClient();
ApiClient.BaseAddress = new Uri("https://mywebapisite.com/");
ApiClient.DefaultRequestHeaders.Accept.Clear();
ApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task PostSomething(FormUrlEncodedContent data)
{
using (HttpResponseMessage response = await ApiClient.PostAsync("/item",data)
{
var result = await response.Content.ReadAsAsync<string>();
}
}
}

Asp.net web api controller long querystring returns BadRequest

I have an Asp.net web api with one method that receive a crypted string with variable length, my problem is it string some times could take a length near 5000.
When that method receive a string under 1930 length it process everything ok, but for lengths over 1929 returns
404 Operation returned an invalid status code 'BadRequest'
I changed method GET to POST but problem persists.
I changed filter options on server to very very long limits, but problem persists
This is my controller:
public class LicencingManagerController : ApiController
{
[HttpPost]
[Route(nameof(SaveCustomer2))]
public string SaveCustomer2(string custInfo)
{
return $"ItsOk = {custInfo}";
}
}
Actually I made calls to controller using autogenerated c# client by AutoRest 2.0.483.
I tried hand building PostAsync Request using HttpClient but nothing works.
string custInfo = "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";
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("custInfo", custInfo)
};
var content = new FormUrlEncodedContent(pairs);
var client = new HttpClient();
// call sync
var response = client.PostAsync($"{Modelos.Shared.HttpsServicesReference.Licencing}/LicencingAPI/SaveCustomer2", content).Result;
if (response.IsSuccessStatusCode)
{
}
What is the right way to process this controller call?
There is another approach to perform this ?
Create model to hold data
public class Customer {
public string CustumerInfo { get; set; }
}
Update API to expect model in body of request
public class LicencingManagerController : ApiController {
[HttpPost]
[Route(nameof(SaveCustomer2))]
public IHttpActionResult SaveCustomer2([FromBody]Customer model) {
if(!ModelState.IsValid)
return BadRequest(ModelState);
var custInfo = model.CustumerInfo;
return Ok($"ItsOk = {custInfo}");
}
}
Post content to API in body of the request like you did before
string custInfo = "H4sIAAAAAAAEAA...";
string url = $"{Modelos.Shared.HttpsServicesReference.Licencing}/LicencingAPI/SaveCustomer2";
var pairs = new List<KeyValuePair<string, string>> {
new KeyValuePair<string, string>("CustumerInfo", custInfo)
};
var content = new FormUrlEncodedContent(pairs);
var client = new HttpClient();
var response = await client.PostAsync(url, content);
if (response.IsSuccessStatusCode) {
}

How to invoke the API action of type [HttpPatch] from HttpClient class in asp.net core mvc

My API has an [HttpPatch] action which i need to invoke.
[HttpPatch("{id}")]
public StatusCodeResult Patch(int id, [FromBody]JsonPatchDocument<Reservation> patch)
{
Reservation res = Get(id);
if (res != null)
{
patch.ApplyTo(res);
return Ok();
}
return NotFound();
}
I am trying it from HttpClient class but it does not have .PatchAsync() method?
Also the parameter is of type JsonPatchDocument<Reservation> and so how to send it from client when invoking this action?
Please help
You have to create an HttpRequestMessage manually and send it via SendAsync:
var request = new HttpRequestMessage
{
RequestUri = new Uri("http://foo.com/api/foo"),
Method = new HttpMethod("patch"),
Content = new StringContent(json, Encoding.UTF8, "application/json-patch+json")
};
var response = await _client.SendAsync(request);

ASP.NET Web API Posted value not automatically map to object

I'm trying to send my request with json content to web api, bit these value isn't automatically map to my object.
This is My API Action that result in null.
[HttpPost]
public IEnumerable<string> GetCustomerByName([FromBody] Request_GetCustomerByName request)
{
// Some Action
}
If I change parameter like below I can receive my data fine. So I wonder why my json string not automatically map to object.
[HttpPost]
public IEnumerable<string> GetCustomerByName([FromBody] dynamic request)
{
// Some action
}
This is where I send my request .
public ActionResult Index()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:40175/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Request_GetCustomerByName r = new Request_GetCustomerByName()
{
Customer = new Customer() { CustomerId = 1, CustomerName = "Name" },
RequestBase = new RequestBase() { Somefield="123"}
};
var json = new JavaScriptSerializer().Serialize(r);
HttpResponseMessage response = client.PostAsJsonAsync("api/values/GetCustomerByName", json).Result;
if (response.IsSuccessStatusCode)
{
var resVal = response.Content.ReadAsStringAsync().Result;
Response.Write(resVal);
}
}
return View();
}
Thanks, I've been stuck at this point for some hour...
You should probably inspect the Json string, this online json to c# object mapper might help: http://json2csharp.com/.

Web API External Bearer Unauthorized

I am trying to call the RegisterExternal method in Web API, after having retrieved a token from facebook. But I keep getting a 401 Unauthorized from my Web API. I am not sure I am correctly implementing the logic flow. My code is;
Ask for supported external login providers;
public async Task<List<ExternalLoginViewModel>> GetExternalLoginsAsync()
{
using (var client = GetNewHttpClient(false))
{
var response = await client.GetAsync("api/account/externalLogins?returnUrl=/&generateState=true");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsAsync<List<ExternalLoginViewModel>>();
}
}
From this, I am returned a facebook URL. I follow this and then enter in my facebook username and password. I return back to my app via a deep link and then try and call the RegisterExternal method in the web API like this, passing the facebook "access token" that is returned.
public async Task<bool> SendSubmitRegisterExternalAsync(RegisterExternalBindingModel ro, string accessToken)
{
using (var client = GetNewHttpClient(true))
{
client.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", accessToken));
HttpResponseMessage response = await client.PostAsJsonAsync("api/Account/RegisterExternal", ro);
if (response.IsSuccessStatusCode) return true;
var value = await response.Content.ReadAsStringAsync();
throw new ResponseErrorException(ErrorHelper.GetErrorString(value));
}
}
I receive 'Unauthorized' every time. I do not know what is wrong. My Web API method looks like this, and the class is marked with the [Authorize] attribute.
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
...
I have found three different posts this evening of people asking this exact same question, and in all cases there are no replies, so I am not hopeful but if anyone can shed some light on this it would be great!
EDIT: I have also changed the method signature to 'allowanonymous' and still get unauthorized!
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[AllowAnonymous]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
I have sorted this by not using FacebookSessionClient and doing it via a WebBrowser control instead.
I use the URL from the first step (provided to me by the WebAPI). Then on the Navigated event from the WebBrowser control, i parse the Url for the access token;
public async void ParseUrlForAccessToken(string url)
{
string fieldName = "access_token";
int accessTokenIndex = url.IndexOf(fieldName, StringComparison.Ordinal);
if (accessTokenIndex > -1)
{
int ampersandTokenIndex = url.IndexOf("&", accessTokenIndex, StringComparison.Ordinal);
string tokenField = url.Substring(accessTokenIndex, ampersandTokenIndex - accessTokenIndex);
string token = tokenField.Substring(fieldName.Length);
token = token.Remove(0, 1);
await _dataService.SubmitLoginExternal("Test", token);
}
}
Then as shown above, I call SubmitLoginExternal, which is a call to the following code which uses the access token retrieved from the WebBrowser control Url to register the account (in this case a 'Test' account);
using (var client = GetNewHttpClient(true))
{
client.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", accessToken));
HttpResponseMessage response = await client.PostAsJsonAsync("api/Account/RegisterExternal", ro);
if (response.IsSuccessStatusCode) return true;
var value = await response.Content.ReadAsStringAsync();
throw new ResponseErrorException(ErrorHelper.GetErrorString(value));
}
This has worked and now I have the user registered in my database.
The key was to use a WebBrowser control and not the FacebookSessionClient object or a WebBrowserTask. You cannot use a WebBrowserTask as you need to hook in to the navigated event once the page has loaded to call ParseUrlForAccessToken().

Resources