How to implement Di in WinForms properly - c#

I am building a Winforms app.
I have few Projects
The main project is the winforms project
I have DB project (using EF core) and business project with my services
I am using Ninject for DI injection of the business services. I am initializing the StandartKernel in the main form with all my registered bindings.
So when i open a Form from the Main form i am passing the needed services from the kernel to the constructor of the form.
The problem is when i want to create a form from other form (not the main one)
Example:
From the Main Form i create ClientForm
But i want to add to the client's collection "Cars" a new object so I want to create a Car form directly from the ClientForm. And here is the problem: in the ClientForm i dont have CarService to pass to the new form, i have only ClientService.
What is the best solution to do the DI in such a project?
I am thinking to make all my services static but...
Any other solution?

Well, I was working with something like that these days. I was using the Unity Container to make my DI. The code is not entirely complete and not optimized at all.
If you've seen or used ASP.NET APIs, I tried to play the same operation in a windows forms application.
I used a extension method like below to add all my forms to the Unity Container.
public static void AddForms(this IUnityContainer container, Assembly assembly = null)
{
if (assembly == null) assembly = Assembly.GetCallingAssembly();
foreach (var form in assembly.GetTypes().Where(x => typeof(Form).IsAssignableFrom(x)))
{
var initForm = form.GetCustomAttribute<InitialFormAttribute>();
if (initForm != null)
{
container.RegisterType(typeof(Form), form, "InitialForm", new TransientLifetimeManager());
}
else
{
container.RegisterType(form, new TransientLifetimeManager());
}
}
}
And use some coding to implements the startup just like in ASP.NET. At startup I added the EF Core DbContext to the container, just as I added everything I needed to be able to simply make the Unity Container create the instances of the forms for me, and I always have access to my services within the forms.
If you want to see the full code, comment below.

Related

MVC Page Load instantiate several controllers with shared resources

