Skip to content
jamescrowley edited this page Apr 1, 2012 · 50 revisions

Working with Spark

Spark support in FubuMVC works in a way that follows the FubuMVC mindset yet retains most of the good parts from Spark. In order to have views picked up and attached conventionally by FubuMVC we scan for all files that are of relevance to FubuMVC.Spark during the bootstrapping of a web application and build up a semantic model. This model holds information about these files and their interrelations.

The templates we define as valid views for action calls have a view model type specified. Thus, the reliance on being able to deduce the view model of a Spark view is crucial. We require that a <viewdata model="..."/> is specified in a view. See the section about "Views" for the particulars.

Spark support encompasses both views from a web application and views from its installed packages. A web application with multiple packages entails some restrictions on how views are organized and picked up, i.e. some sort of isolation is needed. In order to avoid template conflicts the following isolation rules are applied:

  • A web application picks up templates from its own folders excluding all package folders.

  • A package picks up templates from its own folders plus from dedicated shared folders in the web application. This means templates like master page, bindings, macros and so on.

  • Templates are not shared among packages.

Note that we do not support all features mentioned in the Spark documentation - The general idea is support what we find most useful and natural in a FubuMVC environment. If you encounter some parts that are lacking then please feel free to contact us on the mailing list and we might be able to figure something out :)

How to use it

In order to enable Spark support for your web application you have two choices. The first is to add a library reference to FubuMVC.Spark and specify the following in of your FubuRegistry class:

this.UseSpark();

The second approach is to use FubuMVC.Spark as a package for your web application - this approach does not require explicit reference to FubuMVC.Spark nor changes to your FubuRegistry.

Views

The central piece in view attachment is the view model type (corresponding output type on action call). We require that you specify the full type name of a view model in your view, e.g. <viewdata model="full.type.name"/>. This causes it to be picked up if some action call has that output type.

Given that views are picked up by view model type enables support for built-in view attachment conventions in FubuMVC:

  • by_ViewModel_and_Namespace_and_MethodName()
  • by_ViewModel_and_Namespace()
  • by_ViewModel()

You are free to organize your views at will. For instance, place them in the same folder as their corresponding controller or in a folder that contains all your views. If you have multiple views with same view model type then placement of your ".spark" matters.

When views are registered by FubuMVC.Spark, a log that records the process is available from diagnostics (/_fubu/fulllog). The log records information about each view with regards to master page, view model and bindings available.

Master Pages

Master pages should be located under a shared folder - you have three ways of specifying a master page for your view:

  • Implicit: No usage of <use master="..."/> in the view assumes a template called "Application.spark" under a shared folder.

  • Explicit: E.g. <use master="Admininistration"/>.

  • Suppressing: <use master=""/> entails no master page being used.

The default search for a master page tries to locate the nearest one under folders called "Shared" in the ancestor path of the view. When the first master is found the search is done. If no master page is found for a view then it is rendered without one.

Examples

The examples below assume the default master, "Application.spark" and illustrate different possible selection scenarios of master pages.

~/FeatureA/WizardA/ViewX.spark (1) => (6)
...
~/FeatureB/WizardB/ViewY.spark (2) => (3)
~/FeatureB/WizardB/Shared/Application.spark (3)
...
~/FeatureC/WizardC/ViewZ.spark (4) => (5)
~/FeatureC/Shared/Application.spark (5)
...
~/Shared/Application.spark (6)

###Packages

When it comes to packages the approach is similar as described earlier, just with a little twist. The search also includes the top-level shared folder in the web application root. This means that if no master page is found in the package then the top-level shared folder in the web application is searched as well.

Configuration

Note that currently we only look for a folder called "Shared" when searching for shared folders. Soon this will be configurable by way of DSL where you can specify the name of a shared folder, as well as the ability to specify different names for shared folders.

Moreover, the default master page name is assumed to be "Application.spark". Soon you are able to configure this name via DSL.

Bindings

Placement of bindings files is similar to that of master pages, e.g. under a shared folder. However, with bindings the search also includes direct ancestor directories of a view's path.

We include support for being able to use multiple bindings for a view, i.e. we merge all bindings we find. This entails the search for bindings does not halt with the first match as it would with master pages.

Example

~/FeatureA/WizardA/ViewX.spark (1) => (2) \(\cup\) (4) \(\cup\) (5)
~/FeatureA/WizardA/bindings.xml (2)
...
~/FeatureB/WizardB/ViewY.spark (3) => (4) \(\cup\) (5)
~/FeatureB/bindings.xml (4)
...
~/Shared/bindings.xml (5)

When we merge all bindings reachable from a view's path some simple rules apply. If you have the same binding definitions in multiple bindings the most specific definitions wins. This implies you can overrule binding definitions in the ancestor path of a view.

###Packages

Bindings support for packages is as described above with the addition of that bindings in the web application's root and in the top-level shared folder are available for a package view.

###Configuration

Note that currently bindings are required to be named "bindings.xml". Soon you are able to specify the name of the bindings through the DSL.

Special Templates

Special templates such as _partial.spark, _global.spark and macros are located as you would normally expect, i.e. in the direct ancestor path folders and under shared folders.

###Packages

The same applies to packages with the addition that partials in the application's root and top-level shared folders are also available.

Render Strategies:

We support different ways of rendering a view. All views can be rendered in the following ways, depending on how they are requested:

  • Normal: The view is requested normally, i.e. as a result of an action call invocation - the master, if any, is used.

  • Nested: The view is requested from within another view, e.g. invoked via Partial - no master used.

  • Ajax: The view is requested from an AJAX request - no master used.

[TODO: mention that we have pluggability for custom strategies]

Pluggability

  • Parts you can replace...

##Caveats

  • [Describe assembly name + view folder approach for namespace and its limitations]

  • If you have two output types with the exact same assembly qualified name then we do not attempt to attach the view as we do not know which one to choose. When this occurs it is reported in the diagnostics log.

  • You need to specify full type name. We do not (currently) account for <use namespace="..."/>.

Not supported

  • We only support C# generated view code.

  • No support for including files with <include href=""> in ".spark" templates.

  • Dynamic viewdata in the form of <viewdata Caption="string"/> is currently not supported.