Reputation: 725
We have a custom templating framework used by our web applications with implementations which are written in a variety of languages, and I'm investigating whether its possible to use this in an ASP.NET MVC application using the Razor View engine. We already have an implementation that uses the Web Forms View engine, but I'm keen to be able to use Razor as well.
The template is defined in a html file which contains macro tags that are interpreted and replaced at runtime with the applicable html. Below is a highly simplified version of this file:-
[doctype]
<html>
<head>
[HeadScript]
[HeadSectionText]
</head>
<body id="[if Home][Home][else]body[end if]">
[form]
[Content]
[end form]
[EndBodyScript]
</body>
</html>
As you can see, there are opportunities to inject html into various sections of the document, with some of this being handled by a simple conditional logic implementation. In order to use this with Razor, I'd need to be able to process all the macro tags in the template, including inserting the HTML from the Razor view being rendered, and use the output of this operation as the HTML to be ultimately sent to the client.
I'm pretty green when it comes to MVC development, but I know I can create a custom ViewEngine and IView implementation. Perhaps I can use this to achieve what I want, with a custom engine using the RazorView class to render the actual content to be inserted into our template. Does this sound like a feasible solution? And if so, does anyone have any tips to get me started?
Currently I have a kludgy solution where I use the ASP.NET WebForms engine and render partial Razor views, but longterm I'd prefer to have a solution that can take the WebForms engine out of the equation entirely.
Any shoves in the right direction greatly appreciated.
Upvotes: 2
Views: 1953
Reputation: 10620
I've managed to figure something out. Although my problem is not exactly the same you have, but it can certainly help you. But first things first.
The problem
I have a number of controls (in my case they are Partial Views). For example:
Views/Shared/EditName.cshtml
Views/Shared/EditAddress.cshtml
Views/Shared/EditEmail.cshtml
Views/Shared/EditFavoriteColour.cshtml
I want to define groups of these controls (in database or web.config), for example:
SimpleEditGroup:
EditName
ExtendedEditGroup:
EditName
EditEmail
FullEditGroup:
EditName
EditAddress
EditEmail
EditFavoriteColour
Then I want to render a view based on a particular group. I was thinking the following syntax would be sufficient.
@Html.Partial("ControlGroup:ExtendedEditGroup", Model)
Draft of the solution
I wanted to create my own render engine which will do the following:
Research
I've found following resources:
Final solution
MyViewEngine:
public class MyViewEngine : RazorViewEngine
{
IDictionary<string, List<string>> groups = new Dictionary<string, List<string>>();
public MyViewEngine()
{
// Temporary data source
groups["SimpleEditGroup"] = new List<string>() { "EditName"};
groups["ExtendedEditGroup"] = new List<string>() { "EditName", "EditEmail"};
}
public override ViewEngineResult FindView(ControllerContext controllerContext,
string viewName, string masterName, bool useCache)
{
if (viewName.StartsWith("ControlGroup"))
{
var groupName = viewName.Split(':')[1];
var controls = new List<ViewEngineResult>();
foreach (var controlName in groups[groupName])
{
// Find each control using Razor magic
var control = base.FindPartialView(controllerContext, controlName, useCache);
if (control.View != null)
{
controls.Add(control);
}
}
if(controls.Count > 0)
return new ViewEngineResult(new MyView(controls), this);
}
return base.FindView(controllerContext, viewName, masterName, useCache);
}
}
MyView.cs:
public class MyView : IView
{
IList<ViewEngineResult> controls;
public MyView(IList<ViewEngineResult> _controls)
{
controls = _controls;
}
public void Render(ViewContext viewContext, TextWriter textWriter)
{
// For simplicity I used table for layout
textWriter.Write("<table border='1'>");
foreach (var ctrl in controls)
{
textWriter.Write("<tr><td>");
// Render control using Razor
ctrl.View.Render(viewContext, textWriter);
textWriter.Write("</td></tr>");
}
textWriter.Write("</table>");
}
}
Don't forget to register your new engine in Global.asax ViewEngines.Engines.Add(new MyViewEngine());
Happy ending
I can use this in two ways: embedded in a view using Render.Partial
or just returning PartialView
from my controller.
Let me know if it helps you. And also you can share your solution.
Upvotes: 1