Dependency injection
CodeBlock DevKit registers core and supporting (and web client) modules with the host’s dependency injection container. Each module exposes work through interfaces—application services, repositories, facades, and similar contracts—so your code depends on abstractions, not concrete types.
You inject those interfaces wherever the host resolves dependencies: Blazor or Razor UI, use case handlers, application services, minimal APIs or controllers, background jobs, and infrastructure classes. You do not register DevKit module services yourself; reference the packages, add the usual startup wiring for your template, then request the interface in a constructor or inject attribute.
To find what to inject for a given area, open that module in the docs (Core modules, Supporting modules, or Web client modules) and read its Introduction and Services pages. Cross-cutting contracts used across every host (dispatcher, current user, notifications, encryption, files) are listed in Services in this section.
Examples
Below, a core module interface and a supporting module style interface show the same pattern: inject in Blazor (@inject or constructor-injected components) or in a use case handler constructor.
Core module: ISubscriptionService (Subscription)
The Subscription module exposes ISubscriptionService for subscription checks. The admin demo page SubscribedUsersOnly.razor injects it with @inject and calls UserHasAnyActiveSubscription in OnInitializedAsync:
@page "/subscribedusers-only"
@using CodeBlock.DevKit.Subscription.Services.Subscriptions
@inject ISubscriptionService SubscriptionService
<PageTitle>@AdminPanelLocalizer[AdminPanelResource.SubscribedUsersOnly]</PageTitle>
<h1 class="page-title">
@AdminPanelLocalizer[AdminPanelResource.SubscribedUsersOnly]
</h1>
<p class="mb-4 text-muted">
@AdminPanelLocalizer[AdminPanelResource.SubscribedUsersOnlyInfo]
</p>
@if (UserHasAnyActiveSubscription)
{
<div class="alert alert-success">
@AdminPanelLocalizer[AdminPanelResource.ActiveSubscriptionMessage]
</div>
}
else
{
<div class="alert alert-danger">
@AdminPanelLocalizer[AdminPanelResource.NoActiveSubscriptionMessage]
<div class="mt-3">
<a class="btn btn-success" href="/pricing/demo">@AdminPanelLocalizer[AdminPanelResource.ViewAvailablePlans]</a>
</div>
</div>
}
@code {
private bool UserHasAnyActiveSubscription = false;
protected override async Task OnInitializedAsync()
{
await CheckIfUserHasAnyActiveSubscription();
}
private async Task CheckIfUserHasAnyActiveSubscription()
{
var result = await SubscriptionService.UserHasAnyActiveSubscription(CurrentUser.GetUserId());
if (result.IsSuccess)
UserHasAnyActiveSubscription = result.Value;
else
result.ShowErrorToast(ToastService);
}
}
The same interface fits a use case constructor. The following shape matches how you gate work on an active subscription (place the handler in your Application project; define SampleRequest as the command or query type your dispatcher uses—often inheriting BaseCommand in this template):
using System.Linq;
using CodeBlock.DevKit.Application.Commands;
using CodeBlock.DevKit.Application.Exceptions;
using CodeBlock.DevKit.Core.Helpers;
using CodeBlock.DevKit.Subscription.Services.Subscriptions;
using MediatR;
namespace CanBeYours.Application.UseCases.Examples;
public sealed record SampleRequest : IRequest<CommandResult>;
internal sealed class SampleSubscriptionGatedUseCase
: IRequestHandler<SampleRequest, CommandResult>
{
private readonly ISubscriptionService _subscriptionService;
private readonly ICurrentUser _currentUser;
public SampleSubscriptionGatedUseCase(
ISubscriptionService subscriptionService,
ICurrentUser currentUser)
{
_subscriptionService = subscriptionService;
_currentUser = currentUser;
}
public async Task<CommandResult> Handle(
SampleRequest request,
CancellationToken cancellationToken)
{
var subscriptionResult = await _subscriptionService.UserHasAnyActiveSubscription(
_currentUser.GetUserId());
if (!subscriptionResult.IsSuccess)
throw new ApplicationException(
subscriptionResult.Errors.FirstOrDefault() ?? "Unable to verify subscription.");
if (!subscriptionResult.Value)
throw new ApplicationException("An active subscription is required for this operation.");
return CommandResult.Create();
}
}
Supporting module: IEmailService (Email)
IEmailService is the contract used when something in your stack sends mail through DevKit (see Email service and Services). The SaaS template does not ship a dedicated demo page for it; you follow the same inject-and-call pattern as any other service.
Blazor — inject in the markup and call Send from @code (configure Email in Settings first). Hook SendSampleAsync to a button’s @onclick or call it from OnInitializedAsync when appropriate:
@using CodeBlock.DevKit.Application.Services
@inject IEmailService EmailService
@code {
private async Task SendSampleAsync()
{
await EmailService.Send(
to: "[email protected]",
subject: "Hello",
body: "<p>Your message here.</p>",
isBodyHtml: true);
}
}
Use case — inject in the handler constructor and await Send inside Handle:
using CodeBlock.DevKit.Application.Commands;
using CodeBlock.DevKit.Application.Services;
using CodeBlock.DevKit.Core.Helpers;
using MediatR;
namespace CanBeYours.Application.UseCases.Examples;
public sealed record NotifyAdminRequest(string ToEmail, string Subject, string HtmlBody)
: IRequest<CommandResult>;
internal sealed class NotifyAdminByEmailUseCase
: IRequestHandler<NotifyAdminRequest, CommandResult>
{
private readonly IEmailService _emailService;
public NotifyAdminByEmailUseCase(IEmailService emailService) =>
_emailService = emailService;
public async Task<CommandResult> Handle(
NotifyAdminRequest request,
CancellationToken cancellationToken)
{
await _emailService.Send(
request.ToEmail,
request.Subject,
request.HtmlBody,
isBodyHtml: true);
return CommandResult.Create();
}
}