Обнаруживать, когда Visual Studio тестирует веб-сайт для intellisense

Здесь много изложения, но это необходимо.

Не знаете, сколько людей знают об этом, но редактор кода Razor в Visual Studio заставляет ваш сайт "тестироваться" до самого события Application_Start, и это вызывает некоторые неприятные проблемы в мой текущий проект, который использует WebActivator для многого инициализации сайта.

Обновление - при ближайшем рассмотрении это не просто Razor - похоже, что это Visual Studio-wide - отсюда изменение названия

Мне нужно иметь возможность обнаруживать, когда код сайта выполняется Visual Studio, а не веб-сервером.

Чтобы продемонстрировать - сделайте следующее ( точно как написано для обеспечения его воспроизведения):

  • Создайте новый сайт MVC 4, я использовал шаблон интернет-приложения, поэтому на его создании было несколько страниц.
  • Добавить пакет WebActivator из nuget
  • Добавьте класс в папку 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);
        }
      }
    }
  }
}

Обратите внимание, что этот код не является тем, что обычно работает на веб-сервере, так как он записывает на диск C: (действительно, это может не работать на вашем компьютере, если вы не запускаете VS как администратор).

  • Теперь создадим проект.
  • Этот следующий бит работает лучше всего, если у вас уже открыт Explorer на C: как только это будет завершено, найдите представление Razor и откройте его.
  • Подождите, пока все биты С#/VB будут выделены.
  • Посмотрите на диск C - oh look, там файл под названием "trace.txt" и дата в течение последних нескольких секунд!

Итак, это демонстрирует проблему здесь - редактор кода Razor запускает AppDomain и, фактически, обходит сайт, чтобы получить intellisense (включая такие вещи, как вещи в папке App_Helpers и т.д.). Теперь он фактически не вызывает метод Application_Start, но когда у вас есть WebActivator и в проекте, любой из его методов запуска до запускается.

В моем случае это вызывает огромные проблемы: высокая загрузка процессора и использование памяти в devenv.exe (что эквивалентно только что запущенному веб-сайту), потому что я инициализирую контейнеры DI и бог знает, что еще на данный момент, но один в особенно на самом деле раздражает.

На моем веб-сайте есть компонент, который прослушивает в сети сообщения о статусе и кэшировании с других компьютеров в веб-ферме. В средах QA и Live этот слушатель никогда не перестает открывать порт и слушать - на моей машине dev, однако он часто терпит неудачу - говорит, что порт уже используется. Когда я ищу процесс, который его открывает, он всегда devenv.exe.

Вы уже догадались - я начинаю этот прослушиватель в инициализированном вызове загрузки WebActivator.

Итак, вопрос: кто-нибудь знает, как обнаружить, что код не запускается "правильным" веб-хостом, поэтому я могу остановить его запуск? Я особенно надеюсь на это, так как это также означает, что мои опыты по редактированию Visual Studio и Razor в итоге станут черным сайтом быстрее!

В качестве бонуса любое исправление может быть законно отправлено Дэвиду Эббо - автору WebActivator - поэтому он может использовать его ранее в своем стеке, чтобы полностью предотвратить проблему!

Обновление

Я только что добавил проблему на страницу WebActivator в GitHub, чтобы узнать, может ли Дэвид Эббо нажать на мое исправление или на лучшее, вниз в компонент WebActivator.

Ответ 1

Вместо того, чтобы писать свою собственную логику, чтобы обнаружить это, вы можете просто использовать System.Web.Hosting.HostingEnvironment.InClientBuildManager, что будет верно и для того, когда VS запускает этот код и когда он запускается в aspnet_compiler.exe.

Подробнее об этом см. .

Ответ 2

Угадайте, что будет в этом случае значением Process.GetCurrentProcess().ProcessName?

Ответ: Microsoft.VisualStudio.Web.Host.

Итак, если в названии процесса есть VisualStudio, вы можете спокойно его очистить.

Также проверьте this article информацию о хостинге.

Ответ 3

В то время как Дарин прав с информацией о хостинговом процессе, который применим только к 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 уже находится в списке namespaces, я могу это сделать:

if(HostInformation.IsDevelopmentEnvironment)
  return;

Таким образом, чтобы все методы запуска были выгружены раньше.

Я ненавижу это решение, если честно, но тем не менее нет более простого способа сделать это.

На стороне плюса мой VS (как 2010, так и 2012) теперь очень быстро представляет мне intellisense для файлов Razor; не растет массово в памяти и - что более важно - никогда не захватывает этот сетевой порт...