1 Востаннє редагувалося Faltfromoss (22.05.2015 01:37:18)

Тема: Використання IoC контейнеру Uinity

Отже, тема доволі цікава, але дотепної інформації про неї обмаль.
В мене є потреба реалізувати програму "Бібліотека". Вирішив вперше, нарешті, побудувати більш-менш правильну архітектуру програми. Зупинився на патерні 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 повинен створити відповідний об'єкт і потім передати интерфейсне посилання на нього, а виходить зовсім не те.

Загалом, тема, як скрізь пишуть, популярна, а толкової інформації немає. На простеньких примірчиках начебто все більш-менш ясно, а коли справа доходить до власної реалізації, то починається ... *WALL*

Знаю, форум цей не дуже жвавий, але може хтось є тямущий по цій темі...

2

Re: Використання IoC контейнеру Uinity

public MainPresenter (IMainView mainView, IMessageService messageService, IMainService mainService)

ви не зарегістрували правило для IMainService mainService можливо через це падає