Message
Hiperspace Provides the fastest possible performance by only loading elements that are needed, and fact loading of objects when they are required. Referenced objects can be loaded directly or asynchronously when required by remote clients (such as Blazor WebAssembly clients). For some client scenarios it is faster to the collect all related objects on a server and return to the client:
- Transitive Graphs : Hiperspace includes the notion of HiperEdge that traverse complex graphs but present the results as a set of edges. An example is StrategicEdges that shows every Enterprise Architecture element that is related to a work package. This can simply be used to prioritize projects that have the highest alignment with strategic goals, without the need for complex graph queries. The parallel recursive search is much faster on a server and does not transfer intermediate nodes that will be discarded before presentation.
- Cubes : To display a hipercube for a user with fast drill-down to further detail, it is better to fetch the recursive structure of cubes, drilldown and more detailed cubes together and avoid latency when the connection is very slow.
- Search : Searching for elements with a partial match benefit from specific query actions that stream results, but can be cancelled when the desired entry is found.
- Paging : For very long list browsed from a client over the internet is useful to providing paging parameters.
- Domain Specific database : where logic and presentation are partitioned between
subspace
on the client and server.
For these scenarios, Hiperspace provides the message element, is invoked on the client, but processed on a server. Unlike other Hiperspace elements, messages do not load-on-demand but transfer both key and value (since you'd use a smaller message if you only required a subject of values). Messages can also reference elements added at compile time (like Cube that is derived from @Fact elements and all distinct @Dimension that are related to the fact)
message
Consider the Accounting example where CustomerCube provides all the information needed to present a Cube of data for a customer, together with drilldown to details.
message API.CustomerCube
(
Customer : Acc.Customer #1
)
{
CustomerTree : List<Acc.Customer> #2,
Sector : List<Acc.Sector> #3,
Accounts : List<Acc.Account> #4 ,
"Using the generated cube element from Transaction and its dimensions"
Cube : List<Acc.Transaction_Cube> #5,
"Using the generated cube drilldown from cube"
Drilldown : List<Acc.Transaction_CubeDrillDown> #6
};
To retrieve the customer, dimensions and all cube data, executing
var msg = await space.InvokeAsync(new CustomerCube {Customer = myCust});
with the query executed on the server and returned to the client, either as a single message, or streamed (using await foreach (var part in InvokeStreamAsync(new CustomerCube {Customer = myCust})) {...}
)
public partial class CustomerCube : IMessage
{
public Task<IMessage> InvokeAsync(CancellationToken token = default)
{
ArgumentNullException.ThrowIfNull(Customer, "Customer parameter is required.");
var customerTree = new List<Acc.Customer>();
var accounts = new List<Acc.Account>();
var cube = new List<Acc.Transaction_Cube>();
var drill = new List<Acc.Transaction_CubeDrillDown>();
var sectors = new HashSet<Acc.Sector>();
customerTree.Add(Customer!);
customerTree.AddRange(Children(Customer));
foreach (var customer in customerTree)
{
accounts.AddRange(customer.Accounts);
}
Drilldowns(Customer.Transaction_Cube, cube, drill);
foreach (var cust in customerTree)
{
if (cust.Sector != null)
sectors.Add(cust.Sector);
}
return Task.FromResult<IMessage>(new CustomerCube(this)
{
CustomerTree = customerTree,
Accounts = accounts,
Cube = cube,
Drilldown = drill,
Sector = sectors.ToList()
});
}
Like other Hiperspace Elements, message can inherit other elements, and provide views and extent properties if needed