Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide an overload to allow users to provide dispose preference #3547

Merged
merged 3 commits into from
Aug 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,73 @@ public void UseHttpClientBeforeConstructingServiceClient()
Assert.Equal(new Uri(DEFAULT_URI), contosoClient.HttpClient.BaseAddress);
}

/// <summary>
/// Test verifies that HttpClient provided to ServiceClient can be resued even after Disposing ServiceClient
/// </summary>
[Fact]
public void UseHttpClientAfterServiceClientDispose()
{
HttpClient hc = new HttpClient(new ContosoMessageHandler());
hc.BaseAddress = new Uri(DEFAULT_URI);
HttpResponseMessage resMsg = SendAndReceiveResponse(hc);
Assert.Equal(HttpStatusCode.OK, resMsg.StatusCode);

ContosoServiceClient contosoClient = new ContosoServiceClient(hc, false);
HttpResponseMessage response = contosoClient.DoSyncWork();
string cont = response.Content.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
Assert.Equal("Contoso Rocks", cont);
Assert.Equal(new Uri(DEFAULT_URI), contosoClient.HttpClient.BaseAddress);

contosoClient.Dispose();

HttpResponseMessage secondTimeMsg = SendAndReceiveResponse(hc);
Assert.Equal(HttpStatusCode.OK, secondTimeMsg.StatusCode);
}

/// <summary>
/// Dispose ServiceClient while request is being processed
/// </summary>
[Fact]
public void DisposeServiceClientWhileProcessingRequest()
{
HttpClient hc = new HttpClient(new DelayedHandler("DelayingResponse", TimeSpan.FromSeconds(5)));
hc.BaseAddress = new Uri(DEFAULT_URI);
HttpResponseMessage resMsg = SendAndReceiveResponse(hc);
string resStr = resMsg.Content.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
Assert.Equal("DelayingResponse", resStr);

ContosoServiceClient contosoClient = new ContosoServiceClient(hc, false);

var result = Task.Run<HttpResponseMessage>(async () =>
{
return await contosoClient.DoAsyncWork();
});

contosoClient.Dispose();

HttpResponseMessage delayedResponse = result.ConfigureAwait(false).GetAwaiter().GetResult();
string delayedContent = delayedResponse.Content.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
Assert.Equal("DelayingResponse", delayedContent);
}

/// <summary>
/// This is to verify if a HttpClient is passed, we still add default userAgent information
/// inside defaultheaders of the passed in HttpClient
/// </summary>
[Fact]
public void NullReferenceExceptionAfterClientDispose()
{
ContosoServiceClient contosoClient = new ContosoServiceClient(null);
HttpResponseMessage response = contosoClient.DoSyncWork();
string cont = response.Content.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
Assert.NotNull(response);

contosoClient.Dispose();

Assert.ThrowsAny<NullReferenceException>(() => SendAndReceiveResponse(contosoClient.HttpClient));
}


/// <summary>
/// THe HttpClient that is provided to ServiceClient will have it's own set of UserAgent information
/// inside default headers. This is to verify if we merge DefaultHeader information
Expand Down Expand Up @@ -140,12 +207,8 @@ public void AddFxVersionHeaderInformation()
Assert.Equal(defaultVersion.ToString(), "1.0.0.0");
}


private HttpResponseMessage SendAndReceiveResponse(HttpClient httpClient)
{
// Construct URL
//string url = "http://www.microsoft.com";

// Create HTTP transport objects
HttpRequestMessage _httpRequest = null;

Expand All @@ -155,10 +218,7 @@ private HttpResponseMessage SendAndReceiveResponse(HttpClient httpClient)

// Set Headers
_httpRequest.Headers.Add("x-ms-version", "2013-11-01");

return Task.Run<HttpResponseMessage>(async () => await httpClient.SendAsync(_httpRequest, new CancellationToken()).ConfigureAwait(false)).ConfigureAwait(false).GetAwaiter().GetResult();

}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ namespace Microsoft.Rest.ClientRuntime.Tests.CustomClients
/// </summary>
public class ContosoServiceClient : ServiceClient<ContosoServiceClient>
{
const int defaultDelaySeconds = 3;
/// <summary>
/// Initializes with default contosomessage handler
/// </summary>
public ContosoServiceClient():base()
public ContosoServiceClient() : base()
{
HttpClient = new HttpClient(new ContosoMessageHandler());
}
Expand All @@ -28,7 +29,7 @@ public ContosoServiceClient():base()
/// <param name="overRideDefaultHandler"></param>
public ContosoServiceClient(bool overRideDefaultHandler)
{
if(overRideDefaultHandler)
if (overRideDefaultHandler)
{
HttpClient = new HttpClient(new DelayedHandler("Delayed User Provided HttpClient after initialization"));
}
Expand All @@ -42,12 +43,12 @@ public ContosoServiceClient(bool overRideDefaultHandler)
/// Constructor that accepts HttpClient
/// </summary>
/// <param name="httpClient"></param>
public ContosoServiceClient(HttpClient httpClient) : base (httpClient)
public ContosoServiceClient(HttpClient httpClient, bool disposeHttpClient = true) : base(httpClient, disposeHttpClient)
{

}

public ContosoServiceClient(HttpClientHandler rootHandler, DelegatingHandler[] handlers)
public ContosoServiceClient(HttpClientHandler rootHandler, DelegatingHandler[] handlers)
: base(rootHandler, handlers)
{ }

Expand All @@ -64,6 +65,11 @@ public HttpResponseMessage DoSyncWork(string content = null)
}).Unwrap().GetAwaiter().GetResult();
}

