/// <summary>
 /// This method will asynchronously load the <see cref="AsyncResourceFactory{TResource}"/> based on information in this <see cref="ResourceFactoryDynamicCreationFileBasedConfiguration"/>.
 /// </summary>
 /// <typeparam name="TResource">The type of the resources provided by returned <see cref="AsyncResourceFactory{TResource}"/>.</typeparam>
 /// <param name="configuration">This <see cref="ResourceFactoryDynamicCreationFileBasedConfiguration"/>.</param>
 /// <param name="assemblyLoader">The callback to asynchronously load assembly. The parameters are, in this order: package ID, package version, and path within the package.</param>
 /// <param name="token">The <see cref="CancellationToken"/> for this asynchronous operation.</param>
 /// <param name="creationParametersProvider">The optional callback to create creation parameters to bind the returned <see cref="AsyncResourceFactory{TResource}"/> to. Will be result of <see cref="Defaults.CreateDefaultCreationParametersProvider"/> if not provided here.</param>
 /// <returns>Asynchronously returns instance of <see cref="AsyncResourceFactory{TResource}"/>, or throws an exception.</returns>
 /// <exception cref="NullReferenceException">If this <see cref="ResourceFactoryDynamicCreationConfiguration"/> is <c>null.</c></exception>
 /// <exception cref="InvalidOperationException">If for some reason the <see cref="AsyncResourceFactory{TResource}"/> could not be loaded.</exception>
 public static Task <AsyncResourceFactory <TResource> > CreateAsyncResourceFactoryUsingConfiguration <TResource>(
     this ResourceFactoryDynamicCreationFileBasedConfiguration configuration,
     Func <String, String, String, CancellationToken, Task <Assembly> > assemblyLoader,
     CancellationToken token,
     Func <AsyncResourceFactoryProvider, Object> creationParametersProvider = null
     )
 {
     return(configuration.CreateAsyncResourceFactory <TResource>(
                assemblyLoader,
                creationParametersProvider ?? Defaults.CreateDefaultCreationParametersProvider(configuration),
                token
                ));
 }
        /// <summary>
        /// This method creates a callback to first check <see cref="ResourceFactoryDynamicCreationFileBasedConfiguration.PoolConfigurationFileContents"/> and then <see cref="ResourceFactoryDynamicCreationFileBasedConfiguration.PoolConfigurationFilePath"/> in order to load the file as JSON.
        /// This JSON is then used to create a configuration object of type <see cref="AsyncResourceFactoryProvider.DataTypeForCreationParameter"/>.
        /// </summary>
        /// <param name="configuration">The <see cref="ResourceFactoryDynamicCreationFileBasedConfiguration"/>.</param>
        /// <returns>A callback which will create configuration object based on <paramref name="configuration"/> and given <see cref="AsyncResourceFactoryProvider"/>.</returns>
        /// <remarks>
        /// The created callback with throw <see cref="InvalidOperationException"/> if both <see cref="ResourceFactoryDynamicCreationFileBasedConfiguration.PoolConfigurationFileContents"/> and <see cref="ResourceFactoryDynamicCreationFileBasedConfiguration.PoolConfigurationFilePath"/> are <c>null</c> or empty.
        /// </remarks>
        /// <exception cref="ArgumentNullException">If <paramref name="configuration"/> is <c>null</c>.</exception>
        public static Func <AsyncResourceFactoryProvider, Object> CreateDefaultCreationParametersProvider(
            ResourceFactoryDynamicCreationFileBasedConfiguration configuration
            )
        {
            ArgumentValidator.ValidateNotNull(nameof(configuration), configuration);
            return(factoryProvider =>
            {
                var contents = configuration.PoolConfigurationFileContents;
                IFileProvider fileProvider;
                String path;
                if (!String.IsNullOrEmpty(contents))
                {
                    path = StringContentFileProvider.PATH;
                    fileProvider = new StringContentFileProvider(contents);
                }
                else
                {
                    path = configuration.PoolConfigurationFilePath;
                    if (String.IsNullOrEmpty(path))
                    {
                        throw new InvalidOperationException("Configuration file path was not provided.");
                    }
                    else
                    {
                        path = System.IO.Path.GetFullPath(path);
                        fileProvider = null; // Use defaults
                    }
                }


                return new ConfigurationBuilder()
                .AddJsonFile(fileProvider, path, false, false)
                .Build()
                .Get(factoryProvider.DataTypeForCreationParameter);
            });
        }