Azure / azure-cosmos-dotnet-v2

Contains samples and utilities relating to the Azure Cosmos DB .NET SDK
MIT License
577 stars 838 forks source link

Provide DocumentClient constructor for a connection string #203

Open ghost opened 7 years ago

ghost commented 7 years ago

The DocumentDB SDK does not provide a DocumentClient constructor that simply takes a connection string like other Azure SDKs, e.g. the Azure Storage SDK. It would be really nice to just store a connection string in the application settings or an environment variable and use that to instantiate a DocumentClient. At the moment you have to parse the endpoint uri and key from that yourself to provide it to the client.

rnagpal commented 7 years ago

@stefan-akelius Please upvote: https://feedback.azure.com/forums/263030-documentdb/suggestions/17777323-connection-string It's a fair ask from the consistency point of view for an Azure service.

We also provide the URI and Keys as separate properties in the Azure portal, so you shouldn't need to parse that and just use it as 2 different properties.

Anyways, I'll add this to our backlog and use the UserVoice one for gauging interest and close this GitHub issue.

ghost commented 7 years ago

Ok, would have liked to help out if the source code was available here. Yes, it does not block any scenario and is mainly desirable from a consistency point of view, but it would be much less of a hassle in some situations like in Azure Functions. Those guys do use the DocumentDB connection string for their binding. Unfortunately for some operations (like delete) you need a DocumentClient. And in that case you either put the url and key into the app settings - which means you have the same credentials in there twice - or you manually parse the connection string and feed that to the DocumentClient yourself. Both not that nice.

rnagpal commented 7 years ago

@stefan-akelius Sounds good. We will get this prioritized.

spelltwister commented 7 years ago

Here is an implementation similar to CloudStorageAccount.

public static class DocumentDbAccount
{
    public static DocumentClient Parse(string connectionString)
    {
        DocumentClient ret;

        if (String.IsNullOrWhiteSpace(connectionString))
        {
            throw new ArgumentException("Connection string cannot be empty.");
        }

        if(ParseImpl(connectionString, out ret, err => { throw new FormatException(err); }))
        {
            return ret;
        }

        throw new ArgumentException($"Connection string was not able to be parsed into a document client.");
    }

    public static bool TryParse(string connectionString, out DocumentClient documentClient)
    {
        if (String.IsNullOrWhiteSpace(connectionString))
        {
            documentClient = null;
            return false;
        }

        try
        {
            return ParseImpl(connectionString, out documentClient, err => { });
        }
        catch (Exception)
        {
            documentClient = null;
            return false;
        }
    }

    private const string AccountEndpointKey = "AccountEndpoint";
    private const string AccountKeyKey = "AccountKey";
    private static readonly HashSet<string> RequireSettings = new HashSet<string>(new [] { AccountEndpointKey, AccountKeyKey }, StringComparer.OrdinalIgnoreCase);

    internal static bool ParseImpl(string connectionString, out DocumentClient documentClient, Action<string> error)
    {
        IDictionary<string, string> settings = ParseStringIntoSettings(connectionString, error);

        if (settings == null)
        {
            documentClient = null;
            return false;
        }

        if (!RequireSettings.IsSubsetOf(settings.Keys))
        {
            documentClient = null;
            return false;
        }

        documentClient = new DocumentClient(new Uri(settings[AccountEndpointKey]), settings[AccountKeyKey]);
        return true;
    }

    /// <summary>
    /// Tokenizes input and stores name value pairs.
    /// </summary>
    /// <param name="connectionString">The string to parse.</param>
    /// <param name="error">Error reporting delegate.</param>
    /// <returns>Tokenized collection.</returns>
    private static IDictionary<string, string> ParseStringIntoSettings(string connectionString, Action<string> error)
    {
        IDictionary<string, string> settings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        string[] splitted = connectionString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

        foreach (string nameValue in splitted)
        {
            string[] splittedNameValue = nameValue.Split(new char[] { '=' }, 2);

            if (splittedNameValue.Length != 2)
            {
                error("Settings must be of the form \"name=value\".");
                return null;
            }

            if (settings.ContainsKey(splittedNameValue[0]))
            {
                error(string.Format(CultureInfo.InvariantCulture, "Duplicate setting '{0}' found.", splittedNameValue[0]));
                return null;
            }

            settings.Add(splittedNameValue[0], splittedNameValue[1]);
        }

        return settings;
    }
}
leftler commented 7 years ago

@rnagpal You have this issue marked as planned here but on on August 29th it was set to Unplanned on the link https://feedback.azure.com/forums/263030-documentdb/suggestions/17777323-connection-string you provided with no comment.

Is this still going to be done? It is a very useful feature and promotes constancy with the connection methods of CloudServiceAccount for blob storage.

The reason I bring this up is I am running in to the exact same issue @ghost brought up, I am using DocumentDb with azure functions but I need to have a trigger run when the upsert is performed. The built in binding for AF does not let you specify what triggers should be enabled on upsert so I have to switch do DocumentClient but that does not let me use the same connection string my other DocumentDB functions are using.

syedhassaanahmed commented 6 years ago

@rnagpal Any update on this issue?

ryancole commented 6 years ago

ping @rnagpal

Jameskmonger commented 5 years ago

@rnagpal any update?

kirankumarkolli commented 5 years ago

@Jameskmonger latest V3 CosmosClient has connection-string constructor. ref: https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-sdk-dotnet-standard Connection string constructor