C
C#7mo ago
Elianora

Vertical Slice Architecture and adding IdentityDbContext<TUser>

https://github.com/elianora/VerticalSliceTodo/tree/feature/initial-server I'm following along with the vertical slice architecture template and I have a few questions about changing the AppDbContext : DbContext to be an AppDbContext : IdentityDbContext<MyUser>: - Where would the right place to put identity classes such as MyUser be? As a feature slice? - How can I handle the change messages that I'd normally inherit from BaseEntity on my MyUser class since MyUser has to inherit from IdentityUser? I don't want to mess up the logic in EventPublisher
27 Replies
Elianora
Elianora7mo ago
(if there is an example of using this architecture with ASP.NET identity somewhere to look at that would be useful)
jcotton42
jcotton427mo ago
Identity stuff goes in your database right? so it goes in the Data layer (one of the few layers a VSA project will have)
Elianora
Elianora7mo ago
Hmm in the sample they have Common/Domain/BaseEntity and Feature/Todos/Domain/Todo so I was under the impression you still vertically split the domain objects it makes sense that it would go in the data layer
jcotton42
jcotton427mo ago
they're db models, keep them together also, what template?
Elianora
Elianora7mo ago
the one from this repository (dotnet new hona-vsa): https://github.com/Hona/VerticalSliceArchitecture
GitHub
GitHub - Hona/VerticalSliceArchitecture: A small but opinionated Ve...
A small but opinionated Vertical Slice Architecture solution template for .NET 8 & C# - Hona/VerticalSliceArchitecture
Elianora
Elianora7mo ago
dotnet
YouTube
Vertical Slice Architecture: How Does it Compare to Clean Architect...
Is Vertical Slice Architecture the next big thing or just as cool new kid? Enterprise software development requires you to choose the right architecture. This session with Luke Parker will provide a realistic dive into Vertical Slice Architecture (VSA) with .NET; showcasing the potential shift from Clean Architecture (CA) to VSA. You will lear...
jcotton42
jcotton427mo ago
oh hm I don't like how he's split up the dbcontext everywhere the splitting by technical concern within features is also kinda silly imo @viceroypenguin | 🦋🐧🌟 ping
Elianora
Elianora7mo ago
So essentially you're saying you think the DB stuff should be a horizontal layer that exists across vertical slices
jcotton42
jcotton427mo ago
yes
jcotton42
jcotton427mo ago
I like this image as a summary
Elianora
Elianora7mo ago
good image OK I think I also don't understand the EventPublisher / MediatR well enough to wrap my brain around the right way to add ASP.NET identity with it? Like I'm sort of understanding what the code is doing but it seems weird to me that the domain object has this StagedEvents list property on it that isn't mapped to the DB
viceroypenguin
viceroypenguin7mo ago
i'm not the biggest fan of it, and luke has a bit more formality than I prefer, but it's a pretty good template. yes, DB is a layer that supports every feature. any feature can access anything in the db it needs to. there's really no reason to restrict whether a feature can access a particular table or not. i'll be honest, i don't like MediatR. i avoid it like the plague. i like the concept of command dispatching, but using a central class for it is too much of a service-locator antipattern. @ɐɹouɐᴉʅƎ if you have any more specific questions about VSA or how to organize, let me know. not sure what you're looking for here.
Elianora
Elianora7mo ago
I think I grasp VSA well enough, just not the technologies that the template used I'll try playing around with it some more to come up with more concrete questions
viceroypenguin
viceroypenguin7mo ago
note that he is using immediate.handlers (which is my library), and he and i are talkign about how to migrate to immediate.apis (which is also my library) so if you have questions about [Handler], feel free to ask me anyway. 😄
Elianora
Elianora7mo ago
Will do 🙂 My goal is to get ASP.NET identity stuff to work with my project right now and I was going to use the handler/endpoint pattern from the template for it I think I'm getting it now I updated the code to use Immediate.Apis and removed a ton of the boilerplate from that template and removed MediatR so now I have this folder structure:
Elianora
Elianora7mo ago
No description
viceroypenguin
viceroypenguin7mo ago
yup. very close to what i have:
No description
Elianora
Elianora7mo ago
Now I just need to figure out how to actually do the auth stuff between the frontend and backend 😅 @🌟🐧🦋 | uınƃuǝdʎoɹǝɔıʌ quick question - how do I capture query params with Immediate.Api HttpPut endpoints? Is there something similar to [FromQuery] model binding for the record Command ?
viceroypenguin
viceroypenguin7mo ago
so currently, the query parameter is done as [AsParameters], so each item inside of that is done as a parameter (i.e. it can come from query/route/body/etc., and can be marked with [FromRoute], etc.) i'm pondering... if adding [FromBody] on the object itself might make sense so that for an [HttpPost], you can make the whole thing a body and not have to make two objects (one for the query, and one for the [FromBody]
Elianora
Elianora7mo ago
in my head I'd expect the API to look something like
[Handler]
[MapPost("/login/{redirectUri}")]
[AllowAnonymous]
public partial class LoginCommand
{
public record Command(string Username, string Password, bool RememberMe);

private static async ValueTask HandleAsync(
[FromQuery]string redirectUri,
[FromBody]Command command,
SignInManager<AppUser> signInManager,
CancellationToken _)
{
var result = await signInManager.PasswordSignInAsync(command.Username, command.Password, command.RememberMe, lockoutOnFailure: true);
}
}
[Handler]
[MapPost("/login/{redirectUri}")]
[AllowAnonymous]
public partial class LoginCommand
{
public record Command(string Username, string Password, bool RememberMe);

private static async ValueTask HandleAsync(
[FromQuery]string redirectUri,
[FromBody]Command command,
SignInManager<AppUser> signInManager,
CancellationToken _)
{
var result = await signInManager.PasswordSignInAsync(command.Username, command.Password, command.RememberMe, lockoutOnFailure: true);
}
}
viceroypenguin
viceroypenguin7mo ago
problem is, that doesn't work well with the Immediate.Handlers interface because the expectation is that there's a single parameter to HandleAsync(), and everything else comes from DI
Elianora
Elianora7mo ago
OK
viceroypenguin
viceroypenguin7mo ago
[Handler]
[MapPost("/login/{redirectUri}")]
[AllowAnonymous]
public partial class LoginCommand
{
public record Command(
[FromRoute] string RedirectUri,
[FromBody] CommandValues CommandValues);

public record CommandValues(string Username, string Password, bool RememberMe);

private static async ValueTask HandleAsync(
Command command,
SignInManager<AppUser> signInManager,
CancellationToken _)
{
var result = await signInManager.PasswordSignInAsync(command.Username, command.Password, command.RememberMe, lockoutOnFailure: true);
}
}
[Handler]
[MapPost("/login/{redirectUri}")]
[AllowAnonymous]
public partial class LoginCommand
{
public record Command(
[FromRoute] string RedirectUri,
[FromBody] CommandValues CommandValues);

public record CommandValues(string Username, string Password, bool RememberMe);

private static async ValueTask HandleAsync(
Command command,
SignInManager<AppUser> signInManager,
CancellationToken _)
{
var result = await signInManager.PasswordSignInAsync(command.Username, command.Password, command.RememberMe, lockoutOnFailure: true);
}
}
Elianora
Elianora7mo ago
ah that makes more sense is that how it works now? or are you saying that's how you'd like it to work? if I'm reading this correct, this is how it works now
viceroypenguin
viceroypenguin7mo ago
yes what i would like to add is possibly:
[Handler]
[MapPost("/login")]
[AllowAnonymous]
public partial class LoginCommand
{
[FromBody]
public record Command(string Username, string Password, bool RememberMe);

private static async ValueTask HandleAsync(
Command command,
SignInManager<AppUser> signInManager,
CancellationToken _)
{
var result = await signInManager.PasswordSignInAsync(command.Username, command.Password, command.RememberMe, lockoutOnFailure: true);
}
}
[Handler]
[MapPost("/login")]
[AllowAnonymous]
public partial class LoginCommand
{
[FromBody]
public record Command(string Username, string Password, bool RememberMe);

private static async ValueTask HandleAsync(
Command command,
SignInManager<AppUser> signInManager,
CancellationToken _)
{
var result = await signInManager.PasswordSignInAsync(command.Username, command.Password, command.RememberMe, lockoutOnFailure: true);
}
}
if you only need body values
Elianora
Elianora7mo ago
that makes sense to me
Want results from more Discord servers?
Add your server