How do I call mixed code (async and sync)? - c#

I'm working on an ASP.NET MVC application which has an external reference like this:
public class AuthorizationApi : BaseApi
{
public AuthorizationApi()
{
}
public Configuration LogIn(string username, string password)
{
return LogIn(new Credentials(username, password));
}
public Configuration LogIn(Credentials credentials)
{
AuthLoginWithHttpInfo(credentials);
//missing code
return configuration;
}
protected ApiResponse<object> AuthLoginWithHttpInfo(Credentials credentials)
{
string path = "/auth/login";
RestResponse response = (RestResponse)base.Configuration.ApiClient.CallApiAsync(path, Method.Post, ComposeEmptyQueryParams(), ComposeBody(credentials), ComposeAcceptHeaders(HeaderContentType.None), ComposeEmptyFormParams(), ComposeEmptyFileParams(), ComposeEmptyPathParams(), ComposeContentHeaders(HeaderContentType.Json | HeaderContentType.Xml | HeaderContentType.WwwForm)).Result;
VerifyResponse(response, "AuthLogin");
return GetResponseHeaders(response);
}
}
Calling this code from the web application like so, hangs at LogIn and never returns:
AuthorizationApi api = new AuthorizationApi();
var config = api.LogIn(); //hangs, never returns
The specific line where it hangs is in the external library, where the .RESULT is added to the obvious async method. I have no control over it, and cannot change it:
RestResponse response = (RestResponse)base.Configuration.ApiClient.CallApiAsync(path, Method.Post, ComposeEmptyQueryParams(), ComposeBody(credentials), ComposeAcceptHeaders(HeaderContentType.None), ComposeEmptyFormParams(), ComposeEmptyFileParams(), ComposeEmptyPathParams(), ComposeContentHeaders(HeaderContentType.Json | HeaderContentType.Xml | HeaderContentType.WwwForm)).Result;
Calling from a new Task, sometimes works, sometimes doesn't:
AuthorizationApi api = new AuthorizationApi();
System.Threading.Tasks.Task loginTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
configuration = authApi.LogIn();
});
loginTask.Wait(); //hangs here
How to properly call the LogIn() method from an ASP.NET MVC app?

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).

Is it possible to call WebApi inside Middleware Asp .Net Core

I'm workin on a MVC Aps.Net Core project and I have this situation :
User A is loggedin device A, and user B is trying to login in device A. I allow to login the user B to device A without problem, but in that case I show pop-up message to user A that user A now is disconected from device A.
Evrithing works fine. I call WebApi where I have SQL function, and that function do all the job. The problem is that I have the same code(that call the WebApi) in each function on my project. So I was thinking to make custom middleware so in that way I don't need to replace that code in every function/method in my project.
This is what I tried :
public class Middleware
{
private readonly RequestDelegate _next;
string strBaseUrl = string.Empty;
string strMappaturaUrl = string.Empty;
private readonly IConfiguration config;
private readonly HttpClient client;
public Middleware(RequestDelegate next, IConfiguration _config, HttpClient _client)
{
_next = next;
client = _client;
config = _config;
strBaseUrl = config.GetValue<string>("AppSettings:BaseUrl");
strMappaturaUrl = config.GetValue<string>("AppSettings:MapUrl");
}
public async Task Invoke(HttpContext httpContext)
{
string returnErrore = string.Empty;
CheckUtenteDTO userRequest = new CheckUtenteDTO();
string strUrlApi = string.Empty;
string strContext = string.Empty;
try
{
userRequest.user = HttpContext.Session.GetString("nomeUten");
userRequest.macchina = HttpContext.Session.GetString("macchina");
//Here I call WebApi where I have SQL functio
strUrlApi = config.GetValue<string>("AppSettings:BaseUrl") + "/Users/CheckLoginUser";
string stringData = JsonConvert.SerializeObject(userRequest);
var contentData = new StringContent(stringData, System.Text.Encoding.UTF8, "application/json");
using (var responseMessage = await client.PostAsync(strUrlApi, contentData))
{
if (responseMessage.IsSuccessStatusCode)
{
strContext = await responseMessage.Content.ReadAsStringAsync();
var strReturn = JsonConvert.DeserializeObject<string>(strContext);
if (string.IsNullOrWhiteSpace(strReturn))
returnErrore = string.Empty;
else
throw new UtenteException(strReturn);
}
else
{
strContext = await responseMessage.Content.ReadAsStringAsync();
throw new Exception(strContext);
}
}
}
catch (UserException ex1)
{
returnErrore = ex1.Message.Trim();
HttpContext.Session.SetString("strErrore", ex1.Message);
HttpContext.Session.SetString("nextAction", "LogoutAfterCheck");
HttpContext.Session.SetString("nextController", "Login");
}
catch (Exception ex)
{
returnErrore = ex.Message.Trim();
HttpContext.Session.SetString("strErrore", ex.Message);
HttpContext.Session.SetString("nextAction", "Index");
HttpContext.Session.SetString("nextController", "HomeScreen");
}
return Json(returnErrore);
//return _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<Middleware>();
}
}
}
And I get this errors .
Is it possible to do it in this way?
Any suggestions how to fix this?
Thanks in advance!
That looks like your middleware don't have access to HttpContext and thus the error. In such case, you can pass the context as a parameter to your middleware from your presentation layer where you have access to HttpContext and calling the Middleware function.
Essentially, you are using only the below two parameters from session .. then why not just extract them in your presentation layer and pass them as argument to the middleware function
userRequest.user = HttpContext.Session.GetString("nomeUten");
userRequest.macchina = HttpContext.Session.GetString("macchina");
Change your Invoke method signature to
Task Invoke(string user, string macchina) //assuming both are type string

