Add new sample project for ASP.NET Hangfire Integration
Introduced a new sample project to demonstrate ASP.NET integration with Hangfire, including setup configurations in `appsettings.json`, program initialization, and a background job activity. This will serve as a reference implementation for integrating Elsa with Hangfire in ASP.NET applications.
This commit is contained in:
parent
d46d0b53bc
commit
a397b6799e
9
Elsa.sln
9
Elsa.sln
|
|
@ -383,6 +383,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Tenants.AspNetCore", "
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Agents.Persistence.EntityFrameworkCore.PostgreSql", "src\modules\Elsa.Agents.Persistence.EntityFrameworkCore.PostgreSql\Elsa.Agents.Persistence.EntityFrameworkCore.PostgreSql.csproj", "{2B939AC9-03A4-479E-AA0D-CB58F4A7F480}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{0350351C-E347-41D8-8E9C-ECF90653418B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.AspNet.HangfireIntegration", "samples\Elsa.Samples.AspNet.HangfireIntegration\Elsa.Samples.AspNet.HangfireIntegration.csproj", "{FAE7B132-8AD3-44C0-B45B-1B2BA64B1DB4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -815,6 +819,10 @@ Global
|
|||
{2B939AC9-03A4-479E-AA0D-CB58F4A7F480}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2B939AC9-03A4-479E-AA0D-CB58F4A7F480}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2B939AC9-03A4-479E-AA0D-CB58F4A7F480}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FAE7B132-8AD3-44C0-B45B-1B2BA64B1DB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FAE7B132-8AD3-44C0-B45B-1B2BA64B1DB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FAE7B132-8AD3-44C0-B45B-1B2BA64B1DB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FAE7B132-8AD3-44C0-B45B-1B2BA64B1DB4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -959,6 +967,7 @@ Global
|
|||
{D5720DBC-8C2B-42D5-9D9F-2FF6EAD4001C} = {2F3E1026-5054-4E1F-899B-F1A7F70F9912}
|
||||
{2B939AC9-03A4-479E-AA0D-CB58F4A7F480} = {50470834-4CD8-479A-8B58-0A1869BA5D37}
|
||||
{2CDF3E1C-267D-4198-B1C7-7E1F548FC120} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
{FAE7B132-8AD3-44C0-B45B-1B2BA64B1DB4} = {0350351C-E347-41D8-8E9C-ECF90653418B}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D4B5CEAA-7D70-4FCB-A68E-B03FBE5E0E5E}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Samples.AspNet.HangfireIntegration.Jobs;
|
||||
using Elsa.Samples.AspNet.HangfireIntegration.Models;
|
||||
using Elsa.Samples.AspNet.HangfireIntegration.Stimuli;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Attributes;
|
||||
using Hangfire;
|
||||
|
||||
namespace Elsa.Samples.AspNet.HangfireIntegration.Activities;
|
||||
|
||||
[Activity("Samples", "Samples", "Enqueues a background job and resumes the workflow when the job is done.")]
|
||||
public class ExecuteSomeJob : Activity<SomeJobResult>
|
||||
{
|
||||
protected override void Execute(ActivityExecutionContext context)
|
||||
{
|
||||
var stimulus = new SomeJobStimulus();
|
||||
var bookmark = context.CreateBookmark(stimulus, OnResume);
|
||||
var backgroundJobClient = context.GetRequiredService<IBackgroundJobClient>();
|
||||
backgroundJobClient.Enqueue<SomeJob>(x => x.RunAsync(bookmark.Id, default));
|
||||
}
|
||||
|
||||
private async ValueTask OnResume(ActivityExecutionContext context)
|
||||
{
|
||||
var jobResult = context.GetWorkflowInput<SomeJobResult>("JobResult");
|
||||
Result.Set(context, jobResult);
|
||||
await context.CompleteActivityAsync();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\modules\Elsa.EntityFrameworkCore.Sqlite\Elsa.EntityFrameworkCore.Sqlite.csproj" />
|
||||
<ProjectReference Include="..\..\src\modules\Elsa.EntityFrameworkCore\Elsa.EntityFrameworkCore.csproj" />
|
||||
<ProjectReference Include="..\..\src\modules\Elsa.Hangfire\Elsa.Hangfire.csproj" />
|
||||
<ProjectReference Include="..\..\src\modules\Elsa.Workflows.Api\Elsa.Workflows.Api.csproj" />
|
||||
<ProjectReference Include="..\..\src\modules\Elsa\Elsa.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
using Elsa.Samples.AspNet.HangfireIntegration.Models;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Filters;
|
||||
using Elsa.Workflows.Runtime.Options;
|
||||
|
||||
namespace Elsa.Samples.AspNet.HangfireIntegration.Jobs;
|
||||
|
||||
public class SomeJob(IBookmarkResumer bookmarkResumer)
|
||||
{
|
||||
public async Task RunAsync(string bookmarkId, CancellationToken cancellationToken)
|
||||
{
|
||||
Console.Write("Executing some job...");
|
||||
await Task.Delay(5000, cancellationToken);
|
||||
Console.WriteLine("Done!");
|
||||
|
||||
await ResumeBookmarkAsync(bookmarkId, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task ResumeBookmarkAsync(string bookmarkId, CancellationToken cancellationToken)
|
||||
{
|
||||
var resumeOptions = new ResumeBookmarkOptions
|
||||
{
|
||||
Input = new Dictionary<string, object>
|
||||
{
|
||||
["JobResult"] = new SomeJobResult { Message = "Hello from SomeJob!" }
|
||||
}
|
||||
};
|
||||
var filter = new BookmarkFilter
|
||||
{
|
||||
BookmarkId = bookmarkId
|
||||
};
|
||||
await bookmarkResumer.ResumeAsync(filter, resumeOptions, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
namespace Elsa.Samples.AspNet.HangfireIntegration.Models;
|
||||
|
||||
public class SomeJobResult
|
||||
{
|
||||
public string Message { get; set; }
|
||||
}
|
||||
69
samples/Elsa.Samples.AspNet.HangfireIntegration/Program.cs
Normal file
69
samples/Elsa.Samples.AspNet.HangfireIntegration/Program.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
using Elsa.EntityFrameworkCore.Modules.Management;
|
||||
using Elsa.EntityFrameworkCore.Modules.Runtime;
|
||||
using Elsa.Extensions;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var configuration = builder.Configuration;
|
||||
var identitySection = configuration.GetSection("Identity");
|
||||
var identityTokenSection = identitySection.GetSection("Tokens");
|
||||
|
||||
// Add Elsa to the container.
|
||||
builder.Services.AddElsa(elsa =>
|
||||
{
|
||||
// Configure management feature to use EF Core.
|
||||
elsa.UseWorkflowManagement(management =>
|
||||
{
|
||||
management
|
||||
.AddActivitiesFrom<Program>()
|
||||
.UseEntityFrameworkCore();
|
||||
});
|
||||
|
||||
elsa.UseWorkflowRuntime(runtime =>
|
||||
{
|
||||
runtime.UseEntityFrameworkCore();
|
||||
|
||||
// Use Hangfire to schedule background activities.
|
||||
runtime.UseHangfireBackgroundActivityScheduler();
|
||||
});
|
||||
|
||||
// Expose API endpoints.
|
||||
elsa.UseWorkflowsApi();
|
||||
|
||||
// Use Hangfire.
|
||||
elsa.UseHangfire(hangfire =>
|
||||
{
|
||||
hangfire.UseSqliteStorage(sqlite => sqlite.NameOrConnectionString = "elsa.sqlite.db");
|
||||
});
|
||||
|
||||
// Use hangfire for scheduling timer events.
|
||||
elsa.UseScheduling(scheduling => scheduling.UseHangfireScheduler());
|
||||
|
||||
// Configure identity.
|
||||
elsa.UseIdentity(identity =>
|
||||
{
|
||||
identity.TokenOptions = options => identityTokenSection.Bind(options);
|
||||
identity.UseConfigurationBasedUserProvider(options => identitySection.Bind(options));
|
||||
identity.UseConfigurationBasedApplicationProvider(options => identitySection.Bind(options));
|
||||
identity.UseConfigurationBasedRoleProvider(options => identitySection.Bind(options));
|
||||
});
|
||||
|
||||
// Use default authentication (JWT).
|
||||
elsa.UseDefaultAuthentication();
|
||||
});
|
||||
|
||||
// Configure CORS to allow designer app hosted on a different origin to invoke the APIs.
|
||||
builder.Services.AddCors(cors => cors.AddDefaultPolicy(policy => policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
|
||||
|
||||
// Build the web app.
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the web app's request pipeline.
|
||||
app.UseHttpsRedirection();
|
||||
app.UseCors();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseWorkflowsApi();
|
||||
app.UseWorkflows();
|
||||
|
||||
// Run the web app.
|
||||
app.Run();
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:3978",
|
||||
"sslPort": 44367
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5090",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7020;http://localhost:5090",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
## Secrets
|
||||
The following are the secrets stored in hashed form in appsettings.json:
|
||||
|
||||
**API key**: `4E753976726458745954355043687772-e54d5a2c-33a3-4c05-a216-b09569062aed`
|
||||
**Admin user**: `admin`
|
||||
**Admin password**: `password`
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
namespace Elsa.Samples.AspNet.HangfireIntegration.Stimuli;
|
||||
|
||||
public record SomeJobStimulus;
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Warning",
|
||||
"Microsoft.Hosting": "Information",
|
||||
"Hangfire": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Identity": {
|
||||
"Tokens": {
|
||||
"SigningKey": "secret-signing-key-of-at-least-256-bits",
|
||||
"AccessTokenLifetime": "1:00:00:00",
|
||||
"RefreshTokenLifetime": "1:00:10:00"
|
||||
},
|
||||
"Roles": [{
|
||||
"Id": "admin",
|
||||
"Name": "Administrator",
|
||||
"Permissions": ["*"]
|
||||
}],
|
||||
"Users": [
|
||||
{
|
||||
"Id": "a2323f46-42db-4e15-af8b-94238717d817",
|
||||
"Name": "admin",
|
||||
"HashedPassword": "TfKzh9RLix6FPcCNeHLkGrysFu3bYxqzGqduNdi8v1U=",
|
||||
"HashedPasswordSalt": "JEy9kBlhHCNsencitRHlGxmErmSgY+FVyMJulCH27Ds=",
|
||||
"Roles": ["admin"]
|
||||
}
|
||||
],
|
||||
"Applications": [{
|
||||
"id": "529572c2df854b13807b8bf23f1784cd",
|
||||
"name": "Postman",
|
||||
"roles": [
|
||||
"admin"
|
||||
],
|
||||
"clientId": "Nu9vrdXtYT5PChwr",
|
||||
"clientSecret": "011pp2C$|j01-qrMZpC9VC0F00XCJq(5",
|
||||
"hashedApiKey": "d0rDld3A+ugKmdctGtMzOLTYjQFkOlUWN+kt0VyW9D0=",
|
||||
"hashedApiKeySalt": "EnutGOyy5MuJWV0fF5jCQiciK7a8PU/DRF+fr6nekSY=",
|
||||
"hashedClientSecret": "ERia2zBcCSWb/9dvB0grQ9yf7fWgFrClNeR8A5RMTzk=",
|
||||
"hashedClientSecretSalt": "z3z8KmzHt+xkAj/zYTXcB8I7y0xAkLm95v4Er/oNqiY="
|
||||
}]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue