Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Before getting started you will need the following in your environment:

Available [here](https://dotnet.microsoft.com/download)

### 2. PostgreSQL 12 or above database
### 2. PostgreSQL 13 or above database

The fastest possible way to develop with Marten is to run PostgreSQL in a Docker container. Assuming that you have Docker running on your local box, type:
`docker-compose up`
Expand Down
10 changes: 8 additions & 2 deletions docs/configuration/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ When writing integration tests, make sure to enable host auto-start in your test
JasperFxEnvironment.AutoStartHost = true;
```

Without this setting, creating the test server will fail. See also [Creating an Integration Test Harness](https://wolverinefx.net/tutorials/cqrs-with-marten.html#creating-an-integration-test-harness)
or in Marten V7 or earlier:

```csharp
OaktonEnvironment.AutoStartHost = true;
```

Without this setting, creating the test server will fail to bootstrap. See also [Creating an Integration Test Harness](https://wolverinefx.net/tutorials/cqrs-with-marten.html#creating-an-integration-test-harness)
:::

Through dependencies on the _JasperFx_ and _Weasel_ libraries, Marten has support for command line tools to apply or generate
Expand All @@ -34,7 +40,7 @@ builder.Host.ApplyJasperFxExtensions();
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/samples/MinimalAPI/Program.cs#L10-L18' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_webapplication_1' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

And finally, use Oakton as the command line parser and executor by replacing `App.Run()` as the last line of code in your
And finally, use JasperFx as the command line parser and executor by replacing `App.Run()` as the last line of code in your
`Program.cs` file:

<!-- snippet: sample_using_WebApplication_2 -->
Expand Down
6 changes: 3 additions & 3 deletions docs/configuration/environment-checks.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Environment Checks

Marten has a couple options for adding [environment checks](https://jeremydmiller.com/2019/10/01/environment-checks-and-better-command-line-abilities-for-your-net-core-application/) to your application that can assert on whether the Marten database(s)
are in the correct state. The first way is to use [Oakton](https://jasperfx.github.io/oakton) as your command line parser for your application (which you are if you're using Marten's command line tooling) and take advantage
of its built in [environment check](https://jasperfx.github.io/oakton/guide/host/environment.html) functionality.
are in the correct state. The first way is to use the built in JasperFx command execution that comes with Marten as your command line parser for your application (which you are if you're using Marten's command line tooling) and take advantage
of its built in environment check functionality.

To add an environment check to assert that the actual Marten database matches the configured state, just use the `AddMarten().AddEnvironmentChecks()` extension method that is contained in the Marten.CommandLine library.
To add an environment check to assert that the actual Marten database matches the configured state, just use the `AddMarten().AddEnvironmentChecks()` extension method.

Another option is this usage:

Expand Down
72 changes: 28 additions & 44 deletions docs/configuration/hostbuilder.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@ builder.Services.AddMarten(options =>
// Establish the connection string to your Marten database
options.Connection(builder.Configuration.GetConnectionString("Marten")!);

// Specify that we want to use STJ as our serializer
options.UseSystemTextJsonForSerialization();
// If you want the Marten controlled PostgreSQL objects
// in a different schema other than "public"
options.DatabaseSchemaName = "other";

// If we're running in development mode, let Marten just take care
// of all necessary schema building and patching behind the scenes
if (builder.Environment.IsDevelopment())
{
options.AutoCreateSchemaObjects = AutoCreate.All;
}
});
// There are of course, plenty of other options...
})

// This is recommended in new development projects
.UseLightweightSessions()

// If you're using Aspire, use this option *instead* of specifying a connection
// string to Marten
.UseNpgsqlDataSource();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/AspNetCoreWithMarten/Program.cs#L16-L34' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_startupconfigureservices' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/AspNetCoreWithMarten/Program.cs#L16-L37' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_startupconfigureservices' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

The `AddMarten()` method will add these service registrations to your application:
Expand Down Expand Up @@ -135,7 +138,7 @@ services.AddMarten()
.UseLightweightSessions()
.UseNpgsqlDataSource();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/bootstrapping_with_service_collection_extensions.cs#L329-L337' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_usenpgsqldatasource' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/bootstrapping_with_service_collection_extensions.cs#L330-L338' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_usenpgsqldatasource' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

If you're on .NET 8 (and above), you can also use a dedicated [keyed registration](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#keyed-di-services). This can be useful for scenarios where you need more than one data source registered:
Expand All @@ -151,7 +154,7 @@ services.AddMarten()
.UseLightweightSessions()
.UseNpgsqlDataSource(dataSourceKey);
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/bootstrapping_with_service_collection_extensions.cs#L379-L389' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_usenpgsqldatasource_keyed' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/bootstrapping_with_service_collection_extensions.cs#L380-L390' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_usenpgsqldatasource_keyed' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## Using a Multi-Host Data Source <Badge type="tip" text="7.11" />
Expand All @@ -173,7 +176,7 @@ services.AddMarten(x =>
.UseLightweightSessions()
.UseNpgsqlDataSource();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/bootstrapping_with_service_collection_extensions.cs#L351-L363' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_usenpgsqldatasourcemultihost' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/bootstrapping_with_service_collection_extensions.cs#L352-L364' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_usenpgsqldatasourcemultihost' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

::: warning
Expand Down Expand Up @@ -250,10 +253,10 @@ public interface IConfigureMarten
void Configure(IServiceProvider services, StoreOptions options);
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten/MartenServiceCollectionExtensions.cs#L866-L877' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_iconfiguremarten' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten/MartenServiceCollectionExtensions.cs#L877-L888' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_iconfiguremarten' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

You could alternatively implement a custom `IConfigureMarten` (or `IConfigureMarten<T> where T : IDocumentStore` if you're [working with multiple databases](#working-with-multiple-marten-databases)) class like so:
You could alternatively implement a custom `IConfigureMarten` (or `IConfigureMarten<T> where T : IDocumentStore` if you're working with multiple databases class like so:

<!-- snippet: sample_UserMartenConfiguration -->
<a id='snippet-sample_usermartenconfiguration'></a>
Expand Down Expand Up @@ -314,7 +317,7 @@ public interface IAsyncConfigureMarten
ValueTask Configure(StoreOptions options, CancellationToken cancellationToken);
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten/MartenServiceCollectionExtensions.cs#L879-L891' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_iasyncconfiguremarten' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten/MartenServiceCollectionExtensions.cs#L890-L902' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_iasyncconfiguremarten' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

As an example from the tests, here's a custom version that uses the Feature Management service:
Expand Down Expand Up @@ -600,41 +603,22 @@ This correlation tracking might be better with structural logging with something

## Eager Initialization of the DocumentStore

Lastly, if desirable, you can force Marten to initialize the applications document store as part of bootstrapping instead of waiting for it to be initialized on the first usage with this syntax:

<!-- snippet: sample_AddMartenWithEagerInitialization -->
<a id='snippet-sample_addmartenwitheagerinitialization'></a>
```cs
var connectionString = Configuration.GetConnectionString("postgres");

// By only the connection string
services.AddMarten(connectionString)
.InitializeWith();

// In a "Production" environment, we're turning off the
// automatic database migrations and dynamic code generation
services.CritterStackDefaults(x =>
{
x.Production.GeneratedCodeMode = TypeLoadMode.Static;
x.Production.ResourceAutoCreate = AutoCreate.None;
});
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/AspNetCoreWithMarten/Samples/EagerInitialization/Startup.cs#L21-L37' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_addmartenwitheagerinitialization' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
Sorry, but as of Marten 7, it is no longer possible to force the `DocumentStore` to be initialized during `IHost` bootstrapping.
We had to make this change to avoid using any synchronous IO during bootstrapping.

## Working with Multiple Marten Databases
## Ancillary Marten Stores <Badge type="tip" text="5.0" />

:::tip
This feature is **not** meant for multi-tenancy with separate databases. This is specifically meant for use
cases where a single system needs to work with two or more semantically different Marten databases.
:::
For the increasingly common usage of Marten within modular monoliths or for scalability reasons, you can effectively
use additional Marten stores in the same application. These stores could either address completely different
databases, or use different schemas within the same database.

:::tip
The database management tools in Marten.CommandLine are able to work with the separately registered
The database management tools that come bundled with Marten are able to work with the separately registered
document stores along with the default store from `AddMarten()`.
:::

Marten V5.0 introduces a new feature to register additional Marten databases into a .Net system. `AddMarten()` continues to work as it has, but we can now register and resolve additional store services. To utilize the type system and your application's underlying IoC container, the first step is to create a custom *marker* interface for your separate document store like this one below targeting a separate "invoicing" database:
To utilize the type system and your application's underlying IoC container, the first step is to create a custom *marker* interface for your separate document store like this one
below targeting a separate "invoicing" database:

<!-- snippet: sample_IInvoicingStore -->
<a id='snippet-sample_iinvoicingstore'></a>
Expand Down
12 changes: 8 additions & 4 deletions docs/configuration/json.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ JSON serialization extensible and configurable through the native mechanisms in

## Serializer Choice

Marten ships with implementations for both Newtonsoft.Json & System.Text.Json. Newtonsoft.Json is enabled by default in Marten for backwards compatibility
with previous Marten versions and because it handles some unique edge-cases that System.Text.Json might not.
::: info
Marten 8 uses System.Text.Json as the default JSON serializer. Previous to 8, Marten used Newtonsoft.Json as the default.
:::

That being said, if you're working on a new application
we recommend enabling System.Text.Json for improved performance and serializer alignment with ASP.NET Core & Wolverine defaults.
Marten ships with System.Text.Json as the default, but there is still built in support to opt into Newtonsoft.Json.

Configuration for both serializers hang off the `DocumentStore` `UseNewtonsoftForSerialization` and `UseSystemTextJsonForSerialization` extensions respectively:

Expand Down Expand Up @@ -225,6 +225,10 @@ var store = DocumentStore.For(_ =>

## Integrating a Custom serializer

::: warning
Please talk to the Marten team before you undergo any significant effort to support a new JSON serializer
:::

Internally, Marten uses an adapter interface for JSON serialization:

<!-- snippet: sample_ISerializer -->
Expand Down
9 changes: 3 additions & 6 deletions docs/configuration/multitenancy.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# Multi-Tenancy with Database per Tenant

:::tip
Marten V5.0 largely rewired the internals to be aware of multiple databases in features such as the database cleaning,
the async projection daemon, and the database migrations.
:::

Marten V5.0 introduced (finally) built in support for multi-tenancy through separate databases per tenant or a group of tenants.
Marten has support for two types of multi-tenanted storage and data retrieval, [conjoined multi-tenancy](/documents/multi-tenancy) where
data for separate tenants is stored in the same tables, but separated by a `tenant_id` column. Marten can also efficiently
separate tenant data by using separate databases for each tenant or for a group of logical tenants.

First off, let's try to answer the obvious questions you probably have:

Expand Down
39 changes: 8 additions & 31 deletions docs/configuration/optimized_artifact_workflow.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Optimized Development Workflow

::: warning
The original "optimized development workflow" option introduced in Marten 4/5 was completely eliminated
in Marten 8.0 (and Wolverine 4.0) in favor of the "Critter Stack" common option shown here.
:::

The original point of Marten was to have a persistence option that mostly got out of your way and
let developers just get things done without having to spend a lot of time fiddling with database
scripts or ORM configuration. To that end, the default configuration for Marten is optimized for
Expand Down Expand Up @@ -56,40 +61,12 @@ using var host = await Host.CreateDefaultBuilder()
When using this option, if `IHostEnvironment.IsDevelopment()` as it would be on a local developer box, Marten is using:

* `StoreOptions.AutoCreateSchemaObjects = AutoCreate.CreateOrUpdate` to detect and apply database schema migrations as needed.
* `StoreOptions.GeneratedCodeMode = TypeLoadMode.Auto` to generate dynamic code if necessary, or use pre-built types when they exist. This optimizes the development workflow to avoid unnecessary code compilations when the Marten configuration isn't changed.
* `StoreOptions.GeneratedCodeMode = TypeLoadMode.Dynamic` to generate dynamic code if necessary, or use pre-built types when they exist. This optimizes the development workflow to avoid unnecessary code compilations when the Marten configuration isn't changed.

At production time, that changes to:

* `StoreOptions.AutoCreateSchemaObjects = AutoCreate.None` to short circuit any kind
of automatic database change detection and migration at runtime. This is also a minor performance
optimization that sidesteps potential locking issues.
* `StoreOptions.GeneratedCodeMode = TypeLoadMode.Auto` to generate dynamic code if necessary,
or use pre-built types when they exist. This ensures that the application can
function in production mode even if some dynamic types are not pre-built

In production mode, Marten also disables any source code generated at runtime from
being written to the file system.

To be more strict, you can also turn the code generation to `Static` meaning that
Marten will *not* attempt to generate any dynamic code. This assumes that all types are
pre-built ahead of time:

<!-- snippet: sample_using_optimized_artifact_workflow_static -->
<a id='snippet-sample_using_optimized_artifact_workflow_static'></a>
```cs
using var host = await Host.CreateDefaultBuilder()
.ConfigureServices(services =>
{
services.AddMarten("connection string");

// In a "Production" environment, we're turning off the
// automatic database migrations and dynamic code generation
services.CritterStackDefaults(x =>
{
x.Production.GeneratedCodeMode = TypeLoadMode.Static;
x.Production.ResourceAutoCreate = AutoCreate.None;
});
}).StartAsync();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CoreTests/reading_configuration_from_jasperfxoptions.cs#L98-L113' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_optimized_artifact_workflow_static' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
* `StoreOptions.GeneratedCodeMode = TypeLoadMode.Static` to only try to load pre-built types from
what Marten thinks is the application assembly.
Loading
Loading