11

这里有很多展示 - 但它是必要的。

不知道有多少人知道这一点,但是,Visual Studio 中的 Razor 代码编辑器会导致您的网站在Application_Start事件之前被“测试”——这在我当前的项目中造成了一些烦人的问题,它使用WebActivator 做了很多网站初始化。

更新 - 仔细检查它不仅仅是 Razor - 它看起来像是 Visual Studio 范围的 - 因此标题的变化

我需要能够检测网站代码何时由 Visual Studio 而不是由 Web 服务器运行。

为了演示 - 执行以下操作(完全按照书面说明以确保其重现):

  • 创建一个新的 MVC 4 站点,我使用了 Internet 应用程序模板,因此创建时有一些页面。
  • 从 nuget 添加 WebActivator 包
  • 将一个类添加到 App_Start 文件夹,名为RazorPageBugTest
  • 粘贴此代码(更改相关的命名空间):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MvcApplication6.App_Start;
using System.IO;

[assembly: WebActivator.PreApplicationStartMethod(
  typeof(RazorPageBugTest), "Start", Order = 0)]

namespace MvcApplication6.App_Start
{
  public static class RazorPageBugTest
  {
    public static void Start()
    {
      using (var writer = File.Open(@"c:\trace.txt", FileMode.Create))
      {
        using (var tw = new StreamWriter(writer))
        {
          tw.AutoFlush = true;
          tw.WriteLine("Written at {0}", DateTime.Now);
        }
      }
    }
  }
}

请注意,此代码无论如何通常都不能在 Web 服务器上运行 - 考虑到它正在写入驱动器 C:(如果您不以管理员身份运行 VS,这实际上可能无法在您的计算机上运行)。

  • 现在构建项目。
  • 如果您已经在 C 上打开了资源管理器,则下一点效果最好:完成后,找到 Razor 视图并打开它
  • 等待所有 C#/VB 位被突出显示
  • 看一下驱动器 C - 哦,看,有一个名为“trace.txt”的文件,日期在最后几秒钟内!

这说明了这里的问题 - Razor 代码编辑器正在启动 AppDomain,并且有效地对网站进行炮击以获得智能感知(包括 App_Helpers 文件夹中的内容等)。现在它实际上并没有触发该Application_Start方法 - 但是当您在项目中也有 WebActivator 时,它的任何应用程序启动前方法都会触发。

在我的情况下,这会导致巨大的问题 - 高 CPU 使用率和内存使用率devenv.exe(相当于刚刚启动的网站),因为我初始化了 DI 容器并且天知道此时还有什么,但一个特别是证明真的很烦人。

我的网站有一个组件,它在网络上侦听来自网络场中其他机器的状态和缓存无效消息。在 QA 和 Live 环境中,这个监听器永远不会打开端口并监听 - 但是,在我的开发机器上,它经常失败 - 说端口已经在使用中。当我寻找保持它打开的过程时 - 它总是devenv.exe.

你猜对了——我在一个 WebActivator 初始化的引导调用中启动了这个监听器。

所以问题是 - 有没有人知道一种方法来检测代码不是由“适当的”网络主机运行的,所以我可以阻止它运行?我对此特别充满希望,因为这也意味着我的 Visual Studio 和 Razor 编辑体验将因此更快地成为该死的网站!

作为奖励,任何修复都可以合法地发送给 WebActivator 的作者 David Ebbo,这样他就可以更早地将其粘贴到他的堆栈中以完全防止问题发生!

更新

我刚刚在 GitHub 上的 WebActivator 页面上添加了一个问题,以查看 David Ebbo 是否可以将我的修复或更好的修复推送到 WebActivator 组件中。

4

3 回答 3

4

猜猜Process.GetCurrentProcess().ProcessName在这种情况下的价值是多少?

答案:Microsoft.VisualStudio.Web.Host

因此,如果VisualStudio进程名称中有 a,您可以安全地刮掉它。

另请查看this article托管过程。

于 2012-10-12T15:13:29.077 回答
3

无需编写自己的逻辑来检测这一点,您可以只使用System.Web.Hosting.HostingEnvironment.InClientBuildManager,这对于 VS 运行该代码以及在 aspnet_compiler.exe 中运行时都是如此。

有关更多详细信息,请参阅此答案。

于 2013-01-22T18:09:56.890 回答
1

虽然达林关于托管过程的信息是正确的——从我所见,这只适用于 VS2012。早期版本的 VS 直接在 devenv 中托管。

由于我这里有一个 nuget 包堆栈在工作,我已将此扩展方法放入我们的 Web 核心组件中,该组件合并到WebActivator命名空间中:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace WebActivator
{
  public static class HostInformation
  {
    private static readonly string[] _knownDevEnvironments = new[] { 
      "devenv",
      "microsoft.visualstudio.web.host"
    };
    private static Lazy<bool> _isDevelopmentEnvironment = new Lazy<bool>(
      () => _knownDevEnvironments.Any(
        s => s.Equals(Process.GetCurrentProcess().ProcessName,
                      StringComparison.OrdinalIgnoreCase)
      ));

    /// <summary>
    /// Returns true if the current hosting environment is a known 
    /// development environment instead of a web server or similar.
    /// 
    /// This is used to decide whether or not to actually run 
    /// pre-application-start methods which are undesirable to 
    /// run in the development environment.
    /// </summary>
    /// <returns></returns>
    public static bool IsDevelopmentEnvironment
    {
      get
      {
        return _isDevelopmentEnvironment.Value;
      }
    }

  }
}

所有这些都意味着在我的App_Start初创公司WebActivator中,命名空间列表中已经很方便了——我可以这样做:

if(HostInformation.IsDevelopmentEnvironment)
  return;

从而使所有启动方法都能更早地被淘汰。

老实说,我讨厌这种解决方案,但出于同样的原因,实际上没有更简单的方法可以做到这一点。

从好的方面来说,我的 VS(2010 和 2012)现在可以非常快地向我展示 Razor 文件的智能感知;不会在内存中大量增长,而且 - 更重要的是 - 永远不会抓住那个网络端口......

于 2012-10-12T16:14:42.367 回答