Exemplo n.º 1
0
        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 IisExpressServerManager(Current);

            _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 HandlersModule();

            module.TestInitialize(_serviceContainer, null);

            _feature = new HandlersFeature(module);
            _feature.Load();
        }
Exemplo n.º 2
0
        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();
            }));
        }
Exemplo n.º 3
0
        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();
            }));
        }
Exemplo n.º 4
0
        public PhpDiagDialog(IServiceProvider provider, ServerManager server)
            : 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
                {
                    Debug($"System Time: {DateTime.Now}");
                    Debug($"Processor Architecture: {Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")}");
                    Debug($"OS: {Environment.OSVersion}");
                    Debug($"{server.Type}");
                    Debug(Environment.NewLine);

                    var handlers = new HandlersFeature((Module)provider);
                    handlers.Load();
                    var foundPhpHandler = false;
                    Debug($"Scan {handlers.Items.Count} registered handler(s).");
                    foreach (var item in handlers.Items)
                    {
                        if (string.Equals(item.Path, "*.php", StringComparison.OrdinalIgnoreCase))
                        {
                            Debug($"* Found PHP handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Handler: {item.TypeString}, Entry Type: {item.Flag} }}.");
                            foundPhpHandler = true;
                        }
                    }

                    if (!foundPhpHandler)
                    {
                        Error($"No PHP handler is registered for this web site. 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;
                    }

                    Debug(Environment.NewLine);
                    var fastCgiFeature = new FastCgiFeature((Module)provider);
                    fastCgiFeature.Load();
                    Debug($"Scan {fastCgiFeature.Items.Count} registered FastCGI application(s).");
                    var foundPhp = new List <string>();
                    foreach (var item in fastCgiFeature.Items)
                    {
                        if (item.Path.TrimEnd('"').EndsWith("php-cgi.exe", StringComparison.OrdinalIgnoreCase))
                        {
                            Debug($"* Found PHP FastCGI application registered as {{ Full path: {item.Path}, Arguments: {item.Arguments} }}.");
                            foundPhp.Add(item.Path);
                        }
                    }

                    if (foundPhp.Count == 0)
                    {
                        Error($"No PHP FastCGI appilcation is registered on this server. 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;
                    }

                    Debug(Environment.NewLine);
                    Debug($"Verify PHP installation versions.");
                    foreach (var path in foundPhp)
                    {
                        var info = FileVersionInfo.GetVersionInfo(path);
                        if (info.FileMajorPart < 5)
                        {
                            Error($"* PHP {info.FileVersion} ({path}) is obsolete. Please refer to http://php.net/supported-versions.php for more details.");
                        }
                        else if (info.FileMajorPart == 5)
                        {
                            if (info.FileMinorPart < 6)
                            {
                                Error($"* PHP {info.FileVersion} ({path}) is obsolete. Please refer to http://php.net/supported-versions.php for more details.");
                            }
                            else if (info.FileMinorPart == 6)
                            {
                                Warn($"* PHP {info.FileVersion} ({path}) will soon be obsolete. Please refer to http://php.net/supported-versions.php for more details.");
                            }
                            else
                            {
                                Error($"* PHP {info.FileVersion} ({path}) is unknown. Please refer to http://php.net/supported-versions.php for more details.");
                            }
                        }
                        else if (info.FileMajorPart == 7)
                        {
                            if (info.FileMinorPart == 0)
                            {
                                Warn($"* PHP {info.FileVersion} ({path}) will soon be obsolete. Please refer to http://php.net/supported-versions.php for more details.");
                            }
                            else
                            {
                                Debug($"* PHP {info.FileVersion} ({path}) is supported. Please refer to http://php.net/supported-versions.php for more details.");
                            }
                        }
                        else
                        {
                            Error($"* PHP {info.FileVersion} ({path}) is unknown. Please refer to http://php.net/supported-versions.php for more details.");
                        }
                    }

                    Debug(Environment.NewLine);
                    var systemPath = Environment.GetEnvironmentVariable("PATH");
                    Debug($"Scan Windows PATH: {systemPath}.");
                    string[] paths = systemPath.Split(new char[1] {
                        Path.PathSeparator
                    });
                    foreach (var path in foundPhp)
                    {
                        var folder  = Path.GetDirectoryName(path);
                        var matched = false;
                        foreach (var system in paths)
                        {
                            if (string.Equals(folder, system, StringComparison.OrdinalIgnoreCase))
                            {
                                matched = true;
                                break;
                            }
                        }

                        if (matched)
                        {
                            Debug($"* PHP installation {folder} has been added to Windows PATH.");
                        }
                        else
                        {
                            Error($"* PHP installation {folder} is not yet added to Windows PATH.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Debug(ex.ToString());
                    RollbarDotNet.Rollbar.Report(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();
            }));
        }
Exemplo n.º 5
0
        public PhpDiagDialog(IServiceProvider provider, ServerManager server)
            : 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
                {
                    Debug($"System Time: {DateTime.Now}");
                    Debug($"Processor Architecture: {Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")}");
                    Debug($"OS: {Environment.OSVersion}");
                    Debug($"{server.Type}");
                    Debug(string.Empty);

                    var handlers = new HandlersFeature((Module)provider);
                    handlers.Load();
                    var foundPhpHandler = false;
                    Debug($"Scan {handlers.Items.Count} registered handler(s).");
                    foreach (var item in handlers.Items)
                    {
                        if (string.Equals(item.Path, "*.php", StringComparison.OrdinalIgnoreCase))
                        {
                            Debug($"* Found PHP handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Handler: {item.TypeString}, Entry Type: {item.Flag} }}.");
                            foundPhpHandler = true;
                        }
                    }

                    if (!foundPhpHandler)
                    {
                        Error($"No PHP handler is registered for this web site. 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;
                    }

                    Debug(string.Empty);
                    var fastCgiFeature = new FastCgiFeature((Module)provider);
                    fastCgiFeature.Load();
                    Debug($"Scan {fastCgiFeature.Items.Count} registered FastCGI application(s).");
                    var foundPhp = new List <string>();
                    foreach (var item in fastCgiFeature.Items)
                    {
                        if (item.Path.TrimEnd('"').EndsWith("php-cgi.exe", StringComparison.OrdinalIgnoreCase))
                        {
                            Debug($"* Found PHP FastCGI application registered as {{ Full path: {item.Path}, Arguments: {item.Arguments} }}.");
                            foundPhp.Add(item.Path);
                        }
                    }

                    if (foundPhp.Count == 0)
                    {
                        Error($"No PHP FastCGI appilcation is registered on this server. 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;
                    }

                    Debug(Environment.NewLine);
                    Debug($"Verify PHP installation versions.");
                    foreach (var path in foundPhp)
                    {
                        var info = FileVersionInfo.GetVersionInfo(path);
                        if (info.FileMajorPart < 5)
                        {
                            Error($"* PHP {info.FileVersion} ({path}) is obsolete. Please refer to http://php.net/supported-versions.php for more details.");
                        }
                        else if (info.FileMajorPart == 5)
                        {
                            if (info.FileMinorPart < 6)
                            {
                                Error($"* PHP {info.FileVersion} ({path}) is obsolete. Please refer to http://php.net/supported-versions.php for more details.");
                            }
                            else if (info.FileMinorPart == 6)
                            {
                                Warn($"* PHP {info.FileVersion} ({path}) will soon be obsolete. Please refer to http://php.net/supported-versions.php for more details.");
                            }
                            else
                            {
                                Error($"* PHP {info.FileVersion} ({path}) is unknown. Please refer to http://php.net/supported-versions.php for more details.");
                            }
                        }
                        else if (info.FileMajorPart == 7)
                        {
                            if (info.FileMinorPart == 0)
                            {
                                Warn($"* PHP {info.FileVersion} ({path}) will soon be obsolete. Please refer to http://php.net/supported-versions.php for more details.");
                            }
                            else
                            {
                                Debug($"* PHP {info.FileVersion} ({path}) is supported.");
                            }
                        }
                        else
                        {
                            Error($"* PHP {info.FileVersion} ({path}) is unknown. Please refer to http://php.net/supported-versions.php for more details.");
                        }
                    }

                    Debug(string.Empty);
                    var systemPath = Environment.GetEnvironmentVariable("Path");
                    Debug($"Windows Path: {systemPath}.");
                    Debug(string.Empty);
                    string[] paths = systemPath.Split(new char[1] {
                        Path.PathSeparator
                    });
                    foreach (var path in foundPhp)
                    {
                        var rootFolder = Path.GetDirectoryName(path);
                        Debug($"[{rootFolder}]");
                        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.");
                        }
                        else
                        {
                            Error($"PHP installation is not yet added to Windows Path environment. 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.");
                        }

                        Debug(string.Empty);
                    }

                    // TODO: verify other configurations in php.info.
                }
                catch (Exception ex)
                {
                    Debug(ex.ToString());
                    RollbarDotNet.Rollbar.Report(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();
            }));
        }
Exemplo n.º 6
0
        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();
            }));
        }