Mavi Domates
Mavi Domates

Reputation: 4521

AutoFac - Initialize heavy-weight singletons on app_start

Our configuration is, MVC5 C# app, using AutoFac.

We have a number of singletons, which if they're initialized with the first request, causes a bad experience for the user, because their initialization takes around 3-4 seconds in total. We're using AutoFac for Dependency injection, I'm wondering if there's any way of making sure the singletons (or these specific ones) are built on App_Start so we don't lose time when the user sends the first request? If not, what's the best way of solving this problem?

Upvotes: 4

Views: 1980

Answers (2)

n0099
n0099

Reputation: 1363

As the comment of @Travis Illig said, just use .AutoActivate()

container
    .RegisterType<HeavyInitializationService>()
    .As<IMyService>()
    .SingleInstance()
    .AutoActivate();

Upvotes: 0

Steven
Steven

Reputation: 172666

The general solution to this type of problem is to hide such heavy weight objects after a proxy implementation. This way you can trigger the initialization process directly at application startup, while the operation runs in the background without requests to be blocked (unless they require the uninitialized data during their request).

In case your code looks like this:

// The abstraction in question
public interface IMyService
{
    ServiceData GetData();
}

// The heavy implementation
public class HeavyInitializationService : IMyServic {
    public HeavyInitializationService() {
        // Load data here
        Thread.Sleep(3000);
    }
    public ServiceData GetData() => ...
}

A proxy can be created as follows:

public class LazyMyServiceProxy : IMyService {
    private readonly Lazy<IMyService> lazyService;
    public LazyMyServiceProxy(Lazy<IMyService> lazyService) {
        this.lazyService = lazyService;
    }
    public ServiceData GetData() => this.lazyService.Value.GetData();
}

You can use this proxy as follows:

Lazy<IMyService> lazyService = new Lazy<IMyService>(() =>
    new HeavyInitializationService());

container.Register<IMyService>(c => new LazyMyServiceProxy(lazyService))
    .SingleInstance();

// Trigger the creation of the heavy data on a background thread:
Task.Factory.StartNew(() => {
    // Triggers the creation of HeavyInitializationService on background thread.
    var v = lazyService.Value;
});

Upvotes: 3

Related Questions