State Driven UI in ASP.NET Core MVC

State Driven UI in ASP.NET Core MVCIn most MVC applications when rending Razor Views, I think the tendency is to use the IUrHelperl.Action inside if anchor href or form action.  If you are using ASP.NET Core, maybe you are using tag helpers like anchor tag helper.  But there’s another option I don’t see very often, which is creating the relevant routes and define them in your ViewModel within in your controller action.   This can be really useful when you’re application’s available actions are driven by state.

Razor

Here’s a small example of a shopping cart.  The view model has a list of products that are in your shopping cart.  Something obvious would have the product title be a link to the actual product page.  As mentioned you could do this using the UrlHelper or a tag heper.

Conditional Actions

But how do we handle if there are conditional actions on our page.  For example, there are certain products that you can only purchase a maximum of 1 per cart.  You cannot change the quantity.

If we are using our method above, we also likely need to include something in the view model to indicate if the action is possible.  If it is not, we likely don’t want to render that relevant part of the page.

ViewModel

Instead, an alternative is to generate any links/actions and supply them in your view model.

Now in our razor, we can make the conditional on if the action exists.

Why?

If you generate view models that contain links and routes to actions, and are used in your Razor, what’s stopping you from taking that same view model and serializing it and returning JSON.   The ability to add content negotiation and render HTML (via razor) or JSON (direct or more transformation) depending on the clients Accept header.

This is a simple example.  but if you have a lot of UI that’s visibility is driven by state, then this is a great approach.  Ultimately if you are also creating HTTP API’s, this should be a lead down the road to hypermedia.

Do you have any questions or comments? Are you using a similar approach?  I’d love to hear about it in the comments or on Twitter.

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

EventStore for Orleans Grain Persistence

EventStore for Orleans Grain PersistenceIn my previous post, I used the JournaledGrain to create an Event Sourced grain.  This enabled us to raise events from within our grain which would be applied to our grain state.  Next up, which I’m covering in this post is how to use EventStore for Orleans Grain Persistence.

This means when we raise events, they will also be persisted to EventStore.  When our grain is activated, we can re-hydrate it by retrieving prior events from an EventStore stream and re-running them in our Grain to get back to current state.

Blog Post Series:

EventStore

If you are unfamiliar with EventStore:

The open-source, functional database with Complex Event Processing in JavaScript.

If you don’t have a running instance, the easiest way is probably with Docker.  Pull down the latest image from docker hub and  as single node running.

docker pull eventstore/eventstore

docker run –name eventstore-node -it -p 2113:2113 -p 1113:1113 eventstore/eventstore

There is a .NETStandard 2.0 compatible client package that I will be using in our Grain Project.

Install-Package EventStore.ClientAPI.NetCore

Writing to EventStore

Anytime our grain was calling the JournaledGrain.RaiseEvent, we want to actually persist that to an EventStore Stream.  For my demo, we will have one EventStore stream per instance of an Orleans grain.  Meaning each bank account will have one event stream.

I’m going to create a new RaiseEvent method that will call the base.RaiseEvent and once confirmed they were applied, append them to our EventStore Stream.  The additional private static methods are really just helpers for (de)serializing our events from/to json.

Re-hydrating

When our Grain activates with OnActivateAsync, this is when we will fetch all the events from our event stream and apply them to our grain.  Basically this will be replaying all the events to build our grain state back up to current state.

 

More!

If you want to try the demo, all the source is available on my PracticalOrleans GitHub Repo.

Do you have any questions or comments? Are you using Orleans or EventStore?  I’d love to hear about it in the comments or on Twitter.

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Event Sourced Orleans Grain

Event Sourced GrainI always thought a Event Sourced Orleans Grain would fit a really well as a stateful Aggregate Root.  Take it a step further and have your Grain be event sourced and also encapsulate a projection of current state.  This post is going to setup the basics of how to Raise events and apply them in our Grain state.  I will be covering persisting the events in the next post.

Blog Post Series:

Event Sourced Grain

I’m going to create a typical example using a bank account.  There are basically two events we will raise.  Deposited event to indicated that we have deposited money into the account and and Withdrawn event to that we have taken money out of the account.

Orleans provides a package Microsoft.Orleans.EventSourcing  to help raise events from you Grain as well as apply them to the state.  From the package, you now can have your grain derive from JournaledGrain<TState, TEvent>.

Grain State

From the example Grain above we are missing our actual grain state, which really a projection so we can keep our current balance.  Once an event is Raised the Grain will call the appropriate Apply(T evnt) method in our state.

Persistence

Next I’ll be persisting our events to Event Store.  This will include once a grain is activated, to pull the events and replay them to get to current state.

More!

If you want to try the demo, all the source is available on my PracticalOrleans GitHub Repo.

Do you have any questions or comments? Are you using Orleans?  I’d love to hear about it in the comments or on Twitter.

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.