UltraWelfare
UltraWelfare
CC#
Created by UltraWelfare on 7/17/2024 in #help
✅ Waiting on a task more efficiently
I've made this class for my application that needs to process some things in the background using a queue:
c#
public class IcsBackgroundQueue
{
private ConcurrentQueue<IcsCashDesk> _jobQueue = new();

private OrdersDB _ordersDb = new(Types.Order.sell);
private Task _processingTask;
private CancellationTokenSource _cts = new();

public IcsBackgroundWorker()
{
_processingTask = Task.Run(ProcessJobs, _cts.Token);
}

// ... stop function, enqueue function etc

private async Task ProcessJobs()
{
while (!_cts.IsCancellationRequested)
{
try
{
if (_jobQueue.IsEmpty)
{
await Task.Delay(1000, _cts.Token);
continue;
}

_jobQueue.TryDequeue(out var cashDesk);
if (cashDesk == null) continue;
await cashDesk.CompleteWaitAsync();
}
catch (OperationCanceledException)
{
}
}
}
}
c#
public class IcsBackgroundQueue
{
private ConcurrentQueue<IcsCashDesk> _jobQueue = new();

private OrdersDB _ordersDb = new(Types.Order.sell);
private Task _processingTask;
private CancellationTokenSource _cts = new();

public IcsBackgroundWorker()
{
_processingTask = Task.Run(ProcessJobs, _cts.Token);
}

// ... stop function, enqueue function etc

private async Task ProcessJobs()
{
while (!_cts.IsCancellationRequested)
{
try
{
if (_jobQueue.IsEmpty)
{
await Task.Delay(1000, _cts.Token);
continue;
}

_jobQueue.TryDequeue(out var cashDesk);
if (cashDesk == null) continue;
await cashDesk.CompleteWaitAsync();
}
catch (OperationCanceledException)
{
}
}
}
}
Is there anything to do to better optimize the while loop when no jobs are in the queue? I've done a simple 1s delay but I'd bet there's a better way of doing it..?
8 replies
CC#
Created by UltraWelfare on 2/2/2024 in #help
Blazor Server not responding
I tried for the sake of laughs, to convert my blazor hybrid to blazor server... However as expected it doesn't work. It compiles and runs, but opening the localhost url it doesn't respond (endless http loading)... Any ideas on how to debug it:)?
4 replies
CC#
Created by UltraWelfare on 1/25/2024 in #help
Primary constructor parameter is null after being run in a Task
The following snippet of code is responsible for starting a background service
public class PeriodicCallingIdentificationService(CallService callService)
{
private Task? _executeTask;
private CancellationTokenSource? _stoppingCts;
private Modem? _modem;

public void StartExecuting(CancellationToken cancellationToken)
{
if (_modem is null) throw new InvalidOperationException("Can't start executing without modem");
_stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_executeTask = Task.Run(async () =>
{
await DoWork(_stoppingCts.Token); // <-- here
_modem.Close();
_modem = null;
}, cancellationToken);
}
public class PeriodicCallingIdentificationService(CallService callService)
{
private Task? _executeTask;
private CancellationTokenSource? _stoppingCts;
private Modem? _modem;

public void StartExecuting(CancellationToken cancellationToken)
{
if (_modem is null) throw new InvalidOperationException("Can't start executing without modem");
_stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_executeTask = Task.Run(async () =>
{
await DoWork(_stoppingCts.Token); // <-- here
_modem.Close();
_modem = null;
}, cancellationToken);
}
This service is being registered with Microsoft DI as a singleton. When the StartExecuting function is called, the callService is correctly being passed. However if I set a breakpoint inside the lambda of Task.Run, callService is null there... Any ideas?
12 replies
CC#
Created by UltraWelfare on 1/20/2024 in #help
Tips on error handling
I'm currently using OneOf to handle errors. For example:
public async Task<OneOf<None, NotFound, List<ValidationFailure>, GenericError>> EditOrderItem(Guid uid, EditOrderItemOptions options)
public async Task<OneOf<None, NotFound, List<ValidationFailure>, GenericError>> EditOrderItem(Guid uid, EditOrderItemOptions options)
However that is kinda of mouthful. I could try to refactor it using OneOfBase, but there are cases where I need <None, NotFound> or <None, NotFound, GenericError> or really any combination... Is there any way I can refactor it? I'd like to avoid exceptions as this would migrate the problem to "try-catching" everything then `if - is" on the exceptions
7 replies
CC#
Created by UltraWelfare on 1/19/2024 in #help
How to structure query functions in services
I have the following function in my service layer csharp: PS: A category can have List<Item>
public async Task<List<Category>> GetCategories()
{
await using var db = await contextFactory.CreateDbContextAsync();
return await db.Categories
.AsNoTracking()
.OrderBy(c => c.Sort)
.ToListAsync();
}
public async Task<List<Category>> GetCategories()
{
await using var db = await contextFactory.CreateDbContextAsync();
return await db.Categories
.AsNoTracking()
.OrderBy(c => c.Sort)
.ToListAsync();
}
Sometimes I need GetCategories() to just be the Category without any navigation properties included. But also sometimes I need GetCategories() to also include the Items navigation property... I'm thinking of having two functions with two separate dtos (one has only the category, the other one has the category + the items). But I was wondering if there's a better way to do this
22 replies
CC#
Created by UltraWelfare on 12/26/2023 in #help
Organizing and naming different closely related Dtos
My current setup is as follows (I name my Dtos as 'Models'):
Orders (this is the base order class)
- Models
-- OrderModel.cs
-- OrderModelMapper.cs
- OrderService.cs


OrderItems (every order has 1:N order items)
- Models
-- OrderItemModel
-- OrderItemModelMapper


DraftOrders (a draft order extends order)
- Models
-- DraftOrderModel.cs
-- DraftOrderModelMapper.cs
- DraftOrderService.cs


ReceiptOrders (a receipt order extends order)
- Models
-- ReceiptOrderModel.cs
-- ReceiptOrderModelMapper.cs
- ReceiptOrderService.cs
Orders (this is the base order class)
- Models
-- OrderModel.cs
-- OrderModelMapper.cs
- OrderService.cs


OrderItems (every order has 1:N order items)
- Models
-- OrderItemModel
-- OrderItemModelMapper


DraftOrders (a draft order extends order)
- Models
-- DraftOrderModel.cs
-- DraftOrderModelMapper.cs
- DraftOrderService.cs


ReceiptOrders (a receipt order extends order)
- Models
-- ReceiptOrderModel.cs
-- ReceiptOrderModelMapper.cs
- ReceiptOrderService.cs
The order can be of different types (such as draft or receipt, and there's more but I'm keeping it simple). But we also need a way to fetch multiple types at once (hence why a basic Order exists). There is reason that there's a difference between all of them (some relationship constraints when orders are being transformed). My main problem is the mess that is happening between the models. The DraftOrderModel should expose a List<ReceiptOrderModel>. However when you receive the draft order, you don't want the -full- details of the receipt order (since they contain all the order items etc which is not needed). You want a slimmer model of the receipt order that contains basic stuff such as its id, it's title and maybe its price... But I'm not sure how to make this..? Should I make a new DraftOrderReceiptOrderShortModel ? That sounds obnoxious.... Should I make a nested class ReceiptOrderShortModel inside DraftOrderModel ? Should I make a general OrderShortModel and reuse it whenever I want ? I'm not sure how to continue without making it more of a mess:)
47 replies
CC#
Created by UltraWelfare on 12/20/2023 in #help
Interface using functional `Match` does not work
I'm using the OneOf library for discriminated unions
private static async Task<Results<Created<CustomerResult>, NotFound>> CreateCustomer(
[FromBody] CreateCustomerParameters parameters, CustomerService customerService
)
{
// this is OneOf<CustomerResult, ValueNotFound>
var result = await customerService.CreateCustomerAsync(parameters);

return result.Match<IResult>
(x => TypedResults.Created($"/customers/{x.Id}", x), _ => TypedResults.NotFound());
}
private static async Task<Results<Created<CustomerResult>, NotFound>> CreateCustomer(
[FromBody] CreateCustomerParameters parameters, CustomerService customerService
)
{
// this is OneOf<CustomerResult, ValueNotFound>
var result = await customerService.CreateCustomerAsync(parameters);

return result.Match<IResult>
(x => TypedResults.Created($"/customers/{x.Id}", x), _ => TypedResults.NotFound());
}
I have to use TypedResults in order to get OpenAPI to understand things. For those unaware of the library Match works as public TResult Match<TResult>(Func<T0,TResult> f0, Func<T1,TResult> f1) So it will either call the first lambda if CreateCustomerAsync returns a CustomerResult or the second lambda if it returns ValueNotFound TypedResults.Created and TypedResults.NotFound() both extend the IResult interface, so I hoped it would work but it seems like it doesn't Cannot convert expression type 'Microsoft.AspNetCore.Http.IResult' to return type 'Microsoft.AspNetCore.Http.HttpResults.Results<Microsoft.AspNetCore.Http.HttpResults.Created<Support.Features.Customers.CreateCustomer.CreateCustomerResponse>,Microsoft.AspNetCore.Http.HttpResults.NotFound>'
62 replies
CC#
Created by UltraWelfare on 12/4/2023 in #help
Simplifying creation of inherited classes
class Entity {
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
public int? FieldA { get; set; }
public int? FieldB { get; set; }

}

class Base {
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}

class A : Base {
public int FieldA { get; set; }
}

class B : Base {
public int FieldB { get; set; }
}
class Entity {
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
public int? FieldA { get; set; }
public int? FieldB { get; set; }

}

class Base {
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}

class A : Base {
public int FieldA { get; set; }
}

class B : Base {
public int FieldB { get; set; }
}
Entity entity = GetEntityFromDatabase();
if (entity.Field1 == "A") {
return new A {
Field1 = entity.Field1,
Field2 = entity.Field2,
Field3 = entity.Field3,
FieldA = entity.FieldA.Value
};
} else if (entity.Field2 == "B") {
return new B {
Field1 = entity.Field1,
Field2 = entity.Field2,
Field3 = entity.Field3,
FieldB = entity.FieldB.Value
};
}
Entity entity = GetEntityFromDatabase();
if (entity.Field1 == "A") {
return new A {
Field1 = entity.Field1,
Field2 = entity.Field2,
Field3 = entity.Field3,
FieldA = entity.FieldA.Value
};
} else if (entity.Field2 == "B") {
return new B {
Field1 = entity.Field1,
Field2 = entity.Field2,
Field3 = entity.Field3,
FieldB = entity.FieldB.Value
};
}
Basically we need to fetch Entity from the database and then map it into A or B depending on a field. That means you'll have to repeat the field copies a lot. With more fields and more "A"-"B"-"C"-"D"s... this will become a nightmare to maintain. Any other ideas?
3 replies
CC#
Created by UltraWelfare on 11/14/2023 in #help
dotnet 8 windows target
No description
14 replies
CC#
Created by UltraWelfare on 11/9/2023 in #help
❔ EFCore Interceptor problem
In the MS documentation I see they're using the SaveChanges interceptor as:
public async ValueTask<InterceptionResult<int>> SavingChangesAsync(
DbContextEventData eventData,
InterceptionResult<int> result,
CancellationToken cancellationToken = default)
{
_audit = CreateAudit(eventData.Context);

using var auditContext = new AuditContext(_connectionString);

auditContext.Add(_audit);
await auditContext.SaveChangesAsync();

return result;
}
public async ValueTask<InterceptionResult<int>> SavingChangesAsync(
DbContextEventData eventData,
InterceptionResult<int> result,
CancellationToken cancellationToken = default)
{
_audit = CreateAudit(eventData.Context);

using var auditContext = new AuditContext(_connectionString);

auditContext.Add(_audit);
await auditContext.SaveChangesAsync();

return result;
}
I'm trying to do the same but I get an error and I presume it's because of the value task:
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result,
CancellationToken cancellationToken = new CancellationToken())
{
if (eventData.Context is null) return result;

foreach (var entry in eventData.Context.ChangeTracker.Entries())
{
if (entry is not { State: EntityState.Deleted, Entity: ISoftDelete delete }) continue;
entry.State = EntityState.Modified;
delete.DeletedAt = DateTime.Now;
}

return result;
}
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result,
CancellationToken cancellationToken = new CancellationToken())
{
if (eventData.Context is null) return result;

foreach (var entry in eventData.Context.ChangeTracker.Entries())
{
if (entry is not { State: EntityState.Deleted, Entity: ISoftDelete delete }) continue;
entry.State = EntityState.Modified;
delete.DeletedAt = DateTime.Now;
}

return result;
}
The error is that it cannot convert result to ValueTask.... how does the MS example work though...
3 replies
CC#
Created by UltraWelfare on 10/17/2023 in #help
❔ Blazor and Auth - Identity
I'm using Blazor Hybrid (closer to Blazor WASM) for a desktop app therefore I've made my own custom "AuthenticationStateProvider" to specify my own logic. As far as it seems like I can get the AuthenticationState which includes the ClaimsPrincipal alongside its Identity and claims. I've put the account's username and id inside claims but they seem to only receive string. It's a bit cumbersome to use claims to get the id, and then cast it to int (since int is my id type). Is there any better way to do it ? I was thinking of getting my model directly from my custom authentication state provider (I have a variable _currentUser set), but i don't know if that's a good idea
3 replies
CC#
Created by UltraWelfare on 10/14/2023 in #help
❔ EFCore Change Tracker Confusion
Assuming a entity Order with a relationship to entity Table
var order = new Order() {
...
TableId = requestTableId
};
db.Orders.Add(order);
await db.SaveChangesAsync();

