public async Task SetUp() { const string Original = @"original.config"; const string OriginalMono = @"original.mono.config"; if (Helper.IsRunningOnMono()) { File.Copy("Website1/original.config", "Website1/web.config", true); File.Copy(OriginalMono, Current, true); } else { File.Copy("Website1\\original.config", "Website1\\web.config", true); File.Copy(Original, Current, true); } Environment.SetEnvironmentVariable( "JEXUS_TEST_HOME", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); _server = new ServerManager(Current) { Mode = WorkingMode.IisExpress }; _serviceContainer = new ServiceContainer(); _serviceContainer.RemoveService(typeof(IConfigurationService)); _serviceContainer.RemoveService(typeof(IControlPanel)); var scope = ManagementScope.Server; _serviceContainer.AddService(typeof(IControlPanel), new ControlPanel()); _serviceContainer.AddService(typeof(IConfigurationService), new ConfigurationService(null, _server.GetApplicationHostConfiguration(), scope, _server, null, null, null, null, null)); _serviceContainer.RemoveService(typeof(IManagementUIService)); var mock = new Mock <IManagementUIService>(); mock.Setup( action => action.ShowMessage( It.IsAny <string>(), It.IsAny <string>(), It.IsAny <MessageBoxButtons>(), It.IsAny <MessageBoxIcon>(), It.IsAny <MessageBoxDefaultButton>())).Returns(DialogResult.Yes); _serviceContainer.AddService(typeof(IManagementUIService), mock.Object); var module = new ModulesModule(); module.TestInitialize(_serviceContainer, null); _feature = new ModulesFeature(module); _feature.Load(); }
public PhpDiagDialog(IServiceProvider provider, ServerManager server) : base(provider) { InitializeComponent(); var knownPhpVersions = new Dictionary <string, PhpVersion> { { "5.6", new PhpVersion("5.6", new DateTime(2018, 12, 31), new Version(11, 0)) }, { "7.0", new PhpVersion("7.0", new DateTime(2018, 12, 3), new Version(14, 0)) }, { "7.1", new PhpVersion("7.1", new DateTime(2019, 12, 1), new Version(14, 0)) }, { "7.2", new PhpVersion("7.2", new DateTime(2020, 11, 30), new Version(14, 11)) } }; var container = new CompositeDisposable(); FormClosed += (sender, args) => container.Dispose(); container.Add( Observable.FromEventPattern <EventArgs>(btnGenerate, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { txtResult.Clear(); try { Warn("IMPORTANT: This report might contain confidential information. Mask such before sharing to others."); Warn("-----"); Debug($"System Time: {DateTime.Now}"); Debug($"Processor Architecture: {Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")}"); Debug($"OS: {Environment.OSVersion}"); Debug($"Server Type: {server.Mode.AsString(EnumFormat.Description)}"); Debug(string.Empty); var modules = new ModulesFeature((Module)provider); modules.Load(); Debug($"Scan {modules.Items.Count} installed module(s)."); if (modules.Items.All(item => item.Name != "FastCgiModule")) { Error($"FastCGI module is not installed as part of IIS. Please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); return; } else { Debug("FastCGI module is installed."); } Debug(string.Empty); var handlers = new HandlersFeature((Module)provider); handlers.Load(); var foundPhpHandler = new List <HandlersItem>(); Debug($"Scan {handlers.Items.Count} registered handler(s)."); foreach (var item in handlers.Items) { if (item.Modules == "FastCgiModule") { Debug($"* Found FastCGI handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Handler: {item.TypeString}, Entry Type: {item.Flag} }}."); foundPhpHandler.Add(item); } } if (foundPhpHandler.Count == 0) { Error($"No FastCGI handler is registered for this web site."); Error($" * To run PHP on IIS, please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); Error($" * To run Python on IIS, please refer to https://pypi.org/project/wfastcgi/ or use HttpPlatformHandler https://docs.microsoft.com/en-us/iis/extensions/httpplatformhandler/httpplatformhandler-configuration-reference."); return; } Debug(string.Empty); var fastCgiFeature = new FastCgiFeature((Module)provider); fastCgiFeature.Load(); Debug($"Scan {fastCgiFeature.Items.Count} registered FastCGI application(s)."); var foundPhp = new List <FastCgiItem>(); foreach (var item in fastCgiFeature.Items) { var combination = string.IsNullOrWhiteSpace(item.Arguments) ? item.Path : item.Path + '|' + item.Arguments; foreach (var handler in foundPhpHandler) { if (string.Equals(combination, handler.ScriptProcessor, StringComparison.OrdinalIgnoreCase)) { Debug($"* Found FastCGI application registered as {{ Full path: {item.Path}, Arguments: {item.Arguments} }}."); foundPhp.Add(item); break; } } } if (foundPhp.Count == 0) { Error($"No suitable FastCGI appilcation is registered on this server."); Error($" * To run PHP on IIS, please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); Error($" * To run Python on IIS, please refer to https://pypi.org/project/wfastcgi/ or use HttpPlatformHandler https://docs.microsoft.com/en-us/iis/extensions/httpplatformhandler/httpplatformhandler-configuration-reference."); return; } Debug(Environment.NewLine); Debug($"Verify web stack installation versions."); foreach (var item in foundPhp) { var path = item.Path; if (path.TrimEnd('"').EndsWith("php-cgi.exe", StringComparison.OrdinalIgnoreCase)) { // PHP var info = FileVersionInfo.GetVersionInfo(path); var version = $"{info.FileMajorPart}.{info.FileMinorPart}"; if (knownPhpVersions.ContainsKey(version)) { var matched = knownPhpVersions[version]; if (matched.ExpiringDate <= DateTime.Now) { Error($"* PHP {info.FileVersion} ({path}) is unknown or obsolete. Please refer to http://php.net/supported-versions.php for more details."); } else if (matched.ExpiringDate > DateTime.Now && (matched.ExpiringDate - DateTime.Now).TotalDays < 180) { Warn($"* PHP {version} ({path}) will soon be obsolete. Please refer to http://php.net/supported-versions.php for more details."); } else { Debug($"* PHP {version} ({path}) is supported."); } var x86 = new PeNet.PeFile(path).Is32Bit; var cppFile = Path.Combine( Environment.GetFolderPath(x86 ? Environment.SpecialFolder.SystemX86 : Environment.SpecialFolder.System), $"msvcp{matched.CppVersion.Major}0.dll"); if (File.Exists(cppFile)) { var cpp = FileVersionInfo.GetVersionInfo(cppFile); if (cpp.FileMinorPart >= matched.CppVersion.Minor) { Debug($" Visual C++ runtime is detected (expected: {matched.CppVersion}, detected: {cpp.FileVersion})."); } else { Error($" Visual C++ runtime {matched.CppVersion} is not detected. Please install it following the tips on https://windows.php.net/download/."); } } else { Error($" Visual C++ {matched.CppVersion} runtime is not detected. Please install it following the tips on https://windows.php.net/download/."); } } else { Error($"* PHP {info.FileVersion} ({path}) is unknown or obsolete. Please refer to http://php.net/supported-versions.php for more details."); } } else if (path.TrimEnd('"').EndsWith("python.exe", StringComparison.OrdinalIgnoreCase)) { // Python } } Debug(string.Empty); var systemPath = Environment.GetEnvironmentVariable("Path"); Debug($"Windows Path environment variable: {systemPath}."); Debug(string.Empty); string[] paths = systemPath.Split(new char[1] { Path.PathSeparator }); foreach (var item in foundPhp) { var path = item.Path; if (path.TrimEnd('"').EndsWith("php-cgi.exe", StringComparison.OrdinalIgnoreCase)) { var rootFolder = Path.GetDirectoryName(path); Debug($"[{rootFolder}]"); if (!Directory.Exists(rootFolder)) { Error("Invalid root folder is found. Skip."); continue; } var config = Path.Combine(rootFolder, "php.ini"); if (File.Exists(config)) { Info($"Found PHP config file {config}."); var parser = new ConcatenateDuplicatedKeysIniDataParser(); parser.Configuration.ConcatenateSeparator = " "; var data = parser.Parse(File.ReadAllText(config)); var extensionFolder = data["PHP"]["extension_dir"]; if (extensionFolder == null) { extensionFolder = "ext"; } var fullPath = Path.Combine(rootFolder, extensionFolder); Info($"PHP loadable extension folder: {fullPath}"); var extesionNames = data["PHP"]["extension"]; if (extesionNames == null) { Info("No extension to verify."); } else { var extensions = extesionNames.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Info($"Found {extensions.Length} extension(s) to verify."); var noError = true; foreach (var name in extensions) { var fileName = Path.Combine(fullPath, $"php_{name}.dll"); if (!File.Exists(fileName)) { Error($"* Extension {name} is listed, but on disk the file cannot be found {fileName}"); noError = false; } } if (noError) { Info("All extension(s) listed can be found on disk."); } } } else { Warn($"Cannot find PHP config file {config}. Default settings are used."); } var matched = false; foreach (var system in paths) { if (string.Equals(rootFolder, system, StringComparison.OrdinalIgnoreCase)) { matched = true; break; } } if (matched) { Debug($"PHP installation has been added to Windows Path environment variable."); } else { Error($"PHP installation is not yet added to Windows Path environment variable. Please refer to https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php#13-download-and-install-php-manually for more details."); Warn($"Restart Jexus Manager and rerun PHP Diagnostics after changing Windows Path environment variable."); } Debug(string.Empty); // TODO: verify other configuration in php.info. } else if (path.TrimEnd('"').EndsWith("python.exe", StringComparison.OrdinalIgnoreCase)) { } } } catch (Exception ex) { Debug(ex.ToString()); Rollbar.RollbarLocator.RollbarInstance.Error(ex); } })); container.Add( Observable.FromEventPattern <EventArgs>(btnSave, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { var fileName = DialogHelper.ShowSaveFileDialog(null, "Text Files|*.txt|All Files|*.*"); if (string.IsNullOrEmpty(fileName)) { return; } File.WriteAllText(fileName, txtResult.Text); })); container.Add( Observable.FromEventPattern <EventArgs>(btnVerify, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { txtResult.Clear(); })); }
public KestrelDiagDialog(IServiceProvider provider, Application application) : base(provider) { InitializeComponent(); using (var client = new WebClient()) { var latest = client.DownloadString("https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json"); JObject content; if (string.IsNullOrWhiteSpace(latest)) { // fallback to resources. using var bytes = new MemoryStream(Resources.releases_index); using var stream = new StreamReader(bytes); using var json = new JsonTextReader(stream); content = (JObject)JToken.ReadFrom(json); } else { content = JObject.Parse(latest); } var releases = content["releases-index"]; foreach (var release in releases) { var link = release["releases.json"]; var info = client.DownloadString(link.Value <string>()); JObject details = JObject.Parse(info); foreach (var actual in details["releases"]) { var runtimeObject = actual["runtime"]; if (runtimeObject == null) { // skip no runtime release. continue; } if (runtimeObject["version"] == null) { continue; } var longVersion = runtimeObject["version"].Value <string>(); var aspNetRuntime = actual["aspnetcore-runtime"]; if (aspNetRuntime == null || !aspNetRuntime.HasValues) { continue; } var aspNetCoreModuleObject = aspNetRuntime["version-aspnetcoremodule"]; if (aspNetCoreModuleObject == null || !aspNetCoreModuleObject.HasValues) { // skip no ASP.NET Core module release. continue; } var aspNetCoreModule = aspNetCoreModuleObject.Values <string>().First(); var phase = release["support-phase"].Value <string>(); var expired = phase == "eol"; if (phase == "preview" || longVersion.Contains("-")) { // skip preview release. continue; } var runtime = Version.Parse(longVersion); if (mappings.ContainsKey(runtime)) { Console.WriteLine($"{runtime}: new {aspNetCoreModule}: old {mappings[runtime].Item1}"); } else { mappings.Add(runtime, new Tuple <Version, bool>(Version.Parse(aspNetCoreModule), expired)); } } } } var container = new CompositeDisposable(); FormClosed += (sender, args) => container.Dispose(); container.Add( Observable.FromEventPattern <EventArgs>(btnGenerate, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { txtResult.Clear(); try { Warn("IMPORTANT: This report might contain confidential information. Mask such before sharing to others."); Warn("-----"); Debug($"System Time: {DateTime.Now}"); Debug($"Processor Architecture: {Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")}"); Debug($"OS: {Environment.OSVersion}"); Debug($"Server Type: {application.Server.Mode.AsString(EnumFormat.Description)}"); Debug(string.Empty); var root = application.VirtualDirectories[0].PhysicalPath.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable()); if (string.IsNullOrWhiteSpace(root)) { Error("Invalid site root directory is detected."); return; } // check ANCM. var appHost = application.Server.GetApplicationHostConfiguration(); var definitions = new List <SectionDefinition>(); appHost.RootSectionGroup.GetAllDefinitions(definitions); if (!definitions.Any(item => item.Path == "system.webServer/aspNetCore")) { Error($"ASP.NET Core module is not installed as part of IIS. Please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle for more details."); return; } var modules = new ModulesFeature((Module)provider); modules.Load(); Debug($"Scan {modules.Items.Count} installed module(s)."); var hasV1 = modules.Items.FirstOrDefault(item => item.Name == "AspNetCoreModule"); var hasV2 = modules.Items.FirstOrDefault(item => item.Name == "AspNetCoreModuleV2"); if (hasV1 == null && hasV2 == null) { Error($"ASP.NET Core module is not installed as part of IIS. Please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle for more details."); return; } Version ancmVersion = null; if (hasV2 != null) { var file = hasV2.GlobalModule.Image.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable()); if (File.Exists(file)) { var info = FileVersionInfo.GetVersionInfo(file); ancmVersion = new Version(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, info.FilePrivatePart); Info($"ASP.NET Core module version 2 is installed for .NET Core 2.2 and above: {file} ({info.FileVersion})."); } else { Error("ASP.NET Core module version 2 is not installed properly."); } } else { var file = hasV1.GlobalModule.Image.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable()); if (File.Exists(hasV1.GlobalModule.Image.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable()))) { var info = FileVersionInfo.GetVersionInfo(file); ancmVersion = new Version(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, info.FilePrivatePart); Info($"ASP.NET Core module version 1 is installed for .NET Core 1.0-2.1: {file} ({info.FileVersion})"); } else { Error("ASP.NET Core module version 2 is not installed properly."); } } // check handler. Debug(string.Empty); var handlers = new HandlersFeature((Module)provider); handlers.Load(); var foundHandlers = new List <HandlersItem>(); Debug($"Scan {handlers.Items.Count} registered handler(s)."); foreach (var item in handlers.Items) { if (item.Modules == "AspNetCoreModule") { if (hasV1 != null) { Info($"* Found a valid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }}."); foundHandlers.Add(item); } else { Error($"* Found an invalid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }} because ASP.NET Core module version 1 is missing."); } } else if (item.Modules == "AspNetCoreModuleV2") { if (hasV2 != null) { Info($"* Found a valid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }}."); foundHandlers.Add(item); } else { Error($"* Found an invalid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }} because ASP.NET Core module version 2 is missing."); } } } if (foundHandlers.Count == 0) { Error($"No valid ASP.NET Core handler is registered for this web site."); Error($"To run ASP.NET Core on IIS, please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index for more details."); return; } var name = application.ApplicationPoolName; var pool = application.Server.ApplicationPools.FirstOrDefault(item => item.Name == name); if (pool == null) { Error($"The application pool '{name}' cannot be found."); return; } var x86 = pool.Enable32BitAppOnWin64; // check VC++ 2015. var cppFile = Path.Combine( Environment.GetFolderPath(x86 ? Environment.SpecialFolder.SystemX86 : Environment.SpecialFolder.System), $"msvcp140.dll"); if (File.Exists(cppFile)) { var cpp = FileVersionInfo.GetVersionInfo(cppFile); if (cpp.FileMinorPart >= 0) { Info($" Visual C++ runtime is detected (expected: 14.0, detected: {cpp.FileVersion}): {cppFile}."); } else { Error($" Visual C++ runtime 14.0 is not detected. Please install it following the tips on https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle."); } } else { Error($" Visual C++ 14.0 runtime is not detected. Please install it following the tips on https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle."); } Info($"The application pool '{name}' is used."); // check ASP.NET version. if (pool.ManagedRuntimeVersion != ApplicationPool.ManagedRuntimeVersionNone) { Error($"The application pool '{name}' is using .NET CLR {pool.ManagedRuntimeVersion}. Please set it to 'No Managed Code'."); } Info($"Pool identity is {pool.ProcessModel}"); var user = application.Server.Mode == WorkingMode.IisExpress ? $"{Environment.UserDomainName}\\{Environment.UserName}" : pool.ProcessModel.ToString(); Warn($"Please ensure pool identity has read access to the content folder {application.PhysicalPath}."); var poolBitness = x86 ? "32" : "64"; Info($"Pool bitness is {poolBitness} bit"); var config = application.GetWebConfiguration(); var section = config.GetSection("system.webServer/aspNetCore"); var processPath = (string)section["processPath"]; var arguments = (string)section["arguments"]; var hostingModel = (string)section["hostingModel"]; Debug($"Scan aspNetCore section."); Debug($" \"processPath\": {processPath}."); Debug($" \"arguments\": {arguments}."); Debug($" \"hostingModel\": {hostingModel}."); if (string.Equals("InProcess", hostingModel, StringComparison.OrdinalIgnoreCase)) { Warn("In-process hosting model is detected. To avoid 500.xx errors, make sure that the bitness of published artifacts matches the application pool bitness"); if (string.Equals("dotnet", processPath, StringComparison.OrdinalIgnoreCase)) { Info("Framework dependent deployment is detected. Skip bitness check."); } else { Info("Self-contained deployment is detected. Check bitness."); var path = processPath; if (!File.Exists(path)) { path = Path.Combine(application.PhysicalPath, path); } if (!File.Exists(path)) { Error($"Cannot locate executable: {path}"); } else { var bit32 = DialogHelper.GetImageArchitecture(path); if (bit32 == x86) { Info($"Published artifacts bitness matches."); } else { var artifactBitness = bit32 ? "32" : "64"; Error($"Published artifacts bitness is {artifactBitness} bit. Mismatch detected."); } } } } if (string.IsNullOrWhiteSpace(processPath) && string.IsNullOrWhiteSpace(arguments)) { Warn("There is no ASP.NET Core web app to analyze."); } else if (string.Equals(processPath, "%LAUNCHER_PATH%", StringComparison.OrdinalIgnoreCase) || string.Equals(arguments, "%LAUNCHER_ARGS%", StringComparison.OrdinalIgnoreCase)) { Warn("Value of processPath or arguments is placeholder used by Visual Studio. This site can only be run from within Visual Studio."); } else { try { var fileName = Path.GetFileName(processPath); string executable; if (string.Equals(fileName, "dotnet.exe", StringComparison.OrdinalIgnoreCase) || string.Equals(fileName, "dotnet", StringComparison.OrdinalIgnoreCase)) { if (arguments.StartsWith("exec ", StringComparison.OrdinalIgnoreCase)) { arguments = arguments.Substring("exec ".Length).Replace("\"", null); } executable = Path.GetFileNameWithoutExtension(arguments); } else { executable = Path.GetFileNameWithoutExtension(processPath); } var runtime = Path.Combine(root, executable + ".deps.json"); if (File.Exists(runtime)) { var reader = JObject.Parse(File.ReadAllText(runtime)); var targetName = (string)reader["runtimeTarget"]["name"]; Debug($"\"runtimeTarget\": {targetName}."); var slash = targetName.IndexOf('/'); if (slash > -1) { targetName = targetName.Substring(0, slash); } var actual = reader["targets"][targetName]; Version aspNetCoreVersion = null; foreach (var item in actual.Children()) { if (item is JProperty prop) { if (prop.Name.Contains("Microsoft.AspNetCore.All/")) { Info($"Runtime is {prop.Name}."); Version.TryParse(prop.Name.Substring(prop.Name.IndexOf('/') + 1), out aspNetCoreVersion); } else if (prop.Name.Contains("Microsoft.AspNetCore.App/")) { Info($"Runtime is {prop.Name}."); Version.TryParse(prop.Name.Substring(prop.Name.IndexOf('/') + 1), out aspNetCoreVersion); } } } if (aspNetCoreVersion != null && aspNetCoreVersion >= Version.Parse("2.1.0")) { if (mappings.ContainsKey(aspNetCoreVersion)) { var expired = mappings[aspNetCoreVersion].Item2; if (expired) { Error($".NET Core version {aspNetCoreVersion} is end-of-life. Please upgrade to a supported version."); } var minimal = mappings[aspNetCoreVersion].Item1; if (ancmVersion == null || ancmVersion < minimal) { Error($"Runtime {aspNetCoreVersion} does not work with ASP.NET Core module version {ancmVersion}. Minimal version is {minimal}."); } if (ancmVersion > minimal && (ancmVersion.Major != minimal.Major || ancmVersion.Minor != minimal.Minor)) { Warn($"Runtime {aspNetCoreVersion} requires ASP.NET Core module version {minimal}. Installed version {ancmVersion} might not be compatible."); } } } } else { Error($"Cannot locate runtime config file {runtime}."); } } catch (Exception ex) { Error("Cannot analyze ASP.NET Core web app successfully."); Rollbar.RollbarLocator.RollbarInstance.Error(ex, new Dictionary <string, object> { { "source", "web app" } }); } } Warn($"Please refer to pages such as https://dotnet.microsoft.com/download/dotnet-core/3.1 to verify that ASP.NET Core version {ancmVersion} matches the runtime of the web app."); } catch (COMException ex) { Error("A generic exception occurred."); Error($"To run ASP.NET Core on IIS, please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index for more details."); Debug(ex.ToString()); Rollbar.RollbarLocator.RollbarInstance.Error(ex); } catch (Exception ex) { Debug(ex.ToString()); Rollbar.RollbarLocator.RollbarInstance.Error(ex); } })); container.Add( Observable.FromEventPattern <EventArgs>(btnSave, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { var fileName = DialogHelper.ShowSaveFileDialog(null, "Text Files|*.txt|All Files|*.*", application.GetActualExecutable()); if (string.IsNullOrEmpty(fileName)) { return; } File.WriteAllText(fileName, txtResult.Text); })); container.Add( Observable.FromEventPattern <EventArgs>(btnVerify, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { txtResult.Clear(); })); }
public NewMappingDialog(IServiceProvider serviceProvider, HandlersItem existing, HandlersFeature feature) : base(serviceProvider) { InitializeComponent(); Text = existing == null ? "Add Module Mapping" : "Edit Module Mapping"; txtName.ReadOnly = existing != null; _feature = feature; Item = existing ?? new HandlersItem(null); var modules = new ModulesFeature((Module)serviceProvider); modules.Load(); foreach (var module in modules.Items.Where(module => !module.IsManaged).OrderBy(module => module.Name)) { txtModule.Items.Add(module.Name); } if (existing != null) { txtExecutable.Text = Item.ScriptProcessor; txtModule.Text = Item.Modules; txtName.Text = Item.Name; txtPath.Text = Item.Path; } var container = new CompositeDisposable(); FormClosed += (sender, args) => container.Dispose(); container.Add( Observable.FromEventPattern <EventArgs>(btnOK, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { Item.ScriptProcessor = txtExecutable.Text; Item.Modules = txtModule.Text; Item.Name = txtName.Text; Item.Path = txtPath.Text; if (!txtName.ReadOnly) { if (_feature.Items.Any(item => item.Match(Item))) { ShowMessage( "A handler with this name already exists.", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; } if (txtModule.Text == "FastCgiModule") { var result = ShowMessage( "Do you want to create a FastCGI application for this executable? Click \"Yes\" to add the entry to the FastCGI collection and to enable this executable to run as a FastCGI application.", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); if (result == DialogResult.Yes) { var fastCgi = new FastCgiFeature((Module)ServiceProvider); if (fastCgi.Items.All(item => item.Path != txtExecutable.Text)) { fastCgi.AddItem(new FastCgiItem(null) { Path = txtExecutable.Text }); } } } if (!string.IsNullOrWhiteSpace(txtExecutable.Text) && !File.Exists(txtExecutable.Text)) { ShowMessage( "The specific executable does not exist on the server.", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; } } DialogResult = DialogResult.OK; })); container.Add( Observable.FromEventPattern <EventArgs>(txtName, "TextChanged") .Merge(Observable.FromEventPattern <EventArgs>(txtExecutable, "TextChanged")) .Merge(Observable.FromEventPattern <EventArgs>(txtPath, "TextChanged")) .Sample(TimeSpan.FromSeconds(1)) .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) && !string.IsNullOrWhiteSpace(txtModule.Text) && !string.IsNullOrWhiteSpace(txtPath.Text); })); container.Add( Observable.FromEventPattern <EventArgs>(btnRestrictions, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { var dialog = new RestrictionsDialog(ServiceProvider, Item); if (dialog.ShowDialog() != DialogResult.OK) { return; } })); container.Add( Observable.FromEventPattern <EventArgs>(btnBrowse, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { DialogHelper.ShowFileDialog(txtExecutable, "|*.dll||*.exe"); })); }
public NewMappingDialog(IServiceProvider serviceProvider, HandlersItem existing, HandlersFeature feature) : base(serviceProvider) { InitializeComponent(); Text = existing == null ? "Add Module Mapping" : "Edit Module Mapping"; txtName.ReadOnly = existing != null; _feature = feature; Item = existing ?? new HandlersItem(null); var modules = new ModulesFeature((Module)serviceProvider); modules.Load(); foreach (var module in modules.Items.Where(module => !module.IsManaged).OrderBy(module => module.Name)) { txtModule.Items.Add(module.Name); } if (existing != null) { txtExecutable.Text = Item.ScriptProcessor; txtModule.Text = Item.Modules; txtName.Text = Item.Name; txtPath.Text = Item.Path; } var container = new CompositeDisposable(); FormClosed += (sender, args) => container.Dispose(); container.Add( Observable.FromEventPattern <EventArgs>(btnOK, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { Item.ScriptProcessor = txtExecutable.Text; Item.Modules = txtModule.Text; Item.Name = txtName.Text; Item.Path = txtPath.Text; if ((txtModule.Text == "FastCgiModule" || txtModule.Text == "CgiModule") && !string.Equals(Path.GetExtension(Item.ScriptProcessor), ".exe", StringComparison.OrdinalIgnoreCase)) { ShowMessage("The executable specified for the CgiModule or the FastCgiModule should be a .exe file."); return; } if (!txtName.ReadOnly) { if (_feature.Items.Any(item => item.Match(Item))) { ShowMessage( "A handler with this name already exists.", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; } var path = txtExecutable.Text; string arguments = string.Empty; var index = path.IndexOf('|'); if (index > -1) { arguments = path.Substring(index + 1); path = path.Substring(0, index); } if (!string.IsNullOrWhiteSpace(path)) { var ext = Path.GetExtension(path); if (!string.Equals(ext, ".dll", StringComparison.OrdinalIgnoreCase) && !string.Equals(ext, ".exe", StringComparison.OrdinalIgnoreCase)) { // TODO: test path with spaces case. ShowMessage("The specific executable for the handler must be a .dll or .exe file. If the path to the script processor (only in the case of a .exe file) has spaces, use double quotation marks to specify the executable.", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); return; } if (!File.Exists(path)) { ShowMessage( "The specific executable does not exist on the server.", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; } } if (txtModule.Text == "FastCgiModule") { // IMPORTANT: it is IIS Manager behavior to prompt before verifying duplicate items. var result = ShowMessage( "Do you want to create a FastCGI application for this executable? Click \"Yes\" to add the entry to the FastCGI collection and to enable this executable to run as a FastCGI application.", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); if (result == DialogResult.Yes) { var fastCgi = new FastCgiFeature((Module)ServiceProvider); fastCgi.Load(); if (fastCgi.Items.All(item => item.Path != path && item.Arguments != arguments)) { fastCgi.AddItem(new FastCgiItem(null) { Path = path, Arguments = arguments }); } } } } try { if (txtModule.Text != "FastCgiModule" && txtModule.Text != "CgiModule") { var bit32Condition = "bitness32"; var bit64Condition = "bitness64"; var bit32 = DialogHelper.GetImageArchitecture(txtExecutable.Text); if (bit32 && !Item.PreConditions.Contains(bit32Condition)) { Item.PreConditions.Add(bit32Condition); } else if (!bit32 && !Item.PreConditions.Contains(bit64Condition)) { Item.PreConditions.Add(bit64Condition); } } } catch (Exception) { ShowMessage( "The specific executable is invalid.", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); return; } DialogResult = DialogResult.OK; })); container.Add( Observable.FromEventPattern <EventArgs>(txtName, "TextChanged") .Merge(Observable.FromEventPattern <EventArgs>(txtExecutable, "TextChanged")) .Merge(Observable.FromEventPattern <EventArgs>(txtPath, "TextChanged")) .Sample(TimeSpan.FromSeconds(0.5)) .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) && !string.IsNullOrWhiteSpace(txtModule.Text) && !string.IsNullOrWhiteSpace(txtPath.Text); })); container.Add( Observable.FromEventPattern <EventArgs>(btnRestrictions, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { var dialog = new RestrictionsDialog(ServiceProvider, Item); if (dialog.ShowDialog() != DialogResult.OK) { return; } })); container.Add( Observable.FromEventPattern <EventArgs>(btnBrowse, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { DialogHelper.ShowOpenFileDialog(txtExecutable, "(*.dll)|*.dll|(*.exe)|*.exe", null); })); }
public KestrelDiagDialog(IServiceProvider provider, Application application) : base(provider) { InitializeComponent(); var container = new CompositeDisposable(); FormClosed += (sender, args) => container.Dispose(); container.Add( Observable.FromEventPattern <EventArgs>(btnGenerate, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { txtResult.Clear(); try { Warn("IMPORTANT: This report might contain confidential information. Mask such before sharing to others."); Warn("-----"); Debug($"System Time: {DateTime.Now}"); Debug($"Processor Architecture: {Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")}"); Debug($"OS: {Environment.OSVersion}"); Debug($"Server Type: {application.Server.Mode.AsString(EnumFormat.Description)}"); Debug(string.Empty); var root = application.VirtualDirectories[0].PhysicalPath.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable()); if (string.IsNullOrWhiteSpace(root)) { Error("Invalid site root directory is detected."); return; } // check ANCM. var appHost = application.Server.GetApplicationHostConfiguration(); var definitions = new List <SectionDefinition>(); appHost.RootSectionGroup.GetAllDefinitions(definitions); if (!definitions.Any(item => item.Path == "system.webServer/aspNetCore")) { Error($"ASP.NET Core module is not installed as part of IIS. Please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle for more details."); return; } var modules = new ModulesFeature((Module)provider); modules.Load(); Debug($"Scan {modules.Items.Count} installed module(s)."); var hasV1 = modules.Items.FirstOrDefault(item => item.Name == "AspNetCoreModule"); var hasV2 = modules.Items.FirstOrDefault(item => item.Name == "AspNetCoreModuleV2"); if (hasV1 == null && hasV2 == null) { Error($"ASP.NET Core module is not installed as part of IIS. Please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle for more details."); return; } Version ancmVersion = null; if (hasV2 != null) { var file = hasV2.GlobalModule.Image.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable()); if (File.Exists(file)) { var info = FileVersionInfo.GetVersionInfo(file); ancmVersion = new Version(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, info.FilePrivatePart); Info($"ASP.NET Core module version 2 is installed for .NET Core 2.2 and above: {file} ({info.FileVersion})."); } else { Error("ASP.NET Core module version 2 is not installed properly."); } } else { var file = hasV1.GlobalModule.Image.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable()); if (File.Exists(hasV1.GlobalModule.Image.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable()))) { var info = FileVersionInfo.GetVersionInfo(file); ancmVersion = new Version(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, info.FilePrivatePart); Info($"ASP.NET Core module version 1 is installed for .NET Core 1.0-2.1: {file} ({info.FileVersion})"); } else { Error("ASP.NET Core module version 2 is not installed properly."); } } // check handler. Debug(string.Empty); var handlers = new HandlersFeature((Module)provider); handlers.Load(); var foundHandlers = new List <HandlersItem>(); Debug($"Scan {handlers.Items.Count} registered handler(s)."); foreach (var item in handlers.Items) { if (item.Modules == "AspNetCoreModule") { if (hasV1 != null) { Info($"* Found a valid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }}."); foundHandlers.Add(item); } else { Error($"* Found an invalid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }} because ASP.NET Core module version 1 is missing."); } } else if (item.Modules == "AspNetCoreModuleV2") { if (hasV2 != null) { Info($"* Found a valid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }}."); foundHandlers.Add(item); } else { Error($"* Found an invalid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }} because ASP.NET Core module version 2 is missing."); } } } if (foundHandlers.Count == 0) { Error($"No valid ASP.NET Core handler is registered for this web site."); Error($"To run ASP.NET Core on IIS, please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index for more details."); return; } var name = application.ApplicationPoolName; var pool = application.Server.ApplicationPools.FirstOrDefault(item => item.Name == name); if (pool == null) { Error($"The application pool '{name}' cannot be found."); } else { // check VC++ 2015. var x86 = pool.Enable32BitAppOnWin64; var cppFile = Path.Combine( Environment.GetFolderPath(x86 ? Environment.SpecialFolder.SystemX86 : Environment.SpecialFolder.System), $"msvcp140.dll"); if (File.Exists(cppFile)) { var cpp = FileVersionInfo.GetVersionInfo(cppFile); if (cpp.FileMinorPart >= 0) { Info($" Visual C++ runtime is detected (expected: 14.0, detected: {cpp.FileVersion}): {cppFile}."); } else { Error($" Visual C++ runtime 14.0 is not detected. Please install it following the tips on https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle."); } } else { Error($" Visual C++ 14.0 runtime is not detected. Please install it following the tips on https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle."); } // check ASP.NET version. if (pool.ManagedRuntimeVersion != ApplicationPool.ManagedRuntimeVersionNone) { Error($"The application pool '{name}' is using .NET CLR {pool.ManagedRuntimeVersion}. Please set it to 'No Managed Code'."); } } var config = application.GetWebConfiguration(); var section = config.GetSection("system.webServer/aspNetCore"); var processPath = (string)section["processPath"]; var arguments = (string)section["arguments"]; var hostingModel = (string)section["hostingModel"]; Debug($"Scan aspNetCore section."); Debug($" \"processPath\": {processPath}."); Debug($" \"arguments\": {arguments}."); Debug($" \"hostingModel\": {hostingModel}."); if (string.IsNullOrWhiteSpace(processPath) && string.IsNullOrWhiteSpace(arguments)) { Warn("There is no ASP.NET Core web app to analyze."); } else { try { var fileName = Path.GetFileName(processPath); string executable; if (string.Equals(fileName, "dotnet.exe", StringComparison.OrdinalIgnoreCase) || string.Equals(fileName, "dotnet", StringComparison.OrdinalIgnoreCase)) { if (arguments.StartsWith("exec ", StringComparison.OrdinalIgnoreCase)) { arguments = arguments.Substring("exec ".Length).Replace("\"", null); } executable = Path.GetFileNameWithoutExtension(arguments); } else { executable = Path.GetFileNameWithoutExtension(processPath); } var runtime = Path.Combine(root, executable + ".deps.json"); if (File.Exists(runtime)) { var reader = JObject.Parse(File.ReadAllText(runtime)); var targetName = (string)reader["runtimeTarget"]["name"]; Debug($"\"runtimeTarget\": {targetName}."); var slash = targetName.IndexOf('/'); if (slash > -1) { targetName = targetName.Substring(0, slash); } var actual = reader["targets"][targetName]; Version aspNetCoreVersion = null; foreach (var item in actual.Children()) { if (item is JProperty prop) { if (prop.Name.Contains("Microsoft.AspNetCore.All/")) { Info($"Runtime is {prop.Name}."); Version.TryParse(prop.Name.Substring(prop.Name.IndexOf('/') + 1), out aspNetCoreVersion); } else if (prop.Name.Contains("Microsoft.AspNetCore.App/")) { Info($"Runtime is {prop.Name}."); Version.TryParse(prop.Name.Substring(prop.Name.IndexOf('/') + 1), out aspNetCoreVersion); } } } if (aspNetCoreVersion != null && aspNetCoreVersion > Version.Parse("2.1.0")) { if (mappings.ContainsKey(aspNetCoreVersion)) { var minimal = mappings[aspNetCoreVersion]; if (ancmVersion == null || ancmVersion < minimal) { Error($"Runtime {aspNetCoreVersion} does not work with ASP.NET Core module version {ancmVersion}. Minimal version is {minimal}."); } if (ancmVersion > minimal && (ancmVersion.Major != minimal.Major || ancmVersion.Minor != minimal.Minor)) { Warn($"Runtime {aspNetCoreVersion} requires ASP.NET Core module version {minimal}. Installed version {ancmVersion} might not be compatible."); } } } } else { Error($"Cannot locate runtime config file {runtime}."); } } catch (Exception ex) { Error("Cannot analyze ASP.NET Core web app successfully."); Rollbar.RollbarLocator.RollbarInstance.Error(ex, new Dictionary <string, object> { { "source", "web app" } }); } } Warn($"Please refer to pages such as https://dotnet.microsoft.com/download/dotnet-core/2.2 to verify that ASP.NET Core version {ancmVersion} matches the runtime of the web app."); } catch (COMException ex) { Error("A generic exception occurred."); Error($"To run ASP.NET Core on IIS, please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index for more details."); Debug(ex.ToString()); Rollbar.RollbarLocator.RollbarInstance.Error(ex); } catch (Exception ex) { Debug(ex.ToString()); Rollbar.RollbarLocator.RollbarInstance.Error(ex); } })); container.Add( Observable.FromEventPattern <EventArgs>(btnSave, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { var fileName = DialogHelper.ShowSaveFileDialog(null, "Text Files|*.txt|All Files|*.*", application.GetActualExecutable()); if (string.IsNullOrEmpty(fileName)) { return; } File.WriteAllText(fileName, txtResult.Text); })); container.Add( Observable.FromEventPattern <EventArgs>(btnVerify, "Click") .ObserveOn(System.Threading.SynchronizationContext.Current) .Subscribe(evt => { txtResult.Clear(); })); }