15 Replies
using System.Net;
using JShop.Core;
using JShop.Core.Repositories;
using JShop.Shared.Contracts.Identity;
using JShop.Shared.Results;
using MassTransit;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace JShop.Application.Identity.Commands.RegisterUser;
public sealed class RegisterUserHandler : IConsumer<RegisterUserCommand>
{
private readonly IUsersRepository _usersRepository;
private readonly IPasswordHasher<User> _passwordHasher;
public RegisterUserHandler(IUsersRepository usersRepository, IPasswordHasher<User> passwordHasher)
{
_usersRepository = usersRepository;
_passwordHasher = passwordHasher;
}
public async Task Consume(ConsumeContext<RegisterUserCommand> context)
{
var normalizedEmail = context.Message.Email.ToUpper();
var usedEmail = await _usersRepository.AllUsers()
.FirstOrDefaultAsync(x => x.Email == normalizedEmail);
if (usedEmail is not null)
{
await context.RespondAsync(new Result(HttpStatusCode.Conflict, None.Instance));
return;
}
var user = new User
{
Email = normalizedEmail
};
user.PasswordHash = _passwordHasher.HashPassword(user, context.Message.Password);
await _usersRepository.AddUserAsync(user, context.CancellationToken);
await _usersRepository.SaveChangesAsync(context.CancellationToken);
await context.RespondAsync(new Result(HttpStatusCode.Created, None.Instance));
}
}
using System.Net;
using JShop.Core;
using JShop.Core.Repositories;
using JShop.Shared.Contracts.Identity;
using JShop.Shared.Results;
using MassTransit;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace JShop.Application.Identity.Commands.RegisterUser;
public sealed class RegisterUserHandler : IConsumer<RegisterUserCommand>
{
private readonly IUsersRepository _usersRepository;
private readonly IPasswordHasher<User> _passwordHasher;
public RegisterUserHandler(IUsersRepository usersRepository, IPasswordHasher<User> passwordHasher)
{
_usersRepository = usersRepository;
_passwordHasher = passwordHasher;
}
public async Task Consume(ConsumeContext<RegisterUserCommand> context)
{
var normalizedEmail = context.Message.Email.ToUpper();
var usedEmail = await _usersRepository.AllUsers()
.FirstOrDefaultAsync(x => x.Email == normalizedEmail);
if (usedEmail is not null)
{
await context.RespondAsync(new Result(HttpStatusCode.Conflict, None.Instance));
return;
}
var user = new User
{
Email = normalizedEmail
};
user.PasswordHash = _passwordHasher.HashPassword(user, context.Message.Password);
await _usersRepository.AddUserAsync(user, context.CancellationToken);
await _usersRepository.SaveChangesAsync(context.CancellationToken);
await context.RespondAsync(new Result(HttpStatusCode.Created, None.Instance));
}
}
namespace JShop.Core.Repositories;
public interface IUsersRepository
{
public IQueryable<User> AllUsers();
public Task AddUserAsync(User user, CancellationToken cancellationToken = default);
public Task<User?> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default);
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}
namespace JShop.Core.Repositories;
public interface IUsersRepository
{
public IQueryable<User> AllUsers();
public Task AddUserAsync(User user, CancellationToken cancellationToken = default);
public Task<User?> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default);
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}
using JShop.Core;
using JShop.Core.Repositories;
using Microsoft.EntityFrameworkCore;
namespace JShop.Infrastructure.Repositories;
internal sealed class UsersRepository : IUsersRepository
{
private readonly DatabaseContext _databaseContext;
public UsersRepository(DatabaseContext databaseContext)
{
_databaseContext = databaseContext;
}
public IQueryable<User> AllUsers()
{
return _databaseContext.Users.AsQueryable();
}
public async Task AddUserAsync(User user, CancellationToken cancellationToken = default)
{
_databaseContext.Users.Add(user);
await _databaseContext.SaveChangesAsync(cancellationToken);
}
public async Task<User?> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default)
{
var user = await _databaseContext.Users.Where(x => x.Email == email.ToUpper())
.FirstOrDefaultAsync(cancellationToken);
return user;
}
public async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
return await _databaseContext.SaveChangesAsync(cancellationToken);
}
}
using JShop.Core;
using JShop.Core.Repositories;
using Microsoft.EntityFrameworkCore;
namespace JShop.Infrastructure.Repositories;
internal sealed class UsersRepository : IUsersRepository
{
private readonly DatabaseContext _databaseContext;
public UsersRepository(DatabaseContext databaseContext)
{
_databaseContext = databaseContext;
}
public IQueryable<User> AllUsers()
{
return _databaseContext.Users.AsQueryable();
}
public async Task AddUserAsync(User user, CancellationToken cancellationToken = default)
{
_databaseContext.Users.Add(user);
await _databaseContext.SaveChangesAsync(cancellationToken);
}
public async Task<User?> GetUserByEmailAsync(string email, CancellationToken cancellationToken = default)
{
var user = await _databaseContext.Users.Where(x => x.Email == email.ToUpper())
.FirstOrDefaultAsync(cancellationToken);
return user;
}
public async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
return await _databaseContext.SaveChangesAsync(cancellationToken);
}
}
using Microsoft.EntityFrameworkCore;
using User = JShop.Core.User;
namespace JShop.Infrastructure;
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions options) : base(options)
{
}
public DatabaseContext()
{
}
public DbSet<User> Users { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (optionsBuilder.IsConfigured)
{
return;
}
optionsBuilder.UseCosmos(
"https://localhost:8081",
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
databaseName: "JShop");
}
private const string UsersContainerName = "Users";
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasPartitionKey(x => x.Id)
.ToContainer(UsersContainerName);
}
}
using Microsoft.EntityFrameworkCore;
using User = JShop.Core.User;
namespace JShop.Infrastructure;
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions options) : base(options)
{
}
public DatabaseContext()
{
}
public DbSet<User> Users { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (optionsBuilder.IsConfigured)
{
return;
}
optionsBuilder.UseCosmos(
"https://localhost:8081",
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
databaseName: "JShop");
}
private const string UsersContainerName = "Users";
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasPartitionKey(x => x.Id)
.ToContainer(UsersContainerName);
}
}
that looks like an API key you shouldn't have leaked
it's for the local emulator
I guess it isn't a big deal
i don't see an
AnyAsync
anywhere unless i'm blindoops
wrong code
here it is
using System.Net;
using JShop.Core;
using JShop.Core.Repositories;
using JShop.Shared.Contracts.Identity;
using JShop.Shared.Results;
using MassTransit;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace JShop.Application.Identity.Commands.RegisterUser;
public sealed class RegisterUserHandler : IConsumer<RegisterUserCommand>
{
private readonly IUsersRepository _usersRepository;
private readonly IPasswordHasher<User> _passwordHasher;
public RegisterUserHandler(IUsersRepository usersRepository, IPasswordHasher<User> passwordHasher)
{
_usersRepository = usersRepository;
_passwordHasher = passwordHasher;
}
public async Task Consume(ConsumeContext<RegisterUserCommand> context)
{
var normalizedEmail = context.Message.Email.ToUpper();
var usedEmail = await _usersRepository.AllUsers()
.AnyAsync(x => x.Email == normalizedEmail);
if (usedEmail)
{
await context.RespondAsync(new Result(HttpStatusCode.Conflict, None.Instance));
return;
}
var user = new User
{
Email = normalizedEmail
};
user.PasswordHash = _passwordHasher.HashPassword(user, context.Message.Password);
await _usersRepository.AddUserAsync(user, context.CancellationToken);
await _usersRepository.SaveChangesAsync(context.CancellationToken);
await context.RespondAsync(new Result(HttpStatusCode.Created, None.Instance));
}
}
using System.Net;
using JShop.Core;
using JShop.Core.Repositories;
using JShop.Shared.Contracts.Identity;
using JShop.Shared.Results;
using MassTransit;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace JShop.Application.Identity.Commands.RegisterUser;
public sealed class RegisterUserHandler : IConsumer<RegisterUserCommand>
{
private readonly IUsersRepository _usersRepository;
private readonly IPasswordHasher<User> _passwordHasher;
public RegisterUserHandler(IUsersRepository usersRepository, IPasswordHasher<User> passwordHasher)
{
_usersRepository = usersRepository;
_passwordHasher = passwordHasher;
}
public async Task Consume(ConsumeContext<RegisterUserCommand> context)
{
var normalizedEmail = context.Message.Email.ToUpper();
var usedEmail = await _usersRepository.AllUsers()
.AnyAsync(x => x.Email == normalizedEmail);
if (usedEmail)
{
await context.RespondAsync(new Result(HttpStatusCode.Conflict, None.Instance));
return;
}
var user = new User
{
Email = normalizedEmail
};
user.PasswordHash = _passwordHasher.HashPassword(user, context.Message.Password);
await _usersRepository.AddUserAsync(user, context.CancellationToken);
await _usersRepository.SaveChangesAsync(context.CancellationToken);
await context.RespondAsync(new Result(HttpStatusCode.Created, None.Instance));
}
}
does this part of the code you posted work?
var usedEmail = await _usersRepository.AllUsers()
.FirstOrDefaultAsync(x => x.Email == normalizedEmail);
var usedEmail = await _usersRepository.AllUsers()
.FirstOrDefaultAsync(x => x.Email == normalizedEmail);
yes, as expected
but when I try to use AnyAsync it throws exception
that suggests the db provider doesn't implement a translation for
AnyAsync
i've never used cosmosdb so i wouldn't know for sureWhat db are you using, and what does
_userRepository.AllUsers()
return?it returns
_databaseContext.Users.AsQueryable();
CosmosDB, it returns IQueryable from the DbSet of the Users
bad way to write a repository but that's another topic
Well, the repository at least doesn't do anything special, it's just useless passthrough methods
right now you are both right, I put the repository so if ef core (first time tryting it for cosmosdb) makes the developer experience bad I would switch to the default CosmosDb SDK
EF Core DBContext implements the repository pattern to some extend by itself but that's another topic
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.