-
Notifications
You must be signed in to change notification settings - Fork 1
Using Dapper.CX with Dependency Injection
This topic describes a couple ways to use Dapper.CX with dependency injection in ASP.NET Core.
First, install NuGet package Dapper.CX.SqlServer.AspNetCore in your application project.
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. We'll address that in the next example.
Most applications will have authentication and need to track crud operations by user in some way. You can add your user profile model during Startup
to DapperCX so that the User property is automatically populated with info about the current user. When you do that, you have access to a lot of functionality via interfaces you can opt into.
The only requirement before you begin is that your user profile model class must implement IUserBase or IUserBaseWithRoles. The sample app in this repo has this example. You can also use AO.Models.UserProfileBase as the basis for your own profile class. This advantage with this is that it comes with a local time implementation.
To set the User
property, use this overload of the AddDapperCX
method. You supply a delegate Func<IServiceProvider, TUser> getUser
that returns your TUser
user profile instance. There are a couple built-in IServiceProvider
extension methods you can use for this: GetAspNetUser and GetAspNetUserWithRoles. The following example uses GetAspNetUser
, but GetAspNetUserWithRoles
would work also. This example uses the UserProfile model class from this repo's Sample App, and is adapted from here.
services.AddDapperCX(
connectionString,
(sp) => sp.GetAspNetUser<UserProfile>(connectionString),
(id) => Convert.ToInt32(id));
You can of course provide your method that returns your TUser
instance. This would be necessary if you need to initialize users in a way unique to your application.
When your TUser
type is provided in this way, you inject in components like this:
@inject DapperCX<int, UserProfile> Data
Remember to use your own TUser
model type. In this example, it's UserProfile
.
When you add the DapperCX service, it's a scoped service, meaning it's initialized anew for each HTTP request. When you use a method like GetAspNetUser
to query the user profile, that query executes with every single page view in your application. This can hurt your app's performance at scale. You can mitigate this by using an ISession
provider that will fetch user profile from storage you provide.
The built-in methods GetAspNetUser
and GetAspNetUserWithRoles
have an optional sessionKey
argument. If you have an ISession
service registered and you provide the optional sessionKey
argument, DapperCX will try to use your ISession
service to get user profile data before querying the database. An example might look like this. The ISession
service here is UserAppData. Note also that the sessionKey
argument is a string literal "profile"
.
services.AddScoped<ISession>((sp) => new UserAppData(sp));
services.AddDapperCX(
connectionString,
sp => sp.GetAspNetUserWithRoles<UserProfile>(connectionString, "profile"),
(id) => Convert.ToInt32(id));
The main caveat to bear in mind when using ISession
like this is in highly permission-sensitive applications. If someone's roles changes, your session storage won't be aware of the change until they log out and back in again. So, you may need to implement a way for admins to force a user to logout, or using ISession
might not be a good fit for your application.
Although you can use a method like GetAspNetUserWithRoles
to query the roles from the built-in ASP.NET Identity table, this doesn't integrate with the built-in [Authorize]
attribute nor AuthorizeView
component in Blazor. That said, you can still implement role-based logic in your applications:
-
On your
TUser
type used with theAddDapperCX
startup method, implement IUserBaseWithRoles. Example: UserProfile. -
IUserBaseWithRoles
has just one member Roles. I added a helper method HasRole to make checking for the presence of a role easier. -
In your
Startup
method in theAddDapperCX
call,GetAspNetUserWithRoles
as in this example.
Now anywhere in your application where DapperCX
is injected, you can query roles like this Razor page example:
@if (Model.Data.User.HasRole("Admin"))
{
<p>I have the <code>Admin</code> role!</p>
}