From Console Application to WJb Action
Most developers do not start with WJb.
They start with a problem.
For example:
Send an email.
Before introducing Jobs, Workflows, Scheduling, or other infrastructure, let's solve the problem using a normal console application.
Once the solution works, we'll gradually convert it into a reusable WJb Action.
Step 1. Ask AI to Generate a Console Application
Imagine asking Copilot or ChatGPT:
Create a .NET console application that sends an email using SMTP.
The generated code might look like this:
using System.Net;
using System.Net.Mail;
var message = new MailMessage(
"sender@example.com",
"john@example.com",
"Test",
"Hello from .NET");
using var smtp = new SmtpClient(
"smtp.example.com", 587);
smtp.Credentials = new NetworkCredential(
"user", "password");
smtp.EnableSsl = true;
await smtp.SendMailAsync(message);
Console.WriteLine("Email sent");
At this point there is no WJb.
Just a normal console application.
Step 2. Verify That It Works
Run the application:
dotnet run
Expected output:
Email sent
The most important rule:
Verify the business logic before introducing infrastructure.
If the console application does not work, adding WJb will not magically fix it.
Step 3. Extract the Logic into a Reusable Library
The console application works.
The next step is moving the email logic into reusable code that can be called from any application.
public sealed class EmailInput
{
public string? To { get; set; }
public string? Subject { get; set; }
public string? Body { get; set; }
}
public sealed class SmtpSettings
{
public string Host { get; set; } = default!;
public int Port { get; set; }
public string? User { get; set; }
public string? Password { get; set; }
public string? From { get; set; }
public bool EnableSsl { get; set; }
}
public static class EmailSdk
{
public static Task SendAsync(
SmtpSettings settings, EmailInput input, CancellationToken ct = default)
{
var message = new MailMessage(
"sender@example.com",
"john@example.com",
"Test",
"Hello from .NET");
using var smtp = new SmtpClient(
"smtp.example.com", 587);
smtp.Credentials = new NetworkCredential(
"user", "password");
smtp.EnableSsl = true;
await smtp.SendMailAsync(message);
Console.WriteLine("Email sent");
return Task.CompletedTask;
}
}
Usage from a console application:
public static class EmailSdk
{
public static Task SendAsync(
SmtpSettings settings, EmailInput input,
CancellationToken ct = default)
{
Console.WriteLine(
$"SMTP: {settings.Host}:{settings.Port}");
Console.WriteLine(
$"From: {settings.From}");
Console.WriteLine(
$"To: {input.To}");
Console.WriteLine(
$"Subject: {input.Subject}");
return Task.CompletedTask;
}
}
The business logic is now isolated from the application entry point and can be reused anywhere.
Step 4. Convert the Library Call into an Action
The original code:
await EmailSdk.SendAsync(smtpSettings, emailInput);
becomes:
public sealed class SendEmailAction(SmtpSettings smtp)
: JobAction<EmailInput>
{
private readonly SmtpSettings _smtp = smtp;
public override async ValueTask<ActionResult> ExecuteAsync(
EmailInput input, CancellationToken ct = default)
{
await EmailSdk.SendAsync(_smtp, input, ct);
return Results.Done();
}
}
Notice that the business logic remains inside EmailSdk.
The Action simply becomes a WJb entry point.
Step 5. Run the Action Directly
An Action is still just a class.
using WJb;
var wjb = WJbBuilder.Create(cfg =>
{
cfg.AddAction<SendEmailAction>();
cfg.AddService(
new SmtpSettings
{
Host = "smtp.local",
Port = 587,
User = "user",
Password = "password",
From = "sender@example.com",
EnableSsl = true
});
});
var action =
await wjb.CreateAsync<SendEmailAction>();
await action.ExecuteAsync(
new EmailInput
{
To = "john@example.com",
Subject = "Test",
Body = "Hello from .NET"
});
No Job is required.
No Workflow is required.
No Store is required.
You can execute the Action exactly like any other class.
Step 6. Run Under WJb
Previously:
Console Application
↓
EmailSdk.SendAsync()
Now:
WJb
↓
SendEmailAction
↓
EmailSdk.SendAsync()
The same business logic can now be:
- executed directly;
- executed by WJb;
- scheduled;
- retried;
- executed on another machine.
Why This Approach Works
Many workflow frameworks force developers to learn framework concepts first.
WJb allows the opposite approach:
Problem
↓
Working Console Application
↓
Reusable Library
↓
Action
This means developers can:
- Build and verify a solution.
- Extract reusable business logic.
- Wrap it with an Action.
- Reuse it anywhere WJb runs.
The business logic remains independent.
WJb simply adds orchestration on top of code that already works.
Top comments (0)