【问题标题】:Can I load an ITemplate from a database or string?我可以从数据库或字符串中加载 ITemplate 吗?
【发布时间】:2011-03-22 14:36:51
【问题描述】:

我希望在 Web 应用程序中实现一些模板,并希望利用 ASP.NET 的模板化控件。但是,我不想依赖物理 .ascx 文件或 VirtualPathProvider 来加载模板。

我希望能够从数据库或其他数据存储(在内存中?)加载模板。 在给定 .ascx 模板的字符串表示的情况下,是否有任何 LoadTemplate() 方法的实现返回 ITemplate?

如果没有,我该怎么写?

仅供参考,Kentico 具有类似的功能,但它们依赖于 VirtualPathProvider 才能在 TemplateControl 类上使用 LoadTemplate()。使用该方法,他们能够加载存储在数据库中的模板(他们称之为转换)。

【问题讨论】:

  • 如果我没记错的话,我也在 Sitefinity 中看到过这个,我认为这是最好的方法。或者您可以为 ascx 标记创建自己的解析器,但这并不简单。
  • 是的,我认为很多基于 .NET 的 CMS 和其他可扩展应用程序都使用这种方法。看起来这似乎是微不足道的,我发现很难理解为什么拥有一个物理 ASCX 文件和一个字符串变量真的有什么不同。

标签: c# asp.net templates itemplate loadcontrol


【解决方案1】:

是的,VirtualPathProvider 可能是您想要使用的方法,如果字符串或数据库是您想要使用的源。 (也有可以发出代码的代码生成器,但通常在动态构建代码时使用它们——而不是像您的情况那样从外部源加载。)

你没有提到为什么你不想使用 VirtualPathProvider。是因为不想,还是因为您在特定情况下有一些特殊要求而不能?

最后,如果动态加载和编译代码“看起来很简单”,那么你不知道整个 .Net 系统在运行动态代码之前必须做什么——程序集生成、编译和 JIT、应用程序上下文、类/成员名称解析、代码安全等。也许您刚刚被 .Net 使执行其他复杂任务变得多么容易而被宠坏了。 ;-)

【讨论】:

    【解决方案2】:

    我也遇到过类似的问题。但是,VirtualPathProvider 实现如此小的收益实在是太麻烦了——更不用说它在安全方面的实现似乎有点风险。我发现了两种可能的解决方法:

    1) 使用反射得到你想要的:

    var page = HttpContext.Current.Handler as Page;
    string text = "<table><tr><td>Testing!!!</td></tr></table>";
    var systemWebAssembly = System.Reflection.Assembly.GetAssembly(typeof(Page));
    var virtualPathType = systemWebAssembly.GetTypes().Where(t => t.Name == "VirtualPath").FirstOrDefault(); // Type.GetType("System.Web.VirtualPath");
    var createMethod = virtualPathType.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).Where(m => m.Name == "Create" && m.GetParameters().Length == 1).FirstOrDefault();
    object virtualPath = createMethod.Invoke(null, new object[]
    { 
        page.AppRelativeVirtualPath 
    });
    var template = (ITemplate)typeof(TemplateParser).GetMethod("ParseTemplate", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).Invoke(null, new object[]{text, virtualPath, true});
    

    2) 使用有点老套的解决方法:

    var page = HttpContext.Current.Handler as Page;
    string text = "<table><tr><td>Testing!!!</td></tr></table>";
    string modifiedText = string.Format("<asp:UpdatePanel runat=\"server\"><ContentTemplate>{0}</ContentTemplate></asp:UpdatePanel>", text);
    var control = page.ParseControl(modifiedText);
    var updatePanel = control.Controls[0] as UpdatePanel;
    var template = updatePanel.ContentTemplate;
    

    我公开表示这两者都不是一个很好的解决方案。理想情况下,.Net Framework 中会有一种方法来处理这类事情。比如:

    public class TemplateParser
    {
        public static ITemplate ParseTemplate(string content, string virtualPath, bool ignoreParserFilter)
        {
            return TemplateParser.ParseTemplate(string content, VirtualPath.Create(virtualPath), ignoreParserFilter);
        }
    }
    

    这将减轻实现 VirtualPathProvider 的整体需求。也许我们会在 ASP.NET vNext 中看到它:-)

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-15
    • 1970-01-01
    • 1970-01-01
    • 2010-11-17
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    相关资源
    最近更新 更多