[Abp vNext 源码分析] - 23. 二进制大对象系统(BLOB) (3)

GetContainerName() 方法也很简单,如果容器类型没有指定 BlobContainerNameAttribute 特性,那么就会默认使用类型的 FullName 作为名称。

public static string GetContainerName(Type type) { var nameAttribute = type.GetCustomAttribute<BlobContainerNameAttribute>(); if (nameAttribute == null) { return type.FullName; } return nameAttribute.GetName(type); }

最后的最后,看一下这个类型化的 BLOB 容器。

public class BlobContainer<TContainer> : IBlobContainer<TContainer> where TContainer : class { private readonly IBlobContainer _container; public BlobContainer(IBlobContainerFactory blobContainerFactory) { _container = blobContainerFactory.Create<TContainer>(); } // ... 其他代码。 }

对应的是模块初始化的工厂方法:

context.Services.AddTransient( typeof(IBlobContainer), serviceProvider => serviceProvider .GetRequiredService<IBlobContainer<DefaultContainer>>()

这里的 DefaultContainer 就指定了该特性,所以本质上一个 IBlobContainer 就是一个类型化的容器,它的泛型参数是 DefaultContainer。

[BlobContainerName(Name)] public class DefaultContainer { public const string Name = "default"; } 2.2.3.1 BLOB 的配置提供者

BLOB 容器工厂使用 IBlobContainerConfigurationProvider 来匹配对应容器的配置信息,实现比较简单,直接注入了 AbpBlobStoringOptions 并尝试从它的 BlobContainerConfigurations 中获取配置对象。

public class DefaultBlobContainerConfigurationProvider : IBlobContainerConfigurationProvider, ITransientDependency { protected AbpBlobStoringOptions Options { get; } public DefaultBlobContainerConfigurationProvider(IOptions<AbpBlobStoringOptions> options) { Options = options.Value; } public virtual BlobContainerConfiguration Get(string name) { return Options.Containers.GetConfiguration(name); } }

这里的 BlobContainerConfigurations 对象,核心就是一个键值对,键就是 BLOB 容器的名称,值就是容器对应的配置对象。

public class BlobContainerConfigurations { private BlobContainerConfiguration Default => GetConfiguration<DefaultContainer>(); private readonly Dictionary<string, BlobContainerConfiguration> _containers; public BlobContainerConfigurations() { _containers = new Dictionary<string, BlobContainerConfiguration> { // 添加默认的 BLOB 容器。 [BlobContainerNameAttribute.GetContainerName<DefaultContainer>()] = new BlobContainerConfiguration() }; } // ... 其他代码 public BlobContainerConfigurations Configure( [NotNull] string name, [NotNull] Action<BlobContainerConfiguration> configureAction) { Check.NotNullOrWhiteSpace(name, nameof(name)); Check.NotNull(configureAction, nameof(configureAction)); configureAction( _containers.GetOrAdd( name, () => new BlobContainerConfiguration(Default) ) ); return this; } public BlobContainerConfigurations ConfigureAll(Action<string, BlobContainerConfiguration> configureAction) { foreach (var container in _containers) { configureAction(container.Key, container.Value); } return this; } // ... 其他代码 }

在使用过程中,我们在模块里面调用的 Configure() 方法,就会在字典添加一个新的 Item,并为其赋值。而 ConfigureAll() 就是遍历这个字典,为每个 BLOB 容器调用委托,以便进行配置。

2.2.3.2 BLOB 的 Provider 选择器

在构造 BLOB 容器的时候,BLOB 容器工厂通过 IBlobProviderSelector 来选择对应的 BLOB Provider,具体选择哪一个是根据 BlobContainerConfiguration 里面的 ProviderType 决定的。

public virtual IBlobProvider Get([NotNull] string containerName) { Check.NotNull(containerName, nameof(containerName)); // 获得当前 BLOB 容器对应的配置信息。 var configuration = ConfigurationProvider.Get(containerName); if (!BlobProviders.Any()) { throw new AbpException("No BLOB Storage provider was registered! At least one provider must be registered to be able to use the Blog Storing System."); } foreach (var provider in BlobProviders) { // 通过配置信息匹配对应的 Provider。 if (ProxyHelper.GetUnProxiedType(provider).IsAssignableTo(configuration.ProviderType)) { return provider; } } throw new AbpException( $"Could not find the BLOB Storage provider with the type ({configuration.ProviderType.AssemblyQualifiedName}) configured for the container {containerName} and no default provider was set." ); }

上面的 BlobProviders 其实就是直接从 IoC 解析的 IEnumerable<IBlobProvider> 对象,我还找了半天是哪个地方进行赋值的。当 ABP 框架自动之后,会自动将已经实现的 BLOB Provider 注入到 IoC 容器中,如果某个容器在使用时指定了对应的配置参数,则会匹配对应的 BLOB Provider。

2.3 Provider 的实现 2.3.1 File System

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjpfg.html