C# 检测Visual Studio何时为intellisense测试启动网站

C# 检测Visual Studio何时为intellisense测试启动网站,c#,asp.net-mvc-3,visual-studio-2010,razor,asp.net-mvc-4,C#,Asp.net Mvc 3,Visual Studio 2010,Razor,Asp.net Mvc 4,这里有很多解释,但这是必要的 不知道有多少人知道这一点,但是,Visual Studio中的Razor代码编辑器会导致您的网站在应用程序启动之前被“测试启动”事件-这会在我当前的项目中造成一些恼人的问题,该项目使用WebActivator进行大量的网站初始化 更新-仔细观察,它不仅仅是剃须刀-它看起来像是Visual Studio范围内的-因此更改了标题 我需要能够检测网站代码何时由VisualStudio而不是web服务器运行 演示-按照书面要求执行以下操作(准确地执行),以确保其再现: 创

这里有很多解释,但这是必要的

不知道有多少人知道这一点,但是,Visual Studio中的Razor代码编辑器会导致您的网站在
应用程序启动之前被“测试启动”
事件-这会在我当前的项目中造成一些恼人的问题,该项目使用WebActivator进行大量的网站初始化

更新-仔细观察,它不仅仅是剃须刀-它看起来像是Visual Studio范围内的-因此更改了标题

我需要能够检测网站代码何时由VisualStudio而不是web服务器运行

演示-按照书面要求执行以下操作(准确地执行),以确保其再现:

  • 创建一个新的MVC4站点,我使用了Internet应用程序模板,因此在创建时有一些页面
  • 从nuget添加WebActivator包
  • 将名为
    RazorPageBugTest
  • 粘贴此代码(更改相关命名空间):
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.Web;
使用mvcapapplication6.App_启动;
使用System.IO;
[组件:WebActivator.PreApplicationStartMethod(
类型(RazorPageBugTest),“开始”,顺序=0)]
名称空间MVCAPApplication6.App_开始
{
公共静态类RazorPageBugTest
{
公共静态void Start()
{
使用(var writer=File.Open(@“c:\trace.txt”,FileMode.Create))
{
使用(var tw=新的StreamWriter(writer))
{
tw.AutoFlush=true;
tw.WriteLine(“写在{0}”,DateTime.Now);
}
}
}
}
}
请注意,这段代码通常不会在web服务器上运行,因为它正在写入驱动器C:(如果您不以管理员身份运行VS,这可能在您的计算机上不起作用)

  • 现在构建项目
  • 如果您已经在C上打开了资源管理器,那么下一步的工作效果最好:完成后,找到一个Razor视图并打开它
  • 等待所有C#/VB位高亮显示
  • 看看驱动器C-哦,看,有一个名为“trace.txt”的文件,日期在最后几秒钟内
这就说明了问题所在——Razor代码编辑器正在启动一个AppDomain,并有效地对网站进行炮轰,以获得intellisense(包括App_Helpers文件夹中的内容等)。现在它实际上不会触发
应用程序启动
方法,但是当项目中也有WebActivator时,它的任何应用程序启动前方法都会被触发

在我的例子中,这导致了巨大的问题-在
devenv.exe中的CPU使用率和内存使用率很高(相当于刚刚启动的网站),因为我初始化了DI容器,上帝知道在这一点上还有什么,但有一个特别令人讨厌

我的网站有一个组件,它在网络上侦听状态并缓存来自web场中其他机器的无效消息。在QA和实时环境中,此侦听器从不失败地打开端口并侦听—在我的开发人员机器上,它经常失败—表示端口已在使用中。当我寻找保持它打开的进程时,它总是
devenv.exe

你猜对了-我在WebActivator初始化的引导调用中启动了这个侦听器

所以问题是——有没有人知道一种方法可以检测到代码不是由“适当”的web主机运行的,这样我就可以停止它的运行?我对此特别有希望,因为这也意味着我的VisualStudio和Razor编辑体验将因此更快地成为一个该死的网站

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

更新


我刚刚添加了一个测试,看看David Ebbo是否可以将我的补丁或更好的补丁推到WebActivator组件中

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

回答:
Microsoft.VisualStudio.Web.Host

因此,如果流程名称中有
VisualStudio
,您可以安全地将其删除


另外,请查看有关托管过程的信息。

而Darin关于托管过程的信息是正确的-从我所看到的情况来看,这仅适用于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;
      }
    }

  }
}
因此,所有的启动方法都可以更早地退出

老实说,我讨厌这个解决方案,但出于同样的原因,没有更简单的方法


另一方面,我的VS(2010年和2012年)现在非常快地向我展示了intellisense的Razor文件;不会在内存中大量增长,更重要的是,永远不会占用该网络端口…

您可以使用
System.Web.Hosting.HostingEnvironment.InClientBuildManager
,而不是编写自己的逻辑来检测此问题,无论是VS运行该代码还是在aspnet\u compiler.exe中运行,这都是正确的


有关此问题的更多详细信息,请参阅此部分。

很有趣-我有一个修复程序(在回来检查答案之前,我刚刚实现了它);但在我的例子(Visual Studio 2010)中,
Process.GetCurrentProcess().ProcessName
的值实际上是
devenv
,这肯定不是托管进程,因为网站想要使用的网络端口总是由devenv获取的——检查进程名称仍然是我知道的最好的方法,尽管如此,还是把它作为答案,因为没有比检查流程更好的方法了
if(HostInformation.IsDevelopmentEnvironment)
  return;