dapplo / dapplo.microsoft.extensions.hosting Goto Github PK
View Code? Open in Web Editor NEWExtensions for generic host based applications
License: MIT License
Extensions for generic host based applications
License: MIT License
Hi!
I added the Dapplo.Microsoft.Extensions.Hosting.Wpf
package to a project and noticed that the package was missing a package description.
Would you like a PR that adds descriptions to the packages in this repo or is that something you want to handle on your own?
Thanks for an interesting NuGet package!
Make it possible to configure the directories and globs for matching the plug-in assemblies in the configuration, instead of from code. This makes it easier to extend the application later, without recompiling.
Although I agree with David Fowlers comment here: dotnet/extensions#1151 (comment)
Loading assemblies from the file-system will make it hard to maintain an order, so I would introduce an attribute which can be placed on plugins to make it possible to specify an order.
Suggestion: PluginOrderAttribute which can use int or enums (improves readability), and when the plugins are loaded this attribute is used to order the plugins. Plugins without an attribute will get a default order.
When loading everything into the AssemblyContextLoader, using the dependency resolver, there will be issues with Assemblies which are needed in multiple plugins and / or the host.
There should be a way to specify which assemblies need to be loaded into the AssemblyContextLoader.Default.
Currently all assemblies that are already in the AppDomain, unfortunately there is no AssemblyContextLoader.Default.AllAssemblies or similar API, will not be loaded.
It should be enough to add an extension which is similar to the AddPlugins, suggestion: AddFrameworkAssemblies(this IHostBuilder hostBuilder, params string[] globs)
Hello
I have forked, built and tested your WinForms project succesfully in .NET Framework 4.7.2.
Is there any specific reason why this isn't yet supported?
Firstly thanks for this great project. It's exactly what I have searched and needed.
My issue is more a question.
I'm starting to use Dapplo with Winforms for DI, to have the possibility to use same code for a web api.
Until now, in my Winforms (GUI) programs I used - additional to Exception handling - following code in program.cs:
System.Windows.Forms.Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException,false);
public static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
log.Error(e);
MessageBox.Show((e.ExceptionObject as Exception).Message, "Unhandled UI Exception");
// here you can handle the exception ...
}
public static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
log.Error(e);
MessageBox.Show(e.Exception.Message, "Unhandled Thread Exception");
// here you can handle the exception ...
}
I have read that those events only work if Application.Run was started. Therefore I have the suspicion that those won't work with using: .UseWinFormsLifetime()
Is this correct? Are there any possibilities to include such central exception handling without losing user data in the form?
Thanks a lot for your great work!
System.IO.FileNotFoundException: 'Could not load file or assembly 'Caliburn.Micro, Version=3.2.0.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f'. The system cannot find the file specified.'
I guess it should be possible to add WinUI support, with a sample project.
Hi
I've created both a WinForm test application and also tested the included sample. No matter what the configuration files are set to, the LogLevel minimums do not change and no filters are added.
Hostsettings.json is set to Development
appsettings.Development.json is getting loaded as I can get configuration values
However if LogLevel is set nothing changes. I was trying to get debug level logging for the application code but can only get information level. And changing the Microsoft category level has no effect either.
I assume in the solution that all the configuration .json files should be set to "copy if newer" to the output directory.
Thanks.
It should be possible to add MAUI support, with a sample project.
This was also suggested in dotnet/maui#24
Currently it's pretty much impossible to detect if the correct plug-ins are loaded.
While being in the HostBuilder, the logging is not yet configured (??), I'm not sure how to log this...
There is a nuget package called https://github.com/vcsjones/AuthenticodeExaminer which can improve the security of applications using the plugins loading system.
In the new versions of Microsoft.Extension.Hosting, there's a new way to create a host:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
The current documentation explains more about it: https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host
The extensions in this project, however, only work with IHostBuilder
. Is there any possibility HostApplicationBuilder
will be supported?
First of all, kudos for your work on this repo.
Could I suggest the creation of an extension that uses GtkSharp? It would be amazing.
If there is an error during the setup of a DI Container the following Error appears and closes the application immediatly:
Unhandled exception. System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'IServiceProvider'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ThrowHelper.ThrowObjectDisposedException()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Dapplo.Microsoft.Extensions.Hosting.Wpf.Internals.WpfThread.PreUiThreadStart() in D:\a\1\s\src\Dapplo.Microsoft.Extensions.Hosting.Wpf\Internals\WpfThread.cs:line 33
at Dapplo.Microsoft.Extensions.Hosting.UiThread.BaseUiThread`1.InternalUiThreadStart() in D:\a\1\s\src\Dapplo.Microsoft.Extensions.Hosting.UiThread\BaseUiThread.cs:line 61
Reproduction Attempt:
var builder = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
services.ConfigureAndValidate<AppSettingsRootConfiguration>(options =>
{
context.Configuration.Bind(options);
throw new Exception("bla"); // <-- Exception which could appear during startup
});
await builder.ConfigureWpf(wpfBuilder =>
{
wpfBuilder.UseApplication<App>();
wpfBuilder.UseWindow<MainWindow>();
})
.UseWpfLifetime()
.UseConsoleLifetime()
.Build()
.RunAsync();
Thank you for this useful repository.
Could you please provide some samples about using the extensions with some more complex WPF .NET Core applications using MVVM? For instance how can view models be registered and assigned to the different views from some WPF application?
Currently the startup of the UI for the application is quite slow, I assume that this is while we are waiting for the thread to startup before continuing some of the work.
Let's just start the thread, return, and have the work on the second thread run as soon as possible.
Perception is the most important thing, so get the user it's UI as soon as possible!
Stack Trace:
System.ObjectDisposedException
HResult=0x80131622
Message=Cannot access a disposed object.
Object name: 'IServiceProvider'.
Source=Microsoft.Extensions.DependencyInjection
StackTrace:
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ThrowHelper.ThrowObjectDisposedException()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Dapplo.Microsoft.Extensions.Hosting.Wpf.Internals.WpfThread.b__1_0(Object s, ExitEventArgs e) in D:\a\1\s\src\Dapplo.Microsoft.Extensions.Hosting.Wpf\Internals\WpfThread.cs:line 46
at System.Windows.Application.OnExit(ExitEventArgs e)
at System.Windows.Application.DoShutdown()
at System.Windows.Application.ShutdownImpl()
at System.Windows.Application.ShutdownCallback(Object arg)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at Dapplo.Microsoft.Extensions.Hosting.Wpf.Internals.WpfThread.UiThreadStart() in D:\a\1\s\src\Dapplo.Microsoft.Extensions.Hosting.Wpf\Internals\WpfThread.cs:line 90
at Dapplo.Microsoft.Extensions.Hosting.UiThread.BaseUiThread`1.InternalUiThreadStart() in D:\a\1\s\src\Dapplo.Microsoft.Extensions.Hosting.UiThread\BaseUiThread.cs:line 68
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
This exception was originally thrown at this call stack:
[External Code]
Code:
public static async Task Main(string[] _)
{
CancellationTokenSource cancellationToken = new(TimeSpan.FromSeconds(20));
await host.RunAsync(cancellationToken.Token);
}
Hi Robin!
I've been playing around some more with the library and I wonder if it would be possible to find an alternative solution to the IWpfShell
marker interface. Let's say that the shell is located in separate assembly from the host. It would be nice to avoid the dependency on the marker interface in that case.
Perhaps the API could have a method UsingWpfShell<TShell>()
instead and use the provided type for lookup.
Or would you say this is out of scope and rather recommend using a custom implementation of ConfigureWpf
alltogether?
It would be nice if I wasn't required to use the IWpfShell
marker interface to have the startup window. This requirement means that specific Window
is special, and it is so at compile time. Using attributes has similar problems.
As an alternative, consider if there was an IStartupWindowFactory
interface, whose duty was to provide a list of startup Window
. It could provide different Window
based on whatever factors the developer chooses.
The default implementation of IStartupWindowFactory
could use the current IWpfShell
marker interface, making it a drop-in replacement.
See this repository / diff showing one way it could be done.
IWpfShell
interface has been removed from the window. (Source)IStartupWindowFactory
is included that uses IWpfShell
. Since it's using TryAddSingleton
, it will be added if and only if the user has not already added their own implementation. (Source)IStartupWindowFactory
. With this implementation there is no change in behavior from current. (Source)IStartupWindowFactory
(Source)IStartupWindowFactory
. Since it's using AddSingleton
, it's going to override the default factory that was added with TryAddSingleton
. (Source)Hi,
just found this exciting package and experimenting with it. However, I'm falling short because my Plugin is not loaded/executed. Anything wrong with this code. How can I know the reason why the plugin is not loaded?
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<FileSystemWorker>();
})
.ConfigurePlugins(builder =>
{
builder.AddScanDirectories(Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location), "PlugIns"));
builder.IncludePlugins(@"**\*.Service.dll");
});
The "FileSystemWorker" is loaded of course, but my runtime service in the "PlugIn" folder is never loaded, no matter what globs I pass to the builder.
The runtime service also has a public class that implements IPlugin.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.