How Data Flows in the Server
2sxc is simple to use, but to enable that, it's pretty sophisticated on the inside. Let's take a look at how data is accessed, cached, queried, maybe cached again, and provided to the output.
All the data handling systems come from the EAV. This is then enhanced and customized by Sxc and Sxc.Dnn.
Rule #1: Data is Reactive
As you'll soon see, the EAV performs a lot of automatic lookup and caching, but as a first rule, this happens Reactively, only when data is actually accessed. This is similar to how ReactiveX or NgRx work, just much simpler.
Rule #2: Data is Read-Only
Any data the code receives as IEntity objects is read-only. This allows for a much more robust data model and API which in a CMS environment is usually 99% read, 1% write.
Rule #3: Data Always Comes from DataSources
Inside the system everything is loosely coupled (think Depedency Injection). So anything requesting data will always use a DataSource provided by some magic, and then use what was given.
Rule #4: Data is Managed and Cached per App
Once data from an App was requested, the entire app is loaded and cached. Within an app a lot of data can be linked together using Content-Types, Relationships, Sub-Lists, Metadata and more. If we would lazy-load this on-demand from the storage system (SQL), it would result in a ping-pong of requests, which would be very inefficient. This unit of cache is called an AppState.
Overall Flow When Creating Html
Imagine that your custom Razor template in a Dnn module is initialized. Here's what happens:
2sxc starts with the ModuleId as it's inside a Dnn Module. It will then create a Block for this InstanceId (which is the ModuleId).
- The Block internally will create a CmsBlock DataSource, pass in the InstanceId and then wait for data to pour in.
- The CmsBlock knows about Dnn, and will use the InstanceId to get the ModuleSettings in Dnn. This contains only 2 pieces of information: the
AppIdwhich it is visualizing, and a
ContentBlockIdwhich is the full configuration of the Content-Block which will be shown. The CmsBlock also knows if the user is an editor (which would result in draft-items being included).
- The CmsBlock DataSource will then ask the underlying EAV for this block configuration (stored as an Entity) which is then loaded from the Cache.
- When the configuration is found, the CmsBlock then knows what View will be used.
- The CmsBlock itself is a DataSource and is now configured to deliver the data which the view expects.
The CmsBlock doesn't know about the internals of the cache, it just asks for it. The cache will auto-initialize the AppState if it hasn't been accessed before.
The CmsBlock will also not load any data yet. It just knows what would be loaded, should it ever be accessed.
When you use views which don't have a content-type configured, then properties like
Header will be null. But
App.Data will still work.
The Block is now ready. 2sxc now consults the View to find out which Engine to use (Razor or Token). It will now load this engine, give it the Block and wait for the resulting Html to be created.
- The engine loads the template and lets it do what it should.
- If the template has code accessing Data then the underlying source will retrieve the necessary data.
- If it's a normal content-view, then the items provided will be the ones which an editor has manually added, since they were referenced in the ContentBlock.
- If the view relies on a Query, then this query is built and will be waiting to execute if the data is accessed.
- If the code accesses App.Data then this data source will build up everything necessary so it just works.
- If the code accesses App.Query then the underlying system will prepare the Query as needed.
All the data retrieving features like
Data do not actually retrieve any data unless accessed.
This also means that
Header won't use any CPU cycles unless accessed.
The same goes for
App.Data - nothing is processed unless it's accessed.
The queries are only provided by the App for immediate use. They won't be built or executed unless they are actually read.
Overall Flow when Creating WebAPIs
This works just like the Html creation, except that we don't need an engine. The code which inherits from ApiController now works with the data as needed.
The same lazy-execution rules apply: neither
App.Query use any CPU cycles, unless the data is actually pulled by reading it.
- Rendering Engines like Token/Razor
- Custom WebApi (which is also kind of a dynamic rendering engine)