Skip to content

Commit

Permalink
Remove Uri usage from System.Configuration (Azure#20)
Browse files Browse the repository at this point in the history
* changes to options

* more immutability and ability to set options

* Removed usages of Url from System.Configuration
  • Loading branch information
KrzysztofCwalina authored Dec 17, 2018
1 parent 57f4ffb commit 0694adb
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 64 deletions.
4 changes: 2 additions & 2 deletions Azure.Configuration.Test/ConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public async Task ConfiguringTheClient()
options.Transport = new GetMockTransport(s_testSetting.Key, default, s_testSetting);

var client = new ConfigurationClient(connectionString, options);
Response<ConfigurationSetting> response = await client.GetAsync(key: s_testSetting.Key, filter: default, CancellationToken.None);
Response<ConfigurationSetting> response = await client.GetAsync(key: s_testSetting.Key, filter: null, CancellationToken.None);

response.Dispose();
}
Expand All @@ -68,7 +68,7 @@ public async Task Get()
var transport = new GetMockTransport(s_testSetting.Key, default, s_testSetting);
var (service, pool) = CreateTestService(transport);

Response<ConfigurationSetting> response = await service.GetAsync(key: s_testSetting.Key, filter: default, CancellationToken.None);
Response<ConfigurationSetting> response = await service.GetAsync(key: s_testSetting.Key, filter : default, CancellationToken.None);
Assert.AreEqual(200, response.Status);
Assert.True(response.TryGetHeader("ETag", out string etagHeader));
Assert.AreEqual(response.Result.ETag, etagHeader);
Expand Down
21 changes: 10 additions & 11 deletions Azure.Configuration/ConfigurationClient.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
using Azure.Core;
using Azure.Core.Net;
using Azure.Core.Net.Pipeline;
using System;
using System.Buffers;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -13,6 +10,8 @@
// TODO (pri 1): Support "KeyValue Revisions"
// TODO (pri 1): Support "Real-time Consistency"
// TODO (pri 2): Add retry policy with automatic throttling
// TODO (pri 2): Add support for filters (fields, label, etc.)
// TODO (pri 2): Make sure the whole object gets deserialized/serialized.
namespace Azure.Configuration
{
public partial class ConfigurationClient
Expand Down Expand Up @@ -43,11 +42,11 @@ public async Task<Response<ConfigurationSetting>> AddAsync(ConfigurationSetting
if (setting == null) throw new ArgumentNullException(nameof(setting));
if (string.IsNullOrEmpty(setting.Key)) throw new ArgumentNullException($"{nameof(setting)}.{nameof(setting.Key)}");

Url url = BuildUrlForKvRoute(setting);
Uri uri = BuildUrlForKvRoute(setting);

PipelineCallContext context = null;
try {
context = Pipeline.CreateContext(_options, cancellation, ServiceMethod.Put, url);
context = Pipeline.CreateContext(_options, cancellation, ServiceMethod.Put, uri);

context.AddHeader(MediaTypeKeyValueApplicationHeader);
context.AddHeader(IfNoneMatchWildcard);
Expand All @@ -70,7 +69,7 @@ public async Task<Response<ConfigurationSetting>> SetAsync(ConfigurationSetting
if (setting == null) throw new ArgumentNullException(nameof(setting));
if (string.IsNullOrEmpty(setting.Key)) throw new ArgumentNullException($"{nameof(setting)}.{nameof(setting.Key)}");

Url url = BuildUrlForKvRoute(setting);
Uri url = BuildUrlForKvRoute(setting);

PipelineCallContext context = null;
try {
Expand All @@ -97,7 +96,7 @@ public async Task<Response<ConfigurationSetting>> UpdateAsync(ConfigurationSetti
if (string.IsNullOrEmpty(setting.Key)) throw new ArgumentNullException($"{nameof(setting)}.{nameof(setting.Key)}");
if (string.IsNullOrEmpty(setting.ETag)) throw new ArgumentNullException($"{nameof(setting)}.{nameof(setting.ETag)}");

Url url = BuildUrlForKvRoute(setting);
Uri url = BuildUrlForKvRoute(setting);

PipelineCallContext context = null;
try {
Expand All @@ -123,7 +122,7 @@ public async Task<Response<ConfigurationSetting>> DeleteAsync(string key, Settin
{
if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));

Url url = BuildUrlForKvRoute(key, filter);
Uri url = BuildUrlForKvRoute(key, filter);

PipelineCallContext context = null;
try {
Expand All @@ -145,7 +144,7 @@ public async Task<Response<ConfigurationSetting>> LockAsync(string key, SettingF
{
if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));

Url url = BuildUriForLocksRoute(key, filter);
Uri url = BuildUriForLocksRoute(key, filter);

PipelineCallContext context = null;
try {
Expand All @@ -167,7 +166,7 @@ public async Task<Response<ConfigurationSetting>> UnlockAsync(string key, Settin
{
if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));

Url url = BuildUriForLocksRoute(key, filter);
Uri url = BuildUriForLocksRoute(key, filter);

PipelineCallContext context = null;
try {
Expand All @@ -189,7 +188,7 @@ public async Task<Response<ConfigurationSetting>> GetAsync(string key, SettingFi
{
if (string.IsNullOrEmpty(key)) { throw new ArgumentNullException(nameof(key)); }

Url url = BuildUrlForKvRoute(key, filter);
Uri url = BuildUrlForKvRoute(key, filter);

PipelineCallContext context = null;
try {
Expand Down
75 changes: 24 additions & 51 deletions Azure.Configuration/ConfigurationClient_private.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,17 @@ namespace Azure.Configuration
{
public partial class ConfigurationClient
{
#region String Table
const string MediaTypeProblemApplication = "application/problem+json";
const string AcceptDateTimeFormat = "ddd, dd MMM yyy HH:mm:ss 'GMT'";
const string AcceptDatetimeHeader = "Accept-Datetime";

const string KvRoute = "/kv/";
static readonly byte[] KvRouteBytes = Encoding.ASCII.GetBytes(KvRoute);

const string LocksRoute = "/locks/";
static readonly byte[] LocksRouteBytes = Encoding.ASCII.GetBytes(LocksRoute);

const string RevisionsRoute = "/revisions/";
static readonly byte[] RevisionsRouteBytes = Encoding.ASCII.GetBytes(RevisionsRoute);

const string KeyQueryFilter = "key";
static readonly byte[] s_keyQueryFilter = Encoding.ASCII.GetBytes(KeyQueryFilter);

const string LabelQueryFilter = "label";
static readonly byte[] s_labelQueryFilter = Encoding.ASCII.GetBytes(LabelQueryFilter);

const string FieldsQueryFilter = "fields";
static readonly byte[] s_fieldsQueryFilter = Encoding.ASCII.GetBytes(FieldsQueryFilter);

static readonly byte[] s_after = Encoding.ASCII.GetBytes("after");

const string IfMatchName = "If-Match";
Header IfNoneMatchWildcard = new Header("If-None-Match", "*");
#endregion

static readonly Header MediaTypeKeyValueApplicationHeader = new Header(
Header.Constants.Accept,
Expand Down Expand Up @@ -120,69 +103,59 @@ static void ParseConnectionString(string connectionString, out Uri uri, out stri
};
}

Url BuildUrlForKvRoute(ConfigurationSetting keyValue)
Uri BuildUrlForKvRoute(ConfigurationSetting keyValue)
=> BuildUrlForKvRoute(keyValue.Key, new SettingFilter() { Label = keyValue.Label }); // TODO (pri 2) : does this need to filter ETag?

Url BuildUrlForKvRoute(string key, SettingFilter filter)
Uri BuildUrlForKvRoute(string key, SettingFilter filter)
{
var builder = new UrlWriter(_baseUri.ToString(), 100);
builder.AppendPath(KvRouteBytes);
builder.AppendPath(key);
var builder = new UriBuilder(_baseUri);
builder.Path = KvRoute + key;

if (filter != null) {
if (filter.Label != null) {
builder.AppendQuery(s_labelQueryFilter, filter.Label);
}
if (filter.Fields != SettingFields.All)
{
// TODO (pri 3): this should be optimized
var filterString = (filter.Fields).ToString().ToLower().Replace(" ", "");
builder.AppendQuery(s_fieldsQueryFilter, filterString);
}
if (filter != null && filter.Label != null) {
builder.AppendQuery(LabelQueryFilter, filter.Label);
}
return builder.ToUrl();

return builder.Uri;
}

Url BuildUriForLocksRoute(string key, SettingFilter options)
Uri BuildUriForLocksRoute(string key, SettingFilter filter)
{
var builder = new UrlWriter(_baseUri.ToString(), 100);
builder.AppendPath(LocksRouteBytes);
builder.AppendPath(key);
var builder = new UriBuilder(_baseUri);
builder.Path = LocksRoute + key;

if (options != null && options.Label != null) {
builder.AppendQuery(s_labelQueryFilter, options.Label);
if (filter != null && filter.Label != null) {
builder.AppendQuery(LabelQueryFilter, filter.Label);
}
return builder.ToUrl();

return builder.Uri;
}

Url BuildUrlForGetBatch(BatchFilter options)
Uri BuildUrlForGetBatch(BatchFilter options)
{
var urlBuilder = new UrlWriter(new Url(_baseUri), 100);
urlBuilder.AppendPath(KvRouteBytes); // TODO (pri 1): it seems like this causes the path to end with /. is that ok?
var builder = new UriBuilder(_baseUri);
builder.Path = KvRoute;

if (options.StartIndex != 0) {
urlBuilder.AppendQuery(s_after, options.StartIndex);
builder.AppendQuery("after", options.StartIndex);
}

if (!string.IsNullOrEmpty(options.Key)) {
urlBuilder.AppendQuery(s_keyQueryFilter, options.Key);
builder.AppendQuery(KeyQueryFilter, options.Key);
}

if (options.Label != null) {
if (options.Label == string.Empty) {
options.Label = "\0";
}
urlBuilder.AppendQuery(s_labelQueryFilter, options.Label);
builder.AppendQuery(LabelQueryFilter, options.Label);
}

if (options.Fields != SettingFields.All) {
// TODO (pri 3): this should be optimized
var filter = (options.Fields).ToString().ToLower().Replace(" ", "");
urlBuilder.AppendQuery(s_fieldsQueryFilter, filter);
var filter = (options.Fields).ToString().ToLower();
builder.AppendQuery(FieldsQueryFilter, filter);
}

return urlBuilder.ToUrl();
return builder.Uri;
}

// TODO (pri 1): serialize the Tags field
Expand Down

0 comments on commit 0694adb

Please sign in to comment.