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).
Related
I have an API (asp net core 3.1) and a web application (asp net Blazor WebAssembly).
In my API I have a CustomerController with the following method for POST:
[HttpPost]
public async
Task<ActionResult>
CreateOrderAsync(OrderDto orderDto)
{
orderDto.IdOrder =
await repository
.CreateOrderAsync(mapper.Map<Order>(orderDto));
return CreatedAtRoute(nameof(GetOrderByIdAsync),
new { idOrder = orderDto.IdOrder }, orderDto);
}
In my web application I have the class DataServiceHelper, which I use in the actual data services for the web app. Here I have methods for POST and GET and so on:
...
static public async Task PostAsync(HttpClient httpClient, string endpoint, T item)
{
await httpClient.PostAsJsonAsync(endpoint, item);
}
static public async Task<T> FindOneByIdAsync(HttpClient httpClient, string endpoint)
{
return await JsonSerializer.DeserializeAsync<T>
(await httpClient.GetStreamAsync(endpoint), new JsonSerializerOptions()
{ ropertyNameCaseInsensitive = true });
}
...
If I send a POST request to the API (say via Postman) the response contains (among others) the body, which is a jsonized version of my database object. Can I somehow catch that body in my Web App with JsonSerializer and return it like I do with my FindOneByIdAsync method?
Alternatively, in the API, could I create a new header in the responses headers that only contains the Id, that the database creates for the new object, and catch that in my web apps post method from the response?
Use System.Net.Http.Json. Examples:
Task<O> CallGet<O>(string requestUrl) => http.GetFromJsonAsync<O>(requestUrl);
async Task<O> CallPost<I, O>(string requestUrl, I input)
{
using var response = await http.PostAsJsonAsync(requestUrl, input);
return await response.Content.ReadFromJsonAsync<O>();
}
See the documentation for more methods and overloads.
It is available also as a nuget: https://www.nuget.org/packages/System.Net.Http.Json
Might be a little cumbersome, but this works:
static public async Task<T>PostAndListenAsync(HttpClient httpClient, string endpoint, T item)
{
var content = await httpClient.PostAsJsonAsync(endpoint, item);
var stream = await content.Content.ReadAsStreamAsync();
T t = await JsonSerializer.DeserializeAsync<T>(stream, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
return t;
}
Feel free to make a neat one-liner out of it.
My Data Service:
public async Task<OrderDto> PostOrderAsync(OrderDto orderDto)
{
return await DataServiceHelper<OrderDto>.PostAndListenAsync(httpClient, "/Orders", orderDto);
}
In razor:
...
private async Task CreateNewOrder()
{
OrderDto orderDto = await dataService.PostOrderAsync(newOrder);
}
...
I have a simple API gateway controller which returns an IActionResult. The issue is I am not able to read the body of the response.
If I comment out the using block in ExecuteResultAsync it seems to work fine but there is not content/body.
Not sure how to get this working with the httpbody being returned. RouteRequest returning HttpResponseMessage is not an option as it puts the response from the microservice as the body of the response from the Gateway.
So I need to use the HttpResponseMessageResult middleware, which works as expected for headers but not for the body.
public async Task<IActionResult> RouteRequest()
{
// Calls a method which send a request and gets a response and constructs a HttpResponseMessage
_contextAccessor.HttpContext.Response.RegisterForDispose(response);
return new HttpResponseMessageResult(response);
}
public class HttpResponseMessageResult : IActionResult
{
private readonly HttpResponseMessage _responseMessage;
public HttpResponseMessageResult(HttpResponseMessage responseMessage)
{
_responseMessage = responseMessage;
}
public async Task ExecuteResultAsync(ActionContext context)
{
context.HttpContext.Response.StatusCode = (int)_responseMessage.StatusCode;
var responseMessageHeadersArray = _responseMessage.Headers.ToArray();
for (int i = 0; i < responseMessageHeadersArray.Length; i++)
{
var header = responseMessageHeadersArray[i];
context.HttpContext.Response.Headers.TryAdd(header.Key, new StringValues(header.Value.ToArray()));
}
using (var stream = await _responseMessage.Content.ReadAsStreamAsync())
{
await stream.CopyToAsync(context.HttpContext.Response.Body);
await context.HttpContext.Response.Body.FlushAsync();
}
}
}
Try this out, based on this good answer to a similar question, I used the ObjectResult class instead of manually manipulating the streams. When I run it with response from one of our API's (JSON), I get the same amount of data in the body of objectResult when it calls ExecuteAsync as were in the initial response.
public class HttpResponseMessageResult : IActionResult
{
private readonly HttpResponseMessage _responseMessage;
public HttpResponseMessageResult(HttpResponseMessage responseMessage)
{
_responseMessage = responseMessage;
}
public async Task ExecuteResultAsync(ActionContext context)
{
var objectResult = new ObjectResult(await _responseMessage.Content.ReadAsStreamAsync())
{StatusCode = (int)_responseMessage.StatusCode};
foreach (KeyValuePair<string, IEnumerable<string>> h in _responseMessage.Headers)
{
context.HttpContext.Response.Headers.TryAdd(h.Key, string.Join("", h.Value));
}
await objectResult.ExecuteResultAsync(context);
}
}
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");
}
I am trying to consume/call an MVC Web API controller method, which will be used to upload a file. I am struggling to call it from my MVC controller.
Here's my code for the API Controller
public class ImportController : ApiController
{
[HttpPost]
public bool PutImportFile(byte[] fileToBeImported, string nameOfTheFileToBeImported)
{
// I am doing file saving stuff here
}
}
I have tested the file saving part by changing the method to HttpGet and its working when I called it directly from the browser. I removed the parameters for that.
However, I am not able to figure out how to call it from a client.
I have tried below.
public class ImportFileModel
{
public byte[] FileToBeImported { get; set; }
public string NameOfTheFileToBeImported { get; set; }
}
The below code will accept a file from the browser uploaded by user and post it to the API controller to save the file.
[HttpPost]
public async Task<JsonResult> Upload()
{
byte[] file;
string fileName = string.Empty;
if (Request.Files.Count > 0)
{
try
{
fileName = Request.Files[0].FileName;
using (MemoryStream ms = new MemoryStream())
{
Request.Files[0].InputStream.CopyTo(ms);
file = ms.ToArray();
}
//To do: get url from configuration
string url = "http://localhost:(port)/api/Import/PutImportFile";
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/bson"));
ImportFileModel request = new ImportFileModel
{
FileToBeImported = file,
NameOfTheFileToBeImported = fileName
};
MediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
var result = await client.PostAsync(url, request, bsonFormatter);
HttpResponseMessage response = result.EnsureSuccessStatusCode();
}
}
catch (Exception ex)
{
// exception handling here
}
}
return Json(true, JsonRequestBehavior.AllowGet);
}
It ends up in an exception at the last line.
HttpResponseMessage response = result.EnsureSuccessStatusCode();
Throwing 404 not found error.
I have also tried the same from a console application using HttpWebRequest. It also throws the same error.
Your Web API method PutImportFile is setup to receive two values, not a single model; hence, your HttpClient call is not recognized (no matching route found). Change your Web API method to receive a model:
public class ImportController : ApiController
{
[HttpPost]
public bool PutImportFile(ImportFileModel fileInfo)
{
//Your code to save the file...
}
}
I have a MVC5 project that is using a service and repository in a class library project. When I run/debug the following code as a MVC project, the execution hangs at "return await client.GetAsync(url);" in the repository. No exception is thrown.
If I call the same service code and repository code from a unit test or console application, then the code works fine.
What is wrong with the code or what am I doing wrong?
//File: TestController.cs
public ActionResult Index(string q)
{
//Code
var mySvc = new MyService();
var svcResponse = mySvc.GetAsync(q).Result;
//More code
}
//File: MyService.cs
public async Task<MyResponse> GetAsync(string q)
{
var myRepo = new MyRepository();
var response = await myRepo.GetAsync(q);
var json = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<MyResponse>(json);
}
//File: MyRepository.cs
public async Task<HttpResponseMessage> GetAsync(string q)
{
var url = URL_CONSTANT + q;
using (var client = new HttpClient())
{
return await client.GetAsync(url); //Execution hangs here when MVC!
}
}
You should make your controller method async instead of blocking on .Result (which causes a deadlock). Your controller action should be something like this
public async Task<IActionResult> Index(string q)
{
//Code
var mySvc = new MyService();
var svcResponse = await mySvc.GetAsync(q);
//More code
}
See for example here for more details http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html