[OpenStack .NET API]:有没有办法在一次调用中组合对象创建和容器创建?

时间:2013-08-05 22:35:38

标签: openstack rackspace-cloud rackspace

目前我这样做

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;
     }
}

所以基本上如果容器不存在那么它的3个单独的API调用。

有更有效的方法吗?

1 个答案:

答案 0 :(得分:4)

您可以通过将代码缩减为以下两行来简化代码。

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

CreateContainer可以安全地调用已存在的容器。如果创建了容器,则返回ContainerCreated;如果由于容器已经存在而未创建容器,则返回ContainerExists

PS:版本1.2.0.0中将详细记录IObjectStorageProvider方法的返回值(包含上述信息)。


编辑:要减少代码所做的API调用次数,可以使用如下所示的缓存类。 CreateIfNecessary方法只有在不创建容器时才尝试创建容器以前已知存在。即使删除容器,ClearCache方法也提供了手动方法来继续使用缓存。

此代码目前尚未经过测试。

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;
    }
}