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
Related
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?
My Xamarin app deadlocks when trying to make API call (asp.net core web API). The mobile app is using Android emulator. I created both API and client app following Microsoft's own tutorial. Requests run normally when making call with Postman or directly in the browser of my dev machine.
Constants class:
public static class Constants
{
public static string BaseAddress =
DeviceInfo.Platform == DevicePlatform.Android
? "https://10.0.2.2:44348"
:"https://localhost:44348";
public static string AppointmentsUrl = $"{BaseAddress}/api/appointments/";
}
Handler:
public class AppointmentHandler
{
HttpClient client;
JsonSerializerOptions serializerOptions;
private List<Appointment> Appointments { get; set; }
public AppointmentHandler()
{
client = new HttpClient();
serializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
}
public async Task<List<Appointment>> GetAppointments()
{
Appointments = new List<Appointment>();
try
{
Uri uri = new Uri(string.Format(Constants.AppointmentsUrl, string.Empty));
// the program deadlocks here
HttpResponseMessage response = await this.client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<List<Appointment>>(content, serializerOptions);
}
}
catch (Exception e)
{
var m = e.Message;
}
return null;
}
}
Have you tried using
.ConfigureAwait(false)
This is a common issue with async code and user interfaces. More here:
https://forums.xamarin.com/discussion/174173/should-i-use-configureawait-bool-or-not
I've got a ASP.NET Core middleware that calls another HTTP service to check if user is authorized to proceed with request or not. At the moment it depends on a provided custom header, called X-Parameter-Id.
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
namespace ParameterAuthorization.Middleware
{
public class ParameterAuthorizationMiddleware
{
private readonly RequestDelegate _next;
private readonly IParameterAuthorizationService _parameterAuthorizationService;
public ParameterAuthorizationMiddleware(RequestDelegate next, IParameterAuthorizationService parameterAuthorizationService)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
_parameterAuthorizationService = parameterAuthorizationService ?? throw new ArgumentNullException(nameof(parameterAuthorizationService));
}
public async Task InvokeAsync(HttpContext httpContext, IConfiguration configuration)
{
if (httpContext is null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (parameterRequestContext is null)
{
throw new ArgumentNullException(nameof(parameterRequestContext));
}
if (!(httpContext.Request.Headers.ContainsKey("X-Parameter-Id") && httpContext.Request.Headers.ContainsKey("Authorization")))
{
await ForbiddenResponseAsync(httpContext);
}
var parameterIdHeader = httpContext.Request.Headers["X-Parameter-Id"].ToString();
if (!int.TryParse(parameterIdHeader, out var parameterId) || parameterId < 1)
{
await ForbiddenResponseAsync(httpContext);
}
var authorizationHeader = httpContext.Request.Headers["Authorization"].ToString();
var parameterResponse = await _parameterAuthorizationService.AuthorizeUserParameterAsync(parameterId, authorizationHeader);
if (string.IsNullOrWhiteSpace(parameterResponse))
{
await ForbiddenResponseAsync(httpContext);
}
await _next.Invoke(httpContext);
}
private static async Task ForbiddenResponseAsync(HttpContext httpContext)
{
httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
await httpContext.Response.WriteAsync("Forbidden");
return;
}
}
}
And that's the HTTP call implementation:
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace ParameterAuthorization.Middleware.Http
{
public class ParameterAuthorizationService : IParameterAuthorizationService
{
private readonly HttpClient _httpClient;
private readonly JsonSerializer _jsonSerializer;
public ParameterAuthorizationService(HttpClient httpClient, JsonSerializer jsonSerializer)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_jsonSerializer = jsonSerializer ?? throw new ArgumentNullException(nameof(jsonSerializer));
}
public async Task<string> AuthorizeUserParameterAsync(int parameterId, string authorizationHeader)
{
var request = CreateRequest(parameterId, authorizationHeader);
var result = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
if (!result.IsSuccessStatusCode)
{
return string.Empty;
}
using (var responseStream = await result.Content.ReadAsStreamAsync())
using (var streamReader = new StreamReader(responseStream))
using (var jsonTextReader = new JsonTextReader(streamReader))
{
return _jsonSerializer.Deserialize<ParameterResponse>(jsonTextReader).StringImInterestedIn;
}
}
private static HttpRequestMessage CreateRequest(int parameterId, string authorizationHead1er)
{
var parameterUri = new Uri($"parameters/{parameterId}", UriKind.Relative);
var message = new HttpRequestMessage(HttpMethod.Get, parameterUri);
message.Headers.Add("Authorization", authorizationHead1er);
return message;
}
}
}
And this is the boilerplate code to DI named HttpClient
sc.TryAddSingleton<JsonSerializer>();
sc.AddHttpClient<IParameterAuthorizationService, ParameterAuthorizationService>(client =>
{
client.BaseAddress = authorizationServiceUri;
client.DefaultRequestHeaders.Add("Accept", "application/json");
});
authorizationServiceUri is something I provide from a custom extension method.
The issue is that my calls to this service will randomly take 7, 10, even 20 seconds to this service and then it's going to be quick and then again slow. I call this exact ParameterAuthorizationService from Postman, it takes less than 50ms, constantly.
I'm attaching a screenshot from Application Insights showing the whole sequence of events.
Both services are deployed as Azure App Services under the same subscription within the same App Service Plan.
Code works just fine, but I'm already pulling my hair off having no clue what could be causing these performance abnormalities.
I've also checked TCP Connections in Azure App service and it's all green.
What could be the reason that some HTTP calls will be really slow?
Update
My App Service runs on a S1 App Service Plan. https://azure.microsoft.com/en-us/pricing/details/app-service/windows/
You should short circuit the pipeline if you write to httpContent. See Aspnet Core Middleware documentation :
Don't call next.Invoke after the response has been sent to the client.
Use something like this :
if (string.IsNullOrWhiteSpace(parameterResponse))
{
await ForbiddenResponseAsync(httpContext);
}
else
{
await _next.Invoke(httpContext);
}
Consider also handling authentification with a middleware that inherit from the aspnet core AuthenticationHandler class to leverage all the aspnet core Authentification/Authorization facilities. Here is an implementation example of a BasicAuthentification handler for simplicity.
Your ParameterAuthorizationService looks good. I don't think it's the source of your slow request call. To be sure, you can track the entire service call by measuring the time it takes and publishing-it in appinsights :
public class ParameterAuthorizationService : IParameterAuthorizationService
{
//...
private readonly TelemetryClient _telemetryClient;
public ParameterAuthorizationService(HttpClient httpClient, JsonSerializer jsonSerializer)
{
//...
_telemetryClient = new TelemetryClient();
}
public async Task<string> AuthorizeUserParameterAsync(int parameterId, string authorizationHeader)
{
var startTime = DateTime.UtcNow;
var timer = Stopwatch.StartNew();
var isSuccess = true;
try
{
return await AuthorizeUserParameterImpl(parameterId, authorizationHeader);
}
catch (Exception ex)
{
timer.Stop();
isSuccess = false;
_telemetryClient.TrackException(ex);
_telemetryClient.TrackDependency("Http", nameof(ParameterAuthorizationService), nameof(AuthorizeUserParameterAsync),
startTime, timer.Elapsed, isSuccess);
throw;
}
finally
{
if (timer.IsRunning)
timer.Stop();
if (isSuccess)
_telemetryClient.TrackDependency(
"Http", nameof(ParameterAuthorizationService), nameof(AuthorizeUserParameterAsync),
startTime, timer.Elapsed, isSuccess);
}
}
private async Task<string> AuthorizeUserParameterImpl(int parameterId, string authorizationHeader)
{
//Your original code
}
}
I believe I may have found where your trouble might be, taken from Microsoft docs:
Although HttpClient implements the IDisposable interface, it's
designed for reuse. Closed HttpClient instances leave sockets open in
the TIME_WAIT state for a short period of time. If a code path that
creates and disposes of HttpClient objects is frequently used, the app
may exhaust available sockets. HttpClientFactory was introduced in
ASP.NET Core 2.1 as a solution to this problem. It handles pooling
HTTP connections to optimize performance and reliability.
Recommendations:
Do not create and dispose of HttpClient instances directly.
Do use HttpClientFactory to retrieve HttpClient instances. For more information, see Use HttpClientFactory to implement resilient HTTP
requests.
I can see you are using HttpClient in your code, which might hint where you should focus your performance solution.
You tagged asp.net core 2.2 in the question, So I do recommend you use HttpClientFactory instead of HttpClient in your code, as suggested.
I have been following a youtube tutorial on connecting my a xamarin forms app to an asp.net web api. Unfortunately my Listview is not getting populated by data from the api.
The Xamarin forms app has the following Files:
RestClient.cs
public class RestClient<T> {
private const string WebServiceUrl = "http://localhost:49864/api/Oppotunities/";
public async Task<List<T>> GetAsync()
{
var httpClient = new HttpClient();
var json = await httpClient.GetStringAsync(WebServiceUrl);
var OppotunityList = JsonConvert.DeserializeObject<List<T>>(json);
return OppotunityList ;
} }
MainViewModel.cs
public MainViewModel()
{
InitializeDataAsync();
}
private async Task InitializeDataAsync()
{
var oppotunitiesServices = new OppotunitiesServices();
OppotunitiesList = await oppotunitiesServices.GetOppotunitiesAsync();
}
OppotunityServices.cs
public class OppotunitiesServices
{
public async Task<List<Oppotunity>> GetOppotunitiesAsync()
{
RestClient<Oppotunity> restClient = new RestClient<Oppotunity >();
var oppotunitiesList = await restClient.GetAsync();
return oppotunitiesList;
}
}
If you are debugging from an emulator, you should not use localhost to reach your development machine. You have to use the IP address or your running service.
You can test IP addresses directly from the browser of your emulator so you don't waste time starting/stopping your app to debug this...
Hope it helps
I'm wondering how to consume a WEBAPI from another ASP.Net Web API to store the response in a database.
I know how to consume a WEBAPI from clients like javascript,console application etc.
But the requirement is to pull the data from third party API by my WEBAPI & store the result in a database so that using my WEBAPI my clients request me for data.
Is it possible to do this with an Asp.Net Web API?
In this tutorial is explained how to consume a web api with C#, in this example a console application is used, but you can also use another web api to consume of course.
http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client
You should have a look at the HttpClient
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost/yourwebapi");
Make sure your requests ask for the response in JSON using the Accept header like this:
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
Now comes the part that differs from the tutorial, make sure you have the same objects as the other WEB API, if not, then you have to map the objects to your own objects. ASP.NET will convert the JSON you receive to the object you want it to be.
HttpResponseMessage response = client.GetAsync("api/yourcustomobjects").Result;
if (response.IsSuccessStatusCode)
{
var yourcustomobjects = response.Content.ReadAsAsync<IEnumerable<YourCustomObject>>().Result;
foreach (var x in yourcustomobjects)
{
//Call your store method and pass in your own object
SaveCustomObjectToDB(x);
}
}
else
{
//Something has gone wrong, handle it here
}
please note that I use .Result for the case of the example. You should consider using the async await pattern here.
For some unexplained reason this solution doesn't work for me (maybe some incompatibility of types), so I came up with a solution for myself:
HttpResponseMessage response = await client.GetAsync("api/yourcustomobjects");
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
var product = JsonConvert.DeserializeObject<Product>(data);
}
This way my content is parsed into a JSON string and then I convert it to my object.
public class EmployeeApiController : ApiController
{
private readonly IEmployee _employeeRepositary;
public EmployeeApiController()
{
_employeeRepositary = new EmployeeRepositary();
}
public async Task<HttpResponseMessage> Create(EmployeeModel Employee)
{
var returnStatus = await _employeeRepositary.Create(Employee);
return Request.CreateResponse(HttpStatusCode.OK, returnStatus);
}
}
Persistance
public async Task<ResponseStatusViewModel> Create(EmployeeModel Employee)
{
var responseStatusViewModel = new ResponseStatusViewModel();
var connection = new SqlConnection(EmployeeConfig.EmployeeConnectionString);
var command = new SqlCommand("usp_CreateEmployee", connection);
command.CommandType = CommandType.StoredProcedure;
var pEmployeeName = new SqlParameter("#EmployeeName", SqlDbType.VarChar, 50);
pEmployeeName.Value = Employee.EmployeeName;
command.Parameters.Add(pEmployeeName);
try
{
await connection.OpenAsync();
await command.ExecuteNonQueryAsync();
command.Dispose();
connection.Dispose();
}
catch (Exception ex)
{
throw ex;
}
return responseStatusViewModel;
}
Repository
Task<ResponseStatusViewModel> Create(EmployeeModel Employee);
public class EmployeeConfig
{
public static string EmployeeConnectionString;
private const string EmployeeConnectionStringKey = "EmployeeConnectionString";
public static void InitializeConfig()
{
EmployeeConnectionString = GetConnectionStringValue(EmployeeConnectionStringKey);
}
private static string GetConnectionStringValue(string connectionStringName)
{
return Convert.ToString(ConfigurationManager.ConnectionStrings[connectionStringName]);
}
}