UPDATE: I can verify this behavior is fixed in Azure.Storage.Blobs 12.5.1 https://www.nuget.org/packages/Azure.Storage.Blobs https://github.com/Azure/azure-sdk-for-net/issues/9404
How can I connect to azurite using a hostname?
I'm trying to emulate Azure Blob Storage in docker using Azurite for integration tests.
All works well, to the point I have to access Azurite via a hostname (which is AFAIK required for docker networking)
My connection string looks like this (which is the default well-known connection string):
"AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://azurite:10000/devstoreaccount1;"
My docker compose part for azurite looks like this:
services:
azurite:
image: mcr.microsoft.com/azure-storage/azurite
hostname: azurite
command: "azurite-blob --loose --blobHost 0.0.0.0"
ports:
- "10000:10000"
volumes:
- ./test/azurite:/data
networks:
- stillsnet
images:
container_name: images
image: myapp/images
build:
context: .
dockerfile: Dockerfile
ports:
- "5000:5000"
- "5001:5001"
environment:
- ASPNETCORE_ENVIRONMENT=Test
- ASPNETCORE_URLS=http://+:5000
- imagesStorage__AzureBlobStorage__ConnectionString=AccountName=devstoreaccount1;DefaultEndpointsProtocol=http;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000;
depends_on:
- azurite
links:
- azurite
networks:
- stilssnet
my code looks like this:
private const string ConnectionString ="AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://azurite:10000/devstoreaccount1;";
[Fact]
public async Task UploadFile()
{
var container = new BlobContainerClient(ConnectionString, "images");
await using var stream = File.OpenRead(@"C:\temp\output\3ee9bc41-40ea-4d05-b180-e74bd5065622\images\00000000.jpg");
await container.UploadBlobAsync("test.jpg", stream);
}
this will throw an exception:
System.Xml.XmlException : Root element is missing.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options)
at System.Xml.Linq.XDocument.Load(Stream stream, LoadOptions options)
at Azure.Storage.Blobs.BlobRestClient.Container.CreateAsync_CreateResponse(Response response)
at Azure.Storage.Blobs.BlobRestClient.Container.CreateAsync(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Uri resourceUri, PublicAccessType access, Nullable`1 timeout, IDictionary`2 metadata, String requestId, Boolean async, String operationName, CancellationToken cancellationToken)
at Azure.Storage.Blobs.BlobContainerClient.CreateInternal(PublicAccessType publicAccessType, IDictionary`2 metadata, Boolean async, CancellationToken cancellationToken, String operationName)
at Azure.Storage.Blobs.BlobContainerClient.CreateIfNotExistsInternal(PublicAccessType publicAccessType, IDictionary`2 metadata, Boolean async, CancellationToken cancellationToken)
at Azure.Storage.Blobs.BlobContainerClient.CreateIfNotExistsAsync(PublicAccessType publicAccessType, IDictionary`2 metadata, CancellationToken cancellationToken)
If I change the connection string from azurite
to 127.0.0.1
it all works fine.
GitHub - Azure/Azurite: A lightweight server clone of Azure Storage that simulates most of the commands supported by it with minimal dependencies.
To start the Azure Storage Emulator: Select the Start button or press the Windows key. Begin typing Azure Storage Emulator . Select the emulator from the list of displayed applications.
Azurite (installed with npm) currently can only be stop by send Ctrl+c.
The host's name in that network is azurite, so you can use this connection string UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://azurite
.
Works for me and I think is the way to do it.
Also you can use the legacy storage emulator (that includes Tables), instead of azurite you put docker.host.internal
UPDATE: I can verify this behavior is fixed in Azure.Storage.Blobs 12.5.1 https://www.nuget.org/packages/Azure.Storage.Blobs https://github.com/Azure/azure-sdk-for-net/issues/9404
It looks like the BlobContainerClient itself strips away the account name from the URL if you use anything else than localhost or an IP address, so the client generates this:
PUT /images?restype=container HTTP/1.1" 400
-
instead of
PUT /devstoreaccount1/images?restype=container
HTTP/1.1 201
As an ugly workaround we can include the account name in the container name when testing against azurite: var container = new BlobContainerClient(ConnectionString, "devstoreaccount1/images");
Though await container.CreateIfNotExistsAsync(); doesn't work properly against azurite then (throws a 409 Exception when it already exist...
So we either have:
It doesn't seem to be related to Azurite itself, or ideally it should support root URL's that are compatible with the Azure blob store without having to specify the account name prefix.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With