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

5

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

然而,我偶尔会收到以下可怕的访问错误:“因为它正在被另一个进程使用”,(注意:这发生在File.WriteAllText行),这是没有意义的,因为我没有打开任何流到该文件,并且执行我认为是单个原子操作的File.WriteAllText。现在我还注意到,当我使用两个不同的浏览器连续修改此文件时,这种错误特别容易发生。我的假设是有两件事情正在发生。要么:a.捆绑打包程序以某种方式锁定了该文件,因为在更新捆绑包时已对其进行了修改,而没有释放锁定;要么b.因为两个不同的连接访问该文件,所以锁定仍然存在。那么,有人遇到类似的情况吗?有什么建议可以帮助解决这个问题吗?PS:我尝试使用HttpRuntime.UnloadAppDomain();作为一种hacky方法来尝试释放文件上的任何锁定,但这似乎并没有帮助。

你在写文件时编译器报错了,是吗? - Abdul Samad
不好意思,如果我表达不清楚了,错误发生在 System.IO.File.WriteAllText 这一行。我没有使用 SassCompiler 来编写实际的文件。 - Maxim Gershkovich
需要编写 style.css 文件吗?您可以在调用时编译Sass并将其注入捆绑包中。 - GGO
如果你使用Visual Studio构建MVC,有很多工具、扩展和插件可以帮助你自动地将SASS和LESS文件转换为CSS文件。Web Essentials 就是其中之一。如果你喜欢把所有东西都打包放在一个地方,你可以尝试BundleTransformer Nuget 包。 - David Liang
当然,我理解这一点并使用那些工具,但我的特定用例需要最终用户在运行时修改Sass文件的能力。 - Maxim Gershkovich
2个回答

1
您的Web服务器在提供文件时会对文件进行读取锁定。因此,如果您同时要编写文件,则冲突将是不可避免的。
选项1:在重试循环中写入磁盘并忽略此异常。文件很可能在非常短的时间内可用于写入。
选项2:通过从缓存中自己提供文件来避免Web服务器锁定文件。
this answer所述:
“……如果您经常更新这些[文件],则实际上正在破坏IIS的缓存机制。让Web服务器提供经常更改的文件并不健康。Web服务器非常适合提供静态文件。现在,如果您的[文件]如此动态,也许您需要通过服务器端程序来提供它。”
由于您在评论中提到您的最终用户正在更改文件,因此建议执行以下操作以确保不存在锁定冲突:
  1. 使用一个动作方法来提供捆绑包的内容。
  2. 默认情况下,从磁盘上读取文件。
  3. 当最终用户加载应用程序的“编辑”功能时,将内容从文件中加载到缓存中。您提供内容的操作方法应首先检查此缓存,如果可用,则提供它,如果不可用,则从磁盘上提供文件。
  4. 当最终用户保存内容时,编译内容,将其写入磁盘,然后使缓存失效。如果用户没有保存,缓存将最终超时并且文件将被最终用户再次从磁盘上读取。

请参阅如何将ASP.NET MVC控制器操作的结果添加到Bundle中?以获取一些潜在的解决方案,以便从操作方法提供捆绑包。我可能会使用类似于这个的解决方案(尽管缓存策略可能需要不同)。

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


非常感谢,这正是我正在寻找的解释类型。我发现自己面临的权衡是不想过于复杂化方法(即使该功能仅由我使用-尽管它可供最终用户使用)。我采用了忽略错误并执行重试循环的方法,目前似乎运行良好。再次感谢... - Maxim Gershkovich

0

当一个页面在浏览器上呈现时,优化器会将捆绑的CSS和jQuery处理成缓存。因此,当页面被缓存后,再次请求浏览器的页面首先会检查页面缓存内容,如果不存在,则才会进行服务调用。对于您的问题,只有两个解决方案:使用less或sass类型的CSS。

  1. 关闭捆绑
  2. Less、coffeescript、scss和sass捆绑

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接