What is Marten and why do I care?
Marten (no relation) is an open source .NET driver for Postgresql that focuses on Postgres’ JSON-based document storage capabilities. Think of it like an alternative to MongoDB or RavenDB for your .NET applications.
This article is going to walk you through the first steps of getting an ASP.NET Core project up and running with Marten, as well as basic querying. This should work on all operating systems.
The first thing you’ll want to do is start a new ASP.NET Core project. Remember, in the new .NET Core world an ASP.NET Core project is just a regular old .NET Core console app that hosts its own web server and uses ASP.NET libraries. This guide is the canonical reference for getting started here. You’ll end up with three files in your project that look like this.
Add a model and a controller
Let’s quickly add a model - this will be the object that maps to our table in Postgresql. Create a new Model directory and add a BlogPost model.
And we’ll need a controller which manages this. Create a new Controllers folder and create a file called BlogPostController.cs.
For this step you’ll also need to add a depedency on Microsoft.AspNetCore.Mvc to project.json - while we’re here, add dependencies on Kestrel (the built-in web server for aspnetcore development) and Marten:
Finally before using this controller you’ll need to setup the ASP.NET MVC framework. Edit your Startup.cs file:
At this stage it’s a good idea to fire up the web server and make sure everything is working as expected. Go to your command line terminal and run ‘dotnet run’. It should tell you that the server is running on localhost on some port (default is 5000). Open up a browser, Postman or your HTTP client of choice and make sure that when you hit http://localhost:5000/posts an empty array is returned. If not, something has gone wrong.
Configure dependency injection
The next step is to get the Marten DocumentStore object injected into our controllers so we can use it. Open up your Startup.cs file and edit the ConfigureServices method so that it looks like below. ConfigureServices is the method that the ASP.NET Core framework will call to set up your dependency injection framework - a simple DI container is included with ASP.NET core, so that’s what we’re going to use.
This line tells the dependency injection framework that we want to be able to ask for instances of IDocumentStore, and when we ask for them you should call that DocumentStore.For() method to get one. Additionally because we use the AddScoped method, this object will exist for the lifetime of a single request. You can read more about object lifetimes in ASP.NET Core here.
Obviously you’ll need to change your connection string to point to your own Postgresql instance. You can find more information about Postgresql connection strings here.
Querying in the controller
Now we should be able to just add an IDocumentStore to the controller’s constructor and the framework will supply it to us, ready to use. Let’s give it a crack. First add a constructor to the controller which takes the IDocumenStore and stores it in an instance variable.
And let’s flesh out the methods we defined earlier.
Let’s dig into what we’re doing here. The IDocumentStore can supply sessions which we use to query the database.
You may notice we’re using two different methods to get the DB session - QuerySession() and LightweightSession(). The query session is a read-only session, optimised for read scenarios. LightweightSession is a read-write session which requires you to manage object change tracking yourself.
The other alternatives are OpenSession() which supplies an implementation of IDocumentSession which is backed by an identity map - basically an in-memory cache of any data that has been retrieved. And finally there’s DirtyTrackedSession() which is a session which will track changes you make to any retrieved entities by storing the original document in memory. I don’t recommend using this unless you really need to - other than the performance penalty, in my experience it’s simpler to be explicit with your changes.
Once we have the session we can query it by calling Query<T> where T is the document type we’re trying to look up. The object returned by Query() is a Linq IQueryable so you can call most common Linq extension methods on it (although you should be cautious with how you query a document database - see more query information here).
Test it out
And you’ll receive a response:
Interestingly you’ll find that Marten has automatically assigned a value to the Id field on our object. When you use an integer or long, Marten will use an auto-incrementing algorithm, and it will generate GUIDs if your Id field is a GUID. See here for more info on Marten object identity.
The most interesting thing is how Marten is using Postgres to store your data. If you open your database instance you’ll find a table that’s defined something like
The interesting bit is “data jsonb NOT NULL” which is the column that stores all of the data. The json document stored in there looks just like the one that was returned after your POST request. The jsonb data type in Postgresql is much more than just a JSON string - there’s real potential to do some cool stuff with this data type, and that’s why Marten is so interesting.