Chase Florell
Chase Florell

Reputation: 47377

How to overwrite Instances in Autofac and push it down the object graph?

In our mobile app (Xamarin), we register an instance of the current user for use with our Repository (every repository requires an instance of CurrentUser).

When we start the app for the first time, we register the Guest User so that we can create our first records before the actual user logs in or registers.

    public static UserModel GuestUserForRegistration()
    {
        return new UserModel
        {
            Id = Migration001.GuestUserId,
            Email = Migration001.GuestEmail,
            PasswordHash = Migration001.GuestPassword
        };
    }

    _containerBuilder.RegisterInstance(GuestUserForRegistration());

After the app starts up, we have a single entry point where we resolve the MainPage

return Container.Resolve<MainPage>();

It's at this point that the object graph is built, and we use DI for everything (no service location).

After a user signs in / registers for the first time, we call the following method

    public static IContainer Container;

    public static void RegisterCurrentUser(UserModel userModel)
    {
        CurrentUser = userModel;
        var builder = new ContainerBuilder();
        builder.RegisterInstance(userModel);
        builder.Update(Container);
    }

This method is supposed to do two things.

  1. drop the current user into the global static (working)
  2. register the instance of the user into our IoC Container

The problem is that after the user signs in, if I put a break point in my Repository, the resolved user in the constructor is still guest.

Is this because the object graph has been completely built already using the GuestUser, and therefore the Repository has already been built before I ever updated the Container?

If so, is there a way around this?

Upvotes: 1

Views: 1230

Answers (1)

Jim Bolla
Jim Bolla

Reputation: 8295

There's 2 ways you could solve this that don't require your application code to be aware of your container.

The first method, instead replacing the registered instance of UserModel with a new instance, you'd just update the registered instances properties to the new values. This is probably the simplest, if your type is mutable and not overly complex.

This second method would be appropriate if updating the original UserModel instance is undesirable or impossible. Basically, just add a layer of indirection:

// -------------------------
// add this class:
public class Changeable<T>
{
    public T Value { get; set; }
}

// -------------------------
// set up registrations like so:

// register the default value like so
builder.RegisterInstance(
    new Changeable<UserModel>
    {
        Value = new UserModel
            {
                Id = Migration001.GuestUserId,
                Email = Migration001.GuestEmail,
                PasswordHash = Migration001.GuestPassword
            }
     });

// register UserModel directly, which can be used by all the classes that don't
// need to change the instance
builder.Register(c => c.Resolve<Changeable<UserModel>>().Value);

Now your service classes can take a constructor parameter of either Changeable<UserModel> or just UserModel depending on whether they need to be able to change the instance or not, with no more direct reference to the container.

Upvotes: 1

Related Questions