I have been using Prism for a while now and enjoy how much easier it is to decouple my modules.
This works especially great for views and view models since you can inject the view models via interfaces and the views via the region manager.
Unfortunately this only works when my views are full blown user controls unless I'm missing something here (and I sincerely hope I am).
A lot of times though, I'll create a ViewModel and a matching DataTemplate. These can then be used by other assemblies to compose a view.
My problem is, that I see no way of referring to these datatemplates without referencing the containing assembly, so in my xaml file I write something like:
<ResourceDictionary Source="pack://application:,,/......>
Of course this is not really decoupled, although I try to make sure, that I don't refer to the assembly anywhere else in my code.
Another solution I thought of, was to put the datatemplates into the Infrastructure project, but I don't like that too much either,as I want everything that belongs to a module to be contained in it (except the interfaces of course).
So, does anyone have a good workaround, or did I miss some Prism feature?
I would suggest creating a service that encapsulates adding resource dictionaries to the Application.Resources.MergedDictionaries collection.
// Service interface (defined in the 'infrastructure' project)
public interface IResourceAggregator
{
void AddResource(Uri resourceUri);
}
// Service implementation (implemented at the application/shell level)
class ResourceAggregator : IResourceAggregator
{
public void AddResource(Uri resourceUri)
{
var resourceDictionary = new ResourceDictionary() { Source = resourceUri };
var app = Application.Current;
app.Resources.MergedDictionaries.Add(resourceDictionary);
}
}
I would expect you would "resolve" this service during module load and use it to "register" the module-local resource dictionaries.
You would need to merge the resources when the module starts. You can read more about this here: http://blogs.southworks.net/jdominguez/2008/09/presentation-model-with-datatemplates-in-compositewpf-prism-sample/
Of course you can further abstract this functionality into a reusable service.
Related
I have a WPF application with MVVM. Assuming object composition from the ViewModel down looks as follows:
MainViewModel
OrderManager
OrderRepository
EFContext
AnotherRepository
EFContext
UserManager
UserRepository
EFContext
My original approach was to inject dependencies (from the ViewModelLocator) into my View Model using .InCallScope() on the EFContext and .InTransientScope() for everything else. This results in being able to perform a "business transaction" across multiple business layer objects (Managers) that eventually underneath shared the same Entity Framework Context. I would simply Commit() said context at the end for a Unit of Work type scenario.
This worked as intended until I realized that I don't want long living Entity Framework contexts at the View Model level, data integrity issues across multiple operations described HERE. I want to do something similar to my web projects where I use .InRequestScope() for my Entity Framework context. In my desktop application I will define a unit of work which will serve as a business transaction if you will, typically it will wrap everything within a button click or similar event/command. It seems that using Ninject's ActivationBlock can do this for me.
internal static class Global
{
public static ActivationBlock GetNinjectUoW()
{
//assume that NinjectSingleton is a static reference to the kernel configured with the necessary modules/bindings
return new ActivationBlock(NinjectSingleton.Instance.Kernel);
}
}
In my code I intend to use it as such:
//Inside a method that is raised by a WPF Button Command ...
using (ActivationBlock uow = Global.GetNinjectUoW())
{
OrderManager orderManager = uow.Get<OrderManager>();
UserManager userManager = uow.Get<UserManager>();
Order order = orderManager.GetById(1);
UserManager.AddOrder(order);
....
UserManager.SaveChanges();
}
Questions:
To me this seems to replicate the way I do business on the web, is there anything inherently wrong with this approach that I've missed?
Am I understanding correctly that all .Get<> calls using the activation block will produce "singletons" local to that block? What I mean is no matter how many times I ask for an OrderManager, it'll always give me the same one within the block. If OrderManager and UserManager compose the same repository underneath (say SpecialRepository), both will point to the same instance of the repository, and obviously all repositories underneath share the same instance of the Entity Framework context.
Both questions can be answered with yes:
Yes - this is service location which you shouldn't do
Yes you understand it correctly
A proper unit-of-work scope, implemented in Ninject.Extensions.UnitOfWork, solves this problem.
Setup:
_kernel.Bind<IService>().To<Service>().InUnitOfWorkScope();
Usage:
using(UnitOfWorkScope.Create()){
// resolves, async/await, manual TPL ops, etc
}
hi we have a PRISM WPF MVP application, we would like to have a state to share data between the views in the same module. Since PRISM by default doesnt have a state, was wondering if there is any way i could implement this. Presently i have injected a State with Dictionary as back-store, but the problem is its Global i.e available across the modules. i would really like to scope this injection being module specific.
I believe unity allows registering different classes to the same interface based on name, not sure if the only choice i have is to leverage that for my scenario.
Any help would be great! Thanks!
-ioWint
I would agree, scoping Unity's type registration with the ModuleName would be a place to start.
Inject a local(module level) state object into all the views that want to have share state. If the interface that defines the state object is local to your module then other modules won't be able to reference the state object because they can't reference the interface.
So: If Module A has 3 views that take an object implementing IStatefulContainer (also declared in Module A) and IStatefulContainer is registered with Unity using RegisterInstance rather than just RegisterType you'll have a singleton that is scoped to the module.
My preference would be to have a "State" service that managed state. This could allow you to add more functionality here if you needed it and is a more "Prismy" approach.
EDIT
If you're using this state object across modules then you can do the following:
1)Put the interface in an assembly that will be referenced by any module that wants to use it.
Assembly A
public interface IBlah
{
string Add(string stateKey, string stateValue);
}
Assembly B (referencing Assembly A)
public class Module:IModule
{
private IUnityContainer _container;
public Module(IUnityContainer container)
{
_container=container;
}
public void Initialize()
{
IBlah blah1=new BlahContainer();
IBlah blah2=new BlahContainer();
_container.RegisterInstance<IBlah>(blah1,"BlahContainer1");
_container.RegisterInstance<IBlah>(blah2,"BlahContainer2");
}
}
Module C(references assembly A)
_container.Resolve<IBlah>("BlahContainer1");
_container.Resolve<IBlah>("BlahContainer2");
Basically, we define the interface in an assembly we're happy to share between modules. Some projects have "Infrastructure" or Common assemblies that contain service interfaces that are used by other modules - this would fit well here.
We then have our module reference the assembly with the contract in it.
At the moment I'm relying on "magic strings" here but there are lots of ways around this.
Hope this is a little more clear.
thanks for your updated solution. I was trying to avoid a name based Unity registration, which would force my Presenter in knowing the Modules State registration Key.
I was reading stackoverflow posts on Unity and found the discussion over here Is it possible to override parameter values when using Method Injection with Unity? .
After couple of hours of trial and errors, i ended up achieving the desired functionality.
What i have done:
I have a BaseClass for my Modules -> BaseModule:IModule i have a State Property in it which conforms to my IStateService defined in the Infrastructure.Interface. I Instantiate this State property in the BaseModule() constructor.
Note: to go with this approach i have to make my Presenter's have a public IStateService State; property..
At the time of registering the Presenter in the module, i am specifying
<UnityContainer>.RegisterType<MyPresenter, new InjectionProperty("State", State).
Am overriding a public property in Presenter which has name "State" with the State instance value defined in the Module.
this way i am able to get the Modules State as the State for each of the View's presenter.
Thanks guys for directing me towards a solution.
-ioWint
I want to have create a WPF or Silverlight module which cannot only be utilised by Shell's bootstrapper, but also can be embedded in non-PRISM applications.
In short is there a way PRISM module can be intialised from module itself rather than initialsing from Shell?
Ulimate goal is to have WPF/Silverlight PRISM module, which can be initialsed by non-PRISM applications.
There is no barrier to this.
The IModule interface has a single, parameterless void method: Initialize().
A non-prism application can initialize the module by calling that method. That's it.
If the other application has a different plugin system, with a different interface, your module can implement that interface as well, and the body of whatever initialization method that interface uses can simply call Initialize(), or vice versa.
For example:
public interface IMyPluginModule
{
void StartModule();
}
public class MyModule : IModule, IMyPluginModule
{
public void Initialize()
{
// actual initialization code here
}
public void StartModule()
{
Initialize();
}
}
It's a little more complicated than it appears at first glance, but it is doable. I don't know if you are using Prism 4 yet, but if so, Microsoft actually provides guidance for this scenario:
http://msdn.microsoft.com/en-us/library/ff921109(v=PandP.40).aspx
There is a bit of project manipulation you need to do to get two projects running side-by-side. There is a sample included with Prism v4 called "MultiTargeting" if you need to see a working sample.
Your question regarding to allowing a module to be initialized by itself, rather than having the orchestrating Shell / Bootstrapper is the wrong approach, however. Essentially what you would have would be two shells... one WPF and one Silverlight. Take a look at the samples and see what you think.
Hope this helps.
I'm trying out Ninject with a winforms app (basically a sketch, I'm using it sort of like a kata, but nothing so rigorous or specific) in .net 4.
To create the main form, I'm doing something like:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
[...]
IKernel kernel = BuildKernel();
Application.Run(kernel.Get<frmMain>());
}
static IKernel BuildKernel()
{
var modules = new INinjectModule[]
{
[..modules]
};
return new StandardKernel(modules);
}
}
Fine. This creates a main form and displays it nicely, passing the appropriate interface implementations to the injected constructor.
Now what? My application is an MDI and will have several child windows for manipulating the application model. I don't have a reference to the kernel anymore, so how am I supposed to Get() these forms? The obvious answer is 'pass the kernel to the form' I suppose, but that's a horribly messy strategy and I'm sure that doesn't fit into the philosophy of DI.
I will point out here that the documentation for Ninject 2 sucks. Everything I can find repeats the basic examples, without really explaining how DI using Ninject makes anything easier. The standard of example given isn't complicated enough to make the trouble of coding and creating modules and bindings worthwhile.
edit #1:
Having studied the links kindly provided by Sam Holder, I'm trying out the 'composition root' approach. My architecture now forces all the Forms it uses to derive from a CompositedForm with constructor semantics thus:
[Inject]
public CompositingForm(ICompositionRoot CompositionRoot)
{
InitializeComponent();
this.CompositionRoot = CompositionRoot;
}
public readonly ICompositionRoot CompositionRoot;
public CompositingForm() : this(new DummyCompositionRoot()) { }
The second constructor is for the benefit of the Forms Designer, which is stupid and can't understand the form markup unless you provide an empty constructor. Now, every form created using IKernel.Get<AForm>() will (should) have a composition root injected into it.
So, as I am a slow learner - now the question is really 'What should go in this composition root'?
can't you pass a factory for creating the child forms to the forms constructor, and the form uses this to get them, then ninject will wire up the factory dependency when the form is created using the get?
I think you should configure everything in the application root using the DI container and after that the container shouldn't be needed, but I've not really used DI containers in anger, and not NInject at all, so am going on what I've read...
This answer may help
Note: I do not know much about Ninject but i worked with Spring.net that is much more complicated. The principles behind sould be something similar.
Sam Holder answer is excellent if you have several objects of one (injected) type to create (for example CustomerOrderItem).
If you just want to wire your mainform i would sugest that your mdi-frmMain constructor gets parameters for every childwindow it should contain and let Ninject create and insert the childwindows. This way there is no need to Reference NInject outside "class Program
". This is called Constructor-Injection.
Alternatively you can add a method to the form that adds a page to you mdi (MethodInjection).
static void Main()
{
[...]
IKernel kernel = BuildKernel();
var main = kernel.Get<frmMain>();
main.AddClientForm(kernel.Get<CustomerForm>()) ;
main.AddClientForm(kernel.Get<InvoiceForm>()) ;
Application.Run(main);
}
Thanks to João Almeida and Kellabyte I have found a method that is more or less satisfactory:
Define a custom Attribute which exposes whatever business rules you care about;
Define an implementation of IInjectionHeuristic which recognises this attribute;
Use a ViewModelLocator to load modules into the ninject kernel.
In this stackoverflow question I learned that Prism/Unity is not as decoupled as I thought, e.g. if I have this class which gets menuManager injected into its constructor, then I have to make sure that this class actually exists somewhere (I thought that you could just pull the .dll that contains the class and the container would deal with it, e.g. injecting a null in its place):
public class EmployeesPresenter
{
public EmployeesPresenter(IMenuManager menuManager)
{
}
}
But I can deal with that: the application cannot run without a MenuModule (or else as was suggested I could have a NullMenuModule which does nothing but keeps the application from breaking).
However, the application I am building will have a MenuManager class in the MenuModule and every module will have to register everything it wants to have in the menu with the MenuManager. However, I want to be able to swap out MenuModules e.g. have a InfragisticsMenuModule and have a TelerikMenuModule, etc.
However, when I am in e.g. the CustomersModule, in order to use TelerikMenuModule, I need to reference it. And when I want to use InfragisticsMenuModule, I need to reference that.
So how will I be able to "hot swap" TelerikMenuModule with InfragisticsMenuModule without recompiling all my modules with new references, e.g. I want to replace this:
Application.exe
Customers.dll
TelerikMenuModule.dll
with this:
Application.exe
Customers.dll
InfragisticsMenuModule.dll
and simply be able to restart the application and it runs with the new InfragisticsMenuModule.dll and does not complain that TelerikMenuModule.dll no longer exists.
This is where interfaces come in. You need something like:
public interface IMenuSystem
{
// whatever operations need to be offered by a menu system
}
Application.exe and Customers.dll may only refer to that interface. They aren't allow to know about a specific implementation.
Then you would use configuration steps (calling Register... methods or using a config file) to specify which type will provide the implementation of MenuSystem.
For obvious reason MEF comes to mind here and is designed for stuffs like this. I haven't had a chance to use Unity, so I'm not sure if it has something built in like this (i.e. scanning a directory for an IMenuModule implementation), but MEF can do this.
Suggestion also is to put this IMenuModule in a common assembly (separate from your other assembly). I usually called this thing Something.Core.dll.
So you might have: Application.exe, Customer.dll, Application.Core.dll, and your specific MenuModule implementation.
Your specific MenuModule implementation will reference the Application.Core assembly to gain access to its IMenuModule interface and implement it there.