I have an application for creating forms in ASP.NET MVC3 with Razor views. It looks like this: https://examples.wufoo.com/forms/workshop-registration/
I need users to be able to customize the page design. Not only to download custom css, but also to customize the HTML page template. Let them say that users should have full control over the layout of HTML for their custom web form page. The user should be able to edit any HTML on the page, in addition to the form included in the layout.
I'm not sure how to do this with Razor and ASP.NET MVC 3. Is it possible:
- download location somewhere from the database as a string or whatever
- replace some custom tags of the FORM1_INCLUDE type with @ Html.Partial ("some_non_customizable_layout_for_form1")
- use the result as a valid layout file for a custom form page
Maybe 1-3 is not the best way to do what I need. What can you offer for this custom approach to page layout in ASP.NET MVC 3 with Razor views?
UPDATE 1 Using VirtualPathProvider, I was able to load the View from the database, but it just returns the text, for example:
@inherits System.Web.Mvc.WebViewPage <body> @Html.EditorFor(z => z.Customer) </body>
and doesn’t process Razor syntax at all. What could be the problem?
SOLVED:
You must place this line as the first in the Application_Start () method:
HostingEnvironment.RegisterVirtualPathProvider(new MyVirtualPathProvider());
UPDATE 2 The custom view provider is registered with Global.asax.cs as:
protected void Application_Start() { HostingEnvironment.RegisterVirtualPathProvider(new MyVirtualPathProvider()); AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); }
MyVirtualPathProvider Code:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Hosting; using System.IO; using System.Text; namespace new_frontend { public class MyVirtualPathProvider : VirtualPathProvider { public override bool FileExists(string virtualPath) { var td = FindTemplate(virtualPath); if (td == null) { return true; //return base.FileExists(virtualPath); } else { return true; } } public override VirtualFile GetFile(string virtualPath) { var td = FindTemplate(virtualPath); if (td == null) { return new MyVirtualFile(virtualPath, ""); //return base.GetFile(virtualPath); } else { return new MyVirtualFile(virtualPath, td.ContentStep1); } } private Facade.Dto.TemplateData FindTemplate(string virtualPath) { string prefix = "Template#"; int id = 0; Facade.Dto.TemplateData td = null; string fileName = System.IO.Path.GetFileNameWithoutExtension(virtualPath); if (fileName.StartsWith(prefix)) Int32.TryParse(fileName.Substring(prefix.Length), out id); if (id > 0) td = Facade.FrontEndServices.GetTemplate(id); return td; } } public class MyVirtualFile : VirtualFile { private byte[] data; public MyVirtualFile(string virtualPath, string body) : base(virtualPath) { // 'System.Web.WebPages.ApplicationStartPage string _body = /*body +*/ @" @inherits System.Web.Mvc.WebViewPage @using (Ajax.BeginForm(""Submit"", new AjaxOptions { UpdateTargetId = ""main"" })) { } <div id=""personal_info"" class=""op2-block""> </div> "; this.data = Encoding.UTF8.GetBytes(_body); } public override System.IO.Stream Open() { return new MemoryStream(data); } } }
And now for the Razor view code defined as the line above, I get this exception:
"Compiler error message: CS1061:" System.Web.Mvc.AjaxHelper "does not contain a definition for" BeginForm "and no extension method" BeginForm "that takes the first argument of the type" System.Web.Mvc.AjaxHelper ", (you did not specify use directive or assembly link?) "
And when I changed the Razor View code to:
string _body = /*body +*/ @" @using System.Web.WebPages; @using System.Web.Mvc; @using System.Web.Mvc.Ajax; @using System.Web.Mvc.Html; @using System.Web.Routing; @inherits System.Web.Mvc.WebViewPage<dynamic> @using (Ajax.BeginForm(""Submit"", new AjaxOptions { UpdateTargetId = ""main"" })) { } <div id=""ppg_op2_personal_info"" class=""op2-block""> </div> ";
I have another error:
The type "ASP._Page__appstart_cshtml" is not inherited from "System.Web.WebPages.ApplicationStartPage"
When i change
@inherits System.Web.Mvc.WebViewPage
to
@inherits System.Web.WebPages.ApplicationStartPage
to fix the error above, I get a new one:
"Compiler error message: CS0103: The name" Ajax "does not exist in the current context"
Update3: I tried using base.XXX:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Hosting; using System.IO; using System.Text; namespace new_frontend { public class MyVirtualPathProvider : VirtualPathProvider { public override bool FileExists(string virtualPath) { var td = FindTemplate(virtualPath); if (td == null) { //return true; return base.FileExists(virtualPath); } else { return true; } } public override VirtualFile GetFile(string virtualPath) { var td = FindTemplate(virtualPath); if (td == null) { //return new MyVirtualFile(virtualPath, ""); return base.GetFile(virtualPath); } else { return new MyVirtualFile(virtualPath, td.ContentStep1); } } private Facade.Dto.TemplateData FindTemplate(string virtualPath) { string prefix = "Template#"; int id = 0; Facade.Dto.TemplateData td = null; string fileName = System.IO.Path.GetFileNameWithoutExtension(virtualPath); if (fileName.StartsWith(prefix)) Int32.TryParse(fileName.Substring(prefix.Length), out id); if (id > 0) td = Facade.FrontEndServices.GetTemplate(id); return td; } } public class MyVirtualFile : VirtualFile { private byte[] data; public MyVirtualFile(string virtualPath, string body) : base(virtualPath) { // 'System.Web.WebPages.ApplicationStartPage string _body = /*body +*/ @" @inherits System.Web.Mvc.WebViewPage<PPG.Facade.Dto.NewOrderPageData> @using (Ajax.BeginForm(""Submit"", new AjaxOptions { UpdateTargetId = ""main"" })) { } <div id=""personal_info"" class=""op2-block""> </div> "; this.data = Encoding.UTF8.GetBytes(_body); } public override System.IO.Stream Open() { return new MemoryStream(data); } } }
In this case, I get a view that is not parsed at all, this is what I get in a web browser:
@using System.Web.WebPages; @using System.Web.Mvc; @using System.Web.Mvc.Ajax; @using System.Web.Mvc.Html; @using System.Web.Routing; @inherits System.Web.Mvc.WebViewPage<PPG.Facade.Dto.NewOrderPageData> @using (Ajax.BeginForm("Submit", new AjaxOptions { UpdateTargetId = "main" })) { } <div id="ppg_op2_personal_info" class="op2-block"> </div>