Code reorganization related to MediatR infrastructure

This commit is contained in:
Anton Kasyanov
2018-02-18 17:17:52 +02:00
parent 7b5858287a
commit 59f4e193d6
29 changed files with 182 additions and 180 deletions

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace EveOPreview
{
@@ -8,11 +10,17 @@ namespace EveOPreview
/// </summary>
public interface IIocContainer
{
void Register<TService, TImplementation>() where TImplementation : TService;
void Register<TService, TImplementation>()
where TImplementation : TService;
void Register(Type serviceType, Assembly container);
void Register<TService>();
void RegisterInstance<T>(T instance);
TService Resolve<TService>();
bool IsRegistered<TService>();
void Register<TService>(Expression<Func<TService>> factory);
void Register<TService, TArgument>(Expression<Func<TArgument, TService>> factory);
void RegisterInstance<TService>(TService instance);
TService Resolve<TService>();
IEnumerable<TService> ResolveAll<TService>();
object Resolve(Type serviceType);
IEnumerable<object> ResolveAll(Type serviceType);
bool IsRegistered<TService>();
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using LightInject;
namespace EveOPreview
@@ -19,31 +21,38 @@ namespace EveOPreview
return this._container.CanGetInstance(typeof(TService), "");
}
public void Register<TService>()
public void Register(Type serviceType, Assembly container)
{
if (!typeof(TService).IsInterface)
if (!serviceType.IsInterface)
{
this._container.Register<TService>(new PerContainerLifetime());
this._container.Register(serviceType, new PerContainerLifetime());
return;
}
foreach (Type implementationType in typeof(TService).Assembly.DefinedTypes)
if (serviceType.IsInterface && serviceType.IsGenericType)
{
this._container.RegisterAssembly(container, (st, it) => st.IsConstructedGenericType && st.GetGenericTypeDefinition() == serviceType);
}
else
{
foreach (TypeInfo implementationType in container.DefinedTypes)
{
if (!implementationType.IsClass || implementationType.IsAbstract)
{
continue;
}
if (!typeof(TService).IsAssignableFrom(implementationType))
if (serviceType.IsAssignableFrom(implementationType))
{
continue;
this._container.Register(serviceType, implementationType, new PerContainerLifetime());
}
}
}
}
this._container.Register(typeof(TService), implementationType, new PerContainerLifetime());
break;
}
public void Register<TService>()
{
this.Register(typeof(TService), typeof(TService).Assembly);
}
public void Register<TService, TImplementation>()
@@ -52,12 +61,17 @@ namespace EveOPreview
this._container.Register<TService, TImplementation>(new PerContainerLifetime());
}
public void Register<TService>(Expression<Func<TService>> factory)
{
this._container.Register(f => factory);
}
public void Register<TService, TArgument>(Expression<Func<TArgument, TService>> factory)
{
this._container.Register(f => factory);
}
public void RegisterInstance<T>(T instance)
public void RegisterInstance<TService>(TService instance)
{
this._container.RegisterInstance(instance);
}
@@ -66,5 +80,20 @@ namespace EveOPreview
{
return this._container.GetInstance<TService>();
}
public IEnumerable<TService> ResolveAll<TService>()
{
return this._container.GetAllInstances<TService>();
}
public object Resolve(Type serviceType)
{
return this._container.GetInstance(serviceType);
}
public IEnumerable<object> ResolveAll(Type serviceType)
{
return this._container.GetAllInstances(serviceType);
}
}
}

View File

