Call to DB gets stuck on await (but works when called from a Blazor component) - asynchronous

When calling the method from the .cs file, the app gets stuck on the await line; but if I call it from the .razor it works flawlessy.
.cs
public AccountService(IUserData userData)
{
_userData = userData;
}
...
public async Task<bool> Validate(string userId, string password)
{
...
try
{
List<UserModel> users = new List<UserModel<();
users = await _userData.GetUsers();
//NEVER GETS HERE
return true;
}
catch (Exception ex)
{
return false;
}
...
}
.razor
#inject IUserData _db;
#code {
private List<UserModel> users;
...
protected override async Task OnInitializedAsync()
{
users = await _db.GetUsers();
}
...
UserData
public class UserData : IUserData
{
private readonly ISqlDataAccess _db;
public UserData(ISqlDataAccess db)
{
_db = db;
}
public Task<List<UserModel>> GetUsers()
{
string sql = "Select *from dbo.Users";
return _db.LoadData<UserModel, dynamic>(sql, new { });
}
...
}
IUserData
public interface IUserData
{
Task<List<UserModel>> GetUsers();
...
}
DBAccess
public async Task<List<T>> LoadData<T, U>(string sql, U parameters)
{
string connectionString = _config.GetConnectionString(ConnectionStringName);
using (IDbConnection connection = new SqlConnection(connectionString))
{
var data = await connection.QueryAsync<T>(sql, parameters); //I GET STUCK HERE
return data.ToList();
}
}
IDBAccess
Task<List<T>> LoadData<T, U>(string sql, U parameters);
PS
I updated this post https://stackoverflow.com/questions/68225154/implementing-an-interface-on-a-class-with-dependency-injection with this question, but sinced I had already marked it as answered I decided to make a new one

Your problem is how your code is calling the asynchronous method:
if (((AccountService)AccountService).Validate(user.UserCredentials, user.Password).Result)
The .Result may seem weird, but otherwise I get an error: can't convert ...Task to bool
The proper solution for this error is to use await, not Result:
if (await ((AccountService)AccountService).Validate(user.UserCredentials, user.Password))
Using Result can cause deadlocks.

Related

firebase repository in .net core 3.1 does not work on the server when i deploy it, and works well locally