I have detected, that during loading the main page several controllers are instantiated (I think because the main page is built from several parts). The controllers instantiate the API classes to query some data through them. I was wondering how and where I could share the same API class instance between them.
I can imagine such a code:
class HomeController : Controller
{
private MyApi Api;
public HomeController()
{
this.Api = get the pervious MyApi instance form somewhere
if (this.Api == null) // 1st time
{
this.Api = new MyApi();
put this instance to somewhere to share between controllers
}
This "somewhere" is not a session, because next page load needs another MyApi instance. It must go to an object property which remains intact during the whole page load process, but is dismissed when the html result is generated. It must be really a simple thing, but I really don't know where it is :( Could somebody help me?
You can consider using Microsoft Unity Framework in your application.
Using Unity Dependency Injector you will be able to inject instances of MyApi class into the any controller and avoid writing " if (this.Api == null) " these types of checks and also managing instances of it in some Session or Application level variables, which makes code dirty.
For this specific problem "It must go to an object property which remains intact during the whole page load process, but is dismissed when the html result is generated", You can configure Unity Injected object to have a life time of "Scoped". Meaning, the object will be created once per request.
Here's is a link on configuring Unity in an asp.net core application
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2

Dependency Registrar for other assembly

I have a simple question about dependecy registration.
I'm developing a brand new web application that use Engine Context paradigm with Autofac container. For any library on the solution I have one class implementing IDependencyRegistrar that implement a common Register method, due to add one the container some specific implementation of some interfaces and components.
In this way, a base Core library (running at application startup) provide a RegisterDependencies method that lookup on every Executing Assembly to discover all the DDL's used by the application and registering them on Autofac Container.
The code that provide this behavior is:
builder = new ContainerBuilder();
var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>();
var drInstances = new List<IDependencyRegistrar>();
foreach (var drType in drTypes)
drInstances.Add((IDependencyRegistrar) Activator.CreateInstance(drType));
//sort
drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList();
foreach (var dependencyRegistrar in drInstances)
dependencyRegistrar.Register(builder, typeFinder, config);
builder.Update(container);
Where the FindClassOfType<IDependencyRegistrar> works thanks to a Method implementation like that:
public virtual IList<Assembly> GetAssemblies()
{
var addedAssemblyNames = new List<string>();
var assemblies = new List<Assembly>();
if (LoadAppDomainAssemblies)
AddAssembliesInAppDomain(addedAssemblyNames, assemblies);
AddConfiguredAssemblies(addedAssemblyNames, assemblies);
return assemblies;
}
And, AddAssemblyInAppDomain is:
private void AddAssembliesInAppDomain(List<string> addedAssemblyNames, List<Assembly> assemblies)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (Matches(assembly.FullName))
{
if (!addedAssemblyNames.Contains(assembly.FullName))
{
assemblies.Add(assembly);
addedAssemblyNames.Add(assembly.FullName);
}
}
}
}
The problem is: when I end up on adding in mysolution the MVC project (the front-end), I've referenced on it only direct accessing library (service layer and some infrastructure components) but no DataLayer components and some other DLL. Due to the fact that MVC not referencing directly some libraries of deep layers, my Engine Context doesn't see the others sub-components and not registering them on the Autofac container, causing a
'no registered services'
exception when execution make explicit request on them.
The whole system just works if I add reference to any library from the MVC project but, for layered architectured application, this is not a best practice: my MVC need to know nothing about DataLayer or others low-layered services.
However, in this way, no ExecutingAssembly are discovered, so, not dependency are registered anymore.
Wich is the best approch to resolve this situation without referencing all assemblies directly from main MVC project?
What you are trying to do is described in Autofac documentation as Assembly Scanning, take a look here. Basically, to get all assemblies in IIS-hosted application you need this piece of code:
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();
EDIT:
Ok, so I understand the situation is like this:
Project Web is a MVC web app.
Project Model is a class library where you have your contracts (interfaces) defined, e.g. for DAL, but also for Web.
Project DAL contains some implementations of contracts from Model.
There might be some additional class libraries, but they all uses Model for contracts.
So to sum up - all projects have reference to Model, but they have no references to each other.
I think for every library (except Model) you should create a module. To do so, create a class implementing Module type from Autofac library and override Load method - put all your module registration in there. Then, in Web app start you should load all assemblies and register their modules. But, as you mentioned, assemblies other than Web are not present in bin directory; you should copy them there "manually", for example in Post-Build action (Project Properties -> Build Events -> Post-Build action). The following command should do the work:
xcopy /Y "$(TargetDir)*.dll" "$(ProjectDir)..\{Your Web App}\bin"
Also, in your solution properties you should set, that Web project "depends" on all other projects. It would assure all other libraries would be build before Web. It does not add any reference between these assemblies.
Then, during application startup, you should search for you assemblies in bin folder and register each assembly module, like this:
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterControllers(typeof(MvcApplication).Assembly);
var libFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/bin"));
var libFiles = libFolder.GetFiles("*.dll", SearchOption.AllDirectories);
foreach (var lib in libFiles)
{
var asm = Assembly.LoadFrom(lib.FullName);
containerBuilder.RegisterAssemblyModules(asm);
}
var container = containerBuilder.Build();
You might want to add some filter to libFolder.GetFiles() to retreive only your assemblies, not all from bin.
If your other assemblies contains Mvc Controllers, you should take a look how to manage the situation here (see Initializer class). Basically, in pre-start of application you would need to add assemblies to BuildManager. Otherwise, the code above should work just fine.
If you are working on a non-web project then my answer might help?
To your Ioc class add a method i.e:
public static void SetIocForTesting(bool forUnitTesting)
{
_testContext = forUnitTesting;
}
Sample container set-up code, delegate out the responsibility of getting the assemblies to load into the builder. i.e GetModules():
public static IContainer Container
{
get
{
if (_container != null)
{
return _container;
}
var builder = new ContainerBuilder();
foreach (var lib in GetModules())
{
builder.RegisterAssemblyModules(lib);
}
_container = builder.Build();
return _container;
}
}
When scanning for Assemblies, switch on the testContext variable:
private static IEnumerable<Assembly> GetModules()
{
if (_testContext)
{
return AppDomain.CurrentDomain.GetAssemblies();
}
var currentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if (currentPath == null)
{
throw new NullReferenceException("Unable to build the container because currentPath variable is null.");
}
// XXXX = assign a wild card
var libFolder = new DirectoryInfo(currentPath);
var libFiles = libFolder.GetFiles("XXXX.*.dll", SearchOption.TopDirectoryOnly);
return libFiles.Select(lib => Assembly.LoadFrom(lib.FullName)).ToList();
}
When unit testing your IoC provider and a registration:
protected virtual void GivenThat()
{
IocProvider.SetIocForTesting(true);
}
.. you have a method that switches the IoC to ensure it works correctly with all assemblies referenced and loaded by your test project. The above method lives inside an abstract base class I use for BDD style unit testing.
Your test project usually ends up referencing a lot of assemblies which means resolving services have a higher success rate.
Finally, for non UnitTesting code add a static constructor:
static IocProvider()
{
_testContext = false;
}
This will ensure a default work flow for production code.
Feel free to play with the above format to suit your needs; I hope it helps someone in the way the above question and answer helped me.