@@ -10,7 +10,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>EveOPreview</RootNamespace>
<AssemblyName>Eve-O Preview</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<TargetFrameworkProfile />
@@ -83,6 +83,10 @@
<HintPath>..\packages\LightInject.5.1.2\lib\net452\LightInject.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MediatR, Version=4.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\MediatR.4.0.1\lib\net45\MediatR.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Newtonsoft.Json">
<HintPath>R:\eve-o-preview\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
@@ -110,26 +114,27 @@
<Compile Include="Configuration\IAppConfig.cs" />
<Compile Include="Configuration\IThumbnailConfiguration.cs" />
<Compile Include="Configuration\ZoomAnchor.cs" />
<Compile Include="Mediatr\Handlers\Services\StartServicesHandler.cs" />
<Compile Include="Mediatr\Handlers\Services\StopServicesHandler.cs" />
<Compile Include="Mediatr\Messages\Services\StartServices.cs" />
<Compile Include="Mediatr\Messages\Services\StopServices.cs" />
<Compile Include="Services\Implementation\ProcessInfo.cs" />
<Compile Include="Services\Implementation\ProcessMonitor.cs" />
<Compile Include="Services\Interface\IProcessInfo.cs" />
<Compile Include="Services\Interface\IProcessMonitor.cs" />
<Compile Include="WindowManager\Implementation\DwmThumbnail.cs" />
<Compile Include="WindowManager\Interface\IDwmThumbnail.cs" />
<Compile Include="WindowManager\Interface\InteropConstants.cs" />
<Compile Include="WindowManager\Interop\DWM_BLURBEHIND.cs" />
<Compile Include="WindowManager\Interop\DWM_THUMBNAIL_PROPERTIES.cs" />
<Compile Include="WindowManager\Interop\DWM_TNP_CONSTANTS.cs" />
<Compile Include="WindowManager\Interface\IWindowManager.cs" />
<Compile Include="WindowManager\Interop\MARGINS.cs" />
<Compile Include="WindowManager\Interop\RECT.cs" />
<Compile Include="Services\Implementation\DwmThumbnail.cs" />
<Compile Include="Services\Interface\IDwmThumbnail.cs" />
<Compile Include="Services\Interface\InteropConstants.cs" />
<Compile Include="Services\Interop\DWM_BLURBEHIND.cs" />
<Compile Include="Services\Interop\DWM_THUMBNAIL_PROPERTIES.cs" />
<Compile Include="Services\Interop\DWM_TNP_CONSTANTS.cs" />
<Compile Include="Services\Interface\IWindowManager.cs" />
<Compile Include="Services\Interop\MARGINS.cs" />
<Compile Include="Services\Interop\RECT.cs" />
<Compile Include="Configuration\ClientLayout.cs" />
<Compile Include="ApplicationBase\IPresenter.cs" />
<Compile Include="WindowManager\Implementation\WindowManager.cs" />
<Compile Include="WindowManager\Interop\User32NativeMethods.cs" />
<Compile Include="Mediator\Implementation\Mediator.cs" />
<Compile Include="Mediator\Interface\IMediator.cs" />
<Compile Include="Mediator\Interface\INotification.cs" />
<Compile Include="Services\Implementation\WindowManager.cs" />
<Compile Include="Services\Interop\User32NativeMethods.cs" />
<Compile Include="Presentation\MainPresenter.cs" />
<Compile Include="Presentation\ViewCloseRequest.cs" />
<Compile Include="Presentation\ViewZoomAnchorConverter.cs" />
@@ -190,7 +195,7 @@
<Compile Include="UI\Implementation\ThumbnailView.Designer.cs">
<DependentUpon>ThumbnailView.cs</DependentUpon>
</Compile>
<Compile Include="WindowManager\Interop\DwmApiNativeMethods.cs" />
<Compile Include="Services\Interop\DwmApiNativeMethods.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />

View File

@@ -1,90 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
namespace EveOPreview.Mediator.Implementation
{
class Mediator : IMediator
{
#region Private fields
private readonly ReaderWriterLockSlim _lock;
private readonly IDictionary<Type, IList> _handlers;
#endregion
public Mediator()
{
this._lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
this._handlers = new Dictionary<Type, IList>();
}
public void Subscribe<T>(Action<T> handler)
where T : INotification
{
this._lock.EnterWriteLock();
try
{
IList handlers;
if (!this._handlers.TryGetValue(typeof(T), out handlers))
{
handlers = new List<Action<T>>();
this._handlers.Add(typeof(T), handlers);
}
handlers.Add(handler);
}
finally
{
this._lock.ExitWriteLock();
}
}
public void Unsubscribe<T>(Action<T> handler)
where T : INotification
{
this._lock.EnterWriteLock();
try
{
this._handlers.TryGetValue(typeof(T), out var handlers);
handlers?.Remove(handler);
}
finally
{
this._lock.ExitWriteLock();
}
}
public void Publish<T>(T notification)
where T : INotification
{
// Empty notifications are silently swallowed
if (notification.IsEmpty())
{
return;
}
IList<Action<T>> handlers;
this._lock.EnterReadLock();
try
{
if (!this._handlers.TryGetValue(typeof(T), out var untypedHandlers))
{
return;
}
// Clone the list to minimize lock time
// and possible deadlock issues (f.e. one of subscribers could raise an event ar add/remove subsctibers etc)
handlers = new List<Action<T>>((IList<Action<T>>)untypedHandlers);
}
finally
{
this._lock.ExitReadLock();
}
foreach (var handler in handlers)
{
handler.Invoke(notification);
}
}
}
}

