【问题标题】:Generic Repository Loc通用存储库位置
【发布时间】:2015-08-29 15:35:06
【问题描述】:

我正在学习实体框架并尝试使用工作者模式的通用存储库。使用 Castle Windsor 我通过接口注入所有内容。

但是工作单元属性 InternetRepository 是紧密耦合的:

public interface IUnitOfWork
{
    IGenericRepository<RecordInternetSpeed> InternetSpeedRepository { get; }
    void Save();
}

public class UnitOfWork :IUnitOfWork, IDisposable
{
    private bool disposed = false;
    private InternetSpeedEntities context = new InternetSpeedEntities();

    private IGenericRepository<RecordInternetSpeed> internetSpeedRepository;
    public IGenericRepository<RecordInternetSpeed> InternetSpeedRepository
    {
        get
        {
            if(this.internetSpeedRepository == null)
            {
                this.internetSpeedRepository = new GenericRepository<RecordInternetSpeed>(context);
            }
            return internetSpeedRepository;
        }
    }

    public void Save()
    {
        context.SaveChanges();
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

如何注入此属性以使用接口?下面是IUnitOfWork 的调用方式:

    private Timer timer;
    private ICalculateInternetSpeed internetSpeed;
    private IUnitOfWork unitOfWork;

    public MyRunner(ICalculateInternetSpeed internetSpeed, IUnitOfWork unitOfWork)
    {
        this.internetSpeed = internetSpeed;
        this.unitOfWork = unitOfWork;
    }

    public void Start()
    {
        timer = new Timer
                    {
                        //1000 (1 sec)
                        Interval = 5000,
                        Enabled = true
                    };

        timer.Elapsed += (TimerElapsed);
    }

   public void Stop()
   {

   }

   private void TimerElapsed(object sender, ElapsedEventArgs e)
   {
       try
       {
           timer.Enabled = false;
           //Kick off method to get the download speed
           var speed = internetSpeed.CalculateInternetDownloadSpeed();
           Logger.Logger.Info("Internet Speed calculated.");
           unitOfWork.InternetSpeedRepository.Insert(speed);
           unitOfWork.Save();
           Logger.Logger.Info(string.Format("Inserted record with ID {0} into the database.", speed.RecordId));
       }
       catch (Exception ex)
       {
           Logger.Logger.Error(ex.ToString());
       }
       finally
       {
           timer.Enabled = true;
       }
   }
}

然后在我的程序的主类中调用它:

private static void Main(string[] args)
    {
        container = new WindsorContainer(new XmlInterpreter());
        container.Install(FromAssembly.This());
        var runner = container.Resolve<IMyRunner>();

        HostFactory.Run(x =>
            {
                x.Service<IMyRunner>(s =>
                    {
                        s.SetServiceName(ServiceName);
                        s.ConstructUsing(c => runner);
                        s.WhenStarted(tc => tc.Start());
                        s.WhenStopped(tc =>
                            {
                                tc.Stop();
                                container.Release(runner);
                            });
                    });

                x.RunAsLocalSystem();
                x.SetDescription(ServiceDescription);
                x.SetDisplayName(ServiceDisplayName);
                x.SetServiceName(ServiceName);
                x.StartAutomatically();

            });
    }

我认为需要的最后一个代码 sn-p 是我的安装程序类:

public class Installer : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For<IMyRunner>().ImplementedBy<MyRunner>().LifeStyle.Transient,
                           Component.For<ICalculateInternetSpeed>().ImplementedBy<CalculateInternetSpeed>().LifeStyle.Transient,
                           Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>().LifeStyle.Transient,
                           Component.For<ISimpleWebClient>().ImplementedBy<SimpleWebClient>(),
                           Component.For<IConfig>().ImplementedBy<Config>(),
                           Component.For<IGenericRepository<RecordInternetSpeed>>().ImplementedBy<GenericRepository<RecordInternetSpeed>>());
    }
}

如您所见,我已尝试在此处注入它,但不确定这是否可行。这是进行属性注入的正确方法吗?

【问题讨论】:

    标签: c# castle-windsor


    【解决方案1】:

    首先,请务必同时注册InternetSpeedEntities
    然后,要么接受 IGenericRepository&lt;RecordInternetSpeed&gt; 作为工作单元构造函数中的参数并设置私有字段,要么使用 getter 和 setter 将该属性转换为自动属性,Castle Windsor 将为您完成工作。

    不过还有一些其他注意事项:

    • 尝试习惯于通过约定注册组件(例如,container.Register( Classes.FromThisAssembly() .Pick().WithServiceDefaultInterfaces()
      );
      ) 这样您就不必手动执行所有操作了..
    • 注意组件的生活方式。如果你没有指定一个 - 默认情况下它是一个单例。在容器被处置之前,这些不会被处置。或者,您可以将组件的生活方式绑定到对象图中的父对象类型。

    希望这会有所帮助,祝你好运!

    -编辑-

    作为一个示例,您的UnitOfWork 可能如下所示:

    public class UnitOfWork : IUnitOfWork, IDisposable
    {
        public UnitOfWork(GenericRepository<RecordInternetSpeed> repository, InternetSpeedEntities context)
        {
            this.context = context;
            this.InternetSpeedRepository = repository;
        }
    
        private bool disposed = false;
        private InternetSpeedEntities context;
    
        public IGenericRepository<RecordInternetSpeed> InternetSpeedRepository { get; private set; }
    
        ...
    
    } 
    

    您的安装程序可能看起来像这样:

    public class Installer : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Classes.FromThisAssembly()
                .Pick().WithServiceDefaultInterfaces()
                .LifestyleTransient()
                );
        }
    }  
    

    存储库和上下文是您的UnitOfWork依赖项。只要 windsor 知道如何创建它们,它就会在解析过程中将它们提供给构造函数。

    【讨论】:

    • 感谢您的回复。你有任何我可以参考的代码示例吗?有你的建议吗?
    • 你是指我的笔记还是直接回答你的问题?
    • 你的笔记非常好。我的意思是直接回答这个问题。
    • 我将它放在安装程序文件中,但 unitofwork 将不再工作,因为 LifestyleTransient 每次调用对象时都会创建新实例。我该如何解决这个问题?我通过在安装程序中删除 .LifestyleTransient() 来修复。这有意义吗?
    • 删除.LifestyleTransient等于写.LifestyleSingleton。如果这是您想要的行为,那么是的。但请注意,调用 release 方法不会释放单例对象。它们会在容器的整个生命周期内一直存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-13
    • 2017-06-12
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多