Skip to content

Using Dapper.CX with Dependency Injection

Adam O'Neil edited this page Jan 18, 2021 · 31 revisions

Nuget

This topic describes a couple ways to use Dapper.CX with dependency injection in ASP.NET Core. You can also use Dapper.CX as a set of IDbConnection extension methods.

In all use cases below, install NuGet package Dapper.CX.SqlServer.AspNetCore in your application project first.

The Simplest Case

During Startup you add the DapperCX service with a connection string and a delegate for converting SELECT SCOPE_IDENTITY() to your entity identity type. This example uses int Id types and a connection string retrieved from configuration:

public void ConfigureServices(IServiceCollection services)
{
    var connectionString = Configuration.GetConnectionString("Default");
    services.AddDapperCX(connectionString, (value) => Convert.ToInt32(value));
}

Now, in your pages or controllers, you'd inject it like this:

public class SampleController : Controller
{
    private readonly DapperCX<int> _data;

    public SampleController(DapperCX<int> data)
    {
        _data = data;
    }
}

In your Razor pages or Blazor components, you'd inject it like this:

@inject DapperCX<int> Data

Now you have access to all DapperCX methods but without the User access.

User Profile Integration with ISession

Most applications will have authentication and need to track crud operations by user in some way. You can add your user profile model to DapperCX so that the User property is automatically populated with info about the current user. Once you have that, there's a lot of functionality you can opt into via several interfaces. For instance you can make sure rows are updated with user and timestamps, validate tenant isolation, and apply application-level permission logic. Here's how to add your user profile class to DapperCX:

Implement IOnboardUser<T> and add your implementation to your service collection as shown below. T represents your user model class in your application. Your T class must implement IUserBase, which is part of the AO.Models package. It's installed automatically as a Dapper.CX dependency. In this example GetSessionUser is the implementation class, implemented in the sample app here.

services.AddSessionUser((session) => new GetSessionUser(session, connectionString));
services.AddDapperCX<int, User>(connectionString, (value) => Convert.ToInt32(value));

Use this overload when adding DapperCX to your service collection, like this. In this example User is the model class type with user profile data.

In this approach, you get efficient user profile access throughout your application wherever you inject the DapperCX service, and you have access to the User property of the DapperCX service.

Injecting the DapperCX service in this usage looks like this, assuming the user model class is User:

@inject DapperCX<int, User> Data

User Profile Integration with Claims

User Profile integration with claims requires a couple of custom classes.

  1. As before, you must start with a user profile model class that implements IUserBase. Example: UserProfile.

  2. Add a service to your project that derives from abstract class DbUserClaimsConverter<TUser>. This used to convert your user profile model class to a set of claims that map onto it. Example: UserProfileClaimsConverter

  3. Add a service to your project that derives from DbUserClaimsFactory<TUser>. Example: UserProfileClaimsFactory. This is used when adding identity during your application startup. This uses the DbUserclaimsFactory<TUser> class you created in step 3, and allows Identity to generate your desired claims when users log in. See example:

services
    .AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddClaimsPrincipalFactory<UserProfileClaimsFactory>();
  1. Use the AddDapperCX extension method in your application startup, like this example:
services.AddDapperCX(
    connectionString, 
    (id) => Convert.ToInt32(id), 
    () => new UserProfileClaimsConverter(connectionString));

The AddDapperCX extension method accepts a database connection string, a delegate that returns your identity column type of choice (-- currently int and long are supported), and lastly a factory that instantiates your DbUserClaimsConverter<TUser> that you created in step 3 above.

Now, you can inject the Dapper.CX SqlServerCrudService<TIdentity, TUser> into your pages or components as per this example.

public class BasePageModel : PageModel
{
    public BasePageModel(DapperCX<int, UserProfile> data)
    {
        Data = data;
    }

    public DapperCX<int, UserProfile> Data { get; }
}

Here, I use a read-only property Data as the accessor for all CRUD operations. The DapperCX class derives from SqlCrudService. CRUD method reference is here.

Extension Methods

There are several extension methods defined here:

  • Task<RedirectResult> SaveAndRedirectAsync (this DapperCX<TIdentity, TUser> crudService, TModel model, Func<TModel, Exception, RedirectResult> redirect, [ ChangeTracker changeTracker ], [ Action beforeSave ], [ Func<TModel, Task> onSuccess ], [ Func<TModel, Exception, Task> onException ])
  • Task<RedirectResult> DeleteAndRedirectAsync (this DapperCX<TIdentity, TUser> crudService, TIdentity id, Func<TModel, Exception, RedirectResult> redirect, [ Func<TModel, Task> onSuccess ], [ Func<TModel, Exception, Task> onException ])
  • Task<RedirectResult> DeleteAndRedirectAsync (this DapperCX<TIdentity, TUser> crudService, TIdentity id, string redirect)
  • Task<IEnumerable<TResult>> QueryAsync (this DapperCX<TIdentity, TUser> crudService, Query query)
  • Task<TResult> QuerySingleAsync (this DapperCX<TIdentity, TUser> crudService, Query query)
  • Task<TResult> QuerySingleOrDefaultAsync (this DapperCX<TIdentity, TUser> crudService, Query query)
  • Task<SelectList> QuerySelectListAsync (this DapperCX<TIdentity, TUser> crudService, Query query, [ object selectedValue ])
  • Task<SelectList> QuerySelectListAsync (this DapperCX<TIdentity, TUser> crudService, SelectListQuery query, [ object selectedValue ])

More Examples

Clone this wiki locally