c# asp.net website calling a webApi - c#

I meet a problem because of my inexperience managing Threads.
I have this Action bellow :
public static async Task<joueurs> loadjoueurs(int id)
{
joueurs EmpInfo = new joueurs();
using (var client = new HttpClient())
{
//Passing service base url
client.BaseAddress = new Uri("http://www.myWebApi.fr/api/");
client.DefaultRequestHeaders.Clear();
//Define request data format
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Sending request to find web api REST service resource GetAllEmployees using HttpClient
HttpResponseMessage Res = await client.GetAsync("joueurs?id=" + id);
//Checking the response is successful or not which is sent using HttpClient
if (Res.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
var EmpResponse = Res.Content.ReadAsStringAsync().Result;
//Deserializing the response recieved from web api and storing into the Employee list
EmpInfo = JsonConvert.DeserializeObject<joueurs>(EmpResponse);
return EmpInfo;
}
return null;
}
it s just client to get my data from a webApi (no ssl no authentication, when I test it I receive the right values)
but when I make a call using the function above (in my asp.net website) .... it stay stucked at the HttpResponseMessage = await .... eternally.
In my webApi I have two functions same name but different parameters .
public async Task<IHttpActionResult> Getjoueur(int iduser, int idsport)
and
public async Task<IHttpActionResult> Getjoueur(int id)
So I am don't know where the problem comes from.
(sequel) Here is the place where I call the Task :
public SuperModel(int id)
{
this.joueur = Repojoueurs.loadjoueurs(id).Result;
/* this.classificationSport = Repoclassificationsport.loadclassificationsport().Result;
...
*/
}
And then my Supermodel is instantiated here in my Home controller :
public ActionResult Index(int id)
{
SuperModel superModel = new SuperModel(id);
return View(superModel);
}

Can you try not to use the async and wait. Around three changes like below
public static HttpResponseMessage loadjoueurs(int id)
{
HttpResponseMessage Res = client.GetAsync("joueurs?id=" + id);
return Request.CreateResponse(HttpStatusCode.OK,EmpInfo, "application/json");
}

Related

.NET API POST Endpoint not getting hit

I have a .net api and I want to test the api from a console app.
The method I am trying to test is a POST Method.I serialize data from my console app into a json string and I want to post it to the API, but the API does not get hit and I dont get any errors from my console app.
My GET calls work though. It is just the post I cant get to work.
My API Controller->
using _ErrorLogger.Shared;
using _ErrorLogger.Server.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Runtime.CompilerServices;
namespace _ErrorLogger.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ExceptionDetailsController : ControllerBase
{
private readonly IExceptionDetailsService _exceptionDetailsService;
public ExceptionDetailsController(IExceptionDetailsService exceptionDetailsService)
{
_exceptionDetailsService = exceptionDetailsService;
}
[HttpGet]
[Route("GetExceptions")]
public async Task<List<ExceptionDetails>> GetAll()
{
return await _exceptionDetailsService.GetAllExceptionDetails();
}
[HttpGet]
[Route("GetExceptionByID/{id}")]
public async Task<ExceptionDetails> GetByID(int id)
{
return await _exceptionDetailsService.GetExceptionDetails(id);
}
[HttpPost]
[Route("CreateException")]
public async Task<IActionResult> CreateException([FromBody]string obj)
{
//await _exceptionDetailsService.AddExceptionDetails(exceptionDetails);
return Ok();
}
[HttpPost]
[Route("Test")]
public async Task<IActionResult> Test([FromBody] string obj)
{
return Ok();
}
}
}
My Call from the console app ->
public async void ExceptionsAnalyzer(Exception exception)
{
HttpClient _httpClient = new HttpClient();
StackTrace stack = new StackTrace(exception, true);
StackFrame frame = stack.GetFrame(stack.FrameCount - 1);
ExceptionDetails exceptionDetails = new ExceptionDetails
{
ExceptionMessage = exception.Message,
InnerException = exception.InnerException?.ToString(),
ExceptionType = exception.GetType().ToString(),
ExceptionSourceFile = frame.GetFileName(),
ExceptionSourceLine = frame.GetFileLineNumber().ToString(),
ExceptionCaller = frame.GetMethod().ToString(),
ExceptionStackTrace = exception.StackTrace,
DateLogged = DateTime.Now
};
string json = JsonSerializer.Serialize(exceptionDetails);
//var stringContent = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage response = await _httpClient.PostAsJsonAsync("http://localhost:5296/api/ExceptionDetails/CreateException", json);
if (response.IsSuccessStatusCode)
{
}
}
I am Expecting the api endpoint to be hit.
I am Expecting the api endpoint to be hit.
Well, Firstly, your method in console app which is ExceptionsAnalyzer structure is wrong. It should be type of static because, main method within console app itself is type of static.
Another mistake is async should be type of Task and while calling the ExceptionsAnalyzer method it should be wait() for response but your console app is static so how it would handle await call? So see the solution below:
Solution:
using System.Net.Http.Json;
using System.Text.Json;
// Calling method
ExceptionsAnalyzer().Wait();
//Defining Method in dotnet 6 console app
static async Task ExceptionsAnalyzer()
{
HttpClient _httpClient = new HttpClient();
var obj = "Test data";
string json = JsonSerializer.Serialize(obj);
HttpResponseMessage response = await _httpClient.PostAsJsonAsync("http://localhost:5094/api/ExceptionDetails/CreateException", json);
if (response.IsSuccessStatusCode)
{
}
}
Note: I haven't consider your parameter Exception exception which you can modify yourself. I am mostly considering why you cannot get to hit API Endpoint. Hope you now got the mistake.
Output:
Unless ExceptionDetails is part of your basepath and as such is included for all API calls, I think you need to remove that.
You defined the route to the call as CreateException, so the url should be <base url>/CreateException
If that doesn't help, please post the code of your entire controller (with endpoint method).

