Archive for the ‘Shaver’ Category
As I explained in Shaver View Engine: a more in-depth look, Shaver is a framework for an extensible view engine that allows views to be written in Razor syntax, captures the HTML/CSS output using the Razor view engine and then makes that output available for use via extension points so that the original Razor view can be repurposed to produce any output you want or perform additional tasks prior to returning to the browser, or both.
If the output you want can be produced from HTML, or make use of HTML, Shaver facilitates this but does nothing with the output itself: that task is left up to concrete implementations of the View Engine. Shaver is an abstract View Engine and we need concrete implementations in order to do anything useful.
This post is going to concentrate on a simple concrete implementation of the Shaver View Engine, LoggingViewEngine. The LoggingViewEngine returns the view as normal but first logs the rendered HTML via Log4Net. And all that is required to achieve this functionality is to change the View’s extension to cslog …
Following on from our in-depth introduction to Shaver and the first part of Shaver’s API, the second part of the API is the ShaverView: https://github.com/alfamale/Shaver/blob/master/ShaverViewEngine/ShaverView.cs.
ShaverView is an abstract class that implements the IView interface and provides a set of extension points. Just like ShaverViewEngine, ShaverView cannot be used directly but is intended to provide a framework and API. Have a look at Logging View Engine, Mailer View Engine and PDF View Engine to see examples of how this is done.
The API is made up of three abstract methods that must be overridden by each implementation (Setup, ActOnHtml and RenderView), a virtual method that may be overridden by an implementation if required (CaptureHtml) and two static helper methods (GetViewData and GetTempData), that extract view and temp data from the controller context.
ShaverView’s constructor accepts two parameters the ControllerContext and an instance of IView. Not co-incidentally, these objects are supplied to ShaverViewEngine’s CreateReturnView method and it is intended that View inheriting from ShaverView will be instantiated in the ViewEngine’s CreateReturnView method. Once again, have a look at Logging View Engine, Mailer View Engine and PDF View Engine to see examples of how this is done.
The constructor calls the API methods in the following order:
- Setup – performs any setup tasks required
- CaptureHtml – captures and returns the HTML rendered by the Razor View Engine
- ActOnHtml – acts on the HTML returned from the CaptureHtml method
Following on from the last post, let’s start our discussion of the Shaver API with the Shaver View Engine itself:https://github.com/alfamale/Shaver/blob/master/ShaverViewEngine/ShaverViewEngine.cs.
There are a couple of things to note: firstly, ShaverViewEngine inherits from RazorViewEngine so that we can re-use and co-opt all the power of the Razor View Engine without re-inventing the wheel: Shaver is about doing unexpected, unenvisioned things with existing Razor syntax not developing a new syntax!
Secondly, there are only two methods: CreateView and CreateReturnView. CreateView overrides Razor’s implementation of the standard CreateView method and uses it to create an IView object which is then passed, along with the ControllerContext to the virtual method CreateReturnView. Custom View Engines that implement the Shaver framework can perform any custom tasks required within their own implementation of CreateReturnView: it is the output of CreateReturnView that is returned to MVC, not the output of CreateView as might be expected. We are letting Razor do the hard work here – it already does it really well, we just want to make it easy to do something different with the output!
CreateReturnView is the first extension point in our Shaver API.
Note also that Shaver itself provides no code to register custom view extensions: Shaver is an abstract View Engine and as such does not provide complete functionality only an API. As such, it makes no sense to attempt to register custom view extensions within the Shaver View Engine itself, this is a task for each concrete implementation such as LoggingViewEngine.
Shaver cannot in fact be used directly: note that it is an abstract class: we need a concrete implementation of the Shaver framework to instantiate – Shaver cannot and does not do the job on its own. Have a look at Logging View Engine, Mailer View Engine and PDF View Engine to see examples of how this is done.
Next: the Shaver API: ShaverView
After my presentation at the MTUG Dev Day earlier this month, I have been asked a number of times for the source code of the sample custom view engines I used in my talk. The delay in posting the source code has been due to the fact that when I started looking at it, I realized that what I had done, with a bit of refactoring and re-engineering, could be made into quite a useful open source project. Hence the delay!
But finally, I am ready to announce the existence of Shaver, an ASP.Net MVC Open Source Project that allows the extension of the Razor View Engine to allow views to be written in standard Razor syntax but used to produce any type of output you want. Most custom view engines for ASP.Net MVC offer different syntax for writing your views in; Shaver reuses standard Razor syntax but allows you to perform any task you want with the output. Examples included in the project include a logging view engine, a view engine that converts HTML / CSS to PDF and displays the generated PDF instead and a mailer view engine that can produce a mail merge from a standard Razor view.
The possibilities are potentially endless …
In the hope that this will prove useful, I have now released this project under the GNU LGPL on GitHub: Shaver. Please have a look, play around with it, offer any constructive criticism and suggestions and let me know what you think!