Hey, did you know that JasperFx Software is ready for formal support plans for Marten and Wolverine? Not only are we trying to make the “Critter Stack” tools be viable long term options for your shop, we’re also interested in hearing your opinions about the tools and how they should change.
Let’s build a small web service application using the whole “Critter Stack” and their friends, one small step at a time. For right now, the “finished” code is at CritterStackHelpDesk on GitHub.
The posts in this series are:
- Event Storming
- Marten as Event Store
- Marten Projections
- Integrating Marten into Our Application (this post)
- Wolverine as Mediator
- Web Service Query Endpoints with Marten
- Dealing with Concurrency
- Wolverine’s Aggregate Handler Workflow FTW!
- Command Line Diagnostics with Oakton
- Integration Testing Harness
- Marten as Document Database
- Asynchronous Processing with Wolverine
- Durable Outbox Messaging and Why You Care!
- Wolverine HTTP Endpoints
- Easy Unit Testing with Pure Functions
- Vertical Slice Architecture
- Messaging with Rabbit MQ
- The “Stateful Resource” Model
- Resiliency
In the previous couple posts I’ve introduced Marten as a standalone library and some of its capabilities for persisting events and creating projected views off those events within an event sourcing persistence strategy. Today I want to end the week by simply talking about how to integrate Marten into an ASP.Net Core application.
Oskar’s Introduction to Event Sourcing – Self Paced Kit has a world of information for folks getting started with event sourcing.
Let’s start a shell of a new web service project and add a Nuget reference to Marten through:
dotnet new webapi
dotnet add package Marten
If you’ll open up the Program.cs
file in your new application, find this line of code at the top where it’s just starting to configure your application:
using Marten;
// Many other using statements
var builder = WebApplication.CreateBuilder(args);
Right underneath that (it doesn’t actually matter most times what order this all happens inside the Program
code, but I’m giving Marten the seat at the head of the table so to speak), add this code:
// "AddTool()" is now the common .NET idiom
// for integrating tools into .NET applications
builder.Services.AddMarten(opts =>
{
// You always have to tell Marten what the connection string to the underlying
// PostgreSQL database is, but this is the only mandatory piece of
// configuration
var connectionString = builder.Configuration.GetConnectionString("marten");
opts.Connection(connectionString);
// We have to tell Marten about the projection we built in the previous post
// so that Marten will "know" how to project events to the IncidentDetails
// projected view
opts.Projections.Add<IncidentDetailsProjection>(ProjectionLifecycle.Inline);
})
// This is a mild optimization
.UseLightweightSessions();;
That little bit of code is adding the necessary Marten services to your application’s underlying IoC container with the correct scoping. The main services you’ll care about are:
Service | Description | Lifetime |
IDocumentStore | Root configuration of the Marten database | Singleton |
IQuerySession | Read-only subset of the IDocumentSession | Scoped |
IDocumentSession | Marten’s unit of work service that also exposes capabilities for querying and the event store | Scoped |
You can read more about the bootstrapping options in Marten in the documentation. If you’re wondering what “Lightweight Session” means to Marten, you can learn more about the different flavors of sessions in the documentation, but treat that as an advanced subject that’s not terribly relevant to this post.
And also, the usage of AddMarten()
should feel familiar to .NET developers now as it follows the common idioms for integrating external tools into .NET applications through the generic host infrastructure that came with .NET Core. As a long term .NET developer, I cannot exaggerate how valuable I think this standardization of application bootstrapping has been for the OSS community in .NET.
Using Marten in an MVC Controller
For right now, I want to assume that many of you are already familiar with ASP.Net MVC Core, so let’s start by showing the usage of Marten within a simple controller to build the first couple endpoints to log a new incident and fetch the current state of an incident in our new incident tracking, help desk service:
public class IncidentController : ControllerBase
{
private readonly IDocumentSession _session;
public IncidentController(IDocumentSession session)
{
_session = session;
}
[HttpPost("/api/incidents")]
public async Task<IResult> Log(
[FromBody] LogIncident command
)
{
var userId = currentUserId();
var logged = new IncidentLogged(command.CustomerId, command.Contact, command.Description, userId);
var incidentId = _session.Events.StartStream(logged).Id;
await _session.SaveChangesAsync(HttpContext.RequestAborted);
return Results.Created("/incidents/" + incidentId, incidentId);
}
[HttpGet("/api/incidents/{incidentId}")]
public async Task<IResult> Get(Guid incidentId)
{
// In this case, the IncidentDetails are projected
// "inline", meaning we can load the pre-built projected
// view
var details = await _session.LoadAsync<IncidentDetails>(incidentId);
return details != null
? Results.Json(details)
: Results.NotFound();
}
private Guid currentUserId()
{
// let's say that we do something here that "finds" the
// user id as a Guid from the ClaimsPrincipal
var userIdClaim = User.FindFirst("user-id");
if (userIdClaim != null && Guid.TryParse(userIdClaim.Value, out var id))
{
return id;
}
throw new UnauthorizedAccessException("No user");
}
}
It’s important to note at this point (that might change in Marten 7) that the IDocumentSession
should be disposed when you’re doing using it to tell Marten to close down any open database connections. In the usage above, the scoped IoC container mechanics in ASP.Net Core are handling all the necessary object disposal for you.
Summary and What’s Next
Today we strictly just looked at how to integrate Marten services into a .NET application using the AddMarten()
mechanism. Using a simple MVC Core Controller
, we saw how Marten services are available and managed in the application’s IoC container and how to perform basic event sourcing actions in the context of little web service endpoints.
In later posts in this series we’ll actually replace this IncidentController
with Wolverine endpoints and some “special sauce” with Marten to be much more efficient.
In the next post, I think I want to talk through the CQRS architectural style with Marten. Bear with me, but I’ll still be using explicit code with MVC Core controllers that folks are probably already familiar with to talk over the requirements and Marten capabilities in isolation. Don’t worry though, I will eventually introduce Wolverine into the mix to show how the Wolverine + Marten integration can make your code very clean and testable.
Great serie so far. There is a small typo “[…] should be disposed when you’re doing using it”. Cheers!