Default View Service

The sample for this topic can be found here

The default implementation of the view service used by IdentityServer is the DefaultViewService. The various assets (HTML, JavaScript, CSS, and fonts) that comprise the views are served up from embedded resources within the IdentityServer assembly.

The DefaultViewService allows for some amount of customization.

CSS and JavaScript customization

One simple approach to customization is that the hosting application can provide a list of either CSS and/or JavaScript files to include in the default web pages. This allows for branding without the need to completely replace the assets themselves.

The DefaultViewServiceOptions class is used to indicate these CSS and/or JavaScript files via the Stylesheets and Scripts lists:

var viewOptions = new DefaultViewServiceOptions();
viewOptions.Stylesheets.Add("/Content/Site.css");

The paths passed to Add can either be relative to IdentityServer’s base path by prefixing the path with a “~” (such as “~/path/file.css”), or the path can be host-relative by prefixing the path with a “/” (such as “/path/file.css”). Absolute URLs are supported as long as they are added to IdentityServer’s CSP options.

To then use the DefaultViewServiceOptions there is a ConfigureDefaultViewService extension method on the IdentityServerServiceFactory. This helper method uses the dependency injection system to register the DefaultViewService and its dependencies based upon the options:

var viewOptions = new DefaultViewServiceOptions();
viewOptions.Stylesheets.Add("/Content/Site.css");

var factory = new IdentityServerServiceFactory();
factory.ConfigureDefaultViewService(viewOptions);

HTML customization

The views in the DefaultViewService use AngularJS to perform dynamic rendering client-side. The rendering is driven by a view model that is included in each view. Each view has a different view model with the pertinent data for the view.

The DefaultViewService does allow for the HTML to be customized, but the assumption is that the same approach will be used for the dynamic rendering of the HTML. If this is not desirable, then consider implementing a custom view service.

Also, many of the views have links or forms that make requests back into IdentityServer. Any customizations to the views must be able to recreate the same requests into IdentityServer. In other words, a custom view can not change how the server is expecteding to be invoked from the view.

When rendering its views, the DefaultViewService uses a templating mechanism (similar to layout templates in MVC). There is a single shared “layout” view, and then there are separate “partial” views (one for each page that needs to be rendered) that contain the contents to be rendered inside of the “layout”. When a view is rendered these two are merged together on the server to emit a single HTML document.

You can see the default layout and partial views here.

Replacing entire views

The default views can be replaced by creating HTML files within an templates folder within the hosting applications base directory. The files contained inside are located by name matching the view being rendered (e.g. the login view will look for a file named login.html). If these files are present then they are responsible for rendering the entirety of the HTML for that view.

Replacing partial views

When customizing the HTML, rather than replacing the entire HTML document you can replace just the partial view. To replace just the partial view the file located in the templates folder simply needs to be distinguished by prefixing the name with an underscore (e.g. _login.html). This will then use the default layout template, but use the custom partial view. It will be merged into the layout template to render the combined HTML to the browser.

In addition to being able to replace the partial views, it’s also possible to replace the default layout template itself. This can be done by creating a file named _layout.html in the templates folder. The DefaultViewService will then use whatever combination of custom layout or partial views discovered on the file system to merge with the default embedded assets to render the requested view.

Custom views location (Added in v2.4)

By default, the custom views are located in a directory named templates within the hosting applications base directory. This can be customized by specifying the CustomViewDirectory property on the DefaultViewServiceOptions. This must be the full filesystem path to the directory.

For example:

var viewOptions = new DefaultViewServiceOptions();
viewOptions.CustomViewDirectory = @"C:\IdentityServerTemplates";

var factory = new IdentityServerServiceFactory();
factory.ConfigureDefaultViewService(viewOptions);

Caching

The custom views will be cached in-memory by default, so if the files are changed then it will require an application restart to load any updated HTML. This behavior can be disabled by setting the CacheViews property to false on the DefaultViewServiceOptions described earlier.

Custom view loader

Finally, if the templates folder on the file system is not desirable, then you can implement your own storage for the custom views by implmeneting the IViewLoader interface. This is configured as a Registration<IViewLoader> on the DefaultViewServiceOptions.

Adding custom data to the rendered view

It is possible that custom views need to render custom data. All of the view models used by the DefaultViewService provide an object property called Custom. This is simply rendered into the client-side view model and is available for use in the AngularJS templates.

To provide Custom data on the view models, it will be necessary to derive from the DefaultViewService and override the appropriate methods for the views where the custom data needs to be rendered.

For example, to add a custom message to the login page:

public class CustomViewService : DefaultViewService
{
    public CustomViewService(DefaultViewServiceOptions config, IViewLoader viewLoader)
        : base(config, viewLoader)
    {
    }

    public override Task<Stream> Login(LoginViewModel model, SignInMessage message)
    {
        model.Custom = new {
            customMessage = "Hello World!"
        };

        return base.Login(model, message);
    }
}

Then in the _login.html template, this custom markup can be added to access the customMessage property:

<div ng-show="model.custom.customMessage">
    <h2></h2>
</div>

Finally, the CustomViewService must be registered with IdentityServer:

var factory = new IdentityServerServiceFactory();
factory.ViewService = new DefaultViewServiceRegistration<CustomViewService>();