Create an IdentityUser object from a method out of Controller - c#

I'm working on an Asp.Net Core project targeted .Net 5 with Microsoft Identity and Entity framework core (Code first approache).
In my project some entities will inherit from IAuditProperties interface.
IAuditProperties:
This interface used to read/write some audition info from/in any Entity that implement it.
string CreatedBy { get; set; }
DateTime CreatedOn { get; set; }
bool IsEdited { get; set; }
string LastEditor { get; set; }
DateTime LastEditDate { get; set; }
In my project I wrote some extension methods that will write some auditon infos, all those extensions for any Entity that implemented the IAuditProperties interface.
WriteCreationAudit extension method as example
/// <summary>
/// Write audit properties for an <see cref="IAuditProperties"/> for the first creation
/// </summary>
/// <param name="obj"><see cref="IAuditProperties"/> object to write in</param>
/// <param name="appUser">Current user</param>
public static void WriteCreationAudit( this IAuditProperties obj,AppUser appUser)
{
obj.CreatedBy = appUser.FullName;
obj.CreatedOn = DateTime.Now.InMorocco();
obj.IsEdited = false;
}
What is exactly the core issue?
As you notice that the extention method WriteCreationAudit is recieves a appUser parameter, this parameter's type (AppUser) inherit from IdentityUser.
So, the exact issue is How can I create object from AppUser without pass it as parameter from the Controller ?
How I handle this issue at this time?
At this time I'm depending on Controllers and DI to get AppUser object and pass it to WriteCreationAudit method, and I don't love this technique.
So please, How can I achieve my goal about creating new object from AppUser from the extension method ? or if I can't achieve it is there any other good way ?
Massive thanks in advance.

Depend on the circumstance, I would suggest 2 approaching ways, then take whichever that suit your case most... or even better, take the idea and implement it your way.
Simple data was required
As your purposed, I saw every thing was required just a FullName and might be in the future userId. So, why just not simply put them somewhere in Jwt or even cookie depend on your authentication mechanism ? They're not such as ultra-secure information to guard. We can easily saw them here, even Jwt was designed to hold that kind of information. So, just inject IHttpContextAccessor into DbContext or repository if we make use of Repository pattern, take out User Info, then tweak a bit on the SaveChanges things.
Data required to process was some kiind complex or need to be secured.
Make something like BaseInfoRequest object that contain all the infomations we need, set them on some upper middleware and store in cache, with absolute expiration that equivalent to request timeout, the key should be HttpContext.Session.Id + "some constants string" that represent request infoObject. Then take them out from the cache wherever we need.
Just a small note: If we doesn't expose the UserName for example, but userId only, which mean foreach request we need to take UserName from somewhere. That's not a good idea in production scenarios. Take some consider about them to balance things out.

What's wrong with DI inject to controller then pass the param to the extension method?
I just recalled a while back Microsoft said don't inject SignInManager and UserManager in razor component (also not razor page/the razor component with #page). Instead, extend UserClaimsPrincipalFactory to add claims like:
public class AdditionalUserClaimsPrincipalFactory
: UserClaimsPrincipalFactory<AppUser, IdentityRole>
{
public AdditionalUserClaimsPrincipalFactory(
UserManager<AppUser> userManager,
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> optionsAccessor)
: base(userManager, roleManager, optionsAccessor)
{ }
public async override Task<ClaimsPrincipal> CreateAsync(AppUser user)
{
var principal = await base.CreateAsync(user);
var identity = (ClaimsIdentity)principal.Identity;
var claims = new List<Claim>();
claims.Add(new Claim("FullName", user.FullName?? ""));
identity.AddClaims(claims);
return principal;
}
}
I agree with #Gordon Khanh Ng. and this is just implementation difference