WPF Prism User Object

I am new to WPF and MVVM Prism. I have been an ASP.NET developer for more than 5 years and recently switched to a WPF project.
I am currently using Prism 5.0 with Unity. The main purpose of following the pattern is to implement modularity and loose coupling.
My question is this: I would like to make my User Object universal and accessible across all modules.
This is what I've done so far. Upon start up, users are greeted with a login screen (LoginView.xaml) in Login project. LoginViewModel will then validate credentials. Upon successful validation, LoginViewModel will then pass this retrieved object to a static class in Infrastructure project. Since user login is only single / universal instance, I have created a static class under Infrastructure project to hold the user object.
I have tried GenericPrincipal, while it does persist data across views, it's not sophisticated enough to hold data that I need. Hence I went for static class instead.
Does anyone have a better suggestion around it?
Instead of registering your User object in a static class, I suggest you to register the User instance in the Unity container itself.
In your LoginViewModel, you should get an instance of your IUnityContainer class.
public LoginViewModel(IUnityContainer container)
{
Container = container;
}
In your Login method, you register your user object:
private void Login(object obj)
{
...
if (user.Authenticated)
{
Container.RegisterInstance("CurrentUser", user);
}
...
}
To access your object, you use the following code snippet:
Container.Resolve<YourUserClassHere>("CurrentUser");
For more details see:
Persisting user credentials in WPF w/Unity and MVVM

A simple IoC container for a a small plugin system

