Added ASP.Net Core exception logging
This commit is contained in:
parent
99c0c628dc
commit
ef9f76ed9c
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using Core.Helper;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Monitor
|
||||||
|
{
|
||||||
|
public static class Logger
|
||||||
|
{
|
||||||
|
// Create a logger
|
||||||
|
private static LogHelper _log = ServiceHelper.BuildLoggerService().GetRequiredService<LogHelper>();
|
||||||
|
|
||||||
|
// Log writer functions
|
||||||
|
public static void WriteLine(string line)
|
||||||
|
{
|
||||||
|
// Write to console and log
|
||||||
|
Console.WriteLine(line);
|
||||||
|
_log.DoLogInfo(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteException(Exception ex, string description = null)
|
||||||
|
{
|
||||||
|
string output;
|
||||||
|
|
||||||
|
output = string.Format("An exception has occurred {0}: {1}", description != null ? description : "", ex.ToString());
|
||||||
|
|
||||||
|
// Write to console and log
|
||||||
|
Console.WriteLine(output);
|
||||||
|
_log.DoLogInfo(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,9 +13,4 @@
|
||||||
<p>
|
<p>
|
||||||
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
||||||
</p>
|
</p>
|
||||||
}
|
|
||||||
|
|
||||||
@if (Model.Exception != null) {
|
|
||||||
<h2>@Model.Exception.Error.Message</h2>
|
|
||||||
<p>@Model.Exception.Error.StackTrace</p>
|
|
||||||
}
|
}
|
|
@ -1,8 +1,4 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Diagnostics;
|
using Microsoft.AspNetCore.Diagnostics;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
|
@ -11,15 +7,16 @@ namespace Monitor.Pages
|
||||||
public class ErrorModel : PageModel
|
public class ErrorModel : PageModel
|
||||||
{
|
{
|
||||||
public string RequestId { get; set; }
|
public string RequestId { get; set; }
|
||||||
public IExceptionHandlerFeature Exception = null;
|
|
||||||
|
|
||||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||||
|
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
Exception = HttpContext.Features.Get<IExceptionHandlerFeature>();
|
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
|
||||||
|
|
||||||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||||
|
|
||||||
|
Logger.WriteException(exceptionFeature.Error, "An error occurred whilst requesting " + exceptionFeature.Path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Core.Main;
|
using Core.Main;
|
||||||
using Core.Helper;
|
using Core.Helper;
|
||||||
using Core.Main.DataObjects.PTMagicData;
|
using Core.Main.DataObjects.PTMagicData;
|
||||||
|
@ -16,7 +15,6 @@ namespace Monitor.Pages
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
base.Init();
|
base.Init();
|
||||||
|
|
||||||
BindData();
|
BindData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,6 @@ namespace Monitor
|
||||||
{
|
{
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
|
|
||||||
// Create a logger
|
|
||||||
private static LogHelper _log = ServiceHelper.BuildLoggerService().GetRequiredService<LogHelper>();
|
|
||||||
|
|
||||||
// Main entry point
|
// Main entry point
|
||||||
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
|
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
|
@ -23,10 +19,10 @@ namespace Monitor
|
||||||
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(GlobalUnhandledExceptionHandler);
|
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(GlobalUnhandledExceptionHandler);
|
||||||
|
|
||||||
// Start
|
// Start
|
||||||
WriteConsoleLogLine("##########################################################");
|
Logger.WriteLine("##########################################################");
|
||||||
WriteConsoleLogLine("#********************************************************#");
|
Logger.WriteLine("#********************************************************#");
|
||||||
WriteConsoleLogLine("INFO: Starting PT Magic Monitor...");
|
Logger.WriteLine("INFO: Starting PT Magic Monitor...");
|
||||||
WriteConsoleLogLine("INFO: Beginning startup checks...");
|
Logger.WriteLine("INFO: Beginning startup checks...");
|
||||||
|
|
||||||
string monitorBasePath = Directory.GetCurrentDirectory();
|
string monitorBasePath = Directory.GetCurrentDirectory();
|
||||||
if (!System.IO.File.Exists(monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json"))
|
if (!System.IO.File.Exists(monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json"))
|
||||||
|
@ -38,12 +34,12 @@ namespace Monitor
|
||||||
string appsettingsJson = monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json";
|
string appsettingsJson = monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json";
|
||||||
if (!File.Exists(appsettingsJson))
|
if (!File.Exists(appsettingsJson))
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("ERROR: appsettings.json not found: '" + appsettingsJson + "'. Please check if the file exists. If not, review the PT Magic setup steps listed on the wiki!");
|
Logger.WriteLine("ERROR: appsettings.json not found: '" + appsettingsJson + "'. Please check if the file exists. If not, review the PT Magic setup steps listed on the wiki!");
|
||||||
if (!Console.IsInputRedirected) Console.ReadKey();
|
if (!Console.IsInputRedirected) Console.ReadKey();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("INFO: appsettings.json found in " + monitorBasePath);
|
Logger.WriteLine("INFO: appsettings.json found in " + monitorBasePath);
|
||||||
|
|
||||||
IConfiguration config = new ConfigurationBuilder()
|
IConfiguration config = new ConfigurationBuilder()
|
||||||
.SetBasePath(monitorBasePath)
|
.SetBasePath(monitorBasePath)
|
||||||
|
@ -61,34 +57,34 @@ namespace Monitor
|
||||||
// Check if PT Magic directoy is correctly configured
|
// Check if PT Magic directoy is correctly configured
|
||||||
if (!Directory.Exists(ptMagicBasePath))
|
if (!Directory.Exists(ptMagicBasePath))
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("ERROR: PT Magic directory not found: '" + ptMagicBasePath + "'. Please check your setting for 'PTMagicBasePath' in 'Monitor/appsettings.json'");
|
Logger.WriteLine("ERROR: PT Magic directory not found: '" + ptMagicBasePath + "'. Please check your setting for 'PTMagicBasePath' in 'Monitor/appsettings.json'");
|
||||||
if (!Console.IsInputRedirected) Console.ReadKey();
|
if (!Console.IsInputRedirected) Console.ReadKey();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("INFO: PT Magic directory found at " + ptMagicBasePath);
|
Logger.WriteLine("INFO: PT Magic directory found at " + ptMagicBasePath);
|
||||||
|
|
||||||
// Check if PT Magic settings file exists
|
// Check if PT Magic settings file exists
|
||||||
string settingsGeneralJson = ptMagicBasePath + "settings.general.json";
|
string settingsGeneralJson = ptMagicBasePath + "settings.general.json";
|
||||||
if (!File.Exists(settingsGeneralJson))
|
if (!File.Exists(settingsGeneralJson))
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("ERROR: PT Magic settings not found: '" + settingsGeneralJson + "'. Please check if you setup PT Magic correctly!");
|
Logger.WriteLine("ERROR: PT Magic settings not found: '" + settingsGeneralJson + "'. Please check if you setup PT Magic correctly!");
|
||||||
if (!Console.IsInputRedirected) Console.ReadKey();
|
if (!Console.IsInputRedirected) Console.ReadKey();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("INFO: settings.general.json found at " + settingsGeneralJson);
|
Logger.WriteLine("INFO: settings.general.json found at " + settingsGeneralJson);
|
||||||
|
|
||||||
// Check if PT Magic settings file exists
|
// Check if PT Magic settings file exists
|
||||||
string lastRuntimeSummaryJson = ptMagicBasePath + Constants.PTMagicPathData + Path.DirectorySeparatorChar + "LastRuntimeSummary.json";
|
string lastRuntimeSummaryJson = ptMagicBasePath + Constants.PTMagicPathData + Path.DirectorySeparatorChar + "LastRuntimeSummary.json";
|
||||||
if (!File.Exists(lastRuntimeSummaryJson))
|
if (!File.Exists(lastRuntimeSummaryJson))
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("ERROR: PT Magic runtime summary not found: '" + lastRuntimeSummaryJson + "'. Please wait for PT Magic to complete its first run!");
|
Logger.WriteLine("ERROR: PT Magic runtime summary not found: '" + lastRuntimeSummaryJson + "'. Please wait for PT Magic to complete its first run!");
|
||||||
if (!Console.IsInputRedirected) Console.ReadKey();
|
if (!Console.IsInputRedirected) Console.ReadKey();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("INFO: LastRuntimeSummary.json found at " + lastRuntimeSummaryJson);
|
Logger.WriteLine("INFO: LastRuntimeSummary.json found at " + lastRuntimeSummaryJson);
|
||||||
|
|
||||||
PTMagicConfiguration ptMagicConfiguration = null;
|
PTMagicConfiguration ptMagicConfiguration = null;
|
||||||
try
|
try
|
||||||
|
@ -103,29 +99,29 @@ namespace Monitor
|
||||||
string wwwrootPath = monitorBasePath + Path.DirectorySeparatorChar + "wwwroot";
|
string wwwrootPath = monitorBasePath + Path.DirectorySeparatorChar + "wwwroot";
|
||||||
if (!Directory.Exists(wwwrootPath))
|
if (!Directory.Exists(wwwrootPath))
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("ERROR: wwwroot directory not found: '" + wwwrootPath + "'. Did you copy all files as instructed on the wiki?");
|
Logger.WriteLine("ERROR: wwwroot directory not found: '" + wwwrootPath + "'. Did you copy all files as instructed on the wiki?");
|
||||||
if (!Console.IsInputRedirected) Console.ReadKey();
|
if (!Console.IsInputRedirected) Console.ReadKey();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("INFO: wwwroot directory found at " + wwwrootPath);
|
Logger.WriteLine("INFO: wwwroot directory found at " + wwwrootPath);
|
||||||
|
|
||||||
string assetsPath = wwwrootPath + Path.DirectorySeparatorChar + "assets";
|
string assetsPath = wwwrootPath + Path.DirectorySeparatorChar + "assets";
|
||||||
if (!Directory.Exists(assetsPath))
|
if (!Directory.Exists(assetsPath))
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("ERROR: assets directory not found: '" + assetsPath + "'. Did you copy all files as instructed on the wiki?");
|
Logger.WriteLine("ERROR: assets directory not found: '" + assetsPath + "'. Did you copy all files as instructed on the wiki?");
|
||||||
if (!Console.IsInputRedirected) Console.ReadKey();
|
if (!Console.IsInputRedirected) Console.ReadKey();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteConsoleLogLine("INFO: assets directory found at " + assetsPath);
|
Logger.WriteLine("INFO: assets directory found at " + assetsPath);
|
||||||
WriteConsoleLogLine("INFO: ALL CHECKS COMPLETED - ATTEMPTING TO START WEBSERVER...");
|
Logger.WriteLine("INFO: ALL CHECKS COMPLETED - ATTEMPTING TO START WEBSERVER...");
|
||||||
WriteConsoleLogLine("#********************************************************#");
|
Logger.WriteLine("#********************************************************#");
|
||||||
WriteConsoleLogLine("");
|
Logger.WriteLine("");
|
||||||
WriteConsoleLogLine("DO NOT CLOSE THIS WINDOW! THIS IS THE WEBSERVER FOR YOUR MONITOR!");
|
Logger.WriteLine("DO NOT CLOSE THIS WINDOW! THIS IS THE WEBSERVER FOR YOUR MONITOR!");
|
||||||
WriteConsoleLogLine("");
|
Logger.WriteLine("");
|
||||||
WriteConsoleLogLine("##########################################################");
|
Logger.WriteLine("##########################################################");
|
||||||
WriteConsoleLogLine("");
|
Logger.WriteLine("");
|
||||||
|
|
||||||
BuildWebHost(args, monitorBasePath, monitorBasePath + Path.DirectorySeparatorChar + "wwwroot", ptMagicConfiguration.GeneralSettings.Monitor.Port).Run();
|
BuildWebHost(args, monitorBasePath, monitorBasePath + Path.DirectorySeparatorChar + "wwwroot", ptMagicConfiguration.GeneralSettings.Monitor.Port).Run();
|
||||||
}
|
}
|
||||||
|
@ -146,29 +142,12 @@ namespace Monitor
|
||||||
.UseWebRoot(webroot)
|
.UseWebRoot(webroot)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
// Log writer
|
|
||||||
private static void WriteConsoleLogLine(string line)
|
|
||||||
{
|
|
||||||
// Write to console and log
|
|
||||||
Console.WriteLine(line);
|
|
||||||
_log.DoLogInfo(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global unhandled exception handler
|
// Global unhandled exception handler
|
||||||
private static void GlobalUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
|
private static void GlobalUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
|
||||||
{
|
{
|
||||||
Exception e = (Exception)args.ExceptionObject;
|
Exception e = (Exception)args.ExceptionObject;
|
||||||
|
|
||||||
Console.WriteLine("Unhandled exception occurred: " + e.ToString());
|
Logger.WriteException(e, "An unhandled fatal exception occurred");
|
||||||
|
|
||||||
if (args.IsTerminating)
|
|
||||||
{
|
|
||||||
_log.DoLogCritical("Unhandled fatal exception occurred: ", e);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_log.DoLogError("Unhandled fatal exception occurred: " + e.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,31 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Session;
|
using Microsoft.AspNetCore.Diagnostics;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Core.Main;
|
using Core.Main;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Monitor {
|
namespace Monitor
|
||||||
public class Startup {
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
PTMagicConfiguration systemConfiguration = null;
|
PTMagicConfiguration systemConfiguration = null;
|
||||||
|
|
||||||
public Startup() {
|
public Startup()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public void ConfigureServices(IServiceCollection services) {
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
string monitorBasePath = Directory.GetCurrentDirectory();
|
string monitorBasePath = Directory.GetCurrentDirectory();
|
||||||
if (!System.IO.File.Exists(monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json")) {
|
if (!System.IO.File.Exists(monitorBasePath + Path.DirectorySeparatorChar + "appsettings.json"))
|
||||||
|
{
|
||||||
monitorBasePath += Path.DirectorySeparatorChar + "Monitor";
|
monitorBasePath += Path.DirectorySeparatorChar + "Monitor";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,14 +36,17 @@ namespace Monitor {
|
||||||
|
|
||||||
string ptMagicBasePath = config.GetValue<string>("PTMagicBasePath");
|
string ptMagicBasePath = config.GetValue<string>("PTMagicBasePath");
|
||||||
|
|
||||||
if (!ptMagicBasePath.EndsWith(Path.DirectorySeparatorChar)) {
|
if (!ptMagicBasePath.EndsWith(Path.DirectorySeparatorChar))
|
||||||
|
{
|
||||||
ptMagicBasePath += Path.DirectorySeparatorChar;
|
ptMagicBasePath += Path.DirectorySeparatorChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
try {
|
{
|
||||||
systemConfiguration = new PTMagicConfiguration(ptMagicBasePath);
|
systemConfiguration = new PTMagicConfiguration(ptMagicBasePath);
|
||||||
} catch (Exception ex) {
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +54,8 @@ namespace Monitor {
|
||||||
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
|
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
|
||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
services.AddDistributedMemoryCache();
|
services.AddDistributedMemoryCache();
|
||||||
services.AddSession(options => {
|
services.AddSession(options =>
|
||||||
|
{
|
||||||
options.IdleTimeout = TimeSpan.FromSeconds(900);
|
options.IdleTimeout = TimeSpan.FromSeconds(900);
|
||||||
options.Cookie.HttpOnly = true;
|
options.Cookie.HttpOnly = true;
|
||||||
options.Cookie.Name = "PTMagicMonitor" + systemConfiguration.GeneralSettings.Monitor.Port.ToString();
|
options.Cookie.Name = "PTMagicMonitor" + systemConfiguration.GeneralSettings.Monitor.Port.ToString();
|
||||||
|
@ -57,26 +63,40 @@ namespace Monitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||||
app.UseStaticFiles();
|
{
|
||||||
if (env.IsDevelopment()) {
|
// Register global exception handler
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
app.UseBrowserLink();
|
app.UseBrowserLink();
|
||||||
app.UseDeveloperExceptionPage();
|
app.UseDeveloperExceptionPage();
|
||||||
//app.UseExceptionHandler("/Error");
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
app.UseExceptionHandler("/Error");
|
app.UseExceptionHandler("/Error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure request pipeline
|
||||||
|
app.UseStaticFiles();
|
||||||
app.UseSession();
|
app.UseSession();
|
||||||
app.UseMvc();
|
app.UseMvc();
|
||||||
|
|
||||||
|
// Open the browser
|
||||||
if (systemConfiguration.GeneralSettings.Monitor.OpenBrowserOnStart) OpenBrowser("http://localhost:" + systemConfiguration.GeneralSettings.Monitor.Port.ToString());
|
if (systemConfiguration.GeneralSettings.Monitor.OpenBrowserOnStart) OpenBrowser("http://localhost:" + systemConfiguration.GeneralSettings.Monitor.Port.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OpenBrowser(string url) {
|
public static void OpenBrowser(string url)
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
{
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); // Works ok on windows
|
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); // Works ok on windows
|
||||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
|
}
|
||||||
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
{
|
||||||
Process.Start("xdg-open", url); // Works ok on linux
|
Process.Start("xdg-open", url); // Works ok on linux
|
||||||
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
|
}
|
||||||
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||||
|
{
|
||||||
Process.Start("open", url); // Not tested
|
Process.Start("open", url); // Not tested
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue