覆盖ASP.NET MVC活动样式表包

时间:2017-09-19 10:22:59

标签: c# asp.net asp.net-mvc sass libsass

我的应用程序~/Content/theme/style.css中有一个样式表。它在我的应用程序中使用标准捆绑引用:

bundles.Add(new StyleBundle("~/Content/css").Include(
 "~/Content/font-awesome/font-awesome.css",
 "~/Content/theme/style.css"));

现在,我使用Sass编译器(Libsass)允许我根据需要将输出style.css文件更改为自定义用户输出文件。

基本上我做的就是这样。

CompilationResult compileResult = SassCompiler.CompileFile(Server.MapPath(Path.Combine(WebConfigSettings.RootSassPath, "style.scss"), options: new CompilationOptions {
    SourceMap = true,
    SourceMapFileUrls = true
});

然后我这样保存。

string outputPath = Server.MapPath(WebConfigSettings.ThemeOutputPath);
if (System.IO.File.Exists(outputPath))
    System.IO.File.Copy(outputPath, string.Format("{0}.bak", outputPath), true);

System.IO.File.WriteAllText(Server.MapPath(WebConfigSettings.ThemeOutputPath), compileResult.CompiledContent);

但是间歇性地我收到以下可怕的访问错误:“进程无法访问文件C:.... \ style.css”,因为它正被另一个进程使用。“(注意:这发生在File.WriteAllText行)

这没有意义,因为我没有打开文件的任何流,并使用File.WriteAllText执行我认为是单个原子操作。

现在我也注意到,当我使用两个不同的浏览器连续修改这个文件时,这个错误特别可能。

我的假设是发生了两件事之一。

或者:

a。捆绑打包程序以某种方式锁定文件,因为它在更新捆绑包时未被修改,而不是释放锁定或

b。由于两个不同的连接以某种方式访问​​该文件,因此锁定会持续存在。

那么,有没有人碰到类似的东西?关于我如何解决这个问题的任何建议?

PS:我尝试使用HttpRuntime.UnloadAppDomain();作为一种愚蠢的方式尝试释放文件上的任何锁定但这似乎没有帮助。

2 个答案:

答案 0 :(得分:1)

您的网络服务器本身将在提供文件时获得对文件的读锁定。所以,如果你要同时写文件,碰撞将是不可避免的。

选项1

在重试循环中写入磁盘并忽略此异常。这些文件很可能在很短的时间内完成。

选项2

避免Web服务器通过从缓存中自行提供文件来锁定文件。

来自this answer

  

...如果你要更新这些[文件],那么你真的在这里击败了IIS的缓存机制。 Web服务器提供不断变化的文件并不健康。 Web服务器非常适合提供静态文件。

     

现在如果您的[文件]如此动态,也许您需要通过服务器端程序来提供它。

由于您在评论中提到您的最终用户正在更改文件,我建议您执行以下操作以确保不存在锁定冲突的可能性:

  1. 使用操作方法提供捆绑包的内容。
  2. 默认情况下,从磁盘读取文件。
  3. 当最终用户加载应用程序的“编辑”功能时,将文件中的内容加载到缓存中。提供内容的操作方法应首先检查此缓存,如果可用则提供服务,如果没有,则从磁盘提供文件。
  4. 当最终用户保存内容时,编译内容,将其写入磁盘,然后使缓存无效。如果用户没有保存,缓存最终会超时,最终用户将再次从磁盘读取文件。
  5. 有关如何从操作方法提供捆绑包的一些可能解决方案,请参阅How can I add the result of an ASP.NET MVC controller action to a Bundle?。我可能会使用类似于this one的解决方案(尽管缓存策略可能需要不同)。

    或者,您可以在每次用户请求中为空时重新加载缓存,并在“保存”操作期间更新文件和缓存,这可能会更简单,并将文件锁定问题的可能性降低到零,但也不会扩展。

答案 1 :(得分:0)

当在浏览器上呈现一个页面时,优化器会将捆绑的css和jqueries处理为缓存。因此,一旦页面获得兑现,一个页面重新请求浏览器将首先检查页面缓存内容,如果不存在则只进行服务调用。对于您的问题较少或sass类型的css使用,只有两种解决方案。

  1. 关闭捆绑
  2. Less,coffeescript,scss & sass bundling