Правильно ли я регистрирую ObjectContext с помощью AutoFac?

У меня есть служба Windows, и я хочу убедиться, что мой EF ObjectContext удаляется между каждым запуском. Служба работает дольше каждый раз, когда она выполняется. Кажется, что ObjectContext продолжает расти. Должен ли мой ObjectContext быть зарегистрирован по-другому или я делаю что-то не так?

Обзор того, чем я занимаюсь.

  • Я использую Quartz.NET для планирования службы.
  • Я использую Atlas для настройки службы Windows.
  • Я использую Autofac в качестве IoC.
  • Я использую Entity Framework в качестве модели данных

Прохождение кода:

  • Итак, программа начинается с регистрации службы с помощью Atlas.
  • Atlas зарегистрирует мои регистрации autofac, которые находятся в модуле MyModule.
  • MyModule регистрирует ObjectContext в InstancePerLifetimeScope (правильная ли это область?), затем он будет иметь один экземпляр моего пользовательского UnitOfWork в качестве InstancePerLifetimeScope (это правильная область?).
  • MyService размещается в Atlas, который получает планировщик Quartz и свойство AutofacJobListener и планирует выполнение задания (MyJob) каждые 5 минут при запуске службы.
  • MyJob, который получает экземпляр свойства ObjectContext, внедренный в него из AutofacJobListener. Эта работа обращается к базе данных и дает мне мои вещи.

Когда задание запускается, оно вызывает и получает мои данные каждый раз, когда оно запускается, это занимает больше времени (пример: 2 минуты при первом запуске, 4 минуты при втором запуске службы, 6 минут при следующем, 8 при следующем и так далее) . Кажется, что мой ObjectContext с каждым разом становится все больше и больше. Данные, которые он извлекает, не изменились, осталось то же количество строк и столбцов. Итак, я думаю, что мои регистрации неверны, так ли это? Если нет, видите ли вы проблему в том, что я делаю?

Программа

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main(string[] args)
    {
        var configuration =
            Host.Configure<MyService>(c =>
            {
                c.AllowMultipleInstances();
                c.WithRegistrations(b => b.RegisterModule(new MyModule()));
            }, args);
        Host.Start(configuration);
    }
}

Модуль

public class MyModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        LoadQuartz(builder);
        LoadServices(builder);

        LoadInfrastructure(builder);
    }

    private void LoadInfrastructure(ContainerBuilder builder)
    {
        builder.Register(c => new ObjectContext())
                .As<IObjectContext>()
                .InstancePerLifetimeScope();

        builder.Register(c => new UnitOfWork(c.Resolve<IObjectContext>()))
            .As<ISession>().As<IObjectContextProvider>()
            .InstancePerLifetimeScope();
    }

    private void LoadQuartz(ContainerBuilder builder)
    {
        builder.Register(c => new StdSchedulerFactory().GetScheduler()).As<IScheduler>().InstancePerLifetimeScope();
        builder.Register(c => new AutofacJobListener(c)).As<IJobListener>();
    }

    private void LoadServices(ContainerBuilder builder)
    {
        builder.RegisterType<MyService>().As<IAmAHostedProcess>().PropertiesAutowired();
    }
}

Прослушиватель AutofacJobListener

public class AutofacJobListener : IJobListener
{
    private readonly IComponentContext _container;

    public AutofacJobListener(IComponentContext container)
    {
        _container = container;
    }

    public void JobToBeExecuted(JobExecutionContext context)
    {
        _container.InjectUnsetProperties(context.JobInstance);
    }

    public void JobExecutionVetoed(JobExecutionContext context)
    {
        /*noop*/
    }

    public void JobWasExecuted(JobExecutionContext context, JobExecutionException jobException)
    {
        /*noop*/
    }

    public string Name
    {
        get { return "AutofacInjectionJobListener"; }
    }
}

Моя служба

public class MyService : IAmAHostedProcess
{
    public IScheduler Scheduler { get; set; }
    public IJobListener AutofacJobListener { get; set; }

    #region Implementation of IAmAHostedProcess

    public void Start()
    {
        var trigger = TriggerUtils.MakeMinutelyTrigger(5);
        trigger.Name = @"Job Trigger";

        Scheduler.ScheduleJob(new JobDetail("Job", null, typeof(MyJob)), trigger);
        Scheduler.AddGlobalJobListener(AutofacJobListener);
        Scheduler.Start();
    }

    public void Stop()
    {
        Scheduler.Shutdown();
    }

    public void Resume()
    {
    }

    public void Pause()
    {
    }

    #endregion
}

Моя работа

public class MyJob : IJob
{
    public IObjectContext ObjectContext { get; set; }

    public void Execute(JobExecutionContext context)
    {
        var myStuff = ObjectContext.GetIQueryable<Stuff>();
    }
}

person Mark    schedule 16.06.2011    source источник


Ответы (1)


Вы регистрируете его правильно, но вы не используете его в рамках срока службы, поэтому он не будет утилизирован, потому что технически ваш срок службы — это срок службы приложения.

Atlas регистрирует все и запускается в рамках времени жизни приложения, поэтому, если вы разрешаете только экземпляры без создания области жизни, они разрешаются в пределах времени жизни приложения. В приложениях Windows жизненный цикл не определен заранее, как в веб-приложениях, вы должны его определить. В вашем случае вам нужно создать жизненный цикл, связанный с выполнением одного задания.

Создайте LifetimeScope в своем AutofacJobListener при выполнении и удалите его при выполнении. Это приведет к тому, что время жизни всех экземпляров, разрешенных в этой области, то есть ваш ObjectContext, будет существовать только на время этой области, выполнения задания.

Добавьте что-то вроде

_lifetimeScope = container.BeginLifetimeScope();
_lifetimeScope.InjectUnsetProperties(context.JobInstance);

и

_lifetimeScope.Dispose();

в соответствующих методах.

person Adam    schedule 17.06.2011
comment
Спасибо именно то, что я искал, и я действительно сделал шаг вперед и использовал силу Атласа. Я изменил свой AutofacJobListener для передачи в Atlas.ContainerProvider.Instance, а затем использовал BeginLifetimeScope() ContainerProvider. - person Mark; 17.06.2011