Redirecting action from one controller to other with different secure attributes, ASP.NETCore 2.0

I have one question, which connected with redirecting and auth policies.
Let's have one controller, which allow Anonymous method like this:
[Route("Authorization")]
[Authorize]
public class AuthorizationController : Controller
{
...
[HttpPost]
[Route("AddUser")]
[AllowAnonymous]
public async Task<IActionResult> AddUser()
{
return await Task.Run<ActionResult>(() =>
{
return RedirectToAction("Post", "Proxy");
});
}
}
Second controller has Post method, which needs authorization
[Authorize]
public class ProxyController : Controller
{
...
[HttpPost]
public async Task Post()
{
var uri = new Uri(UriHelper.GetEncodedUrl(Request));
var routedUri = NewRouteBuilder(uri);
var client = new HttpClient();
var response = await client.PostAsync(routedUri, new StreamContent(Request.Body));
var content = await response.Content.ReadAsStringAsync();
Response.StatusCode = (int)response.StatusCode;
Response.ContentType = response.Content.Headers.ContentType?.ToString();
Response.ContentLength = response.Content.Headers.ContentLength;
await Response.WriteAsync(content);
}
}
If I use this code, I get 401 error in AuthorizationController, when I call AddUser.
Both these controllers are in one project. How it's possible to redirect on action in this case (which allow pass to action only authorized users or calls from ProxyController)?
Thank you.

How to call POST method from API using HttpClient?

I am trying to use the HttpClient class to call a POST method from my API which is supposed to add Server information to a DB.
The way I'm trying to call it is below. But when I step through it to debug it steps through my if statement for response.IsSuccessStatusCode.
public static async Task<Server> PostServer(Server server)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:50489/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
StringContent content = new StringContent(JsonConvert.SerializeObject(server));
// HTTP POST
HttpResponseMessage response = await client.PostAsync("api/Server/", content);
if (response.IsSuccessStatusCode)
{
string data = await response.Content.ReadAsStringAsync();
server = JsonConvert.DeserializeObject<Server>(data);
}
}
return server;
}
Also here is the POST method in my API below it was automatically generated in VS.
// POST: api/Servers
[ResponseType(typeof(Server))]
public async Task<IHttpActionResult> PostServer(Server server)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Servers.Add(server);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = server.Server_ID }, server);
}

MVC controller post entire model to remote api action

