ASP.NET MVC单例或静态类传递数据?

时间:2010-10-14 20:01:39

标签: c# asp.net-mvc design-patterns

我正在创建一个控制器,它将提供我的JavaScript和CSS的组合/缩小版本。我需要沿着这条线的某个地方定义要加载的脚本/样式。

当发出请求时,例如style.css?VersionNumberHere,它将检查合并/缩小的数据是否已经在HttpContext.Cache中,如果是这样,则将其吐出。否则,我需要查找构成style.css的定义。

我创建了一个Script/StyleBuilder(继承自ContentBuilder),它将存储所有需要合并然后压缩的路径(因此这将是style.css的定义)。

我应该将这些引用存储在“构建者”中?它们应该是静态类还是实现接口的单例,以便对其进行测试?

这是抽象类ContentBuilder实现的接口(您可以轻松想象实现):

public interface IContentBuilder : IEnumerable<string>
{
    string Name { get; }
    int Count { get; }
    string[] ValidExtensions { get; }
    void Add(string path);
    bool ValidatePath(string path);
    string GetHtmlReference(); // Spits out <script>, or <link> depending on implementation.
    string Build(); // Minifies, combines etc.
}

理想情况 我希望能够做到这些

ContentBuilderContainer.Current.Add("main.js", c => new ScriptBuilder()
{
    "/path/to/test.js",
    "/path/to/test2.js",
    "/path/to/test3.js"  
});

ContentBuilderContainer.Current.Add("style.css", c => new StyleBuilder()
{
    "/path/to/style.css",
    "/path/to/test.less"
});

然后输出所有已注册的IContentBuilder的所有HTML:

ContentBuilder.Container.Current.BuildHtml();

4 个答案:

答案 0 :(得分:1)

也许你应该看看SquishItthis blog post中的更多信息。我们在生产中使用它。

答案 1 :(得分:0)

通过参数将缓存属性附加到控制器操作和缓存,如下所示:

[OutputCache(Duration = 7200, Location = OutputCacheLocation.Client, VaryByParam = "jsPath;ServerHost")]
[CompressFilter]
// Minifies, compresses JavaScript files and replaces tildas "~" with input serverHost address 
// (for correct rewrite of paths inside JS files) and stores the response in client (browser) cache for a day
[ActionName("tildajs")]
public virtual JavaScriptResult ResolveTildasJavaScript(string jsPath, string serverHost)
...

答案 2 :(得分:0)

我做了以下界面:

public interface IContentBuilderContainer
{
    int Count { get; }
    bool Add(string name, Func<IContentBuilder> contentBuilder);
    string RenderHtml();
}

然后执行ContentBuilderContainer

public class ContentBuilderContainer : IContentBuilderContainer
{

    // Other members removed for simplicity.

    #region Static Properties

    /// <summary>
    /// Gets or sets the current content builder container.
    /// </summary>
    public static IContentBuilderContainer Current
    {
        get;
        set;
    }

    #endregion

    #region Static Constructors

    static ContentBuilderContainer()
    {
        ContentBuilderContainer.Current = new ContentBuilderContainer();
    }

    #endregion

}

通过这种方式,有一个ContentBuilderContainer同时居住。

答案 3 :(得分:0)

我帮助编写了一些最近执行此操作的代码。以下是已实施解决方案的高级概述。希望它会给你一些好主意。

配置:我们创建了自定义配置元素,用于定义密钥及其相应的目录列表。因此,关键JS链接到我们的/ Content / Scripts文件夹,CSS链接到我们的/ Content / Styles文件夹。我已经看到了其他解决方案,其中配置允许列出单个文件。

控制器:控制器设置为接收/ Content / Get / JS和/ Content / Get / CSS的请求。控制器使用配置密钥和客户端请求标头来提供标识我们要服务的内容的缓存密钥:JS-MSIE-ZIP,CSS-FFX等。控制器然后检查我们的缓存服务。如果内容不存在,则会进行连接,缩小,压缩,缓存,然后提供服务。方便的后果是内容在进入缓存之前被压缩,而不是每次都被压缩。

查看:在视图中,链接的设置如下:

<link href="<%: Url.Action("Get", "Content", new { key = "CSS" }) %>" rel="stylesheet" type="text/css" />

缓存服务我们正在使用现有的缓存服务,它只包装应用程序缓存。在某些时候,我们可能会将其转移到Velocity或类似的东西。如果我们缓存的CSS和JS的数量不断增加,我们可能会将密钥的格式更改为正确的文件名并将内容移动到文件系统。但是,记忆非常便宜,我们会看到会发生什么。

推理:(如果重要)

我们这样做是为了将不同功能的JavaScript保存在源代码管理中的单独文件中,而不必单独链接到HTML中的所有文件。因为我们按目录而不是单个文件配置我们的内容,所以我们也可以在生产版本中运行完全缩小,以加快整个运行时过程。然而,我们仍然可以根据客户端浏览器和缓存的压缩版本来确定要提供的内容。

在开发中,可以通过快速配置更改来设置系统,以便每个请求都重建JS。这些文件与注释中注入的文件名连接以便于搜索,但内容不会缩小,并且不会在任何地方缓存任何内容。这允许我们在不重新编译应用程序的情况下更改,测试和调试JS。

无法在包中找到所有这些功能,所以我们花了几天时间来构建它。不可否认,有些功能只是为了好玩,但这就是为什么我们喜欢做我们做的事情。 =)