Is it possible to implement a module that is not a WPF module (a standard class library, no screens)?

Viewed 45

I am developing a modular WPF application with Prism in .Net Core 5.0 (using MVVM, DryIoc) and I would like to have a module that is not a WPF module, i.e., a module with functionality that can be used by any other module. I don't want any project reference, because I want to keep the loosely coupled idea of the modules. My first question is: is it conceptually correct? Or is it mandatory that a module has a screen? I guess it should be ok.

The second and more important (for me) is, what would be the best way to create the instance?

This is the project (I know I should review the names in this project):

enter image description here

HotfixSearcher is the main class, the one I need to get instantiated. In this class, for example, I subscribe to some events. And this is the class that implements the IModule interface (the module class):

namespace SearchHotfix.Library
{
    public class HotfixSearcherModule : IModule
    {
        public HotfixSearcherModule()
        {
        }

        public void OnInitialized(IContainerProvider containerProvider)
        {
            //Create Searcher instance
            var searcher = containerProvider.Resolve<IHotfixSearcher>();
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {

            containerRegistry.RegisterSingleton<IHotfixSearcher, HotfixSearcher>();
            
        }
    }
}

That is the only way I found to get the class instantiated, but I am not a hundred per cent comfortable with creating an instance that is not used, I think it does not make much sense. For modules that have screens, the instances get created when navigating to them using the RequestNavigate method:

_regionManager.RequestNavigate(RegionNames.ContentRegion, "ContentView");

But since this is only a library with no screens, I can't find any other way to get this instantiated.

According to Prism documentation, subscribing to an event shoud be enough but I tried doing that from within my main class HotfixSearcher but it does not work (breakpoints on constructor or on the event handler of the event to which I subscribe are never hit).

When I do this way, instead, the instance is created, I hit the constructor breakpoint, and obviously the instance is subscribed to the event since it is done in the constructor.

To sum up, is there a way to get rid of that var searcher = containerProvider.Resolve<IHotfixSearcher>(); and a better way to achieve this?

Thanks in advance!

1 Answers

Or is it mandatory that a module has a screen?

No, of course not, modules have nothing to do with views or view models. They are just a set of registrations with the container.

what would be the best way to create the instance?

Let the container do the work. Normally, you have (at least) one assembly that only contains public interfaces (and the associated enums), but no modules. You reference that from the module and register the module's implementations of the relevant interfaces withing the module's Initialize method. Some other module (or the main app) can then have classes that get the interfaces as constructor parameters, and the container will resolve (i.e. create) the concrete types registered in the module, although they are internal or even private and completely unknown outside the module.

This is as loose a coupling as it gets if you don't want to sacrifice strong typing.

is there a way to get rid of that var searcher = containerProvider.Resolve<IHotfixSearcher>(); and a better way to achieve this?

You can skip the var searcher = part :-) But if the HotfixSearcher is never injected anywhere, it won't be created unless you do it yourself. OnInitialized is the perfect spot for this, because it runs after all modules had their chance to RegisterTypes so all dependencies should be registered.

If HotfixSearcher is not meant to be injected, you can also drop IHotfixSearcher and resolve HotfixSearcher directly:

public void OnInitialized(IContainerProvider containerProvider)
{
    containerProvider.Resolve<HotfixSearcher>();
}

I am not a hundred per cent comfortable with creating an instance that is not used, I think it does not make much sense.

It is used, I suppose, although not through calling one of its methods. It's used by sending it an event. That's just fine. Think of it like Task.Run - it's fine for the task to exist in seeming isolation, too.

Related