View File

@@ -1,20 +0,0 @@
using System;
namespace EveOPreview.Mediator
{
/// <summary>
/// Message dispatcher.
/// Consider this as a very simple message bus
/// </summary>
public interface IMediator
{
void Subscribe<T>(Action<T> handler)
where T : INotification;
void Unsubscribe<T>(Action<T> handler)
where T : INotification;
void Publish<T>(T notification)
where T : INotification;
}
}

View File

@@ -1,10 +0,0 @@
namespace EveOPreview.Mediator
{
/// <summary>
/// Base class for all Mediator notifications
/// </summary>
public interface INotification
{
bool IsEmpty();
}
}

View File

@@ -0,0 +1,25 @@
using System.Threading;
using System.Threading.Tasks;
using EveOPreview.Mediator.Messages;
using EveOPreview.UI;
using MediatR;
namespace EveOPreview.Mediator.Handlers
{
sealed class StartServicesHandler : INotificationHandler<StartServices>
{
private readonly IThumbnailManager _manager;
public StartServicesHandler(IThumbnailManager manager)
{
this._manager = manager;
}
public Task Handle(StartServices message, CancellationToken cancellationToken)
{
this._manager.Activate();
return Task.CompletedTask;
}
}
}

View File

@@ -0,0 +1,25 @@
using System.Threading;
using System.Threading.Tasks;
using EveOPreview.Mediator.Messages;
using EveOPreview.UI;
using MediatR;
namespace EveOPreview.Mediator.Handlers
{
sealed class StopServicesHandler : INotificationHandler<StopServices>
{
private readonly IThumbnailManager _manager;
public StopServicesHandler(IThumbnailManager manager)
{
this._manager = manager;
}
public Task Handle(StopServices message, CancellationToken cancellationToken)
{
this._manager.Deactivate();
return Task.CompletedTask;
}
}
}

View File

@@ -0,0 +1,8 @@
using MediatR;
namespace EveOPreview.Mediator.Messages
{
sealed class StartServices : INotification
{
}
}

View File

@@ -0,0 +1,8 @@
using MediatR;
namespace EveOPreview.Mediator.Messages
{
sealed class StopServices : INotification
{
}
}

View File

