0

インターフェイスを登録し、オブジェクトを解決/インスタンス化するために IoC コンテナー (Unity) を使用しています。

正常に動作しており、インターフェイスに依存するすべてのクラスがコンストラクターに注入されますが、設計上の問題が発生しています。

特定の時間に登録されたデリゲートを呼び出す CronJob サービスがあります。サービス ロケーターによってもインスタンス化されます。

ジョブを登録できるので、インスタンス化されたクラス内からサービス ロケーター Unity コンテナーを参照しています。ジョブを動的に登録できるため、コンパイル時にどのオブジェクトがコンストラクターに渡されるかわからないため、これを行っています。

ただし、私はIoCとユニティに慣れていませんが、サービス内から静的サービスロケーターを参照するのは悪いことだと理解しているため、すべての依存関係をコンストラクターで渡す必要があります-したがって、これを実行できる他の方法について考えていただければ幸いです。この場合、サービス ロケータを参照してもよろしいですか?

ありがとう、

クリス

コードは以下のとおりです。

Unity を使用したサービス ロケーター

// ServiceManager provides service location facilities, logging facilities, and database access via IUnitOfWork interface
public class ServiceManager
{
    private static readonly UnityContainer m_ServicesContainer = new UnityContainer();
    private static readonly ServiceManager m_Manager = new ServiceManager();
    public static ServiceManager Instance { get { return m_Manager; } }
    private ILogger Logger { get { return Resolve<ILogger>(); } }

    public T Resolve<T>()
    {
        return m_ServicesContainer.Resolve<T>();
    }

    private ServiceManager()
    {
        // register the unit of work class first!!
        RegisterType<IUnitOfWork, UnitOfWork>();
        // always register the logger (without logging)
        RegisterType<ILogger, NLogForEntityFrameworkLogger>(true);
        // always register the settings manager (without logging)
        RegisterType<ISettingsService, SettingsService>();
        RegisterType<IPluginManagerService, PluginManagerService>(true);
        RegisterType<ICronJobService, CronJobService>(true);
        RegisterType<IReminderGeneratorService, ReminderGeneratorService>();
        RegisterType<IInvoiceService, InvoiceService>();
    }

    public void RegisterType<TFrom, TTo>(bool isSingleton = false)
    {
         if (isSingleton == false)
            m_ServicesContainer.RegisterType(typeof(TFrom), typeof(TTo));
        else
            m_ServicesContainer.RegisterType(typeof(TFrom), typeof(TTo), new ContainerControlledLifetimeManager());

    }
}

CronJob クラス

public static class CronJobDelegates
{
    public static void SyncRecords(BusinessUnit businessUnit)
    {
        ISynchronisationService syncService = ServiceManager.Instance.Resolve<ISynchronisationService>();
        syncService.Sync(businessUnit);
    }
}

class CronJobService : ServiceBaseWithUnitOfWork, ICronJobService
{
    public CronJobService(IUnitOfWork unitOfWork, ILogger logger, ISettingsService settings)
        : base(unitOfWork, logger)
    {
        m_Settings = settings;
        RegisterCronJob("SyncAccountRecords", CronJobDelegates.SyncRecords,"*1****");
    }

    ISettingsService m_Settings;

    public class RegisteredCronJob
    {
        public RegisteredCronJob(string jobName, EventJobDelegate job)
        {
            JobName = jobName;
            Job = job;
        }

        public string JobName { get; private set; }
        public EventJobDelegate Job { get; private set; }
    }

    static object Lock = new object();

    Dictionary<string, EventJobDelegate> CronJobs = new Dictionary<string, EventJobDelegate>();

    public void RegisterCronJob(string jobName, EventJobDelegate jobCallback, string jobSetting)
    {
        lock(Lock)
        {
            if(CronJobs.ContainsKey(jobName))
            {
                LogMessage("Job '" + jobName + "' already registered", LogLevel.Warn);
                // warning job already registered
            }
            else
            {
                CronJob cronJobRecord = UnitOfWork.CronJobRepository.GetByID(jobName);

                if (cronJobRecord == null)
                {
                    CronJob newCronJob = new CronJob()
                    {
                        JobName = jobName,
                        JobSetting = jobSetting
                    };
                    UnitOfWork.CronJobRepository.Insert(newCronJob);
                }
                else
                    jobSetting = cronJobRecord.JobSetting;

                LogMessage("Job '" + jobName + "' registered using settings: " + jobSetting + ". Next run due on UTC " + NCrontab.CrontabSchedule.Parse(jobSetting).GetNextOccurrence(DateTime.UtcNow), LogLevel.Info);

                CronJobs.Add(jobName, jobCallback);
                UnitOfWork.Save();
            }
        }
    }

    public void ProcessEvents()
    {
        foreach(BusinessUnit businessUnit in UnitOfWork.BusinessUnitRepository.Get())
        {
            foreach (CronJob cronJob in UnitOfWork.CronJobRepository.Get())
            {
                lock(Lock)
                {
                    NCrontab.CrontabSchedule schedule = NCrontab.CrontabSchedule.Parse(cronJob.JobSetting);

                    if (schedule.GetNextOccurrence(cronJob.LastRan) > DateTime.UtcNow.AddHours(businessUnit.GmtOffset))
                    {
                        EventJobDelegate jobDelegate;
                        if (CronJobs.TryGetValue(cronJob.JobName, out jobDelegate) == true )
                        {
                            jobDelegate(businessUnit);
                            cronJob.LastRan = DateTime.UtcNow;
                            UnitOfWork.CronJobRepository.Update(cronJob);
                            LogMessage("Job '" + cronJob.JobName + "' ran, next schedule on " + schedule.GetNextOccurrence(cronJob.LastRan));
                        }
                    }
                }
            }
        }
        UnitOfWork.Save();
    }
}
4

1 に答える 1

1

ファクトリを注入すると、SyncRecords で行ったように、コンテナを呼び出す ISynchronisationService のインスタンスを解決できます。

ファクトリ アプローチの実装例については、いくつかの代替案がリストされているこちらを参照してください。

于 2012-05-21T10:25:33.727 に答える