Обнаруживать, когда 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; не растет массово в памяти и - что более важно - никогда не захватывает этот сетевой порт...