Search code examples
c#azure.net-corehttp-proxyazure-storage-queues

Connect to Azure Storage Queue Behind Proxy


I have a .NET Core 2.2 Console app to connect to an Azure Storage Queue. It works on my computer, but I can't get it to work behind a corporate proxy. What do I need to do? (I anonymized the storage account name and key and the proxy hostname.)

.csproj:

<Project Sdk="Microsoft.NET.Sdk">    
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>8.0</LangVersion>
    <NullableContextOptions>enable</NullableContextOptions>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  </PropertyGroup>    
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.Management.Fluent" Version="1.21.0" />
    <PackageReference Include="Microsoft.Azure.Storage.Queue" Version="10.0.1" />
  </ItemGroup>    
</Project>

Wrapper class:

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
using System.Threading.Tasks;

namespace Queue
{
    public class Queue
    {
        public Queue(string connectionString, string queueName)
        {
            var storageAccount = CloudStorageAccount.Parse(connectionString);            
            var cloudQueueClient = storageAccount.CreateCloudQueueClient();
            CloudQueue = cloudQueueClient.GetQueueReference(queueName);            
        }

        private CloudQueue CloudQueue { get; }

        public async Task<string> PeekAsync()
        {
            var m = await CloudQueue.PeekMessageAsync();            
            return m.AsString;
        }
    }
}

AppSettings.json

{
  "StorageConnectionString": "DefaultEndpointsProtocol=https;AccountName=someAccount;AccountKey=someKey==;EndpointSuffix=core.windows.net"
}

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.net>
    <defaultProxy enabled="true" useDefaultCredentials="true">
      <proxy 
        usesystemdefault="True" 
        proxyaddress="http://someProxy:8080" 
      />
    </defaultProxy>
  </system.net>
</configuration>

Solution

  • Found some hints on the official azure-storage-net repo:

    Idea:

    1. create a custom class that inherits from DelegatingHandler to set the proxy there
    2. use that class in your application

    Implementation based on your sample:

    DelegatingHandlerImpl.cs (taken from https://github.com/Azure/azure-storage-net/blob/master/Test/Common/TestBase.Common.cs)

    public class DelegatingHandlerImpl : DelegatingHandler
    {
        public int CallCount { get; private set; }
    
        private readonly IWebProxy Proxy;
    
        private bool FirstCall = true;
    
        public DelegatingHandlerImpl() : base()
        {
    
        }
    
        public DelegatingHandlerImpl(HttpMessageHandler httpMessageHandler) : base(httpMessageHandler)
        {
    
        }
    
        public DelegatingHandlerImpl(IWebProxy proxy)
        {
            this.Proxy = proxy;
        }
    
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            CallCount++;
            if (FirstCall && this.Proxy != null)
            {
                HttpClientHandler inner = (HttpClientHandler)this.InnerHandler;
                inner.Proxy = this.Proxy;
            }
            FirstCall = false;
            return base.SendAsync(request, cancellationToken);
        }
    }
    

    Queue.cs

    public class Queue
    {
        public Queue(string connectionString, string queueName)
        {
            var storageAccount = CloudStorageAccount.Parse(connectionString);
            var proxy = new WebProxy()
            {
                // More properties here
                Address = new Uri("your proxy"),
            };
            DelegatingHandlerImpl delegatingHandlerImpl = new DelegatingHandlerImpl(proxy);
            CloudQueueClient cloudQueueClient = new CloudQueueClient(storageAccount.QueueStorageUri, storageAccount.Credentials, delegatingHandlerImpl);
            CloudQueue = cloudQueueClient.GetQueueReference(queueName);
        }
    
        private CloudQueue CloudQueue { get; }
    
        public async Task<string> PeekAsync()
        {
            var m = await CloudQueue.PeekMessageAsync();
            return m.AsString;
        }
    }
    

    Successfully tested this when i am behind our proxy.

    Sidenote: Delete your App.config setting for defaultProxy it is not used by dotnet core.