IBlobNamingNormalizer(BLOB 名称标准化对象),主要用于将一个字符串进行标准化处理,防止 Provider 无法处理这种名称。各大 OSS 都对容器的名称或对象的名称有命名要求,比如必须全部小写,不能有哪些特殊符号等等。
protected virtual (string, string) NormalizeNaming(string containerName, string blobName) { // 从当前的配置信息中获取对应的标准化器,如果不存在任何标准化工具对象,则直接返回原始名称。 if (!Configuration.NamingNormalizers.Any()) { return (containerName, blobName); } using (var scope = ServiceProvider.CreateScope()) { // 获取所有的标准化器,并依次进行名称的标准化处理。 foreach (var normalizerType in Configuration.NamingNormalizers) { var normalizer = scope.ServiceProvider .GetRequiredService(normalizerType) .As<IBlobNamingNormalizer>(); containerName = normalizer.NormalizeContainerName(containerName); blobName = normalizer.NormalizeBlobName(blobName); } return (containerName, blobName); } } 2.2.3.2 BLOB 上下文在 BLOB 里面,ABP 分别为每个操作都定义了一个 ***Args 对象,它就是一个上下文对象,用于在整个调用周期中传递参数。
2.2.3.3 BLOB 配置信息每个 BLOB 容器都会有一个 BlobContainerConfiguration 用于存储配置信息,它主要有以下几个重要的属性。
public class BlobContainerConfiguration { // 当前 BLOB 容器对应的 Provider 类型。 public Type ProviderType { get; set; } // 当前 BLOB 容器是否启用了多租户。 public bool IsMultiTenant { get; set; } = true; // 当前 BLOB 容器的名称标准化对象。 public ITypeList<IBlobNamingNormalizer> NamingNormalizers { get; } // 当前 BLOB 容器的属性。 [NotNull] private readonly Dictionary<string, object> _properties; // 当尝试获取某些配置属性,但是不存在时,会从这个 Configuration 拿取数据。 [CanBeNull] private readonly BlobContainerConfiguration _fallbackConfiguration; public BlobContainerConfiguration(BlobContainerConfiguration fallbackConfiguration = null) { NamingNormalizers = new TypeList<IBlobNamingNormalizer>(); _fallbackConfiguration = fallbackConfiguration; _properties = new Dictionary<string, object>(); } [CanBeNull] public T GetConfigurationOrDefault<T>(string name, T defaultValue = default) { return (T) GetConfigurationOrNull(name, defaultValue); } [CanBeNull] public object GetConfigurationOrNull(string name, object defaultValue = null) { return _properties.GetOrDefault(name) ?? _fallbackConfiguration?.GetConfigurationOrNull(name, defaultValue) ?? defaultValue; } // ... 其他代码。 }在后续各种 Provider 里面定义的配置项,本质上就是对 _properties 字典进行操作。
2.2.3 容器的构造与初始化BLOB 容器并不是通过 IoC 容器直接解析构造的,而是通过 IBlobContainerFactory 工厂进行创建,与容器相关的配置对象和 BLOB Provider 也是在这个时候进行构造赋值。
public class BlobContainerFactory : IBlobContainerFactory, ITransientDependency { protected IBlobProviderSelector ProviderSelector { get; } protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } protected ICurrentTenant CurrentTenant { get; } protected ICancellationTokenProvider CancellationTokenProvider { get; } protected IServiceProvider ServiceProvider { get; } public BlobContainerFactory( IBlobContainerConfigurationProvider configurationProvider, ICurrentTenant currentTenant, ICancellationTokenProvider cancellationTokenProvider, IBlobProviderSelector providerSelector, IServiceProvider serviceProvider) { ConfigurationProvider = configurationProvider; CurrentTenant = currentTenant; CancellationTokenProvider = cancellationTokenProvider; ProviderSelector = providerSelector; ServiceProvider = serviceProvider; } public virtual IBlobContainer Create(string name) { // 根据容器的名称,获取对应的配置。 var configuration = ConfigurationProvider.Get(name); // 构造一个新的容器对象。 return new BlobContainer( name, configuration, // 一样的是根据容器名称,获得匹配的 Provider 类型。 ProviderSelector.Get(name), CurrentTenant, CancellationTokenProvider, ServiceProvider ); } }那么这个工厂方法是在什么时候调用的呢?跳转到工厂方法的实现,发现会被一个静态扩展方法所调用,重要的是这个方法是一个泛型方法,这样就与开头的类型化 BLOB 容器相对应了。
public static class BlobContainerFactoryExtensions { public static IBlobContainer Create<TContainer>( this IBlobContainerFactory blobContainerFactory ) { // 通过 GetContainerName 方法获取容器的名字。 return blobContainerFactory.Create( BlobContainerNameAttribute.GetContainerName<TContainer>() ); } }