练习 - 配置和初始化客户端库
下面是使用 Azure Blob 存储的应用的典型工作流:
检索配置:在启动时,加载存储帐户配置,通常是存储帐户连接字符串。
初始化客户端:若要初始化 Azure 存储客户端库,请使用连接字符串。 此初始化创建应用用于处理 Blob 存储 API 的对象。
使用:要对容器和 blob 进行操作,请使用客户端库进行 API 调用。
配置连接字符串
在运行应用之前,获取使用的存储帐户的连接字符串。 可以使用任何 Azure 管理界面获取它,包括 Azure 门户、Azure CLI 和 Azure PowerShell。 设置 Web 应用以在此模块的末尾附近运行代码时,使用 Azure CLI 获取之前创建的存储帐户的连接字符串。
存储帐户连接字符串包含帐户密钥。 请将帐户密钥视为一个机密,并始终安全地存储它。 在这里,你在应用服务应用设置中存储此连接字符串。 应用服务应用设置是应用机密的安全位置。 此设计不支持本地开发,并且本身不是可靠的端到端解决方案。
重要
此代码示例使用连接字符串授权对你的存储帐户的访问。 此配置作为示例之用。 在应用程序代码中,应谨慎使用连接字符串和帐户访问密钥。 如果帐户访问密钥丢失或意外放置在不安全的位置,服务可能会变得易受攻击。 具有访问密钥的任何人都可以授权针对存储帐户的请求,并且实际上有权访问所有数据。
为了获得最佳安全性,Microsoft 建议尽可能使用 Microsoft Entra ID 和托管标识来授权针对 blob、队列和表数据的请求。 要了解详细信息,请参阅使用 Microsoft Entra ID 授予对 blob 的访问权限。
初始化 Blob 存储对象模型
在适用于 .NET 的 Azure 存储 SDK 中,Blob 存储的标准使用模式如下所示:
实例化一个新的
BlobServiceClient
对象,并向存储帐户提供连接字符串。若要获取
BlobContainerClient
,请使用你要与之交互或创建的容器的名称在BlobServiceClient
上调用GetBlobContainerClient
。
在代码中,这些步骤如下所示。
BlobServiceClient blobServiceClient = new BlobServiceClient(storageConfig.ConnectionString);
BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(storageConfig.FileContainerName);
此初始化代码的任何部分均不通过网络发出调用。 这一事实意味着,由于信息不正确而发生的一些异常稍后才会引发。 例如,如果向 BlobServiceClient
类的构造函数提供了格式不正确的连接字符串,则会立即引发异常。 但是,如果连接字符串指向不存在的存储帐户,则在尝试针对存储帐户执行操作之前,不会引发异常。
在适用于 Java 的 Azure 存储 SDK 中,Blob 存储的标准使用模式包括以下步骤:
通过使用存储帐户的连接字符串实例化一个新的
BlobServiceClientBuilder
对象来构建BlobServiceClient
。通过使用你要与之交互或创建的容器的名称在
BlobServiceClient
上调用getBlobContainerClient
方法来获取BlobContainerClient
。
在代码中,这些步骤如下所示。
BlobServiceClient blobServiceClient = BlobServiceClientBuilder()
.connectionString(connectionString)
.buildClient();
BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(containerName);
此初始化代码的任何部分均不通过网络发出调用。 这一事实意味着,由于信息不正确而发生的一些异常稍后才会引发。 例如,如果向 BlobServiceClientBuilder
提供了格式不正确的连接字符串,则会立即引发异常。 但是,如果连接字符串指向不存在的存储帐户,则在尝试针对存储帐户执行操作之前,不会引发异常。
在启动时创建容器
若要在应用启动或首次尝试使用容器时创建容器,请在 BlobContainerClient
上调用 CreateIfNotExistsAsync
。
如果容器已存在,CreateIfNotExistsAsync
不会引发异常,但它会对 Azure Blob 存储发出网络调用。 在初始化期间对其执行一次调用,而不要在每次尝试使用容器时对其执行调用。
若要在应用启动时或是应用首次尝试使用容器时创建容器,可在BlobContainerClient
上调用exists
以检查容器是否已存在。 如果不存在,则调用create
。 在初始化期间对其执行一次调用,而不要在每次尝试使用容器时对其执行调用。
练习
克隆并探索未完成的应用
首先,克隆 GitHub 中的入门级应用。 在 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 .
在编辑器中,打开文件Controllers/FilesController.cs。 此时无需执行任何操作,但可快速了解应用的功能。
此控制器通过三个操作实现 API:
- 索引:(
GET /api/Files
) 返回一个 URL 列表,每个已上传的文件均具有一个 URL。 应用前端调用此方法以生成指向已上传的文件的超链接列表。 - 上传:(
POST /api/Files
) 接收上传的文件并保存该文件。 - 下载:(
GET /api/Files/{filename}
) 按文件名称下载单个文件。
为了完成其工作,每个方法均使用称为
storage
的IStorage
实例。 Models/BlobStorage.cs中未完全实现IStorage
。- 索引:(
添加 NuGet 包
添加对 Azure 存储 SDK 的引用。 在 Azure Shell CLI 中运行以下命令:
dotnet add package Azure.Storage.Blobs dotnet restore
此命令可确保使用最新版本的 Blob 存储客户端库。
配置
所需的配置值包括存储帐户连接字符串以及应用用于存储文件的容器的名称。 在本模块中,你只会在 Azure 应用服务中运行该应用。 遵循应用服务最佳做法,并将值存储在应用服务应用设置中。 创建应用服务实例时,可以执行该操作。 目前无需执行任何操作。
就使用配置而言,入门级应用包含所需的管道。 BlobStorage
中的IOptions<AzureStorageConfig>
构造函数参数具有两个属性:存储帐户连接字符串和应用用于存储 blob 的容器的名称。 Startup.cs
的 ConfigureServices
方法中具有相应代码,可在启动应用时加载配置中的值。
初始化
在编辑器中,打开Models/BlobStorage.cs。 在文件顶部,添加以下
using
语句,以让其为要添加的代码做好准备。using Azure; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models;
找到
Initialize
方法。 应用首次使用BlobStorage
时会调用此方法。 如果感到好奇,可以在Startup.cs中查看ConfigureServices
,了解调用的实现方法。Initialize
是当容器不存在时你想要创建容器的位置。 使用以下代码替换Initialize
的当前实现并使用CTRL+S保存工作。public Task Initialize() { BlobServiceClient blobServiceClient = new BlobServiceClient(storageConfig.ConnectionString); BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(storageConfig.FileContainerName); return containerClient.CreateIfNotExistsAsync(); }
克隆并探索未完成的应用
首先,克隆 GitHub 中的入门级应用。 在 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 .
在编辑器中,打开文件src/main/java/com/microsoft/azure/samples/jsf/IndexBean.java。 此时无需执行任何操作,但可快速了解应用的功能。
此请求范围的 bean 实现由src/main/webapp/index.xhtml Java Server Faces (JSF) 页面使用的三个操作:
- listFileNames:返回文件名列表,其中包含用于每个上载的文件的名称。 index.xhtml页面调用此方法以生成指向已上传的文件的超链接列表。
- 上传:接收上传的文件并保存该文件。 文件内容和元数据由 JSF 框架注入
uploadedFile
属性。 - 下载:按文件名称下载单个文件。
为了完成其工作,每个方法均使用称为
storage
的Storage
实例。 src/main/java/com/microsoft/azure/samples/service/BlobStorage.java 中未完全实现Storage
。
添加用于 Java 的 Azure 存储 SDK 参考
建议使用 Azure BOM 将 Azure 客户端库添加到项目。 该方法提供了一种简洁的方式来协调多个 Azure 客户端库的使用,同时确保将依赖项冲突降至最低。
在编辑器中,打开文件pom.xml。
要将 Azure BOM 添加到项目中,请在
project
xml 标记下添加以下dependencyManagement
部分。<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>
要添加用于 Java 的 Azure 存储 SDK,请将以下
dependency
添加到project/dependencies
xml 部分。<dependency> <groupId>com.azure</groupId> <artifactId>azure-storage-blob</artifactId> </dependency>
配置
所需的配置值包括存储帐户连接字符串以及应用用于存储文件的容器的名称。 在本模块中,你只会在 Azure 应用服务中运行该应用。 遵循应用服务最佳做法,并将值存储在应用服务应用设置中。 当我们创建应用服务实例时,你可以执行该操作。 目前无需执行任何操作。
当说到使用配置时,是将应用服务应用设置作为环境变量传递给应用代码的。 你在初始化代码中读到这些变量。
初始化
在编辑器中,打开src/main/java/com/microsoft/azure/samples/service/BlobStorage.java。 在文件顶部,添加以下
import
语句,以让其为要添加的代码做好准备。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;
在
BlobStorage
类中添加类属性以保存BlobContainerClient
引用。private BlobContainerClient blobContainerClient;
提示
Azure 客户端是无状态和线程安全的。 建议在可行时缓存其实例。 例如,你使用的应用使用具有固定名称的单个容器,因此最好在应用生存期范围内缓存它。
BlobStorage
使用@Singleton
进行注释,因此建议在其字段中存储BlobContainerClient
引用。找到带有
@PostConstruct
注释的init
方法。 你的应用会在BlobStorage
实例创建后及首次使用之前调用此方法。init
是当容器不存在时创建容器的位置。 使用以下代码替换init
的当前实现并保存你的工作。@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(); } }