开发者

Am I registering the ObjectContext using AutoFac correctly?

I have a windows service and I want to make sure that my EF ObjectContext is disposed of between each time its runs. The service runs longer each time it executes. It seems like the ObjectContext keeps growing. Should my ObjectContext be registered differently or am I doing something wrong?

A overview of what I'm doing.

  • I'm using Quartz.NET to schedule my service
  • I'm using Atlas to configure and setup my windows service
  • I'm using Autofac as my IoC
  • I'm using Entity Framework as my data model

Walkthru of the code:

  • So the program kicks off by registering the service using Atlas.
  • Atlas will register my autofac registrations which are housed in module MyModule
  • MyModule registers the ObjectContext at InstancePerLifetimeScope (Is this the right scope?), then it will have once instance of my custom UnitOfWork as an InstancePerLifetimeScope (Is this the right scope?).
  • MyService is hosted by Atlas which gets a Quartz scheduler and AutofacJobListener property injected and schedules the job (MyJob) to run every 5 minutes when the service starts.
  • MyJob which gets the instance of the ObjectContext property injected into it from the AutofacJobListener. This job calls out to the database and gets me my stuff.

When the job runs it calls out and gets my stuff every time it runs it takes longer (example: 2 minutes the first time it runs, 4 minutes the second time the service runs, 6 minutes the next, 8 the next and so on). It seems like my ObjectContext is getting larger and larger each time. The data its pulling hasn't changed, still the same number of rows and columns. So I'm thinking my registrations are wrong, is this the case? 开发者_Go百科If not can you see a problem with what I'm doing?

Program

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);
    }
}

Module

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"; }
    }
}

MyService

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
}

My Job

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

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


You are registering it correctly, but you are not using it within a lifetime scope so it will not be disposed of because technically your lifetimescope is the life of the application.

Atlas registers everything and runs in the application's lifetimescope, so if you only resolve instances, without creating a lifetimescope, they are resolved for the scope of the application's lifetime. In windows applications a lifetimescope is not pre-determined for you as it is in web applications, you have to define it. In your case you need to create a lifetimescope surrounding the execution of a single job.

Create a LifetimeScope in your AutofacJobListener on the Executing and dispose of it on Executed. This will force the lifetime of all instances resolved in that scope, i.e. your ObjectContext, to exist only for the duration of that scope, the execution of the job.

Add something like

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

and

_lifetimeScope.Dispose();

in the appropriate methods.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