Event upon initialization complete in WPF/Prism app - wpf

In non-Prism WPF app, if I want to run code after initialization (e.g. execute the task specified by command-line argument), I can do it in Loaded event of the main window. However with Prism, the modules are initialized after main window is displayed, that is, IModule.Initialize() is called after Bootstrapper.CreateShell() and Bootstrapper.InitializeShell(). In this case which event/override should I use?

The last thing called by UnityBootstrapper.Run(bool runWithDefaultConfiguration) is InitializeModules() (well apart from a call to Logger.Log). So overide Run(...).
class Bootstrapper : UnityBootstrapper
{
...
public override void Run(bool runWithDefaultConfiguration)
{
base.Run(runWithDefaultConfiguration);
// modules (and everything else) have been initialized when you get here
}
}

Related

Extending DialogService in Prism

On the Prism Library website there is a few notes about Simplify your Application Dialog APIs.
https://prismlibrary.com/docs/wpf/dialog-service.html
Let's say I have a Solution with multiple projects, MainProject, Modules.Module1, CoreProject. So creating this DialogServiceExtensions class in my Core project.
public static class DialogServiceExtensions
{
public static void ShowNotification(this IDialogService dialogService, string message, Action<IDialogResult> callBack)
{
dialogService.ShowDialog(nameof(NotificationDialog), new DialogParameters($"message={message}"), callBack, "notificationWindow");
}
}
I also put NotificationDialog and NotificationDialogViewModel in my Core project
I can call it at any project/module, but the question is how can I tell prism that NotificationDialog ViewModel is NotificationDialogViewModel.
Where should I register the dialog, to be able to use thru the hole solution? In my MainProject App.xaml.cs like usual?
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterDialog<NotificationDialog, NotificationDialogViewModel>();
}
Where should I register the dialog, to be able to use thru the hole solution? In my MainProject App.xaml.cs like usual?
If the app wants to show a dialog, you have to do this, as modules are essentially optional (they can be swapped out after deployment or they don't need to exist).
If a module wants to show a dialog (and not the app), you can decide whether it's part of your app's interface to its modules (then put the registration in the app) or not (then put it in the module, each module that uses it, that is, registrations may override each other).

Prism Library Dialog Service

The following sample never worked for me:
https://prismlibrary.com/docs/wpf/dialog-service.html
Where the dialogService comming from?
public MainWindowViewModel(IDialogService dialogService)
{
_dialogService = dialogService;
}
How can I add the dialog service?
protected override Window CreateShell()
{
var w = Container.Resolve<MainWindow>();
return w;
}
It's have to go within the RegisterTypes?
Where the dialogService comming from?
From the container. When resolving, the container also resolves all dependencies.
How can I add the dialog service?
You don't have to and normally should shouldn't either. Most of the time, the default implementation provided by the prism framework suffices.
It's have to go within the RegisterTypes?
If you use Unity, every non-concrete type has to be registered to be able to be resolved. That means, prism's dialog service implementation is registered somewhere. Have a look at the code of your application's base class as a starting point.

Registering Startup Class In Nancy Using AutoFac Bootstrapper

I've been reading through a lot of the Jabbr code to learn Nancy and trying to implement many of the same patterns in my own application. One of the things I can't seem to get working is the concept of an on application start class. The Jabbr code base has an App_Start folder with a Startup.cs file (here) in it with the following implementation.
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
...
SetupNancy(kernel, app);
...
}
}
private static void SetupNancy(IKernel kernel, IAppBuilder app)
{
var bootstrapper = new JabbRNinjectNancyBootstrapper(kernel);
app.UseNancy(bootstrapper);
}
When I tried to do something similar to that in my project the Startup.cs file was just ignored. I searched the Jabbr code base to see if it was used anywhere but I wasn't able to find anything and the only differences I could see is Jabbr uses Ninject while I wanted to use AutoFac
Is there a way to register a startup class in nancy?
Take a look at my project over on GitHub, you'll be interested in the Spike branch and may have to unload the ChainLink.Web project to run I can't remember.
I had some trouble finding a way to configure the ILifetimeScope even after reading the accepted answer here by TheCodeJunkie. Here's how you do the actual configuration:
In the bootstrapper class derived from the AutofacNancyBootstrapper, to actually configure the request container, you update the ILifetimeScope's component registry.
protected override void ConfigureRequestContainer(
ILifetimeScope container, NancyContext context)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDependency>();
builder.Update(container.ComponentRegistry);
}
The application container can be updated similarly in the ConfigureApplicationContainer override.
You should install the Nancy.Bootstrappers.Autofac nuget, inherit from the AutofacNancyBootstrapper type and override the appropriate method (depending on your lifetime scope requirements: application or request). For more info check the readme file https://github.com/nancyfx/nancy.bootstrappers.autofac
HTH
After following the advice from TheCodeJunkie you can use the Update method on the ILifetimeScope container parameter which gives you a ContainerBuilder through an Action:
protected override void ConfigureRequestContainer(ILifetimeScope container, NancyContext context)
{
container.Update(builder =>
{
builder.RegisterType<MyType>();
});
}

Registering dependencies within TinyIOC for use in NancyFX