I have an API I would like to call from my front end MVC site. These two applications run on separate servers on the same network.
The API Controller has functions similar to:
[AllowCrossSiteJson]
public class VerifyMyModelController : ApiController
{
[HttpPost]
public MyResponse Post(MyModel model)
{
return MyHelper.VerifyMyModel(model);
}
[HttpPost]
public async Task<MyResponse> PostAsync(MyModel model)
{
return await MyHelper.VerifyMyModel(model);
}
// ... Gets below as well
}
Where MyHelper performs model verfication, DB lookups etc... and returns a common response object with response code, database id etc
My front end MVC site has a form the user fills out, this data gets posted to the local controller which I would like to forward on to the API. The API application is not accessible to the public, so I cannot post directly to it using AJAX etc. It must come from the sites controller.
I have tried the following but get a 500 internal server error as a response
[HttpPost]
public async Task<MyResponse> VerifyAsync(MyModel model)
{
var MyServer = ConfigurationManager.AppSettings["MyServer"];
var json = Newtonsoft.Json.JsonConvert.SerializeObject(model);
var requestUri = string.Format(#"http://{0}/api/VerifyMyModel/", MyServer);
using (var c = new HttpClient())
{
var response = await c.PostAsJsonAsync(requestUri, json);
}
...
}
The var response contains the error message response 500.
I have also tried using a query string:
public string GetQueryString(object obj)
{
var properties = from p in obj.GetType().GetProperties()
where p.GetValue(obj, null) != null
select p.Name + "=" + HttpUtility.UrlEncode(p.GetValue(obj, null).ToString());
return String.Join("&", properties.ToArray());
}
[HttpPost]
public async Task<MyResponse> VerifyAsync(MyModel model)
{
var MyServer = ConfigurationManager.AppSettings["MyServer"];
string queryString = GetQueryString(model);
var requestUri = string.Format(#"http://{0}/api/VerifyMyModel/?{1}", MyServer, queryString);
using (var c = new HttpClient()){
var response = await c.GetAsync(requestUri); // API Also has GET methods
}
}
But the querystring method returns a 405 method not allowed response.
The MyModel is part of a shared class library with common models in it and is included in both applications.
Is there a better way of posting the entire model to the remote api action?
Thanks.
*Edit
RouteConfig of API:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
I added the following to the HomeController of the API's MVC site, to test it and I receive back the expected result, without error:
public async Task<ActionResult> TestVerifyMyModel(MyModel model)
{
var api = new VerifyMyModelController();
var res = await api.PostAsync(model);
return Json(res, JsonRequestBehavior.AllowGet);
}
So I know that the PostAsync Action of the controller works.. I just cant get it to work when called remotely.
I also enabled Failed Request Tracing on the server and have uploaded the generated XML file. It doesn't mean anything to me but thought it might help.
The posted route config looks more like your MVC route config than a Web Api one. But if it is the Web Api config, then shouldn't you be adding the ActionName to your url.
[HttpPost]
public async Task<MyResponse> VerifyAsync(MyModel model)
{
var MyServer = ConfigurationManager.AppSettings["MyServer"];
var json = Newtonsoft.Json.JsonConvert.SerializeObject(model);
var requestUri = string.Format(#"http://{0}/api/VerifyMyModel/PostAsync", MyServer);
using (var c = new HttpClient())
{
var response = await c.PostAsJsonAsync(requestUri, json);
}
...
}
Update: Sample code to retrieve Model from HttpClient response
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["MyServer"]);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/VerifyMyModel/PostAsync");
if (response.IsSuccessStatusCode)
{
var myResponseModel = await response.Content.ReadAsAsync<MyResponseModel>();
}
}

Access to web API from a console application

In the process of learning about web API, I have created (or actually Visual Studio has) a simple controller. I have also created a WPF program that can read from web API's GET() part, but I can't access the others.
I have tried a lot and found many blogs and pages that say: "Just do like this..." but nothing works. What am I doing wrong?
MVC part:
namespace MVCWebservice.Controllers
{
public class LaLaController : ApiController
{
// GET: api/LaLa
public string Get()
{
return "Hello from API";
}
// GET: api/LaLa/5
public string Get(int id)
{
return "value";
}
// POST: api/LaLa
public void Post([FromBody]string value)
{
var a = value;
}
// PUT: api/LaLa/5
public void Put(int id, [FromBody]string value)
{
var b = value;
int c = id;
}
// DELETE: api/LaLa/5
public void Delete(int id)
{
int c = id;
}
}
}
And a method from my Console application that actually works:
private static async Task ReadFromWebApi()
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
client.BaseAddress = new Uri("http://localhost:26176/");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var resp2 = await client.GetAsync("api/LaLa/");
resp2.EnsureSuccessStatusCode();
var aaa = resp2.Content;
string result = await aaa.ReadAsStringAsync();
Console.WriteLine(result);
}
A method that just stops:
If I remove the EnsureSuccessStatusCode I'll get the following back:
ss = "{\"Message\":\"The requested resource does not support http
method 'PUT'.\"}"
private static async Task SendToWebApi()
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
client.BaseAddress = new Uri("http://localhost:26176/");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
Console.WriteLine("-1-");
var resp2 = client.PutAsync("api/LaLa/", new System.Net.Http.StringContent("Hey", Encoding.UTF8, "application/json")).Result;
Console.WriteLine("-2-");
resp2.EnsureSuccessStatusCode();
var ss = await resp2.Content.ReadAsStringAsync();
}
How would I write my access to the other methods?
For one thing, you are calling PUT on the URL api/LaLa/, but from the server's method signature
public void Put(int id, [FromBody]string value)
it appears that the URL should include a numeric id to satisfy the first parameter, e.g. api/LaLa/100 or similar. Perhaps you could modify your client to call PutAsync() like this:
var resp2 = client.PutAsync("api/LaLa/100", new System.Net.Http.StringContent("Hey", Encoding.UTF8, "application/json")).Result;
Does POST work? Look at this answer to a question that looks remarkably like yours, and see if you can get that to work.

Categories