Отже, тема доволі цікава, але дотепної інформації про неї обмаль.
В мене є потреба реалізувати програму "Бібліотека". Вирішив вперше, нарешті, побудувати більш-менш правильну архітектуру програми. Зупинився на патерні MVP. Із реалізацією патерну начебто все ясно, але зтикнувся з проблемою як зв'язувати між собою різні елементи цього патерну. Начитавшись ще різної інфи прийшов до висновку, що тут не обітись без IoC контейнеру та принципу DI. Тих контейнерів є багато, але я вибрав Unity, бо він таки дуже поширений судячи зі всього.
Так от, ближче до діла. Зараз у загальних деталях опишу процесс начального етапу розробки проекту.
Для початку, рівень DAL (або Model в даному патерні) реалізується EF і винесений в окрему бібліотеку. Для всіх сутностей створені репозиторії і створений клас, який повинен керувати даними і спілкуватися з презентерами:
▼Прихований текст
public interface ILibraryDataManager
{
//some code...
}
public class LibraryDataManager:ILibraryDataManager
{
//some code...
}
Реалізація примітивна, не варто загострювати на ній увагу ...
Далі в основному солюшні реалізую класи:
MessageService - для можливості виведення повідомлень в будь-якому місці програми
▼Прихований текст
interface IMessageService
{
//some code
}
class MessageService : IMessageService
{
//some code
}
LoginService і MainService - реалізація логіки логіну і основних функцій програми
▼Прихований текст
public interface ILoginService
{
//some code
}
class LoginService : ILoginService
{
private readonly IMessageService messageServise;
private readonly ILibraryDataManager libraryDBManger;
public LoginService(IMessageService messageServise, ILibraryDataManager libraryDataManager)
{
this.messageServise = messageServise;
this.libraryDBManger = libraryDataManager;
}
//some code...
}
public interface IMainService
{
//some code
}
class MainService : IMainService
{
private readonly IMessageService messageService;
private readonly ILibraryDataManager libraryDBManger;
public MainService(ILibraryDataManager libraryDataManager, IMessageService messageService)
{
this.libraryDBManger = libraryDataManager;
this.messageService = messageService;
}
//some code...
}
Далі, відповідно, інтерфейс IView і похідні від нього інтерфейси і класи, які їх реалізують:
▼Прихований текст
public interface IView
{
//some code...
}
public interface ILoginView: IView
{
//some code...
}
public partial class FormLogin : Form, ILoginView
{
//some code...
}
public interface IMainView: IView
{
//some code...
}
public partial class MainForm : Form, IMainView
{
//some code...
}
Тепер реалізуємо сполучну ланку - презентерів:
▼Прихований текст
public interface IPresenter
{
void Run(); // цей метод повинен запускати відповідну форму (IView), передану презентеру в конструкторі
}
class LoginPresenter : IPresenter
{
private readonly ILoginView loginView;
private readonly ILoginService loginService;
private readonly IMessageService messageService;
public LoginPresenter(ILoginView loginView, ILoginService loginService, IMessageService messageService)
{
this.loginView = loginView;
this.loginService = loginService;
this.messageService = messageService;
}
public void Run()
{
loginView.Show();
}
//some code...
}
class MainPresenter : IPresenter
{
private readonly IMainView mainView;
private readonly IMessageService messageService;
private readonly IMainService mainService;
public MainPresenter (IMainView mainView, IMessageService messageService, IMainService mainService)
{
this.mainService = mainService;
this.mainView = mainView;
this.messageService = messageService;
}
public void Run()
{
Application.Run(mainView as Form);
}
І тепер це все щастя потрібно зареєструвати в контейнері і спробувати запустити програму:
▼Прихований текст
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
UnityContainer container = new UnityContainer();
container.RegisterType<ILibraryDataManager, LibraryDataManager>()
.RegisterType<IMessageService, MessageService>()
.RegisterType<ILoginService, LoginService>()
.RegisterType<ILoginView, FormLogin>()
.RegisterType<IMainView, MainForm>();
var obj = container.Resolve<MainPresenter>();
obj.Run();
}
}
З прочитаних статей я так зрозумів, що об'єкти презентерів реєструвати в контейнері не обов'язково, тому спробував запустити додаток таким чином. Проте до рядка obj.Run () виконання не доходить, так як під час виконання попереднього рядка
var obj = container.Resolve<MainPresenter>();
вилітає виключення з таким змістом:
▼Прихований текст
Microsoft.Practices.Unity.ResolutionFailedException was unhandled
HResult=-2146233088
Message=Resolution of the dependency failed, type = "Library.MainPresenter", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, Library.IMainService, is an interface and cannot be constructed. Are you missing a type mapping?
-----------------------------------------------
At the time of the exception, the container was:
Resolving Library.MainPresenter,(none)
Resolving parameter "mainService" of constructor Library.MainPresenter(Library.IMainView mainView, Library.IMessageService messageService, Library.IMainService mainService)
Resolving Library.IMainService,(none)
Як я розумію виходячи з опису помилки під час створення MainPresenter і передачі до нього параметрів UnityContainer намагається створити об'єкт інтерфейсу, що, ясна річ, неможливо. Але я ж додав перед цим зв'язки "Інтерфейс - Клас" в контейнер і, так розумію, Unity повинен створити відповідний об'єкт і потім передати интерфейсне посилання на нього, а виходить зовсім не те.
Загалом, тема, як скрізь пишуть, популярна, а толкової інформації немає. На простеньких примірчиках начебто все більш-менш ясно, а коли справа доходить до власної реалізації, то починається ...
Знаю, форум цей не дуже жвавий, але може хтось є тямущий по цій темі...