dhq_boiler
@dhq_boiler

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

複数のdllからmethod injectionしたい

解決したいこと

実行ディレクトリの下のpluginsディレクトリの中に、複数のdllが入っています。

これらのdllにはIDropPluginインターフェースを実装したクラスとIModuleインターフェースを実装したクラスが含まれています。

IDropPluginインターフェース

IDropPlugin.cs
using System.Windows;

namespace Sunctum.Plugin
{
    public interface IDropPlugin
    {
        string AcceptableDataFormat { get; }

        void Execute(IDataObject dataObject);
    }
}

プラグイン1(インポート機能を実装)

FolderFilesImpoterModule.cs
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
using Sunctum.Plugin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FolderFilesImporter
{
    public class FolderFilesImporterModule : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.Register<IDropPlugin, FolderFilesImporter>();
        }
    }
}

FolderFilesImporter.cs
using NLog;
using Sunctum.Domain.Logic.Async;
using Sunctum.Domain.Models;
using Sunctum.Domain.Models.Managers;
using Sunctum.Plugin;
using System;
using System.Windows;
using Unity;

namespace FolderFilesImporter
{
    public class FolderFilesImporter : IDropPlugin
    {
        private static readonly Logger s_logger = LogManager.GetCurrentClassLogger();

        public string AcceptableDataFormat => DataFormats.FileDrop;

        [Dependency]
        public IBookImporting BookImportingService { get; set; }

        [Dependency]
        public ITaskManager TaskManager { get; set; }

        public async void Execute(IDataObject dataObject)
        {
            if (dataObject.GetData(DataFormats.FileDrop) is string[] objects && objects.Length > 0)
            {
                try
                {
                    BookImportingService.MasterDirectory = Specifications.MASTER_DIRECTORY;
                    BookImportingService.ObjectPaths = objects;
                    await TaskManager.Enqueue(BookImportingService.GetTaskSequence());
                }
                catch (NullReferenceException e)
                {
                    s_logger.Error(e, "Failed to import.");
                }
                catch (Exception e)
                {
                    s_logger.Error(e, "Failed to import.");
                }
            }
        }
    }
}

プラグイン2(ダミー)

Class1.cs
using Prism.Ioc;
using Prism.Modularity;
using Sunctum.Plugin;
using System;

namespace WpfLibrary1
{
    public class Class1 : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.Register<IDropPlugin, Class2>();
        }
    }
}

Class2.cs
using Sunctum.Plugin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace WpfLibrary1
{
    public class Class2 : IDropPlugin
    {
        public string AcceptableDataFormat => string.Empty;

        public void Execute(IDataObject dataObject)
        {
        }
    }
}

dllを読み込むアプリ側の実装

DocumentViewModelBase.cs


using Homura.Core;
using NLog;
using Prism.Commands;
using Prism.Regions;
using Prism.Services.Dialogs;
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
using Sunctum.Converters;
using Sunctum.Core.Extensions;
using Sunctum.Domain.Extensions;
using Sunctum.Domain.Logic.DisplayType;
using Sunctum.Domain.Logic.Load;
using Sunctum.Domain.Logic.Query;
using Sunctum.Domain.Models;
using Sunctum.Domain.Models.Managers;
using Sunctum.Domain.ViewModels;
using Sunctum.Plugin;
using Sunctum.UI.Controls;
using Sunctum.Views;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using Unity;

namespace Sunctum.ViewModels
{
    public abstract class DocumentViewModelBase : DockElementViewModelBase, IDocumentViewModelBase, IDisposable
    {
        :

        [Dependency]
        public ISelectManager SelectManager { get; set; }

        [Dependency]
        public Lazy<ILibrary> LibraryManager { get; set; }

        [Dependency]
        public Lazy<IMainWindowViewModel> MainWindowViewModel { get; set; }

        :

        #region プロパティ

        [Dependency]
        public IEnumerable<Lazy<IDropPlugin>> DropPlugins { get; set; }

        public DocumentViewModelBase(IDialogService dialogService)
        {
            RegisterCommands();
            :
        }

        private void RegisterCommands()
        {
            :
            DropCommand.Subscribe(args =>
            {
                foreach (var dropPlugin in DropPlugins)
                {
                    dropPlugin.Value.Execute(args.Data);
                }
            })
            .AddTo(disposables);
            :
         }
    }
}

私が実現したいことは、「pluginsディレクトリに入っているIDropPluginインターフェースを実装した複数のdllを読み込んで、DropCommandが発火したらそれら全てのdllの機能を実行したい」のですが、

[Dependency]
        public IEnumerable<Lazy<IDropPlugin>> DropPlugins { get; set; }

上記のIEnumerable>の書き方がまずいのか、それともIContainerRegistry.Resigter()を2回実行しているのがまずいのか、一つのdllしかインジェクトされません。(この場合、WpfLibrary1(ダミーの方)がインジェクトされる)

一つのインターフェースを実装した複数のDLLをロードしてメソッドをインジェクトするいいアイディアはないでしょうか?

該当するソースコード

ブランチ:feature/multiple-dll-injection

自分で試したこと

IEnumerable>ではダメでした。これがダメというより、IContainerRegistry.Register()を2回実行していると、最初に実行した方が上書きされてしまっているような気がします。

0

1Answer

PrismではUnityDrylocの2つのDIコンテナをサポートしているようですが、どちらを使用してます?

というのも、以下のPrismのドキュメントにて、同一インターフェースのResolveをサポートしていると書かれています

ただし注記として、

This feature is only supported in DryIoc at this time.
This may become available to those using Unity Container once version 6 releases.

とあり、どうもUnityではサポートしてなさげっぽいから。

現時点最新版のPrismに同梱されているUnityのバージョンは5.11.11っぽかったのでまだダメそうかな?というお気持ち(試さずテキトーなことほざいていることに注意)

追記
Prism.Container.Extensionsのページ眺めてたらMicrosoft.Extensions.DependencyInjectionもサポートされてるっぽい。まぁこいつでResolveAllできるのかは知らんけど。

あと

Support for this container is proof of concept.
This may still have a number of bugs.
It is not advised to use this for production code at this time.

と不吉なことが書かれているので、まだまだ製品レベルには遠いのかも

1Like

Comments

  1. @dhq_boiler

    Questioner

    回答ありがとうございます。
    使用しているのはUnityの方です。
    Unityのバージョンは8.1.97です。
    なるほど、DryIocか。

    以下のissueはこの記事の状況にマッチしていますが、対応しない方針を採ったようですね。
    [Enhancement] ResolveAll the instances of a registered type in the IContainerProvider
    https://github.com/PrismLibrary/Prism/issues/2032

Your answer might help someone💌