var sameOrder = await db.Orders.Include(o => o.Table).Where(o => order.Id).SingleAsync();
var order = new Order() {
...
TableId = requestTableId
};
db.Orders.Add(order);
await db.SaveChangesAsync();

var sameOrder = await db.Orders.Include(o => o.Table).Where(o => order.Id).SingleAsync();
Shouldn't the "sameOrder" be fetched from the tracker and do a single query for the table only? Since it's already being tracked.. Because in my application I'm seeing it fetches the whole order from the start... Unless there's some kinda of rule about relationships that I couldn't find
38 replies
CC#
Created by UltraWelfare on 10/12/2023 in #help
❔ EFCore Expression Reuse Translations`
I have the following piece of projector:
public static Expression<Func<Order, OrderModel>> ProjectToOrderModel()
{
return order => new OrderModel
{
Uid = order.Uid,
Table = ProjectToOrderTable(order.Table),
};
}

public static TableModel ProjectToOrderTableModel(Table table) => new()
{
Id = table.Id,
Name = table.Name
};
public static Expression<Func<Order, OrderModel>> ProjectToOrderModel()
{
return order => new OrderModel
{
Uid = order.Uid,
Table = ProjectToOrderTable(order.Table),
};
}

public static TableModel ProjectToOrderTableModel(Table table) => new()
{
Id = table.Id,
Name = table.Name
};
Where Order is the EFCore entity and OrderModel is a POCO. Whenever I do the following : db.Orders.Select(Mapper.ProjectToOrderModel()) The correct SQL is generated by using the projection fields and not querying the whole columns. This surprised me because ProjectToOrderTableModel is a function and not an expression. However things get confusing when we get into lists. Rewriting the above snippet trying to include a nested collection
public static Expression<Func<Order, OrderModel>> ProjectToOrderModel()
{
return order => new OrderModel
{
Uid = order.Uid,
Table = ProjectToOrderTable(order.Table),
Items = order.OrderItems.AsQueryable().Select(MapToOrderItemsModel).ToList(),
};
}

public static TableModel ProjectToOrderTableModel(Table table) => new()
{
Id = table.Id,
Name = table.Name
};

public static OrderItemModel MapToOrderItemsModel(OrderItem i)
{
return new()
{
Uid = i.Uid,
Name = i.Title,
Price = i.Price
};
}
public static Expression<Func<Order, OrderModel>> ProjectToOrderModel()
{
return order => new OrderModel
{
Uid = order.Uid,
Table = ProjectToOrderTable(order.Table),
Items = order.OrderItems.AsQueryable().Select(MapToOrderItemsModel).ToList(),
};
}

public static TableModel ProjectToOrderTableModel(Table table) => new()
{
Id = table.Id,
Name = table.Name
};

public static OrderItemModel MapToOrderItemsModel(OrderItem i)
{
return new()
{
Uid = i.Uid,
Name = i.Title,
Price = i.Price
};
}
This fails because the Expression of type System.Func cannot be translated, which makes sense. I cannot understand how it works for a singular model, but it cannot work on a collection... ? Is there any tracking bug, or is it a forbidden thing to do?! P.S: I'm aware of the solution of implementing a public static Expression<Func<OrderItem, OrderItemModel>>, I just don't understand why the above doesn't work
17 replies
CC#
Created by UltraWelfare on 10/7/2023 in #help
❔ Method either receive a disposable [context] or use a new one (EFCore - Blazor)
I'm in a blazor project where I wanna reuse some query functions. Basically sometimes I either 1. Wanna use the method on itself where it should create and dispose a new context created by the contextFactory. 2. Wanna use the method inside another method that already has a context, and just wanna pass it so it doesn't create an unneccesary one. What I currently thought of is this:
public async Task<Order?> GetOrderByUid(string uid, DbContext? context)
{
var db = context ?? await _contextFactory.CreateDbContextAsync();
var order = await db.Orders
... Other Stuff ...
.SingleOrDefaultAsync(o => o.Uid == uid);
if (context is null) await db.DisposeAsync();
return order;
}
public async Task<Order?> GetOrderByUid(string uid, DbContext? context)
{
var db = context ?? await _contextFactory.CreateDbContextAsync();
var order = await db.Orders
... Other Stuff ...
.SingleOrDefaultAsync(o => o.Uid == uid);
if (context is null) await db.DisposeAsync();
return order;
}
However I do not like the idea of manually disposing when a context is not passed. Are there any other ideas on how to approach this?
3 replies