I have another newbie question regarding registering additional dependencies within TinyIoc for use within NancyFX.
I am continuing to get the following exceptions when running the application...
Unable to resolve type: AdvancedSearchService.Interfaces.IResponseFactory
Exception Details: TinyIoC.TinyIoCResolutionException: Unable to resolve type: AdvancedSearchService.Interfaces.IResponseFactory
Source Error:
Line 25: var container = TinyIoCContainer.Current;
Line 26:
Line 27: _responseFactory = container.Resolve<IResponseFactory>();
Line 28:
Line 29:
I am currently registering my dependencies incorrectly, but I cannot seem to figure out the correct way. Below is my code within my custom bootstrapper. Also note that I am not currently calling the base.ConfigureRequestContainer method because I cannot seem to figure out how to get the current context to pass into it.
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
container.Register<IRavenSessionManager>(new RavenSessionManager());
base.ConfigureApplicationContainer(container);
ConfigureRequestContainer(container);
}
protected void ConfigureRequestContainer(TinyIoCContainer applicationContainer)
{
var requestContainer = applicationContainer.GetChildContainer();
requestContainer.Register<ISearchRepository>(new SearchRepository(requestContainer.Resolve<IRavenSessionManager>().GetSession()));
requestContainer.Register<IResponseFactory>(new ResponseFactory(requestContainer.Resolve<ISearchRepository>()));
//base.ConfigureRequestContainer(requestContainer,[I NEED THE CONTEXT])
}
Any help would really be appreciated...apparently my ignorance has no limits :)
Ok, not 100% sure where to start.. you don't need the context because you're doing it wrong :-)
Firstly, why are you calling "configure request container" at all, and why are you creating a child container? You don't do that :-) There are two scopes, application scope, configured by overriding ConfigureApplicationContainer, and request scope, configured by overriding ConfigureRequestContainer, you don't call them yourself, you just override them depending on how you want to scope your objects.
Secondly, the default Nancy bootstrapper will "autoregister" everything it can in its default implementation of ConfigureApplicationContainer. By calling "base" after you've made a manual registration you are effectively copying over your original registration by autoregister. Either don't call base, or call it before you do your manual registrations. And, again, don't call ConfigureRequestContainer from your ConfigureApplicationContainer :-)
If you don't care about everything being application scoped (so singetons get the same instance for each request) then you don't need any of this, you can just rely on autoregister.
You're currently constructing your objects manually and putting them into the container, that seems a rather odd way to do it. Normally you'd just register the types and let the container handle instantiating as and when it needs to.
You're not overriding ConfigureRequestContainer, you are just creating a new method (with a different signature).
So, what you probably want is something like:
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
// Autoregister will actually do this for us, so we don't need this line,
// but I'll keep it here to demonstrate. By Default anything registered
// against an interface will be a singleton instance.
container.Register<IRavenSessionManager, RavenSessionManager>();
}
// Need to override this, not just make a new method
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
// Get our session manager - this will "bubble up" to the parent container
// and get our application scope singleton
var session = container.Resolve<IRavenSessionManager>().GetSession();
// We can put this in context.items and it will be disposed when the request ends
// assuming it implements IDisposable.
context.Items["RavenSession"] = session;
// Just guessing what this type is called
container.Register<IRavenSession>(session);
container.Register<ISearchRepository, SearchRepository>();
container.Register<IResponseFactory, ResponseFactory>();
}

Silverlight 4 and COM Interop

I've created a ComVisible-class:
[Guid("73a3f91f-baa9-46ab-94b8-e526c22054a4"), ComVisible(true)]
public interface ITest
{
void Foo();
}
[Guid("99f72d92-b302-4fde-89bb-2dac899f5a48"), ComVisible(true)]
public class Class1 : ITest
{
public void Foo() { }
}
and registered it via
regasm ComClassTest.dll /tlb:ComClassTest.tlb
into the registry.
When I try to call it in my Silverlight 4 out-of-browser, elevated trust application like this:
var foo = AutomationFactory.CreateObject("ComClassTest.Class1");
I get an exception "{System.Exception: Failed to create an object instance for the specified ProgID."
However, I am able to call AutomationFactory.CreateObject("Word.Application") without an Exception and to call Activator.CreateInstance(Type.GetTypeFromProgID("ComClassTest.Class1")) in a normal C#-console application if I copy the ComClassTest.dll into the bin-directory.
What have I forgotton?
First thing to do is test that you can create the object from somewhere else such as VBScript. Create a .vbs file with the content:-
o = CreateObject("ComClassTest.Class1")
If that doesn't generate an error then there is something specifically that SL OOB is upset with otherwise your problem isn't really related to Silverlight at all.
Consider making the following changes to your COM code.
Its often easier to specify ComVisible(true) at the assembly level. You can do that from the application tab of the project properties on the Assembly Information dialog. You can also get Visual Studio to register the assembly with COM and build time using the option found on the build tab of the project properties.
Its a good idea to be specific about the ComInterfaceType you want to expose.
Things get really messy if you expose the class interface directly generally you only want the interface you have defined to be used and that this be the default interface for the class. In addition it probably better to stick to COM naming conventions for the default interface of a class.
Finally (and possibly crucially in your case) its a good idea to be explicit about the ProgId to use for the class.
Applying the above and we get:-
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("73a3f91f-baa9-46ab-94b8-e526c22054a4")]
public interface _Class1
{
void Foo();
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("99f72d92-b302-4fde-89bb-2dac899f5a48")]
[ProgId("ComClassTest.Class1")]
public class Class1 : _Class1
{
public void Foo() { }
}

Resources