Can't figure how routing for controllers works

I'm new to ASP.Net and I'm building a website with Blazor server-side and I'm trying to post a form from the client to a controller like this :
Code for the client (located in /pages) :
private async void LogIn()
{
isSubmitting = true;
var json = JsonConvert.SerializeObject(logInForm);
var data = new StringContent(json, Encoding.UTF8, "application/json");
//The base adress correspond to "https://localhost:port/"
string adress = WebClient.httpClient.BaseAddress + "log_in";
var result = await WebClient.httpClient.PostAsync(adress, data);
isSubmitting = false;
}
Code for the server (located in /controllers) :
public class UserController : Controller
{
private readonly AppDbContext _db;
public UserManager<AppUser> _manager;
public UserController(AppDbContext db, UserManager<AppUser> manager)
{
_db = db;
_manager = manager;
}
[Route("log_in")]
[HttpPost]
private async Task<IActionResult> LogIn([FromBody]LogInForm userForm)
{
var user = new AppUser { UserName = userForm.mail, Email = userForm.mail };
var result = await _manager.CheckPasswordAsync(user, userForm.password);
return null;
}
}
When I execute this code, PostAsync() never redirect to the LogIn() method and return with an HTTP 400 error.
I learned first how to do it with PostJsonAsync() but it was using Blazor WebAssembly, which is in preview so I can't use it in production. I tried to find an answer on Internet first but there is no clear information on how to do it for Blazor server-side.
Any chance I could get a quick and simple explanation on what I'm doing wrong ?
default routing in asp.net is
weburl.com/{controller}/{action}
this would mean the url you're looking for is probably
weburl.com/user/log_in
see : https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-3.0

Azure functions 401 Unauthorized issue with RestSharp

I have been using two different Azure functions to talk to each other, one is an HttpTrigger contained in one app service and another is a TimerTrigger contained in another app service. The HttpTrigger uses Function-level authentication.
Here is my HttpTrigger function:
[FunctionName("PendingOrders")]
public static async Task<HttpResponseMessage> GetPendingOrderIds(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "pending-orders")]
HttpRequestMessage req,
TraceWriter log,
[Inject] OrdersController controller)
{
Calling it with the master key works in a browser, but not with RestSharp. The only thing I changed since the previous deployment was upgrading RestSharp from 106.3.1 to 106.6.9. Not a major-version change so there shouldn't be any breaking changes.
private static IRestResponse ProcessRequest(string url, Method method, object requestBody)
{
// Variable "url" is the path plus `?code=<master key here>
var client = PrepareRequest(url, method, requestBody); // see below
return client.Execute(); // executes here, returns 401 Unauthorized.
}
private static PreparedClient PrepareRequest(string url, Method method, object requestBody)
{
var uri = new Uri(url);
var client = new RestClient(uri.GetLeftPart(UriPartial.Authority));
var request = new RestRequest(uri.PathAndQuery, method)
{
OnBeforeDeserialization = resp =>
{
resp.ContentType = "application/json";
}
};
if (requestBody != null)
{
request.AddJsonBody(requestBody);
}
return PreparedClient.Prepare(client, request);
}
Where PreparedClient is
internal struct PreparedClient
{
public IRestClient Client { get; private set; }
public IRestRequest Request { get; private set; }
public static PreparedClient Prepare(IRestClient client, IRestRequest request)
{
var prepared = new PreparedClient { Client = client, Request = request };
return prepared;
}
public IRestResponse Execute()
{
return Client.Execute(Request);
}
public async Task<IRestResponse> ExecuteAsync()
{
return await Client.ExecuteTaskAsync(Request);
}
}
I have debugged the code and verified that the ?code=xxx master key is being added to the url. Is there a different way of authenticating that I need to use that changed between RestSharp 106.3.1 and 106.6.9? Does something have to be put in the headers?

Async call works on console but not on webapi

I need to connect to Firebase from a C# WebApi.
For this I have made a Class Library which is the one who connects to Firebase and retrieve the information.
When I call this Class Library from a Console application, everything runs smoothly, but when I try to run it from a WebApi using Postman it starts to get async problems. Specifically DeadLock is happening.
I'm using FirebaseDatabase.net nugget as Firebase client.
EDIT
private async Task<string> LoginAsync()
{
var FirebaseApiKey = "XXXXXXXX";
var authProvider = new FirebaseAuthProvider(new FirebaseConfig(FirebaseApiKey));
var auth = await authProvider.SignInWithEmailAndPasswordAsync("myemail#mail.com", "mypassword");
return auth.FirebaseToken;
}
public FirebaseClient getClient()
{
if (client == null)
{
client = new FirebaseClient("https://approach-197117.firebaseio.com", new FirebaseOptions
{
AuthTokenAsyncFactory = LoginAsync
});
}
return client;
}
public static async Task<Dictionary<string, Location>> Run()
{
FirebaseConnect firebaseConnect = new FirebaseConnect().getInstance();
var firebase = firebaseConnect.getClient();
var list = await firebase.Child("Location").OnceSingleAsync<Dictionary<string, Location>>();
return list;
}
The problem comes that when I try to do a OnceSingleAsync asking for Location, the call works on a console app but doesn't work on a webapi call

Categories