i want to send commend in Firestore using a API .net core 3.1, and i am working using clean architecture. and an CQRS pattern.
like this:
namespace SmartRestaurant.Infrastructure.Services
{
public class FirebaseConfig
{
public string BasePath { get; set; }
}
public class FirebaseRepository : IFirebaseRepository
{
readonly string _DataBaseBasepath;
readonly FirestoreDb _db;
public FirebaseRepository(IOptions<FirebaseConfig> conf)
{
_DataBaseBasepath = conf.Value.BasePath;
if (string.IsNullOrEmpty(_DataBaseBasepath))
{
throw new ArgumentNullException("fireBase Path not found in appsettings");
}
var pathConfigFile = Path.Combine(AppContext.BaseDirectory, "jsonProjectConfogFile.json");
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", pathConfigFile);
_db = FirestoreDb.Create("^projectName");
}
public async Task<T> AddAsync<T>(string path, T data, CancellationToken cancellationToken)
{
try
{
DocumentReference doc = _db.Document(_DataBaseBasepath + "/" + path);
var objectTosend = getOrderToDictionary(data);
await doc.SetAsync(objectTosend, null, cancellationToken);
return data;
}
catch (Exception exe)
{
throw exe;
}
}
public async Task<T> UpdateAsync<T>(string path, T data, CancellationToken cancellationToken)
{
try
{
DocumentReference doc = _db.Document(_DataBaseBasepath + "/" + path);
var objectTosend = getOrderToDictionary(data);
await doc.UpdateAsync(objectTosend, null, cancellationToken);
return data;
}
catch (Exception exe)
{
throw exe;
}
}
}
}
that code is in the infrastrecture layer and the interface of this service is in the application layer
public interface IFirebaseRepository
{
Task<T> AddAsync<T>(string path,T data,CancellationToken cancellationToken);
Task<T> UpdateAsync<T>(string path,T data, CancellationToken cancellationToken);
}
the injection of this service is in the infrastrecture layer like this
services.AddTransient < IFirebaseRepository, FirebaseRepository> ();
i use this service in the application layer like this :
public class OrdersCommandsHandlers : IRequestHandler<CreateOrderCommand, OrderDto>,
IRequestHandler<UpdateOrderCommand, NoContent>,
{
private readonly IApplicationDbContext _context;
private readonly IMapper _mapper;
private readonly IUserService _userService;
private readonly IFirebaseRepository _fireBase;
private readonly string CreateAction = "CreateAction";
private readonly string UpdateAction = "UpdateAction";
public OrdersCommandsHandlers(IApplicationDbContext context,
IMapper mapper,
IUserService userService,
IFirebaseRepository fireBase)
{
_context = context;
_mapper = mapper;
_userService = userService;
_fireBase = fireBase;
}
public async Task<OrderDto> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
var validator = new CreateOrderCommandValidator();
var result = await validator.ValidateAsync(request, cancellationToken).ConfigureAwait(false);
if (!result.IsValid) throw new ValidationException(result);
....
await _context.SaveChangesAsync(cancellationToken);
var orderDto = _mapper.Map<OrderDto>(order);
orderDto.CurrencyExchange = CurrencyConverter.GetDefaultCurrencyExchangeList(orderDto.TotalToPay, foodBusiness.DefaultCurrency);
var path = request.FoodBusinessId + "/Orders/" + orderDto.OrderId;
await _fireBase.AddAsync(path, orderDto, cancellationToken);
......
return _mapper.Map<OrderDto>(newOrder);
}
public async Task<NoContent> Handle(UpdateOrderCommand request, CancellationToken cancellationToken)
{
var validator = new UpdateOrderCommandValidator();
var result = await validator.ValidateAsync(request, cancellationToken).ConfigureAwait(false);
if (!result.IsValid) throw new ValidationException(result);
......
var orderDto = _mapper.Map<OrderDto>(order);
var foodBusiness = await _context.FoodBusinesses.FindAsync(order.FoodBusinessId);
if (foodBusiness != null)
orderDto.CurrencyExchange = CurrencyConverter.GetDefaultCurrencyExchangeList(orderDto.TotalToPay, foodBusiness.DefaultCurrency);
var path = order.FoodBusinessId + "/Orders/" + order.OrderId;
await _fireBase.UpdateAsync(path,orderDto, cancellationToken);
return default;
}
}
when i deploiye this code in the server i have this erreur :
Error constructing handler for request of type MediatR.IRequestHandler`2[SmartRestaurant.Application.Orders.Commands.CreateOrderCommand,SmartRestaurant.Application.Common.Dtos.OrdersDtos.OrderDto]. Register your handlers with the container. See the samples in GitHub for examples.
i try to using fireStor in the NetCore 3 api with CQRS, and a erreur Appear when i use the hendler that contaie firebase service.
and locally all work well , the probleme appear in the server when i deploie the code.
the reason of this issues is in the constructor of firebaseService
public FirebaseRepository(IOptions<FirebaseConfig> conf)
{
_DataBaseBasepath = conf.Value.BasePath;
if (string.IsNullOrEmpty(_DataBaseBasepath))
{
throw new ArgumentNullException("fireBase Path not found in appsettings");
}
var pathConfigFile = Path.Combine(AppContext.BaseDirectory, "jsonProjectConfogFile.json");
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", pathConfigFile);
_db = FirestoreDb.Create("^projectName");
}
the conf.Value.BasePath is null in the server because the appsetting.json does not contain the FirebaseConfig section.

Task was canceled but the process continued

I am processing a set of records (batch) based on a ID.
Based on exception, I am collecting exception details and sending an email.
However recently I got a “A Task was canceled” exception, so this information was added and sent in an email. But even after the exception, the record made it to the database. There were other exception and those records didn't make it to the database.
This only happens sporadically. Most of the times the exception and the records getting into the database matches.
I am using Autofac.
To give an idea
internal class Program
{
public static void Main ( )
{
IContainer context = Program.BuildContainer( );
try{
context.Resolve<IBatchProvider>().DoAsynBatchProcess().Wait();
}
catch(Exception ex)
{
//log errors
}
}
private static IContainer BuildContainer( )
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<LogBuilder>.As<ILogBuilder>().InstancePerDependency();
builder.RegisterType<EmailSender>.As<IEmailSender>().InstancePerDependency();
builder.RegisterType<BatchProvider>As<IBatchProvider>().InstancePerDependency();
return builder.Build();
}
}
public class BatchProvider : IBatchProvider {
private readonly ILogBuilder _logBulider;
private readonly IEmailsender _emailSender;
public BatchProvider(ILogBuilder logBuilder, IEmailSender emailSender)
{
_logBuilder = logBuilder;
_emailSender = emailSender;
}
public async Task DoAsyncBatchProcess()
{
//Get ID from DB
….
await BatchProcessing (ID)
}
public async Task BatchProcessing (int ID)
{
//Get all records for this ID
//loop through the records and post it.
for (int index=0; i< dataRowArray.Length; ++ index)
{
try{
bool result = await ServiceClient.PostData(guid)
}
catch(Exception ex)
{
//log exception
}
finally
{
//log to file
}
}
await SendEmail ( )
}
private async Task SendEmail()
{
//email
}
private void LogToFile()
{ //log to file
}
}
public class ServiceClient
{
public static async Task<bool> PostData(string guid)
{
using( var client = new HttpClient(new HttpClientHandler() {useDefaultCredentials = true}))
{
string _baseAddress = “http://Mywebserver/“;
client.baseAddress = new Uri(_baseAddress)
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”);
string _method = “MyMethod”;
HttpResponseMessage response = await client.PostAsJsonAsync(_method, new ServiceRequest() {MyGuid = guid}).configureAwait(false);
if(response.IsSuccessStausCode)
{
var result = await response.Content.ReadAsAsync<ServiceResponse>();
return result.Status;
}
else
{
string message = await _response.Content.ReadAsStringAsync();
throw new Exception(message);
}
}
}
}
In my Main method does the .wait() is enough or should I do the following
Context.Resolve().DoAsyncBatchProcess().ConfigureAwait(false).GetAwaiter().GetResult();
Is there a way to ensure that the exception happen and it doesn't continue for that task but continue for the other tasks?
Thank you.

Why is my blazor app leaving so many ports open

I created a .net 6 app using server side Blazor and SignalR. The app was basically a single page with 10 different components. Each component was a client that looked something like this:
#code {
private HubConnection? hubConnection;
private ExampleViewModel data { get; set; } = new ExampleViewModel();
protected override async Task OnInitializedAsync()
{
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/mainhub"))
.Build();
hubConnection.On<ExampleViewModel>("example", (Data) =>
{
data = Data;
StateHasChanged();
});
await hubConnection.StartAsync();
}
public async ValueTask DisposeAsync()
{
if (hubConnection is not null)
{
await hubConnection.DisposeAsync();
}
}
}
Each component has a "broadcaster" that runs on a timer and makes a call to the database using Mediator and Dapper. Example:
public class ExampleBroadcaster : IDataBroadcaster
{
private readonly IMediator _mediator;
private readonly ILogger<ExampleBroadcaster> _logger;
private readonly IHubContext<MainHub> _mainHub;
private readonly IMemoryCache _cache;
private const string Something = "example";
private Timer _timer;
public ExampleBroadcaster(IHubContext<MainHub> mainHub,
IMediator mediator, ILogger<ExampleBroadcaster> logger,
IMemoryCache cache)
{
_mainHub = mainHub;
_mediator = mediator;
_logger = logger;
_cache = cache;
}
public void Start()
{
_timer = new Timer(BroadcastData, null, 0, 30000);
}
private async void BroadcastData(object? state)
{
ExampleViewModel viewModel;
try
{
if (_cache.TryGetValue(Something, out ExampleViewModel data))
{
viewModel = data;
}
else
{
viewModel = _mediator.Send(new GetExampleData()).Result;
_cache.Set(Something, viewModel, TimeSpan.FromMinutes(10));
}
await _mainHub.Clients.All.SendAsync("example", viewModel);
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message);
}
}
}
The mediator handler simply uses Dapper to get data from the database:
public class GetExampleData : IRequest<ExampleViewModel>
{
}
public class GetExampleDataHandler : IRequestHandler<GetExampleData, ExampleViewModel>
{
private readonly IDbConnectionFactory _connectionFactory;
private string _storedProcedure = "some sproc name";
public GetExampleDataHandler(IDbConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public async Task<ExampleViewModel> Handle(GetExampleData request, CancellationToken cancellationToken)
{
using (var connection = _connectionFactory.GetReadOnlyConnection())
{
return await connection.QueryFirstAsync<ExampleViewModel>(_storedProcedure, CommandType.StoredProcedure);
}
}
}
This is the main razor page that houses all the individual components:
#code {
private HubConnection? hubConnection;
protected override async Task OnInitializedAsync()
{
try
{
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/mainhub"))
.Build();
await hubConnection.StartAsync();
await hubConnection.SendAsync("Init");
}
catch(Exception exception)
{
Logger.LogError(exception, exception.Message);
}
}
public async ValueTask DisposeAsync()
{
if (hubConnection is not null)
{
await hubConnection.DisposeAsync();
}
}
}
Finally, the MainHub.cs code:
public class MainHub : Hub
{
IEnumerable<IDataBroadcaster> _broadcasters;
private static bool _started;
public MainHub(IEnumerable<IDataBroadcaster> broadcasters)
{
_broadcasters = broadcasters;
}
public void Init()
{
if (!_started)
{
StartBroadcasting();
_started = true;
}
}
private void StartBroadcasting()
{
foreach (var broadcaster in _broadcasters)
{
broadcaster.Start();
}
}
}
This all worked fine locally, in our dev environment, and our test environment. In production, we found that the app was crashing after a number of hours. According to the server admins, the app is opening 100s or 1000s of ports and leaving them open until the number of allotted ports was hit, causing the app to crash.
What is the issue here? The broadcasters are registered as singletons. This app only runs on one web server.

Couchbase Generic Repository in .Net Core 3.1

I am having one frustrating time attempting to follow the Couchbase documentation (which is horribly outdated and the examples just do not even compile).
I already have several other persistence stacks following this same pattern. I would like to migrate to Couchbase from CosmosDb and I simply cannot figure out how to implement this in a generic pattern. FYI, I am not here to debate the move from Cosmos to Couchbase, so the let please leave that topic alone.
I have already done this for Mongo, Dynamo, PostresSql, MsftSql, Cosmos Document, Cosmos SQL, and Cosmos Table.
Nuget Packages:
Couchbase.Lite # 2.7.1
CouchbaseNetClient # 3.0.1
The IPlatformRepository interface, used by all repositories in the system
Task<T> CreateAsync(T data);
Task<T> ReadAsync(Guid id);
Task<bool> UpdateAsync(T data);
Task<bool> DeleteAsync(Guid id);
Task<IEnumerable<T>> AllAsync();
Task<IEnumerable<T>> QueryAsync(Expression<Func<T, bool>> predicate = null);
Here is the PoC code that I have in my Couchbase provider, but I am stuck at trying to figure out how to do the AllAsync() and QueryAsync() functions (commented out QueryAsync() is from the CosmosDocument provider I have. I have not started on that one yet. I started with the AllAsync() to just retrieve the documents.
public class CouchbaseRepository<T> : IPlatformRepository<T>
where T: DomainAggregate
{
private readonly string collectionName;
private readonly CouchbaseSettings couchbaseSettings;
private ICluster cluster;
private IBucket bucket;
private ICollection<T> collection;
private ICouchbaseCollection cbc;
public CouchbaseRepository(CouchbaseSettings settings)
{
Inflector.Inflector.SetDefaultCultureFunc = () => new CultureInfo("en");
collectionName = typeof(T).Name.Pluralize().Uncapitalize();
}
public async Task<T> ReadAsync(Guid id)
{
var result = await bucket.Collection(collectionName).GetAsync(id.ToString());
return result.ContentAs<T>();
}
public async Task<IEnumerable<T>> QueryAsync(Expression<Func<T, bool>> predicate)
{
// var results = new List<T>();
//
// var query = client.CreateDocumentQuery<T>(
// UriFactory.CreateDocumentCollectionUri(
// databaseId,
// collectionId),
// new FeedOptions
// {
// MaxItemCount = -1,
// EnableCrossPartitionQuery = true
// });
//
// predicate = null;
// var conditionalQuery = predicate == null
// ? query
// : query.Where(predicate);
//
// var documentQuery = conditionalQuery.AsDocumentQuery();
//
// while (documentQuery.HasMoreResults)
// {
// results.AddRange(await documentQuery.ExecuteNextAsync<T>());
// }
//
// return results;
}
public async Task<IEnumerable<T>> AllAsync()
{
using (var cluseter = new Cluster())
{
}
}
public async Task<T> CreateAsync(T item)
{
var result = await bucket.Collection(collectionName).InsertAsync(item.Id.ToString(), item);
return item;
}
public async Task<bool> UpdateAsync(T item)
{
}
public async Task<bool> DeleteAsync(Guid id)
{
}
private async Task EstablishConnection()
{
cluster = await Cluster.ConnectAsync(couchbaseSettings.Endpoint, couchbaseSettings.User, couchbaseSettings.Password);
bucket = await cluster.BucketAsync(couchbaseSettings.Bucket);
}
}

Use asyn method for synchronous Sqlite on createMethod

I'm using Xamarin, also my SQLite tables contain a large amount of data.
Because I want to avoid UIThread problems in OnCreate(), I need to perform database actions asynchronously.
I'm looking for guidance if I am handling this properly.
First method, which I found on the net:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.InventoryPreviewMain);
Thread thread = new Thread(() =>
{
SQLiteConnection db = new SQLiteConnection(dpPath);
var table = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + Connection.CategoryID + "");
mItems = new List<InventoryPreviewClass>();
foreach (var item in table)
{
mItems.Add(new InventoryPreviewClass() { InventoryItemID = item.InventoryItemID, InventoryItemName = item.InventoryItemName, InventoryItemPrice = item.InventoryItemPrice });
}
MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
mlistview.Adapter = adapter;
});
thread.Start();
Second Method, using async
public async void StartTimer()
{
SQLiteConnection db = new SQLiteConnection(dpPath);
var table = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + Connection.CategoryID + "");
mItems = new List<InventoryPreviewClass>();
foreach (var item in table)
{
mItems.Add(new InventoryPreviewClass() { InventoryItemID = item.InventoryItemID, InventoryItemName = item.InventoryItemName, InventoryItemPrice = item.InventoryItemPrice });
}
MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
mlistview.Adapter = adapter;
await Task.Delay(500);
}
Which of two examples are more safe for keeping alive UIthread? Is there any other solution for making this?What is more reccomended to do?
Answer
Use the Cross-platform SQLite Library made by #FrankKruger to create/access SQLite databases for Xamarin mobile apps.
This library has a built-in asynchronous connection, so you'll never need to worry about accessing the database from the UI Thread again!
Xamarin.Android Example
"Second Method"
public async Task StartTimer()
{
mItems = await InventoryPreviewClassDatabase.GetAllInventoryPreviewClassAsync();
MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
mlistview.Adapter = adapter;
}
BaseDatabase Class
using System;
using System.Threading.Tasks;
using SQLite;
namespace SampleApp
{
public abstract class BaseDatabase
{
#region Constant Fields
static readonly Lazy<SQLiteAsyncConnection> _databaseConnectionHolder = new Lazy<SQLiteAsyncConnection>(() => GetDatabaseConnection());
#endregion
#region Fields
static bool _isInitialized;
#endregion
#region Properties
static SQLiteAsyncConnection DatabaseConnection => _databaseConnectionHolder.Value;
#endregion
#region Methods
protected static async Task<SQLiteAsyncConnection> GetDatabaseConnectionAsync()
{
if (!_isInitialized)
await Initialize().ConfigureAwait(false);
return DatabaseConnection;
}
static async Task Initialize()
{
await DatabaseConnection.CreateTableAsync<InventoryPreviewClass>().ConfigureAwait(false);
_isInitialized = true;
}
SQLiteAsyncConnection GetDatabaseConnection()
{
var sqliteFilename = "YourDatabaseName.db3";
string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
var conn = new SQLiteAsyncConnection(path, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.SharedCache);
return conn;
}
#endregion
}
}
Parent Database Class
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace SampleApp
{
public abstract class InventoryPreviewClassDatabase : BaseDatabase
{
#region Methods
public static async Task<IList<InventoryPreviewClass>> GetAllInventoryPreviewClassAsync()
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.Table<InventoryPreviewClass>().ToListAsync().ConfigureAwait(false);
}
public static async Task<InventoryPreviewClass> GetInventoryPreviewClassByIDAsync(int id)
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.Table<InventoryPreviewClass>().Where(x => x.ID.Equals(id)).FirstOrDefaultAsync().ConfigureAwait(false);
}
public static async Task<int> SaveInventoryPreviewClassAsync(InventoryPreviewClass inventoryPreview)
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
var isObjectInDatabase = await GetInventoryPreviewClassByIDAsync(inventoryPreview.ID).ConfigureAwait(false) != null;
if (isObjectInDatabase)
return await databaseConnection.UpdateAsync(inventoryPreview).ConfigureAwait(false);
return await databaseConnection.InsertAsync(inventoryPreview).ConfigureAwait(false);
}
public static async Task<int> DeleteItemAsync(OpportunityModel opportunity)
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.DeleteAsync(opportunity).ConfigureAwait(false);
}
public static async Task<int> GetNumberOfRowsAsync()
{
var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);
return await databaseConnection.Table<InventoryPreviewClass>().CountAsync().ConfigureAwait(false);
}
#endregion
}
}
This code was inspired from this Xamarin.Forms sample app

Resources