[OpenStack .NET API]: Is there a way to combine the Object creation and Container creation in one call?

StackOverflow https://stackoverflow.com/questions/18068947

Question

Currently I do this

try
{
    cloudFilesProvider.CreateObjectFromFile(inStrContainerName, inStrSrcFilePath, strDesFileName, 4096, FileMetaData);

}
catch (ItemNotFoundException ex1)
{
     try
     {
         cloudFilesProvider.CreateContainer(inStrContainerName);
         cloudFilesProvider.CreateObjectFromFile(inStrContainerName, inStrSrcFilePath, strDesFileName, 4096, FileMetaData);
     }
     catch(Exception ex2)
     {
         return false;
     }
}

So essentially if the container does not exist then its 3 separate API calls.

Is there a more efficient way to do this?

Was it helpful?

Solution

You can simplify the code by reducing it to the following two lines.

cloudFilesProvider.CreateContainer(inStrContainerName);
cloudFilesProvider.CreateObjectFromFile(inStrContainerName, inStrSrcFilePath, strDesFileName, 4096, FileMetaData);

CreateContainer is safe to call for a container that already exists. It returns ContainerCreated if the container is created, or ContainerExists if the container was not created because it already exists.

PS: The return values (with information like the above) for the IObjectStorageProvider methods will be well documented for release 1.2.0.0.


Edit: To reduce the number of API calls your code makes, you could use a cache class like the following. The CreateIfNecessary method attempts to create the container only if it is not previously known to exist. The ClearCache method provides a manual method for continuing to use the cache even if you delete a container.

This code is currently untested.

public class ContainerManager
{
    private readonly CloudFilesProvider _provider;
    private readonly string _region;
    private readonly bool _useInternalUrl;
    private readonly CloudIdentity _identity;

    private readonly HashSet<string> _containers = new HashSet<string>();

    public ContainerManager(CloudFilesProvider provider, string region, bool useInternalUrl, CloudIdentity identity)
    {
        if (provider == null)
            throw new ArgumentNullException("provider");

        _provider = provider;
        _region = region;
        _useInternalUrl = useInternalUrl;
        _identity = identity;
    }

    /// <summary>
    /// Clears the cache of known containers.
    /// </summary>
    /// <remarks>
    /// <alert class="warning">
    /// If a container was deleted after this cache was in use, this method must be called or
    /// <see cref="CreateIfNecessary(string)"/> could fail to create a container which does not
    /// exist.
    /// </alert>
    /// </remarks>
    public void ClearCache()
    {
        lock (_containers)
        {
            _containers.Clear();
        }
    }

    /// <summary>
    /// Ensures that a container exists in the Cloud Files store.
    /// </summary>
    /// <remarks>
    /// <alert class="warning">
    /// If a container was deleted after this cache was in use, and <see cref="ClearCache()"/>
    /// has not been called, this method could fail to create a container which does not exist.
    /// </alert>
    /// </remarks>
    /// <param name="container">The name of the container to create.</param>
    /// <exception cref="ArgumentNullException">If <paramref name="container"/> is <c>null</c>.</exception>
    /// <exception cref="ArgumentException">If <paramref name="container"/> is empty.</exception>
    /// <returns><c>true</c> if the container was created; otherwise <c>false</c> if the container already existed.</returns>
    public bool CreateIfNecessary(string container)
    {
        if (container == null)
            throw new ArgumentNullException("container");
        if (string.IsNullOrEmpty(container))
            throw new ArgumentException("container cannot be empty");

        // don't try to create the same container multiple times
        if (_containers.Contains(container))
            return false;

        ObjectStore result = _provider.CreateContainer(container, _region, _useInternalUrl, _identity);
        if (result == ObjectStore.ContainerCreated || result == ObjectStore.ContainerExists)
        {
            lock (_containers)
            {
                // add to _containers even if the result is ContainerExists, because that
                // means it simply wasn't known to this cache.
                _containers.Add(container);
            }
        }

        // only return true if the container was actually created
        return result == ObjectStore.ContainerCreated;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top