Skip to content

Commit 68bd00c

Browse files
committed
Only allow OpenStackNet.Configure to be called once
When it was called mulitple times, any custom actions were being duplicated. Now ResetDefaults should be used when Configure needs to be called again (mostly for unit testing), this will nuke all existing configuration for OpenStack.NET, Json.NET and Flurl.
1 parent e29f57c commit 68bd00c

2 files changed

Lines changed: 104 additions & 53 deletions

File tree

src/corelib/OpenStackNet.cs

Lines changed: 88 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public static class OpenStackNet
2424
/// </summary>
2525
public static readonly OpenStackNetConfigurationOptions Configuration = new OpenStackNetConfigurationOptions();
2626
private static readonly object ConfigureLock = new object();
27+
private static bool _isConfigured;
2728

2829
/// <summary>
2930
/// Provides thread-safe accesss to OpenStack.NET's global configuration options.
@@ -38,64 +39,99 @@ public static void Configure(Action<FlurlHttpConfigurationOptions> configureFlur
3839
{
3940
lock (ConfigureLock)
4041
{
42+
if (_isConfigured)
43+
return;
44+
4145
if(configure != null)
4246
configure(Configuration);
4347

44-
JsonConvert.DefaultSettings = () =>
48+
ConfigureJson(configureJson);
49+
ConfigureFlurl(configureFlurl);
50+
51+
_isConfigured = true;
52+
}
53+
}
54+
55+
/// <summary>
56+
/// Resets all configuration (OpenStack.NET, Flurl and Json.NET) so that <see cref="Configure"/> can be called again.
57+
/// </summary>
58+
public static void ResetDefaults()
59+
{
60+
lock (ConfigureLock)
61+
{
62+
if (!_isConfigured)
63+
return;
64+
65+
Configuration.ResetDefaults();
66+
67+
ConfigureJson();
68+
69+
FlurlHttp.Configuration.ResetDefaults();
70+
ConfigureFlurl();
71+
72+
_isConfigured = false;
73+
}
74+
}
75+
76+
private static void ConfigureJson(Action<JsonSerializerSettings> configureJson = null)
77+
{
78+
JsonConvert.DefaultSettings = () =>
79+
{
80+
// Apply our default settings
81+
var settings = new JsonSerializerSettings
4582
{
46-
// Apply our default settings
47-
var settings = new JsonSerializerSettings
48-
{
49-
DefaultValueHandling = DefaultValueHandling.Ignore,
50-
MissingMemberHandling = MissingMemberHandling.Ignore,
51-
NullValueHandling = NullValueHandling.Ignore,
52-
ContractResolver = new OpenStackContractResolver()
53-
};
54-
55-
// Apply application's default settings
56-
if (configureJson != null)
57-
configureJson(settings);
58-
return settings;
83+
DefaultValueHandling = DefaultValueHandling.Ignore,
84+
MissingMemberHandling = MissingMemberHandling.Ignore,
85+
NullValueHandling = NullValueHandling.Ignore,
86+
ContractResolver = new OpenStackContractResolver()
5987
};
60-
61-
FlurlHttp.Configure(c =>
88+
89+
// Apply application's default settings
90+
if (configureJson != null)
91+
configureJson(settings);
92+
return settings;
93+
};
94+
}
95+
96+
private static void ConfigureFlurl(Action<FlurlHttpConfigurationOptions> configureFlurl = null)
97+
{
98+
FlurlHttp.Configure(c =>
99+
{
100+
// Apply the application's default settings
101+
if (configureFlurl != null)
102+
configureFlurl(c);
103+
104+
//
105+
// Apply our default settings
106+
//
107+
if (c.HttpClientFactory is DefaultHttpClientFactory)
108+
c.HttpClientFactory = new AuthenticatedHttpClientFactory();
109+
110+
// Apply our event handling without clobbering any application level handlers
111+
var applicationBeforeCall = c.BeforeCall;
112+
c.BeforeCall = call =>
62113
{
63-
// Apply the application's default settings
64-
if (configureFlurl != null)
65-
configureFlurl(c);
66-
67-
//
68-
// Apply our default settings
69-
//
70-
if(c.HttpClientFactory is DefaultHttpClientFactory)
71-
c.HttpClientFactory = new AuthenticatedHttpClientFactory();
72-
73-
// Apply our event handling without clobbering any application level handlers
74-
var applicationBeforeCall = c.BeforeCall;
75-
c.BeforeCall = call =>
76-
{
77-
SetUserAgentHeader(call);
78-
if (applicationBeforeCall != null)
79-
applicationBeforeCall(call);
80-
};
81-
82-
var applicationAfterCall = c.AfterCall;
83-
c.AfterCall = call =>
84-
{
85-
Tracing.TraceHttpCall(call);
86-
if (applicationAfterCall != null)
87-
applicationAfterCall(call);
88-
};
89-
90-
var applicationOnError = c.OnError;
91-
c.OnError = call =>
92-
{
93-
Tracing.TraceFailedHttpCall(call);
94-
if (applicationOnError != null)
95-
applicationOnError(call);
96-
};
97-
});
98-
}
114+
SetUserAgentHeader(call);
115+
if (applicationBeforeCall != null)
116+
applicationBeforeCall(call);
117+
};
118+
119+
var applicationAfterCall = c.AfterCall;
120+
c.AfterCall = call =>
121+
{
122+
Tracing.TraceHttpCall(call);
123+
if (applicationAfterCall != null)
124+
applicationAfterCall(call);
125+
};
126+
127+
var applicationOnError = c.OnError;
128+
c.OnError = call =>
129+
{
130+
Tracing.TraceFailedHttpCall(call);
131+
if (applicationOnError != null)
132+
applicationOnError(call);
133+
};
134+
});
99135
}
100136

101137
private static void SetUserAgentHeader(HttpCall call)

src/testing/unit/OpenStackNetTests.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class OpenStackNetTests : IDisposable
1010
{
1111
public void Dispose()
1212
{
13-
OpenStackNet.Configuration.ResetDefaults();
13+
OpenStackNet.ResetDefaults();
1414
}
1515

1616
[Fact]
@@ -27,6 +27,21 @@ public async void UserAgentTest()
2727
}
2828
}
2929

30+
[Fact]
31+
public async void UserAgentOnlyListOnceTest()
32+
{
33+
using (var httpTest = new HttpTest())
34+
{
35+
OpenStackNet.Configure();
36+
OpenStackNet.Configure(); // Duplicate call to Configure should be ignored
37+
38+
await "http://api.com".GetAsync();
39+
40+
var userAgent = httpTest.CallLog[0].Request.Headers.UserAgent.ToString();
41+
Assert.Contains("openstack.net", userAgent);
42+
}
43+
}
44+
3045
[Fact]
3146
public async void UserAgentWithApplicationSuffixTest()
3247
{

0 commit comments

Comments
 (0)