【问题标题】:Detect when Visual Studio is test-firing the website for intellisense检测 Visual Studio 何时为智能感知测试网站
【发布时间】:2012-10-12 12:56:48
【问题描述】:

这里有很多说明 - 但这是必要的。

不确定有多少人知道这一点,但是,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 时,它的任何应用程序启动前方法都会触发

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

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

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

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

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

更新

我刚刚添加了an issue to the WebActivator page on GitHub,以查看 David Ebbo 是否可以将我的修复或更好的修复推送到 WebActivator 组件中。

【问题讨论】:

  • 您是否尝试向 Visual Studio 团队报告此问题?
  • 这是设计使然——为了在你的页面上获得智能感知,它需要启动运行时环境——所以我怀疑他们会对此做些什么。对于 WebActivator 的作者 David Ebbo 来说,这可能更像是一个问题
  • 除了性能下降之外还有很多问题,资源锁定是最明显的问题。我不认为这是 WebActivator 的问题,而是设计问题。 VS 应该以不同的方式内置智能感知,而不必启动另一个进程然后让它运行。如果它必须这样做,它应该只是为了获得智能感知然后立即关闭它。我认为我们应该为此打开一个 Connect 问题,你怎么看?

标签: c# asp.net-mvc-3 visual-studio-2010 razor asp.net-mvc-4


【解决方案1】:

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

回答:Microsoft.VisualStudio.Web.Host

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

还可以查看this article 了解托管过程。

【讨论】:

  • 有趣 - 我有一个修复(我刚刚实现它,然后再回来检查答案);但在我的情况下(Visual Studio 2010)Process.GetCurrentProcess().ProcessName 的值是devenv
  • 事实上 - 这绝对是 不是 托管进程,因为它总是 devenv 来获取网站想要使用的网络端口 - 检查进程名称仍然是我最好的方法不过,现在还知道。
  • 标记为答案,因为没有比检查进程名称更好的方法 - 甚至对托管环境进行深入反思,寻找内部类型,或者任何不会像 appdomain '看起来那样做的事情' 从这个角度来看是可行的。这是一个可怕的黑客,但它会工作。
【解决方案2】:

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

请参阅answer 了解更多详情。

【讨论】:

  • 谢谢你 - 我将尝试使用它而不是我的hacky尝试:-)
【解决方案3】:

虽然 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;
      }
    }

  }
}

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

if(HostInformation.IsDevelopmentEnvironment)
  return;

从而使所有启动方法都能更早地完成。

说实话,我讨厌这种解决方案,但同样地,没有更简单的方法可以做到这一点。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-07
    • 2016-03-20
    • 2014-07-17
    • 2013-12-07
    • 2013-11-23
    • 1970-01-01
    相关资源
    最近更新 更多