public async Task<HttpResponseMessage> DoAsyncWork(string content = null)
{
return await DoStuff(content, TimeSpan.FromSeconds(defaultDelaySeconds));
}

/// <summary>
/// Creates request and sends
/// </summary>
Expand All @@ -89,9 +95,15 @@ private async Task<HttpResponseMessage> DoStuff(string content = null)

// Set Headers
_httpRequest.Headers.Add("x-ms-version", "2013-11-01");

return await this.HttpClient.SendAsync(_httpRequest, new CancellationToken()).ConfigureAwait(false);
}

private async Task<HttpResponseMessage> DoStuff(string content = null, TimeSpan delayTask = new TimeSpan())
{
await Task.Delay(delayTask);
return await DoStuff(content);
}
}

/// <summary>
Expand Down Expand Up @@ -120,14 +132,19 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
}

/// <summary>
/// Yet another delegating handler for tests
/// Yet another delegating handler for tests.
/// Delays the response by 5 seconds (by default)
/// </summary>
public class DelayedHandler : DelegatingHandler
{
const int DEFAULT_DELAY_SECONDS = 2;
int _delaySeconds;

string _handlerData;
private DelayedHandler() : base()
{
InnerHandler = new HttpClientHandler();
_delaySeconds = DEFAULT_DELAY_SECONDS;
}

public DelayedHandler(string handlerData)
Expand All @@ -136,11 +153,18 @@ public DelayedHandler(string handlerData)
_handlerData = handlerData;
}

public DelayedHandler(string handlerData, TimeSpan delay) : this()
{
_delaySeconds = delay.Seconds;
_handlerData = handlerData;
}

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
StringContent contosoContent = new StringContent(_handlerData);
HttpResponseMessage response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = contosoContent;
await Task.Delay(new TimeSpan(0, 0, _delaySeconds));
return await Task.Run(() => response);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Description>Infrastructure for error handling, tracing, and HttpClient pipeline configuration. Required by client libraries generated using AutoRest.</Description>
<AssemblyName>Microsoft.Rest.ClientRuntime</AssemblyName>
<AssemblyTitle>Client Runtime Library for Microsoft AutoRest Generated Clients</AssemblyTitle>
<VersionPrefix>2.3.8</VersionPrefix>
<VersionPrefix>2.3.9</VersionPrefix>
<PackageId>Microsoft.Rest.ClientRuntime</PackageId>
<PackageTags>Microsoft AutoRest ClientRuntime $(NugetCommonTags) $(NugetCommonProfileTags)</PackageTags>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
[assembly: AssemblyTitle("Microsoft Rest Client Runtime")]
[assembly: AssemblyDescription("Client infrastructure for client libraries generated by AutoRest.")]
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.3.8.0")]
[assembly: AssemblyFileVersion("2.3.9.0")]

[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft Corporation")]
Expand Down
20 changes: 16 additions & 4 deletions src/SdkCommon/ClientRuntime/ClientRuntime/ServiceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public abstract class ServiceClient<T> : IDisposable
/// </summary>
private bool _disposed;

/// <summary>
/// Flag to track if provided httpClient needs to disposed
/// </summary>
private bool _disposeHttpClient;

/// <summary>
/// Field used for ClientVersion property
/// </summary>
Expand Down Expand Up @@ -245,13 +250,15 @@ protected ServiceClient()
/// <summary>
/// Initializes a new instance of the ServiceClient class.
/// </summary>
/// <param name="httpClient">HttpClient</param>
/// <param name="httpClient">HttpClient to be used</param>
/// <param name="disposeHttpClient">true: Will dispose the supplied httpClient on calling Dispose(). False: will not dispose</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Microsoft.Reliability",
"CA2000:Dispose objects before losing scope",
Justification = "The created objects should be disposed on caller's side")]
protected ServiceClient(HttpClient httpClient)
protected ServiceClient(HttpClient httpClient, bool disposeHttpClient = true)
{
_disposeHttpClient = disposeHttpClient;
InitializeHttpClient(httpClient, null);
}

Expand Down Expand Up @@ -373,12 +380,17 @@ protected virtual void Dispose(bool disposing)
_disposed = true;

// Dispose the client
HttpClient.Dispose();
HttpClient = null;
if(_disposeHttpClient)
{
HttpClient.Dispose();
HttpClient = null;
}

FirstMessageHandler = null;
HttpClientHandler = null;
}
}


/// <summary>
/// Initializes HttpClient using HttpClientHandler.
Expand Down