I am designing a simple plugin framework a for a .NET 3.5 application (WinForms).
Our current application needs to start supporting dynamic loading and "hooking" of different "plugins" / "extensions" that are unknown to the application at compile time.
These extensions would be "hooked" into different areas of the application, such as aded as event handlers of certain classes.
For example (simplified):
public class SomeSystem
{
public event Action<string> Completed;
public event Action<string> Failed;
public event Action<string> Stopped;
}
One use case I'd like to have is for developers to be able to define handlers for such events in a plugin assembly, without having the application know about them.
From my knowledge, IoC containers allow dynamically discovering objects at runtime and registering them in a container.
Is an IoC container able to also do this hooking into various events for me? Or is this task easier to do without such a framework?
How does one go about designing how to integrate an IoC container for such a task? (suppose that there are multiple extension points, such as different events that can be used to register on).
Some questions i found myself asking :
Is it common that the plugin itself offer a Register method to do the registration?
Should the IoC do the registration? (how is that usually done?)
How can extension points be easily defined when using an IoC container ?
You probably want to look at MEF. It allows all of the things you have asked about. The terminology it uses (ComposableParts, Exports, etc) is initially confusing, but it's very straightforward to use.
Is it common that the plugin itself offer a Register method to do the
registration?
MEF makes the application do the work of finding and registering plugins. The plugin only needs to implement an interface that states "I am a plugin that can do X".
Should the IoC do the registration? (how is that usually done?)
An application that will consume MEF plugins is able to specify how it will load the plugins. This could be by searching a directory for DLLs, reading the configuration file for a list of assembly names, checking the GAC - anything at all. It's totally extensible (in that you can write your own search classes)
How can extension points be easily defined when using an IoC container
?
MEF uses interfaces to define a Contract between the application and plugin.
This answer will be specific to my container.
Our current application needs to start supporting dynamic loading and "hooking" of different "plugins" / "extensions" that are unknown to the application at compile time.
To be able to do that you have to define some extension interfaces which you place in a class library which will be shared between your application and all of your plugins.
For instance, if you would like your applications to be able to add stuff to the application menu you could create the following interface:
class ApplicationMenu
{
// The "File" menu
IMenuItem File { get; }
}
interface IMenuRegistrar
{
void Register(ApplicationMenu menu);
}
Which means that your plugin can create the following class:
[Component]
public class CoolPluginMenuRegistrar : IMenuRegistrar
{
public void Register(ApplicationMenu menu)
{
menu.File.Add("mnuMyPluginMenuName", "Load jokes");
}
}
The [Component] attribute is used by my container so that it can discover and automatically register classes for you.
All you need to do to register all extension points like the one above is this:
public class Program
{
public static void Main(string[] args)
{
var registrar = new ContainerRegistrar();
registrar.RegisterComponents(Lifetime.Transient, Environment.CurrentDirectory, "MyApp.Plugin.*.dll");
var container = registrar.Build();
// all extension points have been loaded. To load all menu extensions simply do something like:
var menu = GetMainMenu();
foreach (var registrar in container.ResolveAll<IMenuRegistrar>())
{
registrar.Register(menu);
}
}
}
These extensions would be "hooked" into different areas of the application, such as aded as event handlers of certain classes. From my knowledge, IoC containers allow dynamically discovering objects at runtime and registering them in a container.
Yep. You get all of that.
Is an IoC container able to also do this hooking into various events for me? Or is this task easier to do without such a framework?
Yes. I got a built in event mechanism. Put the event classes (regular .NET classes in shared class librararies). The simply subscribe on them by implementing an interface:
[Component]
public class ReplyEmailNotification : ISubscriberOf<ReplyPosted>
{
ISmtpClient _client;
IUserQueries _userQueries;
public ReplyEmailNotification(ISmtpClient client, IUserQueries userQueries)
{
_client = client;
_userQueries = userQueries;
}
public void Invoke(ReplyPosted e)
{
var user = _userQueries.Get(e.PosterId);
_client.Send(new MailMessage(user.Email, "bla bla"));
}
}
And to publish events:
DomainEvent.Publish(new ReplyPosted(user.Id, "This is a subject"));
The events can be handled by any plugin as long as they:
Can access the event class
Have been registered in the container ([Component] or manual registration)
Implements ISubscriberOf<T>
Is it common that the plugin itself offer a Register method to do the registration?
Yep. Through different interfaces which are defines as extension points in a shared assembly.
Should the IoC do the registration? (how is that usually done?)
Yes. If the container provides it.
How can extension points be easily defined when using an IoC container ?
You can read about it in more detail here: http://www.codeproject.com/Articles/440665/Having-fun-with-Griffin-Container

Instantiating a class dynamically c#

I am working on developing a plug and play framework in ASP.Net MVC whereby I can define modules as separate projects from the Main project. So, a developer can create as many modules as they want.
What I need is that to be able to update settings of any of such modules. For that, in the main project, I defined a base class for some common settings plus each module has its own custom settings. When there is any edit on a module, I have to instantiate instance of that module in the main project. But, main project has no knowledge of any modules.
How do I achieve this?
Thanks!
You can use dependency injection and inject those modules to your application at composition root. As per configuration you can use code or xml (configuration file). You can do auto wiring, late binding etc depending on what you really need.
You can also have initializers at each module so whenever you register a module, it should initialize your registered modules and inject dependencies etc.
Depending on your need, you would have to create a solution that relies on interfaces.
Essentially, the application exposes an API dll with an interface called IModule. IModule has one method called Run(). Your main application will load up the module's assembly, look for something that implements IModule, makes one of those objects and calls Run() on it.
Here is an old article describing how to host a sandbox to run modules inside.
http://msdn.microsoft.com/en-us/magazine/cc163701.aspx
namespace MyApplication.Api
{
public interface IModule
{
void Run();
}
}
The developer would create something like this
public class MyObject : MarshalByRefObject, IModule
{
public void Run()
{
// do something here
}
}
The application will load it up with some kind of Reflection.
public void LoadModule()
{
var asm = System.Reflection.Assembly.Load(/* Get the developer module name from somewhere*/);
var types = asm.GetExportedTypes();
foreach(var t in types)
{
foreach(var i = t.GetInterfaces())
{
if(i == typeof(IModule))
{
var iModule = System.Activator.CreateInstance(t);
iModule.Run();
}
}
}
}
It would be best if you run the code in another appDomain, but it adds a lot of complexity.
public void LoadModuleInAppDomain()
{
// Spin up a new AppDomain
// Load the assembly into the app domain
// Get the object
// Call the Run Method
}

Categories