@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using EveOPreview.Configuration;
using EveOPreview.Mediator.Messages;
using MediatR;
namespace EveOPreview.UI
{
@@ -13,6 +15,7 @@ namespace EveOPreview.UI
#endregion
#region Private fields
private readonly IMediator _mediator;
private readonly IThumbnailConfiguration _configuration;
private readonly IConfigurationStorage _configurationStorage;
private readonly IThumbnailDescriptionViewFactory _thumbnailDescriptionViewFactory;
@@ -22,10 +25,11 @@ namespace EveOPreview.UI
private bool _exitApplication;
#endregion
public MainPresenter(IApplicationController controller, IMainView view, IThumbnailConfiguration configuration, IConfigurationStorage configurationStorage,
public MainPresenter(IApplicationController controller, IMainView view, IMediator mediator, IThumbnailConfiguration configuration, IConfigurationStorage configurationStorage,
IThumbnailManager thumbnailManager, IThumbnailDescriptionViewFactory thumbnailDescriptionViewFactory)
: base(controller, view)
{
this._mediator = mediator;
this._configuration = configuration;
this._configurationStorage = configurationStorage;
@@ -62,7 +66,7 @@ namespace EveOPreview.UI
this.View.Minimize();
}
this._thumbnailManager.Activate();
this._mediator.Publish(new StartServices());
}
private void Minimize()
@@ -79,6 +83,8 @@ namespace EveOPreview.UI
{
if (this._exitApplication || !this.View.MinimizeToTray)
{
this._mediator.Publish(new StopServices()).Wait();
this._thumbnailManager.Deactivate();
this._configurationStorage.Save();
request.Allow = true;

View File

@@ -3,9 +3,8 @@ using System.Collections.Generic;
using System.Drawing;
using System.Windows.Threading;
using EveOPreview.Configuration;
using EveOPreview.Mediator;
using EveOPreview.Services;
using EveOPreview.WindowManager;
using MediatR;
namespace EveOPreview.UI
{

View File

@@ -2,10 +2,9 @@ using System;
using System.Threading;
using System.Windows.Forms;
using EveOPreview.Configuration;
using EveOPreview.Mediator;
using EveOPreview.Services;
using EveOPreview.UI;
using EveOPreview.WindowManager;
using MediatR;
namespace EveOPreview
{
@@ -74,10 +73,17 @@ namespace EveOPreview
// Singleton registration is used for services
// Low-level services
container.Register<IMediator>();
container.Register<IWindowManager>();
container.Register<IProcessMonitor>();
// MediatR
container.Register<IMediator, MediatR.Mediator>();
container.RegisterInstance<SingleInstanceFactory>(t => container.Resolve(t));
container.RegisterInstance<MultiInstanceFactory>(t => container.ResolveAll(t));
container.Register(typeof(INotificationHandler<>), typeof(Program).Assembly);
container.Register(typeof(IRequestHandler<>), typeof(Program).Assembly);
container.Register(typeof(IRequestHandler<,>), typeof(Program).Assembly);
// Configuration services
container.Register<IConfigurationStorage>();
container.Register<IAppConfig>();

View File

@@ -1,6 +1,7 @@
using System;
using EveOPreview.Services.Interop;
namespace EveOPreview.WindowManager.Implementation
namespace EveOPreview.Services.Implementation
{
class DwmThumbnail : IDwmThumbnail
{

View File

@@ -1,6 +1,7 @@
using System;
using EveOPreview.Services.Interop;
namespace EveOPreview.WindowManager.Implementation
namespace EveOPreview.Services.Implementation
{
class WindowManager : IWindowManager
{

View File

@@ -1,6 +1,6 @@
using System;
namespace EveOPreview.WindowManager
namespace EveOPreview.Services
{
public interface IDwmThumbnail
{

View File

@@ -1,6 +1,6 @@
using System;
namespace EveOPreview.WindowManager
namespace EveOPreview.Services
{
public interface IWindowManager
{

View File

@@ -1,6 +1,6 @@
using System;
namespace EveOPreview.WindowManager
namespace EveOPreview.Services
{
public static class InteropConstants
{

View File

@@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
namespace EveOPreview.WindowManager.Implementation
namespace EveOPreview.Services.Interop
{
[StructLayout(LayoutKind.Sequential)]
class DWM_BLURBEHIND

View File

@@ -1,6 +1,6 @@
using System.Runtime.InteropServices;
namespace EveOPreview.WindowManager.Implementation
namespace EveOPreview.Services.Interop
{
[StructLayout(LayoutKind.Sequential)]
class DWM_THUMBNAIL_PROPERTIES

View File

@@ -1,4 +1,4 @@
namespace EveOPreview.WindowManager.Implementation
namespace EveOPreview.Services.Interop
{
static class DWM_TNP_CONSTANTS
{

View File

@@ -2,7 +2,7 @@ using System;
using System.Runtime.InteropServices;
using System.Drawing;
namespace EveOPreview.WindowManager.Implementation
namespace EveOPreview.Services.Interop
{
static class DwmApiNativeMethods
{

View File

@@ -1,6 +1,6 @@
using System.Runtime.InteropServices;
namespace EveOPreview.WindowManager.Implementation
namespace EveOPreview.Services.Interop
{
[StructLayout(LayoutKind.Sequential)]
class MARGINS

View File

@@ -1,6 +1,6 @@
using System.Runtime.InteropServices;
namespace EveOPreview.WindowManager.Implementation
namespace EveOPreview.Services.Interop
{
[StructLayout(LayoutKind.Sequential)]
struct RECT

View File

@@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
namespace EveOPreview.WindowManager.Implementation
namespace EveOPreview.Services.Interop
{
static class User32NativeMethods
{

View File

@@ -1,6 +1,6 @@
using System;
using System.Windows.Forms;
using EveOPreview.WindowManager;
using EveOPreview.Services;
namespace EveOPreview.UI
{

View File

@@ -2,8 +2,8 @@ using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using EveOPreview.Services;
using EveOPreview.UI.Hotkeys;
using EveOPreview.WindowManager;
namespace EveOPreview.UI
{

View File

@@ -1,3 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/></startup></configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>

View File

@@ -2,6 +2,7 @@
<packages>
<package id="Costura.Fody" version="1.6.2" targetFramework="net46" developmentDependency="true" />
<package id="Fody" version="2.3.23" targetFramework="net452" developmentDependency="true" />
<package id="LightInject" version="5.1.2" targetFramework="net452" />
<package id="LightInject" version="5.1.2" targetFramework="net452" requireReinstallation="true" />
<package id="MediatR" version="4.0.1" targetFramework="net452" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net452" />
</packages>