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

Overwriting ASP.NET MVC active stylesheet bundle

我的应用程序中有一个样式表 ~/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);

但是我间歇性地收到以下可怕的访问错误:"The process cannot access the file C:....\style.css" 因为它正被另一个进程使用。"(注意:这发生在 File.WriteAllText 行)

这没有意义,因为我没有打开文件的任何流,也没有使用 File.WriteAllText.

执行我认为是单个原子操作的操作

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

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

或者:

a. 捆绑打包程序以某种方式锁定了文件,因为它在更新捆绑包时已被修改并且没有释放锁或

b. 因为两个不同的连接以某种方式访问​​文件,所以锁在它们之间持续存在。

所以,有人 运行 喜欢类似的东西吗?关于如何解决这个问题有什么建议吗?

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

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

选项 1

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

选项 2

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

来自this answer

...if you are updating these [files] a lot, you're really defeating IIS's caching mechanisms here. And it is not healthy for the web server to be serving files that are constantly changing. Web servers are great at serving static files.

Now if your [files] are so dynamic, perhaps you'll need to serve it through a server-side program instead.

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

  1. 使用操作方法提供包的内容。
  2. 默认情况下,从磁盘读取文件。
  3. 当最终用户加载应用程序的“编辑”功能时,将文件中的内容加载到缓存中。提供内容的操作方法应首先检查此缓存,如果可用则提供它,如果不提供则从磁盘提供文件。
  4. 当最终用户保存内容时,编译内容,将其写入磁盘,然后使缓存失效。如果用户不保存,缓存最终将超时,最终用户将再次从磁盘读取文件。

参见 How can I add the result of an ASP.NET MVC controller action to a Bundle? for some potential solutions on how to serve the bundle from an action method. I would probably use a solution similar to this one(尽管缓存策略可能需要不同)。

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

当一个页面在浏览器上呈现时,优化器会将捆绑的 css 和 jqueries 处理到缓存中。因此,当页面被缓存时,一个页面重新请求浏览器首先将检查页面缓存的内容,如果不存在则仅进行服务调用。您的问题只有两种解决方案 less or sass type css usage.

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