Pegged latest versions of all involved projects; split single NuGet package recipe into three, one core and one each for Ninject and Microsoft dependency injection

This commit is contained in:
Markus Ewald 2025-06-19 18:32:22 +02:00
parent b7627e0126
commit 0c2f0f787f
12 changed files with 184 additions and 47 deletions

4
.gitignore vendored
View File

@ -1,4 +1,6 @@
NuclexSupportConfig.cmake
FoundationPackageConfig.cmake
third-party
# Visual Studio Codium
.vscode/*

5
.gitmodules vendored
View File

@ -13,3 +13,8 @@
url = ../../nuclex-shared-dotnet/Nuclex.Windows.Forms.Ninject.git
branch = main
update = rebase
[submodule "Nuclex.Windows.Forms.DependencyInjection"]
path = Nuclex.Windows.Forms.DependencyInjection
url = ../../nuclex-shared-dotnet/Nuclex.Windows.Forms.DependencyInjection.git
branch = main
update = rebase

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Nuclex.Foundation.DependencyInjection</id>
<version>1.2.0</version>
<title>Dependency injection bindings for the Nuclex Foundation Libraries</title>
<authors>Markus Ewald</authors>
<owners></owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">Apache-2.0</license>
<readme>ReadMe.md</readme>
<projectUrl>https://github.com/orgs/nuclex-shared-dotnet/repositories</projectUrl>
<description>Bindings to use Microsoft's (and compatible) dependency injector in Microsoft.Extensions.DependencyInjection(.Asbtraction) for view models with Nuclex.Windows.Forms</description>
<language>en-US</language>
<tags>mvvm,util,ninject,dependency-injection</tags>
<icon>nuclex-logo.png</icon>
<repository type="git" url="https://github.com/nuclex-shared-dotnet/Nuclex.Windows.Forms.DependencyInjection.git" commit="573b7ab93d25034a649bdf401f5439ec15c165f5" />
<dependencies>
<group targetFramework=".NETFramework4.6.2">
<dependency id="Nuclex.Foundation" version="[1.2.0, 2.0.0)" exclude="Build,Analyzers" />
<dependency id="Microsoft.Extensions.DependencyInjection.Asbtraction" version="[8.0.0, 10.0.0)" exclude="Build,Analyzers" />
</group>
<group targetFramework="net8.0-windows7.0">
<dependency id="Nuclex.Foundation" version="[1.2.0, 2.0.0)" exclude="Build,Analyzers" />
<dependency id="Microsoft.Extensions.DependencyInjection.Asbtraction" version="[8.0.0, 10.0.0)" exclude="Build,Analyzers" />
</group>
</dependencies>
<frameworkReferences>
<group targetFramework=".NETFramework4.6.2" />
<group targetFramework="net8.0-windows7.0">
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
</group>
</frameworkReferences>
</metadata>
<files>
<file src="ReadMe.md" target="ReadMe.md" />
<file src="nuclex-logo.png" target="nuclex-logo.png" />
<!-- Feature set for .NET Framework 4.6.2 (with Windows.Forms) -->
<file src="Nuclex.Windows.Forms.DependencyInjection\bin\$Configuration$\net462\Nuclex.Windows.Forms.DependencyInjection.dll" target="lib/net462" />
<file src="Nuclex.Windows.Forms.DependencyInjection\bin\$Configuration$\net462\Nuclex.Windows.Forms.DependencyInjection.xml" target="lib/net462" />
<!-- Feature set for .NET 8.0 on Windows (with Windows.Forms) -->
<!-- Btw, '-windows7.0' means Windows Seven, the one between Vista and 8, not the internal Windows release number -->
<file src="Nuclex.Windows.Forms.DependencyInjection\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.DependencyInjection.dll" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Windows.Forms.DependencyInjection\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.DependencyInjection.xml" target="lib/net8.0-windows7.0" />
</files>
</package>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Nuclex.Foundation.Ninject</id>
<version>1.2.0</version>
<title>Ninject bindings for the Nuclex Foundation Libraries</title>
<authors>Markus Ewald</authors>
<owners></owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">Apache-2.0</license>
<readme>ReadMe.md</readme>
<projectUrl>https://github.com/orgs/nuclex-shared-dotnet/repositories</projectUrl>
<description>Bindings to use Ninject for dependency injection in view model with Nuclex.Windows.Forms</description>
<language>en-US</language>
<tags>mvvm,util,ninject,dependency-injection</tags>
<icon>nuclex-logo.png</icon>
<repository type="git" url="https://github.com/nuclex-shared-dotnet/Nuclex.Windows.Forms.Ninject.git" commit="66a7848d1f149160726fda055051dd7ca7afa312" />
<dependencies>
<group targetFramework=".NETFramework4.6.2">
<dependency id="Nuclex.Foundation" version="[1.2.0, 2.0.0)" exclude="Build,Analyzers" />
<dependency id="Ninject" version="[3.3.6, 4.0.0)" exclude="Build,Analyzers" />
</group>
<group targetFramework="net8.0-windows7.0">
<dependency id="Nuclex.Foundation" version="[1.2.0, 2.0.0)" exclude="Build,Analyzers" />
<dependency id="Ninject" version="[3.3.6, 4.0.0)" exclude="Build,Analyzers" />
</group>
</dependencies>
<frameworkReferences>
<group targetFramework=".NETFramework4.6.2" />
<group targetFramework="net8.0-windows7.0">
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
</group>
</frameworkReferences>
</metadata>
<files>
<file src="ReadMe.md" target="ReadMe.md" />
<file src="nuclex-logo.png" target="nuclex-logo.png" />
<!-- Feature set for .NET Framework 4.6.2 (with Windows.Forms) -->
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net462\Nuclex.Windows.Forms.Ninject.dll" target="lib/net462" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net462\Nuclex.Windows.Forms.Ninject.xml" target="lib/net462" />
<!-- Feature set for .NET 8.0 on Windows (with Windows.Forms) -->
<!-- Btw, '-windows7.0' means Windows Seven, the one between Vista and 8, not the internal Windows release number -->
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.Ninject.dll" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.Ninject.xml" target="lib/net8.0-windows7.0" />
</files>
</package>

View File

@ -2,31 +2,29 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Nuclex.Foundation</id>
<version>1.1.0</version>
<version>1.2.0</version>
<title>Nuclex Foundation Libraries</title>
<authors>Markus Ewald</authors>
<owners></owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">Apache-2.0</license>
<licenseUrl>https://licenses.nuget.org/Apache-2.0</licenseUrl>
<readme>ReadMe.md</readme>
<projectUrl>https://github.com/nuclex-shared-dotnet/Nuclex.Support</projectUrl>
<projectUrl>https://github.com/orgs/nuclex-shared-dotnet/repositories</projectUrl>
<description>Set of basic libraries offering tools for MVVM-based UIs, storage of settings, license keys, collections and observer/subscriber pattern helpers</description>
<language>en-US</language>
<tags>mvvm,util</tags>
<icon>nuclex-logo.png</icon>
<repository type="git" url="https://github.com/nuclex-shared-dotnet/Nuclex.Support.git" commit="a59facff90816bb3d7d53761ffea43c0102e6047" />
<repository type="git" url="https://github.com/nuclex-shared-dotnet/Nuclex.Support.git" commit="5fb433ad983e58725e0d25faa8968a75b3dfd178" />
<dependencies>
<group targetFramework=".NETStandard2.0" />
<group targetFramework=".NETFramework4.6.2">
<dependency id="Ninject" version="[3.3.6, 4.0.0)" exclude="Build,Analyzers" />
</group>
<group targetFramework="net6.0-windows7.0">
<dependency id="Ninject" version="[3.3.6, 4.0.0)" exclude="Build,Analyzers" />
</group>
<group targetFramework=".NETFramework4.6.2" />
<group targetFramework="net8.0-windows7.0" />
</dependencies>
<frameworkReferences>
<group targetFramework=".NETStandard2.0" />
<group targetFramework=".NETFramework4.6.2" />
<group targetFramework="net6.0-windows7.0">
<group targetFramework="net8.0-windows7.0">
<frameworkReference name="Microsoft.WindowsDesktop.App.WindowsForms" />
</group>
</frameworkReferences>
@ -45,17 +43,13 @@
<file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.xml" target="lib/net462" />
<file src="Nuclex.Windows.Forms\bin\$Configuration$\net462\Nuclex.Windows.Forms.dll" target="lib/net462" />
<file src="Nuclex.Windows.Forms\bin\$Configuration$\net462\Nuclex.Windows.Forms.xml" target="lib/net462" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net462\Nuclex.Windows.Forms.Ninject.dll" target="lib/net462" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net462\Nuclex.Windows.Forms.Ninject.xml" target="lib/net462" />
<!-- Featue set for .NET Framework 4.6.2 (with Windows.Forms) -->
<!-- Btw, '-windows7'.0 means Windows Seven, the one between Vista and 8, not the internal Windows relaese number -->
<file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.dll" target="lib/net6.0-windows7.0" />
<file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.xml" target="lib/net6.0-windows7.0" />
<file src="Nuclex.Windows.Forms\bin\$Configuration$\net6.0-windows\Nuclex.Windows.Forms.dll" target="lib/net6.0-windows7.0" />
<file src="Nuclex.Windows.Forms\bin\$Configuration$\net6.0-windows\Nuclex.Windows.Forms.xml" target="lib/net6.0-windows7.0" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net6.0-windows\Nuclex.Windows.Forms.Ninject.dll" target="lib/net6.0-windows7.0" />
<file src="Nuclex.Windows.Forms.Ninject\bin\$Configuration$\net6.0-windows\Nuclex.Windows.Forms.Ninject.xml" target="lib/net6.0-windows7.0" />
<!-- Feature set for .NET 8.0 on Windows (with Windows.Forms) -->
<!-- Btw, '-windows7.0' means Windows Seven, the one between Vista and 8, not the internal Windows release number -->
<file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.dll" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Support\bin\$Configuration$\netstandard2.0\Nuclex.Support.xml" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Windows.Forms\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.dll" target="lib/net8.0-windows7.0" />
<file src="Nuclex.Windows.Forms\bin\$Configuration$\net8.0-windows\Nuclex.Windows.Forms.xml" target="lib/net8.0-windows7.0" />
</files>
</package>

@ -1 +1 @@
Subproject commit e818fae81012b0a819abcf2180b90eee1d998fb7
Subproject commit 5fb433ad983e58725e0d25faa8968a75b3dfd178

@ -1 +1 @@
Subproject commit 563d45f9f2f3b666586eb0862088ac3e00566389
Subproject commit d057f704497b63faa5e57c6330afb436a0d9708c

@ -0,0 +1 @@
Subproject commit 573b7ab93d25034a649bdf401f5439ec15c165f5

@ -1 +1 @@
Subproject commit cb4e39895666e467dec8b3b92abdd73127687385
Subproject commit d3e1a3e24e7ff6615996ec9236495b6d1275de5c

View File

@ -35,7 +35,7 @@ void saveSettingsToIni() {
var iniStore = new ConfigurationFileStore();
saveSettings(iniStore);
using(var writer = new StreamWriteR("awesome-app.ini")) {
using(var writer = new StreamWriter("awesome-app.ini")) {
iniStore.Save(writer);
writer.Flush()
}
@ -78,9 +78,8 @@ static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
using(var windowManager = new WindowManager()) {
Application.Run(windowManager.OpenRoot<MainViewModel>());
}
var windowManager = new WindowManager();
Application.Run(windowManager.OpenRoot<MainViewModel>());
}
```
@ -99,8 +98,8 @@ will be assigned to its `DataContext` property, establishing
the View/ViewModel relationship.
Adding an IoC Container (Ninject) to the MVVM Example
-----------------------------------------------------
Adding Dependency Injection to the MVVM Example
-----------------------------------------------
In the previous example, the view and its view model were constructed using
`Activator.CreateInstance()` - a method provided by .NET that creates a new
@ -111,30 +110,55 @@ to provide the ViewModel with the data it is supposed to be an adapter for.
You can achieve that by constructing the ViewModel yourself and passing it
to the `WindowManager.OpenRoot()` or `WindowManager.ShowModal()` methods.
A much better approach is to use a dependency injector - an IoC container with
automatic constructor parameter injection. My favorite one is Ninject (due to
its neat setup with a fluent interface), but you can use any container you
wish, simply by inheriting your own `WindowManager` class:
A much better approach is to use a dependency injector that automatically
wires up your view models to app-internal services, repositories and managers
to which the view models and mediate.
Let's do the full program with the host application builder from Microsoft's
`Microsoft.Extensions.Hosting` assembly which would also give you logging and
hosted services in addition its dependency injector:
```csharp
public class NinjectWindowManager : WindowManager {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
public NinjectWindowManager(IKernel kernel, IAutoBinder autoBinder = null) :
base(autoBinder) {
this.kernel = kernel;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(
new HostApplicationBuilderSettings() {
DisableDefaults = true,
ContentRootPath = "",
ApplicationName = "Example"
}
);
// These are extension methods in Nuclex.Windows.Forms.DependencyInjection
builder.Services.AddMvvm(); // Window Manager
builder.Services.AddCommonDialogs(); // Message boxes, file dialogs, etc.
// View models and dialogs must be explicitly registered by default.
// This requirement can be relaxed.
builder.Services.AddTransient<MainViewModel>();
builder.Services.AddTransient<MainForm>();
// Create the host (in which all application services and scopes will
// be managed) and run the main window.
using(IHost host = builder.Build()) {
var windowManager = host.Services.GetRequiredService<IWindowManager>();
Application.Run(windowManager.OpenRoot<MainViewModel>());
}
protected override object CreateInstance(Type type) {
return this.kernel.Get(type);
}
private IKernel kernel;
}
```
Your `NinjectWindowManager` will now use `IKernel.Get()` to construct its
ViewModels, allowing their constructors to require any services and instances
you have set up in your Ninject kernel.
Now view models can access any registered services. By default, each view and
view model pair lives inside of an implicit 'scope', meaning that services
added via `builder.Services.AddScoped<T>()` will have unique instances per open
dialog or window.
This is very useful if your dialogs perform background processing via threads
(i.e. using `ThreadedViewModel`) or tasks where a shared database connection,
for example, would lead to trouble when it is asked to run another query while
a data reader is still open.
```csharp
class MainViewModel {

View File

@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nuclex.Windows.Forms.Ninjec
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Unit Tests", "Unit Tests", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nuclex.Windows.Forms.DependencyInjection (net-4.6)(net-8.0)", "Nuclex.Windows.Forms.DependencyInjection\Nuclex.Windows.Forms.DependencyInjection (net-4.6)(net-8.0).csproj", "{3D7D6CA0-A130-FD54-B772-B4B48847E682}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -41,6 +43,10 @@ Global
{98B1CB8B-9202-4008-9254-D0BE0B2D38AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{98B1CB8B-9202-4008-9254-D0BE0B2D38AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{98B1CB8B-9202-4008-9254-D0BE0B2D38AF}.Release|Any CPU.Build.0 = Release|Any CPU
{3D7D6CA0-A130-FD54-B772-B4B48847E682}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3D7D6CA0-A130-FD54-B772-B4B48847E682}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D7D6CA0-A130-FD54-B772-B4B48847E682}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D7D6CA0-A130-FD54-B772-B4B48847E682}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

5
nuget-pack.cmd Normal file
View File

@ -0,0 +1,5 @@
@ECHO OFF
nuget pack Nuclex.Foundation.nuspec -Version 1.2.0 -Properties Configuration=Release
nuget pack Nuclex.Foundation.Ninject.nuspec -Version 1.2.0 -Properties Configuration=Release
nuget pack Nuclex.Foundation.DependencyInjection.nuspec -Version 1.2.0 -Properties Configuration=Release