Как правильно связать типы по соглашению?

Проекты нацелены на мультиплатформу, поэтому я использую максимум кода в библиотеках классов, чтобы его можно было легко использовать повторно.

Архитектура основана на принципе Model-View-Presenter.

Структура проекта следующая:

Solution
    -> Domain
    -> Domain.Tests
    -> MVP
    -> MVP.Tests
    -> Web
    -> Web.Tests
    -> Windows
    -> Windows.Tests

MVP

Этот проект содержит докладчиков и мнения о проекте. Например:

public interface IApplicationView : IView, IHasUiHandler<IApplicationUiHandler> {
}

public class ApplicationPresenter : Presenter<IApplicationView>
    , IApplicationUiHAndler {
    public ApplicationPresenter(IApplicationView view) : base(view) {
        View.Handler = this;
    }
}

Windows

Этот проект содержит графический интерфейс WPF приложения и так называемый Composition Root. Например:

public class ApplicationWindow : Window, IApplicationView {
}

public class App : Application {
    protected override void OnStartUp(StartupEventArgs e) {
        IKernel kernel = new StandardKernel();
        kernel.Bind(x => x
            .FromThisAssembly()
            .SelectAllClasses().EndingWith("Window")
            .BindAllInterfaces().EndingWith("View") // Here's what I'd like to do.
        );
    }
}

Web

Этот проект содержит страницы графического интерфейса ASP.NET для приложения и так называемый корень композиции.

public class ApplicationPage : Page, IApplicationView {
}

public class MvcApplication : HttpApplication {
    protected override void Application_Start() {
        IKernel kernel = new StandardKernel();
        kernel.Bind(x => x
            .FromThisAssembly()
            .SelectAllClasses().EndingWith("Page")
            .BindAllInterfaces().EndingWith("View") // Here's what I'd like to do.
    }
}

Ну, я думаю, вы поняли...

Я довольно новичок в Dependency Injection, и даже новее в связывании конвенций.

Я хотел бы знать, как настроить привязки, используя соглашения с Ninject.

Есть идеи, как связать эти представления с Windows (WPF) и Pages (Web)?

РЕДАКТИРОВАТЬ

После того, как я попробовал то, что предложил @BatteryBackupUnit, я полагаю, что моя проблема заключается в поиске сборок.

using (var kernel = new StandardKernel()) 
    kernel.Bind(scanner => scanner
        .From(AppDomain.CurrentDomain
            .GetAssemblies()
            .Where(a => (a.FullName.Contains("MyProject.MVP") 
                || a.FullName.Contains("Windows"))
                && !a.FullName.Contains("Tests")))
        .SelectAllClasses()
        .EndingWith("Window")
        .BindSelection((type, baseType) =>
            type.GetInterfaces().Where(iface => iface.Name.EndsWith("View"))));

Как указывалось ранее, View интерфейсы не расположены в той же сборке, что и Window классы. Приведенный выше код, основанный на ответе @ BatteryBackupUnit, прекрасно работает.

1 ответ

Решение

Как насчет этого:

using FluentAssertions;
using Ninject;
using Ninject.Extensions.Conventions;
using System.Linq;
using Xunit;

public interface ISomeView { }
public interface ISomeOtherView { }
public interface INotEndingWithViewWord { }

public class SomePage : ISomeView, ISomeOtherView, INotEndingWithViewWord
{
}

public class Demo
{
    [Fact]
    public void Test()
    {
        using (var kernel = new StandardKernel())
        {
            kernel.Bind(x => x
                .FromThisAssembly()
                .SelectAllClasses()
                .EndingWith("Page")
                .BindSelection((type, baseType) => 
                     type.GetInterfaces()
                     .Where(iface => iface.Name.EndsWith("View"))));

            kernel.Get<ISomeView>().Should().BeOfType<SomePage>();

            kernel.Get<ISomeOtherView>().Should().BeOfType<SomePage>();

            kernel.Invoking(x => x.Get<INotEndingWithViewWord>())
                .ShouldThrow<ActivationException>();
        }
    }
}

Примечание: я использую пакеты nuget

  • Ninject
  • Ninject.Extensions.Conventions
  • xunit.net
  • FluentAssertions

из этих xunit.net и FluentAssertions только для запуска теста и не будут использоваться в производстве.

Или вы могли бы также использовать .BindWith<T : IBindingGenerator> или же .BindUsingRegex(...),

Другие вопросы по тегам