Exercise - Configure and initialize the client library
The typical workflow for apps that use Azure Blob storage is as follows:
Retrieve configuration: At startup, load the storage account configuration, typically a storage account connection string.
Initialize client: To initialize the Azure Storage client library, use the connection string. This creates the objects the app will use to work with the Blob storage API.
Use: To operate on containers and blobs, make API calls with the client library.
Configure your connection string
Before running your app, you'll need the connection string for the storage account you'll use. You can use any Azure management interface to get it, including the Azure portal, the Azure CLI, or Azure PowerShell. When you set up the web app to run your code near the end of this module, you'll use the Azure CLI to get the connection string for the storage account you created earlier.
Storage account connection strings include the account key. Consider the account key a secret, and store it securely. Here, you'll store the connection string in an App Service app setting. App Service app settings are a secure place for app secrets, but this design doesn't support local development and isn't a robust, end-to-end solution on its own.
Warning
Do not place storage account keys in code or in unprotected configuration files. Storage account keys enable full access to your storage account. Leaking a key can result in unrecoverable damage and large bills. For storage guidance and advice about how to recover from a leaked key, see the Further Reading section at the end of this module.
Initialize the Blob storage object model
In the Azure Storage SDK for .NET, the standard pattern for using Blob storage is as follows:
Instantiate a new
BlobServiceClient
object and provide the connection string to your storage account.To get a
BlobContainerClient
, callGetBlobContainerClient
on theBlobServiceClient
with the name of the container you want to interact with or create.
In code, these steps look like this.
BlobServiceClient blobServiceClient = new BlobServiceClient(storageConfig.ConnectionString);
BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(storageConfig.FileContainerName);
None of this initialization code makes calls over the network. This means that some exceptions that occur because of incorrect information won't be thrown until later. For example, if an incorrectly formatted connection string is supplied to the constructor of the BlobServiceClient
class, an exception is thrown immediately. However, if the connection string points to a storage account that doesn't exist, no exception will be thrown until you attempt an operation against the storage account.
In the Azure Storage SDK for Java, the standard pattern for using Blob Storage consists of the following steps:
Build a
BlobServiceClient
by instantiating a newBlobServiceClientBuilder
object using the connection string to your storage account.Get a
BlobContainerClient
by calling thegetBlobContainerClient
method on theBlobServiceClient
with the name of the container you want to interact with or create.
In code, these steps look like this.
BlobServiceClient blobServiceClient = BlobServiceClientBuilder()
.connectionString(connectionString)
.buildClient();
BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(containerName);
None of this initialization code makes calls over the network. This means that some exceptions that occur because of incorrect information won't be thrown until later. For example, if an incorrectly formatted connection string is supplied to the BlobServiceClientBuilder
, an exception is thrown immediately. However, if the connection string points to a storage account that doesn't exist, no exception will be thrown until you attempt an operation against the storage account.
Create containers at startup
To create a container when your app starts or when the app first tries to use a container, call CreateIfNotExistsAsync
on a BlobContainerClient
.
CreateIfNotExistsAsync
won't throw an exception if the container already exists, but it does make a network call to Azure Blob Storage. Call it once during initialization, not every time you try to use a container.
To create a container when your app starts or when it first tries to use it, call exists
on a BlobContainerClient
to check whether a container already exists, if it doesn't then call create
. Call it once during initialization; not every time you try to use a container.
Exercise
Clone and explore the unfinished app
First, let's clone the starter app from GitHub. To get a copy of the source code and open it in the editor, run the following command in Azure Shell CLI:
git clone https://github.com/MicrosoftDocs/mslearn-store-data-in-azure.git cd mslearn-store-data-in-azure/store-app-data-with-azure-blob-storage/src/start code .
In the editor, open the file
Controllers/FilesController.cs
. There's no work to do here, but you're going to have a quick look at what the app does.This controller implements an API with three actions:
- Index: (GET /api/Files) returns a list of URLs, one for each file that's been uploaded. The app front end calls this method to build a list of hyperlinks to the uploaded files.
- Upload: (POST /api/Files) receives an uploaded file and saves it.
- Download: (GET /api/Files/{filename}) downloads an individual file by its name.
To do its work, each method uses an
IStorage
instance calledstorage
. There's an incomplete implementation ofIStorage
inModels/BlobStorage.cs
that you're going to fill in.
Add the NuGet package
Add a reference to the Azure Storage SDK. Run the following command in Azure Shell CLI:
dotnet add package Azure.Storage.Blobs dotnet restore
Running this command will ensure you're using the newest version of the Blob Storage client library.
Configure
The configuration values we need are the storage-account connection string and the name of the container the app will use to store files. In this module, you're only going to run the app in Azure App Service, so you'll follow App Service best practice and store the values in App Service app settings. You'll do that when we create the App Service instance, so there's nothing you need to do at the moment.
When it comes to using the configuration, our starter app already includes the plumbing you need. The IOptions<AzureStorageConfig>
constructor parameter in BlobStorage
has two properties: the storage-account connection string and the name of the container your app will use to store blobs. There's code in the ConfigureServices
method of Startup.cs
that loads the values from configuration when the app starts.
Initialize
In the editor, open
Models/BlobStorage.cs
. To the top of the file, add the followingusing
statements to prepare it for the code you're going to add during the exercise.using Azure; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models;
Locate the
Initialize
method. Your app will call this method whenBlobStorage
is used for the first time. If you're curious, you can look atConfigureServices
inStartup.cs
to see how this is done.Initialize
is where you want to create your container if it doesn't already exist. Replace the current implementation ofInitialize
with the following code, and save your work using CTRL + S.public Task Initialize() { BlobServiceClient blobServiceClient = new BlobServiceClient(storageConfig.ConnectionString); BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(storageConfig.FileContainerName); return containerClient.CreateIfNotExistsAsync(); }
Clone and explore the unfinished app
First, let's clone the starter app from GitHub. To get a copy of the source code and open it in the editor, run the following command in Azure Shell CLI:
git clone https://github.com/MicrosoftDocs/mslearn-store-data-in-azure.git cd mslearn-store-data-in-azure/store-java-ee-application-data-with-azure-blob-storage/start code .
In the editor, open the file
src/main/java/com/microsoft/azure/samples/jsf/IndexBean.java
. There's no work to do here, but you're going to have a quick look at what the app does.This request scoped bean implements three actions that are used by
src/main/webapp/index.xhtml
JSF (Java Server Faces) page:- listFileNames: returns a list of file names, one for each file that's been uploaded. The
index.xhtml
page calls this method to build a list of hyperlinks to the uploaded files. - upload: receives an uploaded file and saves it. The file content and metadata is injected into the
uploadedFile
property by the JSF framework. - download: downloads an individual file by its name.
To do its work, each method uses a
Storage
instance calledstorage
. There's an incomplete implementation ofStorage
insrc/main/java/com/microsoft/azure/samples/service/BlobStorage.java
that you're going to fill in.- listFileNames: returns a list of file names, one for each file that's been uploaded. The
Add the Azure Storage SDK for Java reference
The recommended way of adding Azure client libraries to the project is to utilize Azure BOM. It provides a simple and elegant way to orchestrate using multiple Azure client libraries while ensuring minimal dependency conflicts.
In the editor, open the file
pom.xml
.To add Azure BOM to the project add the following
dependencyManagement
section under theproject
xml tag.<dependencyManagement> <dependencies> <dependency> <groupId>com.azure</groupId> <artifactId>azure-sdk-bom</artifactId> <version>1.0.6</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
To add Azure Storage SDK for Java add the following
dependency
to theproject/dependencies
xml section.<dependency> <groupId>com.azure</groupId> <artifactId>azure-storage-blob</artifactId> </dependency>
Configure
The configuration values we need are the storage account connection string and the name of the container the app will use to store files. In this module, you're only going to run the app in Azure App Service, so you'll follow App Service best practice and store the values in App Service app settings. You'll do that when we create the App Service instance, so there's nothing you need to do at the moment.
When it comes to using the configuration, the App Service app settings are passed as environment variables to the app code. You'll read them in the initialization code.
Initialize
In the editor, open
src/main/java/com/microsoft/azure/samples/service/BlobStorage.java
. To the top of the file, add the followingimport
statements to prepare it for the code you're going to add during the exercise.import java.util.stream.Collectors; import com.azure.storage.blob.BlobClient; import com.azure.storage.blob.BlobContainerClient; import com.azure.storage.blob.BlobServiceClient; import com.azure.storage.blob.BlobServiceClientBuilder; import com.azure.storage.blob.models.BlobItem;
Add a class property in the
BlobStorage
class to hold theBlobContainerClient
reference.private BlobContainerClient blobContainerClient;
Tip
Azure clients are stateless and thread-safe. It is recommended to cache their instances where applicable. For example, the app you're working on uses a single container with a constant name, therefore it's best to cache it in app lifetime scope.
BlobStorage
is annotated with@Singleton
therefore, storing theBlobContainerClient
reference in its field is recommended.Locate the
init
method with@PostConstruct
annotation. Your app will call this method after theBlobStorage
instance is created and before it's used for the first time.init
is where you want to create your container if it doesn't already exist. Replace the current implementation ofinit
with the following code, and save your work.@PostConstruct private void init() { String connectionString = System.getenv("STORAGE_CONNECTION_STRING"); String containerName = System.getenv("STORAGE_CONTAINER_NAME"); BlobServiceClient blobServiceClient = new BlobServiceClientBuilder() .connectionString(connectionString) .buildClient(); blobContainerClient = blobServiceClient.getBlobContainerClient(containerName); if (!blobContainerClient.exists()) { blobContainerClient.create(); } }
Need help? See our troubleshooting guide or provide specific feedback by reporting an issue.