adamfoneil / Dapper.CX

A Crud library based on Dapper
MIT License
8 stars 1 forks source link

need TUser integration in SqlCrudService when working with Azure AD #38

Closed adamfoneil closed 3 years ago

adamfoneil commented 3 years ago

Rebuilding Aerie CRM in Blazor with AAD integration, I notice there's no good way to inject TUser into the crud service. Since I don't control the claims coming from Azure (maybe there's a way to do that, but I don't really want to), I can't construct TUser from claims, and therefore need a way to query dbo.User for the TUser type. (For example, Az claims may or may not include user's time zone, permission level, and other app-specific things.) Also, ideally, the query result should be cacheable in some way to avoid repeated queries.

I'm picturing a new interface IUserGetter (or IGetUser) that describes both a database query for TUser and also some kind of (fast synchronous?) cache access, whether it's Session or something else (like, say, NCache). IUserGetter would be its own service.

A complication here is that setting up dependencies in Startup is not async, so the cache requirement is kind of important. In other words, if you have to query the user table synchronously, you certainly don't want repeated queries with every page request. That's why it's important to have some kind of cache solution in use. The new interface IGetUser would not care what kind of caching (if any) is in use, it just provides a place for you to implement.

adamfoneil commented 3 years ago

Got this working in AspNetCore 1.3.23 with

To use, make sure you add some kind of ISession during app startup (services.AddSession() and remember app.UseSession() in Startup.Configure), and provide your implementation of IGetUser<TUser>. It's a private repo where I'm using it, but here is my implementation

public class GetUser : IGetUser<User>
{
    private readonly ISession _session;
    private readonly string _connectionString;

    private const string profile = "UserProfile";

    public GetUser(ISession session, string connectionString)
    {
        _session = session;
        _connectionString = connectionString;
    }

    public User Get(string userName)
    {
        string json;

        if (_session.TryGetValue(profile, out byte[] data))
        {
            json = Encoding.UTF8.GetString(data);                
        }
        else
        {
            User user;
            using (var cn = new SqlConnection(_connectionString))
            {
                user = cn.GetWhere<User>(new { emailAddress = userName });
                //todo: create user if not found
            }

            json = JsonSerializer.Serialize(user);
            _session.Set(profile, Encoding.UTF8.GetBytes(json));
        }

        return JsonSerializer.Deserialize<User>(json);
    }
}