QuickStart Guide | Modelling | Built in Models | Configuration | Storage | Client API | Security
Here's a complete guide to get you started with developing your first Memstate application! The following topics are covered:
- Create a project
- Adding the library to your project
- Define the in-memory model
- Create commands and queries
- Hosting the engine
- Executing commands
- Executing queries
Normally you would create a separate class library where you define the domain model. But for the quick start create a simple console application for either .NET Core or .NET Framework.
Add a reference to Memstate.All nuget package
install-package Memstate.All
Define a root class to serve as the model and any supporting types such as entities. An instance of this class will be kept in-memory and represents the state of your application.
- example : LoyaltyDB.cs
public class LoyaltyModel
{
public LoyaltyModel() {}
public IDictionary<int, Customer> Customers { get; } = new Dictionary<int, Customer>();
}
- example : Customer.cs
public class Customer
{
public Customer(int customerId, int loyaltyPointBalance)
{
CustomerId = customerId;
LoyaltyPointBalance = loyaltyPointBalance;
}
public int CustomerId { get; }
public int LoyaltyPointBalance { get; }
public override string ToString() => $"Customer[{CustomerId}] balance {LoyaltyPointBalance} points.";
}
Commands are used to update the model. Derive from Command<M>
or Command<M,R>
where M
is the type of your model and R
is the result type
- example : SpendPoints.cs
- example : EarnPoints.cs
public class EarnPoints : Command<LoyaltyModel, Customer>
{
public EarnPoints(int customerId, int points)
{
CustomerId = customerId;
Points = points;
}
public int CustomerID { get; }
public int Points { get; }
// it is safe to return a live customer object linked to the Model because
// (1) the class is serializable and a remote client will get a serialized copy
// and (2) in this particular case Customer is immutable.
// if you have mutable classes, then please rather return a view, e.g. CustomerBalance or CustomerView class
public override Customer Execute(LoyaltyModel model)
{
var customer = model.Customers[ID];
var newPoints = customer.LoyaltyPointBalance + Points;
var customerWithNewBalance = new Customer(CustomerId, newPoints);
model.Customers[CustomerId] = customerWithNewBalance;
return customerWithNewBalance;
}
}
The following code will create an initial model, write it as a snapshot to disk and then return an engine ready to execute commands and queries.
var engine = await Engine.Start<LoyaltyDB>();
Creating command objects and passing them to the engine for execution. The following code initialises a new customer with id[10] with 100 loyalty points. Then we execute the EarnPoints command, and finnally we write out the customer balance.
Note how the EarnPoints
Command, returns an immutable Customer
object with the new balance as a return value.
await engine.Execute(new InitCustomer(10, 100));
var customer = await engine.Execute(new EarnPoints(id,100));
Console.WriteLine($"your new balance is {customer.LoyaltyPoints} points.");
You can write strongly typed query classes.
// executing a query
public class Top10Customers : Query<LoyaltyModel, Customer[]>
{
public override Customer[] Execute(LoyaltyModel model) {
return model.Customers
.OrderByDescending(c => c.Value.LoyaltyPointBalance)
.Take(10).Select(c => c.Value).ToArray();
}
}
Customer[] customers = await engine.Execute(new Top10Customers());
(TBD) tests and documentation currently in progress.
We've covered the absolute basics here, but essentially there's not much more to developing than defining the model, and writing commands and queries. We used an anemic model and the transaction script pattern for this sample code.
- For a full end to end working example see QuickStartTests.cs
Documentation for more advanced topics are currently being written. There are extensive unit and integration tests as well that can give you some excellent insights into more advanced details.