Skip to content

Commit f6b6624

Browse files
committed
refactor: Split WebView2 into separate package
- Move WebView2 viewer into its own NuGet package to reduce core dependencies - Implement extension-based architecture for changelog viewers - Add auto-discovery of viewer extensions at runtime - Update core package to dynamically load WebView2 when available - Remove WebView2 dependency from core package - Clean up project structure and dependencies This change makes the WebView2 viewer optional, reducing the core package size and dependencies. Users who want WebView2 support can install the additional package, while the core functionality remains lightweight.
1 parent c6c5a56 commit f6b6624

19 files changed

+318
-59
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project Sdk="Microsoft.NET.Sdk">
3+
<PropertyGroup>
4+
<OutputType>library</OutputType>
5+
<TargetFrameworks>net462;netcoreapp3.1;net5.0-windows;net6.0-windows;net7.0-windows;net8.0-windows</TargetFrameworks>
6+
<UseWindowsForms>true</UseWindowsForms>
7+
<RootNamespace>AutoUpdaterDotNET.WebView2</RootNamespace>
8+
<AssemblyTitle>AutoUpdater.NET.WebView2</AssemblyTitle>
9+
<Company>RBSoft</Company>
10+
<Product>AutoUpdater.NET.WebView2</Product>
11+
<Copyright>Copyright © 2012-2024 RBSoft</Copyright>
12+
<Version>1.9.3.0</Version>
13+
<AssemblyVersion>1.9.3.0</AssemblyVersion>
14+
<FileVersion>1.9.3.0</FileVersion>
15+
<PackageVersion>1.9.3.0</PackageVersion>
16+
<SignAssembly>true</SignAssembly>
17+
<AssemblyOriginatorKeyFile>..\AutoUpdater.NET\AutoUpdater.NET.snk</AssemblyOriginatorKeyFile>
18+
<NeutralLanguage>en</NeutralLanguage>
19+
<PackageId>Autoupdater.NET.WebView2</PackageId>
20+
<IncludeSymbols>true</IncludeSymbols>
21+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
22+
<Title>AutoUpdater.NET WebView2 Extension</Title>
23+
<Authors>rbsoft</Authors>
24+
<Description>WebView2 extension for AutoUpdater.NET that provides modern web rendering capabilities for changelogs.</Description>
25+
<PackageProjectUrl>https://github.com/ravibpatel/AutoUpdater.NET</PackageProjectUrl>
26+
<PackageTags>autoupdate updater webview2 edge</PackageTags>
27+
<PackageReleaseNotes>https://github.com/ravibpatel/AutoUpdater.NET/releases</PackageReleaseNotes>
28+
<PackageOutputPath>build</PackageOutputPath>
29+
<DocumentationFile>$(OutDir)\AutoUpdater.NET.WebView2.xml</DocumentationFile>
30+
<LangVersion>latest</LangVersion>
31+
</PropertyGroup>
32+
33+
<ItemGroup>
34+
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3065.39" />
35+
<ProjectReference Include="..\AutoUpdater.NET\AutoUpdater.NET.csproj" />
36+
</ItemGroup>
37+
</Project>

AutoUpdater.NET/ChangelogViewers/WebView2Viewer.cs renamed to AutoUpdater.NET.WebView2/WebView2Viewer.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
using System.Windows.Forms;
44
using System.Threading.Tasks;
55
using Microsoft.Web.WebView2.Core;
6-
using Microsoft.Web.WebView2.WinForms;
6+
using AutoUpdaterDotNET.ChangelogViewers;
77

8-
namespace AutoUpdaterDotNET.ChangelogViewers;
8+
namespace AutoUpdaterDotNET.WebView2;
99

