我在ASP.NET MVC3中使用Razor视图进行了在线表单构建器应用程序。 它与此类似 - https://examples.wufoo.com/forms/workshop-registration/
我需要用户能够自定义页面设计。 不仅要上传自定义css,还要自定义HTML页面模板。 假设用户应该完全控制Layout的自定义webform页面的HTML。用户应该能够编辑页面上的任何HTML,包括在布局中的表单旁边。
我不确定如何使用Razor和ASP.NET MVC 3。 有可能:
也许1-3不是做我需要的最好方法。 对于使用Razor视图的ASP.NET MVC 3中的这种用户定义的页面布局方法,您有什么建议?
更新1 使用VirtualPathProvider我能够从数据库加载View,但它只返回如下文本:
@inherits System.Web.Mvc.WebViewPage
<body>
@Html.EditorFor(z => z.Customer)
</body>
并且根本不处理任何Razor语法。 它可能有什么问题?
已解决:
需要将此行作为Application_Start()方法中的第一行:
HostingEnvironment.RegisterVirtualPathProvider(new MyVirtualPathProvider());
更新2 Custom View Provider在Global.asax.cs中注册为:
protected void Application_Start()
{
HostingEnvironment.RegisterVirtualPathProvider(new MyVirtualPathProvider());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
MyVirtualPathProvider代码是:
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"" }))
{
}
<!-- <PERSONAL_INFO> -->
<div id=""personal_info"" class=""op2-block"">
</div>
<!-- <PERSONAL_INFO> -->";
this.data = Encoding.UTF8.GetBytes(_body);
}
public override System.IO.Stream Open()
{
return new MemoryStream(data);
}
}
}
现在对于上面定义为字符串的Razor视图代码,我得到了这个例外:
“编译器错误消息:CS1061:'System.Web.Mvc.AjaxHelper'不包含'BeginForm'的定义,也没有扩展方法'BeginForm'接受类型'System.Web.Mvc'的第一个参数可以找到.AjaxHelper'(你错过了使用指令或汇编引用吗?)“
当我将Razor View代码更改为:
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"" }))
{
}
<!-- <PERSONAL_INFO> -->
<div id=""ppg_op2_personal_info"" class=""op2-block"">
</div>
<!-- <PERSONAL_INFO> -->";
我得到了一个不同的错误:
类型'ASP._Page__appstart_cshtml'不会继承自'System.Web.WebPages.ApplicationStartPage'
当我改变
@inherits System.Web.Mvc.WebViewPage
到
@inherits System.Web.WebPages.ApplicationStartPage
要解决上面的错误,我会得到一个新错误:
“编译器错误消息:CS0103:当前上下文中不存在名称'Ajax'”
UPDATE3: 我尝试使用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"" }))
{
}
<!-- <PERSONAL_INFO> -->
<div id=""personal_info"" class=""op2-block"">
</div>
<!-- <PERSONAL_INFO> -->";
this.data = Encoding.UTF8.GetBytes(_body);
}
public override System.IO.Stream Open()
{
return new MemoryStream(data);
}
}
}
在这种情况下,我得到的视图根本没有被解析,这是我在网络浏览器中得到的:
@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" }))
{
}
<!-- <PERSONAL_INFO> -->
<div id="ppg_op2_personal_info" class="op2-block">
</div>
<!-- <PERSONAL_INFO> -->
答案 0 :(得分:7)
您应该创建一个虚拟路径提供程序,从数据库中提取自定义视图。
这里有几个问题。只需搜索VirtualPathProvider
更新(从我的评论到问题讨论)
必须使用HostingEnvironment.RegisterVirtualPathProvider(new MyVirtualPathProvider());
必须为当前无法提供服务的所有文件调用基类。这是必需的,因为只能有一个VirtualPathProvider
。 (否则你会看到许多奇怪的错误)
@model
指令在您提供的文件中不起作用。您必须改为使用@inherits System.Web.Mvc.WebViewPage<YourNameSpace.YourModelName>
。
IIRC您还需要覆盖GetCacheDependency
并为自己的资源返回null
。
答案 1 :(得分:0)
取决于您希望给予的灵活性和定制程度,这可能是非常简单到非常耗时的任务。
如果您希望用户只是在页面上自定义HTML,那么您可以使用WYSIWYG编辑器并将原始html存储在数据库中。
在视图中,使用
@Html.Raw(Model.body) // Where body is the field containing the wysiwyg content
这将按原样呈现标记。
要包含自定义标记/替换,您必须定义可在使用WYSIWYG编辑器时插入的字符串常量列表。然后可以在显示时替换它们。
例如,在您的控制器或型号中:
model.body.replace("$[form1]", "<form action='something' method='post' name='form1'></form>");
当然,根据您的应用程序的性质,您可能希望将其重新分解为某种标签=&gt;标记转换,允许您添加更多自定义标记及其各自的实际HTML标记。
希望这有帮助,干杯!
答案 2 :(得分:0)
我认为你必须使用这样的东西:
http://vibrantcode.com/blog/2010/11/16/hosting-razor-outside-of-aspnet-revised-for-mvc3-rc.html
答案 3 :(得分:0)
我做过类似的事情。你可能会认为XML非常有用。将布局定义作为XML保存到DB。这意味着它可以直接操作,也可以通过序列化/反序列化操作到对象模型中。
如果要显示页面,请使用XSLT将XML转换为HTML,将样式等应用于输出。