WinRTContainer after RegisterPerRequest/RegisterSingleton crashes on object retrieval

Topics: Bootstrappers & IoC
Jan 7, 2013 at 12:46 PM
Edited Jan 7, 2013 at 12:50 PM

Hello everyone!

It took me a little while to track this thing down, since the only exception I was getting on startup was 'Windows.UI.Xaml.Controls.FrameNavigationFailed was unhandled'. Anyway, here goes the story.

Let's say I have a custom interface (IDataAccess) and a Windows-Store implementation (StoreDataAccess) I'd like to inject. The important part of the implementation:

 

public class StoreDataAccess : IDataAccess
{
    private readonly StorageFolder storageFolder;

    public StoreDataAccess(StorageFolder folder)
    {
        storageFolder = folder ?? ApplicationData.Current.LocalFolder;
    }

    public StoreDataAccess() : this(null)
    {
    }
}

 

Now the IoC configuration, this one works just fine (per request):

protected override void Configure()
{
    container = new WinRTContainer();
			
container.RegisterHandler(typeof(IDataAccess), null, simpleContainer => new StoreDataAccess()); container.RegisterWinRTServices(); }

and the following gives the error when trying to retrieve the object: System.Exception {System.MissingMethodException} - "No parameterless constructor defined for this object"

container.RegisterPerRequest(typeof(IDataAccess), null, typeof(StoreDataAccess));

The question is - why? RegisterSingleton gives the same error.

Jan 7, 2013 at 3:48 PM
Edited Jan 7, 2013 at 4:00 PM

how are you trying to retrieve?

By using RegisterHandler you circumventing some of the code buildups, same with RegisterSingleton.  I suspect it has something to do with the constructor.  I actually ran a test...

drop the " : this(null) " and you might be surprised...

the compiler even throws you a bone when you forget to include the 1 constructor with a parameter when you have

StorageDataAccess () : this(null)

It then expects a parametered constructor to exist and I am guess the compiler does a check (constructor signatures all match) and then once buildup occurs in the container it goes ape cause it doesn't have the parameter with the declaration in the RegisterXX method that it actually needs to match up to your object in this case a StorageFolder

 

        /// <summary>
        ///   Registers the instance.
        /// </summary>
        /// <param name = "service">The service.</param>
        /// <param name = "key">The key.</param>
        /// <param name = "implementation">The implementation.</param>
        public void RegisterInstance(Type service, string key, object implementation)
        {
            RegisterHandler(service, key, container => implementation);
        }

        /// <summary>
        ///   Registers the class so that a new instance is created on every request.
        /// </summary>
        /// <param name = "service">The service.</param>
        /// <param name = "key">The key.</param>
        /// <param name = "implementation">The implementation.</param>
        public void RegisterPerRequest(Type service, string key, Type implementation)
        {
            RegisterHandler(service, key, container => container.BuildInstance(implementation));
        }

        /// <summary>
        ///   Registers the class so that it is created once, on first request, and the same instance is returned to all requestors thereafter.
        /// </summary>
        /// <param name = "service">The service.</param>
        /// <param name = "key">The key.</param>
        /// <param name = "implementation">The implementation.</param>
        public void RegisterSingleton(Type service, string key, Type implementation)
        {
            object singleton = null;
            RegisterHandler(service, key, container => singleton ?? (singleton = container.BuildInstance(implementation)));
        }

        /// <summary>
        ///   Registers a custom handler for serving requests from the container.
        /// </summary>
        /// <param name = "service">The service.</param>
        /// <param name = "key">The key.</param>
        /// <param name = "handler">The handler.</param>
        public void RegisterHandler(Type service, string key, Func<SimpleContainer, object> handler)
        {
            GetOrCreateEntry(service, key).Add(handler);
        }


those are the signatures for the different Register methods, slight differences but each has its purpose.  Then you have to look how BuildInstance does its thing to get to a working instance/singleton of the object

Jan 8, 2013 at 10:29 AM
Edited Jan 8, 2013 at 10:30 AM

Thanks for the information.

Actually, if I drop the " : this(null) " part, it still crashes when registering by 'RegisterPerRequest' / 'RegisterSingleton'

It works fine though if I use:

container.RegisterInstance(typeof(IDataAccess), null, new StoreDataAccess());

both with 'this(null)' and without, but this construct is essentially the same as

container.RegisterHandler(typeof(IDataAccess), null, simpleContainer => new StoreDataAccess());

as far as I can tell.

I'll just use the 'RegisterInstance' then, at least for now...