【问题标题】:Overwriting ASP.NET MVC active stylesheet bundle覆盖 ASP.NET MVC 活动样式表包
【发布时间】:2017-09-19 10:22:58
【问题描述】:

我的应用程序~/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(); 作为一种破解方法来尝试释放文件上的任何锁定,但这似乎没有帮助。

【问题讨论】:

  • 您的编译器在写入文件时会出现错误。对吗?
  • 不,抱歉,如果我不清楚,错误发生在 System.IO.File.WriteAllText 行。我不使用 SassCompiler 来编写实际文件。
  • 有必要写style.css文件吗?您可以在调用时编译 sass 并将其注入包中
  • 如果您使用 Visual Studio 构建 MVC,有大量工具、扩展和插件可帮助您将 SASS 和 LESS 文件自动转换为 CSS 文件。 Web Essentials 就是其中之一。如果你喜欢 Bundle 东西在一个地方,你可以试试 BundleTransformer Nuget 包。
  • 是的,当然,我理解这一点并且我使用这些工具,但我的特定用例需要最终用户能够在运行时修改 Sass 文件。

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


【解决方案1】:

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

选项 1

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

选项 2

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

来自this answer

...如果您经常更新这些 [文件],那么您真的在破坏 IIS 的缓存机制。 Web 服务器服务于不断变化的文件是不健康的。 Web 服务器非常擅长提供静态文件。

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

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

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

请参阅How can I add the result of an ASP.NET MVC controller action to a Bundle?,了解有关如何通过操作方法提供捆绑包的一些潜在解决方案。我可能会使用类似于this one 的解决方案(尽管缓存策略可能需要不同)。

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

【讨论】:

  • 非常感谢,这正是我正在寻找的那种解释。我发现自己的权衡是不想使方法过于复杂(这个功能只有我真正使用 - 即使它可供最终用户使用)。我已经采用了忽略错误并进行重试循环的方法,现在似乎可以正常工作。再次感谢...
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-12
    • 1970-01-01
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多