Follow-up: Quickly Build a Log Panel in Winform/WPF

Follow-up: Quickly Build a Log Panel in Winform/WPF

The principle is to host the `Winform or WPF application on ASP.NET Core Web API`

Last updated 4/18/2021 3:45 PM
沙漠尽头的狼
6 min read
Category
WPF Winform
Topic
WPF UI Design
Tags
.NET C# ASP.NET Core WPF Winform

Continuing from yesterday's post "ASP.NET Core Visual Log Component Usage" (Read Article, Watch Video), a friend commented under the video asking, "Can a Winform client program use it?" Another friend on WeChat also asked if it could be integrated into WPF. The site owner tried it this morning, and it works!

The principle is to host the Winform or WPF application onto an ASP.NET Core Web API. Let's first take a short video to see the effect. If you want the code, scroll down:

[Video Placeholder]


Practical steps:

  1. Create a WPF application
  2. Add support for ASP.NET Core and Serilog
  3. Use Serilog in the WPF window
  4. Completion

Let's start the actual implementation.

1. Create a WPF application

Using VS 2019, create a WPF Application project named WPFWithLogDashboard. This article is based on .NET 6.

2. Add support for ASP.NET Core and Serilog

2.1 Install relevant NuGet packages via NuGet

Microsoft.Extensions.Hosting must specify a version not higher than 2.2.0:

Install-Package Microsoft.Extensions.Hosting -Version 2.2.0
Install-Package Serilog.AspNetCore
Install-Package LogDashboard

2.2 Configure Serilog and ASP.NET Core

Open the App.xaml.cs file and add the following code. If you look closely, the configuration below is very similar to the configuration in the Program.cs file from the previous article. The main part is configuring Serilog, and remember to use || as the log output delimiter.

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Events;
using System;
using System.Windows;

namespace WPFWithLogDashboard
{
	/// <summary>
	/// Interaction logic for App.xaml
	/// </summary>
	public partial class App : Application
	{
		protected override void OnStartup(StartupEventArgs e)
		{
			base.OnStartup(e);

			#region Serilog Configuration

			string logOutputTemplate = "{Timestamp:HH:mm:ss.fff zzz} || {Level} || {SourceContext:l} || {Message} || {Exception} ||end {NewLine}";
			Log.Logger = new LoggerConfiguration()
			  .MinimumLevel.Override("Default", LogEventLevel.Information)
			  .MinimumLevel.Override("Microsoft", LogEventLevel.Error)
			  .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
			  .Enrich.FromLogContext()
			  .WriteTo.Console(theme: Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme.Code)
			  .WriteTo.File($"{AppContext.BaseDirectory}Logs/Dotnet9.log", rollingInterval: RollingInterval.Day, outputTemplate: logOutputTemplate)
			  .CreateLogger();

			#endregion

			Host.CreateDefaultBuilder(e.Args)
				.UseSerilog()
				.ConfigureWebHostDefaults(webBuilder =>
				{
					webBuilder.UseStartup<Startup>();
				}).Build().RunAsync();
		}
	}
}

Add the Startup.cs file with the following code:

using LogDashboard;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Serilog;

namespace WPFWithLogDashboard
{
	public class Startup
	{
		private ILogger logger;
		public ILogger MyLoger
		{
			get
			{
				if (logger == null)
				{
					logger = Log.ForContext<Startup>();
				}
				return logger;
			}
		}

		public void ConfigureServices(IServiceCollection services)
		{
			MyLoger.Information("ConfigureServices");

			services.AddLogDashboard();
			services.AddControllers();
		}

		public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
		{
			MyLoger.Information("Configure");

			app.UseLogDashboard();

			app.UseRouting();

			app.UseEndpoints(endpoints =>
			{
				endpoints.MapControllers();
			});
		}
	}
}

In this file, the main purpose is to add the LogDashboard component and configure .NET CORE Web API routing.

With the above code completed, the two components Serilog and LogDashboard are already installed and configured:

  1. The Logs directory in the program output will now generate log files.
  2. Entering the following link in the browser will open the LogDashboard visual log panel.
http://localhost:5000/logdashboard

3. Use Serilog in the WPF window

Add a few buttons to the main window MainWindow.xaml to simulate adding regular logs, adding exception logs, and opening the visual log panel webpage:

<Window
  x:Class="WPFWithLogDashboard.MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="Using Serilog in Windows"
  Height="250"
  Width="350"
>
  <StackPanel Margin="20">
    <button
      Content="Open Log Panel"
      Width="100"
      Height="35"
      Click="OpenLogDashboard_Click"
    />
    <button
      Content="Add Info Log"
      Width="100"
      Height="35"
      Margin="0 20"
      Click="AddInfoLog_Click"
    />
    <button
      Content="Add Error Log"
      Width="100"
      Height="35"
      Click="AddErrorLog_Click"
    />
  </StackPanel>
</Window>

In MainWindow.xaml.cs, implement the above functionalities:

using Serilog;
using System.Diagnostics;
using System.Windows;

namespace WPFWithLogDashboard
{
	public partial class MainWindow : Window
	{
		private ILogger logger;
		public ILogger MyLoger
		{
			get
			{
				if (logger == null)
				{
					logger = Log.ForContext<MainWindow>();
				}
				return logger;
			}
		}

		public MainWindow()
		{
			InitializeComponent();

			MyLoger.Information("Log recorded in WPF window");
		}
		private void AddInfoLog_Click(object sender, RoutedEventArgs e)
		{
			MyLoger.Information("Test adding Info log");

		}

		private void AddErrorLog_Click(object sender, RoutedEventArgs e)
		{
			MyLoger.Error("Test adding error log");
		}

		private void OpenLogDashboard_Click(object sender, RoutedEventArgs e)
		{
			OpenUrl("http://localhost:5000/logdashboard");
		}

		private void OpenUrl(string url)
		{
			Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")
			{
				UseShellExecute = false,
				CreateNoWindow = true
			});
		}
	}
}

OK, the functionality is complete. The project built based on WPF in this article is also applicable to the Winform project template.

4. Completion

This article focuses on practice. If you are not very familiar with ASP.NET Core, it is recommended that you systematically study the official Microsoft documentation. If you don't want to delve into the details, simply copying the code in the article will also work.

Was this article useful to you? Remember to give it a triple tap (like, comment, share).

Sample source code for this article: https://github.com/dotnet9/TerminalMACS.ManagerForWPF/tree/master/src/Demo/WPFWithLogDashboard

Keep Exploring

Related Reading

More Articles
Same category / Same tag 4/7/2022

What is the difference between Winform and WPF?

Some friends always ask, 'What is the difference between WinForm and WPF?' At first thought, this question seems simple to answer, but I never systematically analyzed it. Today, I took the time to write an article that only represents my personal views to record a summary.

Continue Reading