This is a very common behaviour and there are many ways to achieve this. Here is how you can do this. This is probably the easiest way
Override your SaveChanges()/ SaveChangesAsync() method in DbContext class. Also inject the IHttpContextAccessor in the constructor.
Then use this code inside your DbContext class.
The GetCurrentUserId() method may differ depending on your Identity implementation.
private string GetCurrentUserId()
{
var httpContext = _httpContextAccessor?.HttpContext ?? null;
if (httpContext.HasValue() && httpContext.User.HasValue())
{
var authenticatedUsername = httpContext.User.Claims.Where(c => c.Type == "sub")
.Select(c => c.Value).SingleOrDefault();
return authenticatedUsername;
}
return null;
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
ChangeTracker.DetectChanges();
var entries = ChangeTracker.Entries()
.Where(e => e.State != EntityState.Detached && e.State != EntityState.Unchanged);
foreach (var entry in entries)
{
if (entry.Entity is IAuditProperties trackable)
{
var now = DateTime.UtcNow;
var user = GetCurrentUserId();
switch (entry.State)
{
case EntityState.Added:
trackable.CreatedAt = now;
trackable.CreatedBy = user;
trackable.IsEdited = false;
break;
}
}
}
return base.SaveChangesAsync(cancellationToken);
}

Related

Using user variables in dependency injection

I've got a scoped service, that needs to instantiate with user specific variables.
builder.Services.AddScoped<IUserService, UserService>();
UserService currently has a logger as it's constructor.
I'm currently doing the following through a factory, in a hacky way:
public class UserServiceFactory
{
private readonly ServiceProvider _sp;
private readonly DbContext _db;
public UserServiceFactory(ServiceProvider sp, DbContext db) { _sp = sp; _db = db; }
public async Task<IUserService> GetUserServiceForUserAsync(Guid userId)
{
var (apiKey, apiSecret) = await _db.FetchApiKeyAndSecretAsync(userId);
var userService = _sp.GetRequiredService<IUserService>();
userService.InitUser(apiKey, apiSecret);
return userService;
}
}
I'm running into the following problems:
I can't use builder.Services.AddScoped<IUserService, UserService>(); with string parameters, because as soon as it attempts to register in DI, it can't resolve the string parameters in the constructor, even though the only place I'm going to be initializing it will be in the factory, and I'll be providing said string parameters.
If I don't use builder.Services.AddScoped<IUserService, UserService>();, I'd need to use Activator.CreateInstance<UserService>(...), which ties a concrete implementation to this class which is not ideal. In addition, I can't track said UserService for disposal when the scope gets disposed.
It was suggested that I register a Func<> to return a user service. If I do this, I don't believe it will be a scoped service, and thus not be disposed of properly when the scope is destroyed.
The implementation of UserService is essentially an an HTTP Client, that will make requests with an apiKey and apiSecret of the IdentityUser. I'd like it to exist for the duration of the scope (In the case of asp.net core, the request, or in the case of being called from a Quartz job, the duration of the job), and then dispose afterwards.
UserService contains about 20 various methods, such as FetchAccountAsync, BuyItemAsync(itemId, quantity), SellItemAsync(itemId), which should make requests using the initialized httpclient. I'd like to avoid trying to initialize the apiKey/apiSecret in each method, because this will add a level of synchronization that I don't feel is needed. HttpClient is by default multithreaded, so my methods are fairly pain free:
Task BuyItemAsync(string itemId, int quantity)
{
var res = await _httpClient.GetAsync($"{_baseUrl}/buy?itemId={itemId}&qty={quantity}");
res.EnsureSuccessStatusCode();
}
How can I initialize my UserService with these apiKeys, apiSecrets, to be used in a scoped manner?
NOTE: Some of these details I've added based on your comments. Some of these may appear a little contrived because I don't know your full logic, context, or needs.
Design
I suggest the following
Remove the factory.
Go ahead and use builder.Services.AddScoped<IUserService, UserService>();.
Change the constructor of UserService to accept an ISecurityContext that will provide the API key and secret. This context will also be registered with AddScoped.
Have the UserService use the ISecurityContext at runtime, and remove any properties/parameters for API key and secret (if you had them).
Have the SecurityService use an IUserProvider at runtime, and remove any properties/parameters for user ID (if you had them).
This means no runtime data needs to be injected, no hacky method to expose, no factory, and no injecting the service provider.
At startup register the interfaces. It is important that they be scoped. They are going to share the lifetime, which will be short.
...
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<ISecurityContext, SecurityContext>();
builder.Services.AddScoped<IUserProvider, UserProvider>();
Then implement the classes and a Result that can return all the contextual data.
public class Result
{
public Result(string apiKey, string apiSecret, Guid userId)
{
ApiKey = apiKey;
ApiSecret = apiSecret;
UserId = userId;
}
public string ApiKey { get; }
public string ApiSecret { get; }
public Guid UserId { get; }
}
public interface IUserProvider
{
Guid GetUserId();
}
public class UserProvider : IUserProvider
{
public async Task<Guid> GetUserId() => IdentityUser.GetUserId());
}
public interface ISecurityContext
{
Task<Result> GetApiKeyAndSecretAsync();
}
public class SecurityContext : ISecurityContext
{
private readonly DbContext _db;
private readonly IUserProvider userProvider;
// safe because this SecurityContext will be scoped!
private Result _result;
public SecurityContext(DbContext db, IUserProvider userProvider)
{
_db = db;
_userProvider = userProvider;
}
public async Task<Result> GetApiKeyAndSecretAsync()
{
if (_result != null) return _result;
var userId = _userProvider.GetUsedId();
var (apiKey, apiSecret) = await _db.FetchApiKeyAndSecretAsync(userId);
return _result = new Result(apiKey, apiSecret, userId);
}
}
public interface IUserService
{
Task DoWhatever();
}
public class UserService : IUserService
{
private readonly ISecurityContext _context;
public UserService(ISecurityContext context) => _context = context;
public async Task DoWhatever()
{
// use the security context
var result = await _context.GetApiKeyAndSecretAsync();
// use the result; e.g. pass the key/secret/user ID
// on to an HttpClient, RestClient, etc.
...
}
...
}
Usage
Using an IUserService means injecting that into your Quartz.NET job, a message handler, a web controller... wherever. In each case you may realize that one single implementation of any of these interfaces is not enough. That's OK. There are ways in dependency injection to fix that (e.g. named resolutions of multiple different concrete implementations), but I leave that to you.
Here's an example usage for a web controller.
public class MyController
{
private readonly IUserService _userService;
public MyController(IUserService userService, ...)
{
_userService = userService;
...
}
[HttpGet]
public async Task<IActionResult> GetStuff(...)
{
// gets the key and secret first time
await _userService.DoWhatever();
// uses cached versions of key, secret, guid across
// calls of _userService methods within scope
var someResult = await _userService.GetSomethingElse();
...
}
Commentary
This design has a few advantages
Security details are encapsulated behind an abstraction and not mixed into the UserService
The whole thing is more testable because the security details can be mocked when testing the UserService.
Key and secret are cached once within the scope and can be reused across methods in UserService that are invoked while in the same scope.
As #NKosi said in the comments, mixing runtime data at construction time is an anti-pattern. The link they referenced, Dependency Injection Code Smell: Injecting runtime data into components, is a good read and goes into more depth.
As you add more runtime data, you can expand the properties in Result and logic in SecurityContext or you can inject more context-like objects into UserService returning their own result-like instances.
There is a placeholder pattern that I have found useful here.
STARTUP CODE
Define dependencies in your application startup code, something like the following. Note that .NET does not allow you to run async processing in the factory method for IUserService:
app.UseMiddleware<DependencySetupMiddleware>();
services.AddSingleton(new MyDatabase());
services.AddScoped<UserServiceHolder>();
services.AddScoped<IUserService>(ctx =>
{
return ctx.GetRequiredService<UserServiceHolder>().UserService;
});
The holder class just looks like this:
public class UserServiceHolder {
public IUserService UserService { get; set; }
}
MIDDLEWARE CODE
The async processing can be done in a small middleware class. For the HTTP case you would do it like this, assuming that you get the User Id after authentication. Note that dependencies cannot be added to the .NET container at runtime, but you can update the holder object:
public class DependencySetupMiddleware
public DependencySetupMiddleware(RequestDelegate next) {
}
public async Task Invoke(HttpContext context, MyDatabase db) {
var userId = context.User.Claims.First(c => c.Type == "UserId")
var (apiKey, apiSecret) = await db.FetchApiKeyAndSecretAsync(userId);
var userService = new UserService(apiKey, apiSecret)
context.GetRequiredService<UserServiceHolder>().UserService = userService;
await next();
}
}
For Quartz you would have a similar middleware class - a Job Factory, which reads the job's user ID rather than using claims or the HTTP context.
BUSINESS LOGIC
With this code in place you can inject an IUserService into your business logic and forget about the holder class:
class MyController {
public MyController(IUserService userService) {
}
}
I think you might already have an answer here, but let me give you a working example. Here's my assumption:
I want to have an instance of a class that has all the things about the user available.
Here's the approach I used for PopForums.
Step 1: You're using some kind of built-in ASP.NET authentication, probably cookies or something external. I won't cover that here, because there are many ways to do it, but look at HttpContext.SignInAsync() for more. The important part is to use a name or identifier that will be put into the token it reads back in the next step.
Step 2: Use middleware to get your user and make it stick. You'll start with a ClaimsIdentity when you use HttpContext.AuthenticateAsync(schemeName). For example:
public async Task InvokeAsync(HttpContext context, IUserService userService)
{
var authResult = await context.AuthenticateAsync(schemeNameUsedFromSignIn);
var identity = authResult?.Principal?.Identity as ClaimsIdentity;
if (identity != null)
{
var user = userService.GetUserByName(identity.Name);
if (user != null)
{
// add claims to the identity if you want
// then stash your user object in the Items collection, which lasts the duration of the request
context.Items["TheUser"] = user;
context.User = new ClaimsPrincipal(identity);
}
}
await _next.Invoke(context);
Step 3: Enable getting the user anywhere you want by pulling it out of the context of the request, but isolate it to an interface so there are no hard dependencies. Example:
public interface IUserRetrievalShim
{
User GetUser();
}
public class UserRetrievalShim : IUserRetrievalShim
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserRetrievalShim(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public User GetUser()
{
var user = _httpContextAccessor.HttpContext?.Items["TheUser"] as User;
return user;
}
}
What I like about this approach is that any classes up and down the dependency chain can be mocked out and unit tested without all of the HttpContext references. IHttpContextAccessor does a great job isolating it, and if it's not available, you'll get a null. And in this case, you're getting your user object, not the one tied to ASP.NET. You can still check HttpContext.User != null if you want, but this similarly will be null if there's no authenticated user. I only do the above with claims because maybe other app areas may want it.
Step 4: In your controllers, service classes or anything in between, inject IUserRetrievalShim and call its GetUser() method to get the user.
The bottom line here is that dependency injection is not the place to make the user stuff contextual. DI is purely setup and configuration, not run-time context. Use your UserService where ever you want, and combined with this shim, you can pass its ID or whatever to those service methods. You should not expect the service to be contextual out of the box by way of injection.
With that said, your User objects (not to be confused with HttpContext.User) can be composed of whatever you want, so long as you're OK with whatever the cost is to fetch that information and hydrate the object.

Using resource-based authorization on a list in ASP.NET Core/Entity Framework Core 3.1

Premise
The documented method to apply resource-based authorization in ASP.Net Core is to register an AuthorizationHandler, define each OperationAuthorizationRequirement, then check access to resources using the AuthorizeAsync() method of an injected IAuthorizationHandler. (Reference docs)
This is all well and good for checking operations against individual records, but my question is how best to authorize against many resources at once (e.g. checking read permission against a list of records for an index page)?
Example
Let's say we have a list of orders, and we want to provide users with a list of the ones they have created. To do this with the practice defined by Microsoft's docs, we would first create some static OperationAuthorizationRequirement objects:
public static class CrudOperations
{
public static OperationAuthorizationRequirement Create =
new OperationAuthorizationRequirement { Name = nameof(Create) };
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement { Name = nameof(Read) };
public static OperationAuthorizationRequirement Update =
new OperationAuthorizationRequirement { Name = nameof(Update) };
public static OperationAuthorizationRequirement Delete =
new OperationAuthorizationRequirement { Name = nameof(Delete) };
}
..and then create our AuthorizationHandler:
public class OrderCreatorAuthorizationHandler :
AuthorizationHandler<OperationAuthorizationRequirement, Order>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
InspectionManagementUser resource)
{
if (context.User == null || resource == null)
{
return Task.CompletedTask;
}
var currentUserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (resource.CreatedById == currentUserId
&& requirement.Name == CrudOperations.Read.Name) {
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
This is registered as a service in Startup.cs, and is ready to go. In our view logic, we can use our new handler to get a filtered list of orders as such:
//_context is an injected instance of the application's DatabaseContext
//_authorizationService is an injected instance of IAuthorizationService
var allOrders = await _context.Orders.ToListAsync();
var filteredOrders = allOrders
.Where(o => _authorizationService.AuthorizeAsync(User, o, CrudOperations.Read).Result.Succeeded);
This will work just fine, but to me seems extremely computationally expensive as each record is checked separately in memory. This would increase even further as the logic for the authorization handler got more complex (for example, if it involved a database call).
It would presumably be far more efficient to have the database engine filter the list for us as follows:
var currentUserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var filteredOrders = await _context.Orders
.Where(o => o.CreatedById == currentUserId)
.ToListAsync();
This will execute faster, but we've now bypassed our authorization logic completely. If we later decide to change the restrictions in our AuthorizationHandler we must also remember to change it here and anywhere else we use this method. If you ask me that rather seems to defeat the purpose of separating this authorization code out in the first place.
Is there a neat solution to this problem that I'm missing? Any advice or guidance on best practice would be much appreciated.

Can I use a separate query plan cache per session?

I have a multi-tenant ASP.NET application, and our database is set up with soft deletes. Initially, we handled the restriction of data directly at the query level, e.g:
var foos = context.Foos.Where(foo => !foo.Deleted && foo.TenantId = currentTenantId).ToList();
As you can imagine, this bloats all of the queries in our data access layer, and makes the API very vulnerable if one forgets to add the correct filter conditions. We have decided to apply global filtering to the context with Z.EntityFramework.Plus.EF6:
public class FooDataContextFactory
{
public FooDataContext CreateContext()
{
var context = new FooDataContext();
context.Filter<Foo>(collection => collection.Where(foo=> !foo.Deleted));
var principal = Thread.CurrentPrincipal as ClaimsPrincipal;
if (principal.HasClaim(claim => claim.Type == "TenantId"))
{
var currentTenantId = int.Parse(principal.FindFirst("TenantId").Value);
context.Filter<Foo>(collection => collection.Where(foo => foo.TenantId == currentTenantId));
}
return context;
}
}
This works perfectly for a single user. However, when you switch tenant, we have issues with the filter expression being saved in the query plan cache. This is a known issue with Entity Framework Plus, and since it doesn't appear to be resolved, I need to find a workaround.
The most immediate solution I can think of is to associate the lifetime of the query plan cache to the current session, and when the user logs out or switches tenant, the cache is destroyed. Is this possible, and if so, how can I achieve this?
I had this exact same problem and tried to work with Z.EntityFramework.Plus.EF6 with the same issues. I found that the zzzprojects team also has EntityFramework.DynamicFilters which works much better for this purpose. The query that is cached is parameterized and the value is injected at runtime using the selector function you provide.
using System.Data.Entity;
using EntityFramework.DynamicFilters;
public class Program
{
public class CustomContext : DbContext
{
private int _tenantId;
public int GetTenantId()
{
return _tenantId;
}
// Call this function to set the tenant once authentication is complete.
// Alternatively, you could pass tenantId in when constructing CustomContext if you already know it
// or pass in a function that returns the tenant to the constructor and call it here.
public void SetTenantId(int tenantId)
{
_tenantId = tenantId;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Filter applies to any model that implements ITenantRestrictedObject
modelBuilder.Filter(
"TenantFilter",
(ITenantRestrictedObject t, int tenantId) => t.TenantId == tenantId,
(CustomContext ctx) => ctx.GetTenantId(), // Might could replace this with a property accessor... I haven't tried it
opt => opt.ApplyToChildProperties(false)
);
}
}
public interface ITenantRestrictedObject
{
int TenantId { get; }
}
}

Validation in Business Layer: How to call service methods?

I have created a struct on validating models on Business Layer which is based on Steven's answer.
It is working well but something confuses my mind. I inject UserService in CreateUserValidator to able to use GetUser method. This means I call validator in UserService and create a new UserService instance to check whether user exist.
UserService -> [ValidateUser -> new UserService().GetUser()]
It works but seems to be a very bad design. But I have to use that method.
Could you please let me know how I can solve this problem, or Shouldn't I worry about it?
public class CreateUser
{
public string Name { get; set; }
public string Email { get; set; }
}
public sealed class CreateUserValidator : Validator<CreateUser>
{
private IUserService _userService;
public CreateUserValidator(IUserService userService)
{
_userService = userService;
}
protected override IEnumerable<ValidationResult> Validate(
CreateUser entity)
{
var user = _userService.GetUserByEmail(entity.Email);
if (user != null)
{
yield return new ValidationResult("Email", "Email address is already exist!");
}
}
}
UserService.cs
public partial class UserService : IUserService
{
IGenericUnitofWork _uow = null;
private readonly IValidationProvider _validationProvider;
public UserService(IGenericUnitofWork uow, IValidationProvider validationProvider)
{
_uow = uow;
_validationProvider = validationProvider;
}
public User CreateUser(CreateUser createUser)
{
this._validationProvider.Validate(createUser);
var user = new User()
{
Email = createUser.Email,
Name = createUser.Name,
};
_uow.Repository<User>().Insert(User);
_uow.SaveChanges();
return user;
}
public User GetUser(string email)
{
var user = _uow.Repository<User>().Where(m => m.Email == email).FirstOrDefault();
return user;
}
}
You dependency graph is cyclic. As described in section 6.3 of Dependency Injection in .NET second edition, dependency cycles are often caused by Single Responsibility Principle violations, as is the case in your design.
The problem is that UserService has too many responsibilities: Creating a user is a different responsibility than getting a user. Creating a user can become a very complex use case, as the validation logic hints at, while getting a user is something typically quite simple. It would therefore be beneficial to split UserService into multiple smaller classes. This would allow the validator to depend on the service that allows retrieving the user by its mail address, while the 'create user' service can depend on the validator.
To take it even one step further, you might want to remove validation from the 'create user' service completely. Validation is a cross-cutting concern, and mixing it with the class that contains the business logic, makes such class harder to maintain.
A design that might benefit you is one where you place all state changing business actions behind a common abstraction, as described here.

Should repositories be implemented as singletons as best practice?

I have a small webapp that uses EntityFramework to store stuff via repositories into the database.
What I've done so far (based on all the tutorials I read) is create a repository where I need it, as shown below:
In CustomMembershipProvider:
public CustomMembershipProvider()
{
_userRepository = new UserRepository(new TenantApplicationContext());
}
In my RegisterController:
public TenantRepository TenantRepository { get; set; }
public UserRepository UserRepository { get; set; }
protected override void Initialize(RequestContext requestContext)
{
if (MembershipService == null) { MembershipService = new AccountMembershipService(); }
if (TenantRepository == null) { TenantRepository = new TenantRepository(TenantApplicationContext); }
if (UserRepository == null) { UserRepository = new UserRepository(TenantApplicationContext); }
base.Initialize(requestContext);
}
The point is, that I instantiate the UserRepository twice. This becomes a problem when I create a User in one instance, and try to retrieve it in the other instance, and I did not call SaveChanges in between.
The problem lies here:
// Snippet from the register controller class
if (!UserRepository.Exists(model.AccountableEmailAddress))
{
// 1 - Create the user via a custom MembershipProvider
// Note, the CustomMembershipProvider has it's own instance of UserRepository
var createStatus = MembershipService.CreateUser(
model.AccountableUser,
model.Password,
model.AccountableEmailAddress);
if (createStatus == MembershipCreateStatus.Success)
{
// Left out irrelevant code
AdministerUserAndTenant(tenant.Name, model.AccountableEmailAddress);
}
}
private void AdministerUserAndTenant(string tenantName, string emailAddress)
{
// 2 - Try to retrieve the user from a different (!) instance of UserRepository
var user = UserRepository.GetUser(emailAddress);
var tenant = TenantRepository.GetTenantByName(tenantName);
tenant.Users.Add(user);
TenantApplicationContext.SaveChanges();
}
I hope you can still follow, tried to leave out unnecessary parts.
What is the best way to deal with issues like this?
PS: I'm not very fond of the Singleton pattern, so if possible don't go there :).
When exactly does it become a problem? Cause that's where the answer lies. Classes that should know of each other's unsaved changes should use the same repository instance. Since they are probably related, you'll manage passing a reference between them.
If there's reason why all of your application should have one single repository, use Dependency Injection.

Categories