1010
public class WebView2Viewer : IChangelogViewer
1111
{
1212
private bool _isInitialized;
13-
private readonly WebView2 _webView = new()
13+
private readonly Microsoft.Web.WebView2.WinForms.WebView2 _webView = new()
1414
{
1515
Dock = DockStyle.Fill,
1616
AllowExternalDrop = false
@@ -37,11 +37,11 @@ public async void LoadContent(string content)
3737
{
3838
await EnsureInitialized();
3939
_webView.CoreWebView2.SetVirtualHostNameToFolderMapping("local.files", Path.GetTempPath(), CoreWebView2HostResourceAccessKind.Allow);
40-
40+
4141
// Write content to a temporary HTML file
4242
var tempFile = Path.Combine(Path.GetTempPath(), "changelog.html");
4343
File.WriteAllText(tempFile, content);
44-
44+
4545
// Navigate to the local file
4646
_webView.CoreWebView2.Navigate("https://local.files/changelog.html");
4747
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using AutoUpdaterDotNET.ChangelogViewers;
2+
3+
namespace AutoUpdaterDotNET.WebView2;
4+
5+
public class WebView2ViewerProvider(int priority = 2) : IChangelogViewerProvider
6+
{
7+
public WebView2ViewerProvider() : this(2) { }
8+
9+
public bool IsAvailable => WebView2Viewer.IsAvailable();
10+
11+
public int Priority { get; } = priority;
12+
13+
public IChangelogViewer CreateViewer() => new WebView2Viewer();
14+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
3+
<metadata>
4+
<id>Autoupdater.NET.WebView2</id>
5+
<version>1.9.3.0</version>
6+
<title>AutoUpdater.NET WebView2 Extension</title>
7+
<authors>rbsoft</authors>
8+
<requireLicenseAcceptance>false</requireLicenseAcceptance>
9+
<license type="expression">MIT</license>
10+
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
11+
<projectUrl>https://github.com/ravibpatel/AutoUpdater.NET</projectUrl>
12+
<description>WebView2 extension for AutoUpdater.NET that provides modern web rendering capabilities for changelogs.</description>
13+
<releaseNotes>https://github.com/ravibpatel/AutoUpdater.NET/releases</releaseNotes>
14+
<copyright>Copyright 2012-2024 RBSoft</copyright>
15+
<tags>autoupdate updater webview2 edge</tags>
16+
<dependencies>
17+
<group targetFramework=".NETFramework4.6.2">
18+
<dependency id="Autoupdater.NET.Official" version="1.9.3.0" exclude="Build,Analyzers"/>
19+
<dependency id="Microsoft.Web.WebView2" version="1.0.2849.39" exclude="Build,Analyzers"/>
20+
</group>
21+
<group targetFramework=".NETCoreApp3.1">
22+
<dependency id="Autoupdater.NET.Official" version="1.9.3.0" exclude="Build,Analyzers"/>
23+
<dependency id="Microsoft.Web.WebView2" version="1.0.2849.39" exclude="Build,Analyzers"/>
24+
</group>
25+
<group targetFramework="net5.0-windows7.0">
26+
<dependency id="Autoupdater.NET.Official" version="1.9.3.0" exclude="Build,Analyzers"/>
27+
<dependency id="Microsoft.Web.WebView2" version="1.0.2849.39" exclude="Build,Analyzers"/>
28+
</group>
29+
<group targetFramework="net6.0-windows7.0">
30+
<dependency id="Autoupdater.NET.Official" version="1.9.3.0" exclude="Build,Analyzers"/>
31+
<dependency id="Microsoft.Web.WebView2" version="1.0.2849.39" exclude="Build,Analyzers"/>
32+
</group>
33+
<group targetFramework="net7.0-windows7.0">
34+
<dependency id="Autoupdater.NET.Official" version="1.9.3.0" exclude="Build,Analyzers"/>
35+
<dependency id="Microsoft.Web.WebView2" version="1.0.2849.39" exclude="Build,Analyzers"/>
36+
</group>
37+
<group targetFramework="net8.0-windows7.0">
38+
<dependency id="Autoupdater.NET.Official" version="1.9.3.0" exclude="Build,Analyzers"/>
39+
<dependency id="Microsoft.Web.WebView2" version="1.0.2849.39" exclude="Build,Analyzers"/>
40+
</group>
41+
</dependencies>
42+
<frameworkReferences>
43+
<group targetFramework=".NETCoreApp3.1">
44+
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
45+
</group>
46+
<group targetFramework="net5.0-windows7.0">
47+
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
48+
</group>
49+
<group targetFramework="net6.0-windows7.0">
50+
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
51+
</group>
52+
<group targetFramework="net7.0-windows7.0">
53+
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
54+
</group>
55+
<group targetFramework="net8.0-windows7.0">
56+
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
57+
</group>
58+
</frameworkReferences>
59+
</metadata>
60+
<files>
61+
<file src="lib\**" target="lib" />
62+
</files>
63+
</package>

AutoUpdater.NET.sln

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,26 @@ VisualStudioVersion = 16.0.29215.179
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoUpdater.NET", "AutoUpdater.NET\AutoUpdater.NET.csproj", "{FB9E7E6B-B19F-4F37-A708-2996190CEF13}"
77
ProjectSection(ProjectDependencies) = postProject
8-
{91DE558C-6DB8-429B-A069-C0491DCFF15B} = {91DE558C-6DB8-429B-A069-C0491DCFF15B}
8+
{EDB311FC-50D3-468B-AC36-4CDFE04D29A3} = {EDB311FC-50D3-468B-AC36-4CDFE04D29A3}
99
EndProjectSection
1010
EndProject
1111
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1DBD2EE1-6C31-4B24-9212-E221404F4ADE}"
1212
ProjectSection(SolutionItems) = preProject
1313
.gitignore = .gitignore
1414
appveyor.yml = appveyor.yml
15+
build.bat = build.bat
1516
LICENSE = LICENSE
1617
README.md = README.md
17-
build.bat = build.bat
1818
EndProjectSection
1919
EndProject
2020
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZipExtractor", "ZipExtractor\ZipExtractor.csproj", "{EDB311FC-50D3-468B-AC36-4CDFE04D29A3}"
2121
EndProject
2222
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoUpdaterTest", "AutoUpdaterTest\AutoUpdaterTest.csproj", "{5C1E186E-2622-425D-8E90-2CC6C25EDE29}"
23+
ProjectSection(ProjectDependencies) = postProject
24+
{A9848B77-2D66-4C5C-9F0F-2F9F3FB6C5A3} = {A9848B77-2D66-4C5C-9F0F-2F9F3FB6C5A3}
25+
EndProjectSection
26+
EndProject
27+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoUpdater.NET.WebView2", "AutoUpdater.NET.WebView2\AutoUpdater.NET.WebView2.csproj", "{A9848B77-2D66-4C5C-9F0F-2F9F3FB6C5A3}"
2328
EndProject
2429
Global
2530
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -39,6 +44,10 @@ Global
3944
{5C1E186E-2622-425D-8E90-2CC6C25EDE29}.Debug|Any CPU.Build.0 = Debug|Any CPU
4045
{5C1E186E-2622-425D-8E90-2CC6C25EDE29}.Release|Any CPU.ActiveCfg = Release|Any CPU
4146
{5C1E186E-2622-425D-8E90-2CC6C25EDE29}.Release|Any CPU.Build.0 = Release|Any CPU
47+
{A9848B77-2D66-4C5C-9F0F-2F9F3FB6C5A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48+
{A9848B77-2D66-4C5C-9F0F-2F9F3FB6C5A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
49+
{A9848B77-2D66-4C5C-9F0F-2F9F3FB6C5A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
50+
{A9848B77-2D66-4C5C-9F0F-2F9F3FB6C5A3}.Release|Any CPU.Build.0 = Release|Any CPU
4251
EndGlobalSection
4352
GlobalSection(SolutionProperties) = preSolution
4453
HideSolutionNode = FALSE

AutoUpdater.NET/AutoUpdater.NET.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@
4848
<Reference Include="System.Xaml"/>
4949
<Reference Include="System.Runtime.Serialization"/>
5050
</ItemGroup>
51-
<ItemGroup>
52-
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2849.39"/>
53-
</ItemGroup>
5451
<ItemGroup>
5552
<EmbeddedResource Update="DownloadUpdateDialog.ar.resx">
5653
<DependentUpon>DownloadUpdateDialog.cs</DependentUpon>
@@ -242,4 +239,7 @@
242239
<DependentUpon>UpdateForm.cs</DependentUpon>
243240
</EmbeddedResource>
244241
</ItemGroup>
242+
<ItemGroup>
243+
<Compile Remove="ChangelogViewers\ChangelogViewerType.cs" />
244+
</ItemGroup>
245245
</Project>

AutoUpdater.NET/AutoUpdater.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,15 @@ public static class AutoUpdater
247247
public static Mode UpdateMode;
248248

249249
/// <summary>
250-
/// Set this to any of the available types to change the changelog viewer.
250+
/// Gets or sets whether to automatically load and register changelog viewer extensions from DLLs in the application directory.
251+
/// Default is true.
251252
/// </summary>
252-
public static ChangelogViewerType ChangelogViewerType = ChangelogViewerFactory.GetDefaultViewerType();
253+
public static bool AutoLoadExtensions { get; set; } = true;
254+
255+
/// <summary>
256+
/// Gets or sets the provider to use for displaying changelogs. If null, the factory will use the highest priority available provider.
257+
/// </summary>
258+
public static IChangelogViewerProvider ChangelogViewerProvider { get; set; }
253259

254260
/// <summary>
255261
/// An event that developers can use to exit the application gracefully.

AutoUpdater.NET/BasicAuthentication.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ public BasicAuthentication(string username, string password)
2020
Password = password;
2121
}
2222

23-
internal string Username { get; }
23+
public string Username { get; }
2424

25-
internal string Password { get; }
25+
public string Password { get; }
2626

2727
/// <inheritdoc />
2828
public void Apply(ref MyWebClient webClient)
Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,102 @@
11
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Reflection;
5+
using System.Collections.Generic;
26

37
namespace AutoUpdaterDotNET.ChangelogViewers;
48

5-
public static class ChangelogViewerFactory
9+
internal static class ChangelogViewerFactory
610
{
7-
public static IChangelogViewer Create(ChangelogViewerType type)
11+
private static readonly List<IChangelogViewerProvider> Providers =
12+
[
13+
new RichTextBoxViewerProvider(),
14+
new WebBrowserViewerProvider()
15+
];
16+
17+
static ChangelogViewerFactory()
18+
{
19+
if (AutoUpdater.AutoLoadExtensions)
20+
LoadExtensions();
21+
}
22+
23+
public static void RegisterProvider(IChangelogViewerProvider provider)
24+
{
25+
if (provider == null)
26+
throw new ArgumentNullException(nameof(provider));
27+
28+
var providerType = provider.GetType();
29+
var existingProvider = Providers.FirstOrDefault(p => p.GetType() == providerType);
30+
if (existingProvider != null)
31+
{
32+
if (existingProvider.Priority == provider.Priority)
33+
return; // Same type and priority, nothing to do
34+
35+
// Remove existing provider to allow priority override
36+
Providers.Remove(existingProvider);
37+
}
38+
39+
Providers.Add(provider);
40+
}
41+
42+
internal static IChangelogViewer Create(IChangelogViewerProvider provider = null)
843
{
9-
return type switch
44+
provider ??= AutoUpdater.ChangelogViewerProvider;
45+
46+
if (provider != null)
1047
{
11-
ChangelogViewerType.RichTextBox => new RichTextBoxViewer(),
12-
ChangelogViewerType.WebBrowser => new WebBrowserViewer(),
13-
ChangelogViewerType.WebView2 when WebView2Viewer.IsAvailable() => new WebView2Viewer(),
14-
ChangelogViewerType.WebView2 => throw new InvalidOperationException("WebView2 runtime is not available"),
15-
_ => throw new ArgumentException($"Unknown viewer type: {type}")
16-
};
48+
if (!provider.IsAvailable)
49+
throw new InvalidOperationException($"The specified viewer provider '{provider.GetType().Name}' is not available in this environment.");
50+
51+
return provider.CreateViewer();
52+
}
53+
54+
// Get all available providers ordered by priority (highest first)
55+
var availableProviders = Providers
56+
.Where(p => p.IsAvailable)
57+
.OrderByDescending(p => p.Priority);
58+
59+
var changelogViewerProvider = availableProviders.FirstOrDefault();
60+
61+
if (changelogViewerProvider == null)
62+
throw new InvalidOperationException("No changelog viewers are available in this environment.");
63+
64+
return changelogViewerProvider.CreateViewer();
1765
}
1866

19-
public static ChangelogViewerType GetDefaultViewerType()
67+
private static void LoadExtensions()
2068
{
21-
if (WebView2Viewer.IsAvailable())
22-
return ChangelogViewerType.WebView2;
23-
24-
return ChangelogViewerType.WebBrowser;
69+
var extensions = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "AutoUpdater.NET.*.dll");
70+
if (extensions.Length == 0) return;
71+
72+
var iProviderType = typeof(IChangelogViewerProvider);
73+
foreach (var extension in extensions)
74+
{
75+
try
76+
{
77+
var assembly = Assembly.LoadFrom(extension);
78+
var providers = assembly
79+
.GetTypes()
80+
.Where(t => t.IsClass && !t.IsAbstract && iProviderType.IsAssignableFrom(t));
81+
82+
foreach (var provider in providers)
83+
{
84+
try
85+
{
86+
var instance = (IChangelogViewerProvider)Activator.CreateInstance(provider);
87+
if (instance?.IsAvailable == true)
88+
RegisterProvider(instance);
89+
}
90+
catch (Exception ex)
91+
{
92+
System.Diagnostics.Debug.WriteLine($"Failed to create instance of provider {provider.FullName}: {ex.Message}");
93+
}
94+
}
95+
}
96+
catch (Exception ex)
97+
{
98+
System.Diagnostics.Debug.WriteLine($"Failed to load extension {extension}: {ex.Message}");
99+
}
100+
}
25101
}
26102
}

AutoUpdater.NET/ChangelogViewers/ChangelogViewerType.cs

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)