Configure proxy for Azure Storage / CloudTableClient in .NET Core
For a project I’m working on I needed to specify a outgoing proxy for accessing Azure Table Storage in a .NET console application.
Unfortunately the default way of setting a proxy in the app.config of classic .NET applications doesn’t work for .NET core.
After fiddling around for a bit I found the solution for setting it in a .NET core application (based on a answer on stackoverflow). If you use the Microsoft.Azure.Cosmos.Table Nuget package, instead of the old WindowsAzure.Storage package (I’m using version 1.0.1), the CloudTableClient
allows you to pass in a TableClientConfiguration
with a DelegatingHandler
:
public TableStorage(string accountName, string keyValue, IWebProxy proxy)
{
_storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, keyValue), true);
var storageDelegatingHandler = new StorageDelegatingHandler(proxy);
_tableClient = _storageAccount.CreateCloudTableClient(
new TableClientConfiguration
{
RestExecutorConfiguration = new RestExecutorConfiguration
{
DelegatingHandler = storageDelegatingHandler
}
});
/// further config
}
In the DelegatingHandler you can set the proxy for the HttpClientHandler:
public class StorageDelegatingHandler : DelegatingHandler
{
private readonly IWebProxy _proxy;
private bool _firstCall = true;
public StorageDelegatingHandler()
: base()
{
}
public StorageDelegatingHandler(HttpMessageHandler httpMessageHandler)
: base(httpMessageHandler)
{
}
public StorageDelegatingHandler(IWebProxy proxy)
{
_proxy = proxy;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (_firstCall && _proxy != null)
{
HttpClientHandler inner = (HttpClientHandler)InnerHandler;
inner.Proxy = _proxy;
}
_firstCall = false;
return base.SendAsync(request, cancellationToken);
}
}
Now you can configure the proxy where you’re setting up dependency injection:
public class ProxySettings
{
public bool Use => !string.IsNullOrWhiteSpace(Address);
public string Address { get; set; }
public bool BypassOnLocal { get; set; }
}
var proxySettings = Configuration
.GetSection(nameof(ProxySettings))
.Get<ProxySettings>();
IWebProxy proxy = null;
if (proxySettings != null && proxySettings.Use)
{
proxy = new WebProxy(proxySettings.Address, proxySettings.BypassOnLocal);
WebRequest.DefaultWebProxy = proxy;
}
services.AddSingleton<IStorage>(new TableStorage(Configuration["StorageAccountName"], Configuration["StorageAccountKey"], proxy));