当前位置: 首页 > news >正文

全国工程建设信息网站wordpress伪静

全国工程建设信息网站,wordpress伪静,南通 网站建设,wordpress口令查看内容一、简介ABP vNext 在 v 2.9.x 版本当中添加了 BLOB 系统#xff0c;主要用于存储大型二进制文件。ABP 抽象了一套通用的 BLOB 体系#xff0c;开发人员在存储或读取二进制文件时#xff0c;可以忽略具体实现#xff0c;直接使用IBlobContainer 或 IBlobContainerT… 一、简介ABP vNext 在 v 2.9.x 版本当中添加了 BLOB 系统主要用于存储大型二进制文件。ABP 抽象了一套通用的 BLOB 体系开发人员在存储或读取二进制文件时可以忽略具体实现直接使用IBlobContainer 或 IBlobContainerT 进行操作。官方的 BLOB Provider 实现有Azure、AWS、FileSystem(文件系统存储)、Database(数据库存储)、阿里云 OSS你也可以自己继承 BlobProviderBase 来实现其他的 Provider。BLOB 常用于各类二进制文件存储和管理基本就是对云服务的 OSS 进行了抽象在使用当中也会有 Bucket 和 Object Key 的概念在 BLOB 里面对应的就是 ContainerName 和 BlobName。关于 BLOB 的官方使用指南可以参考 https://docs.abp.io/en/abp/latest/Blob-Storing本文的阅读前提是建立在你已经阅读过该指南并有一定的使用经验。二、源码分析2.1 模块分析看一个 ABP 的库项目首先从他的 Module 入手对应的 BLOB 核心库的 Module 就是 AbpBlobStoringModule 类在其内部只进行了两个操作注入了 IBlobContainer 与 IBlobContainer 的实现。public override void ConfigureServices(ServiceConfigurationContext context) {context.Services.AddTransient(typeof(IBlobContainer),typeof(BlobContainer));context.Services.AddTransient(typeof(IBlobContainer),serviceProvider serviceProvider.GetRequiredServiceIBlobContainerDefaultContainer()); } 从上述代码可以看出来IBlobContainer 的默认实现还是基于 BlobContainerT 的。那么为啥会有个泛型的 Container从简介中可以看到 OSS 里面对应的 Bucket 其实就是一个 IBlobContainer。假如你会针对某云的多个 Bucket 进行操作那么就需要类型化的 BlobContainer 了。在这里可以看到IBlobContainer 的实现是一个工厂方法这一点在后面会进行解释。2.2 BLOB 容器2.2.1 容器的定义每个容器就是一个 OSS 的 Bucket开发人员在对 BLOB 进行操作时会注入 IBlobContainer/IBlobContainerT通过接口提供的 5 种方法进行操作这五个方法分别是 保存对象、删除对象、判断对象是否存在、获取对象、获取对象(不存在返回 NULL)。public interface IBlobContainer {// 保存对象Task SaveAsync(string name,Stream stream,bool overrideExisting false,CancellationToken cancellationToken default);// 删除对象Taskbool DeleteAsync(string name,CancellationToken cancellationToken default);// 判断对象是否存在Taskbool ExistsAsync(string name,CancellationToken cancellationToken default);// 获取对象TaskStream GetAsync(string name,CancellationToken cancellationToken default);// 获取对象(不存在返回 NULL)TaskStream GetOrNullAsync(string name,CancellationToken cancellationToken default);//TODO: Create shortcut extension methods: GetAsArraryAsync, GetAsStringAsync(encoding) (and null versions) } 泛型的 BLOB 容器也是集成自该接口内部没有任何特殊的方法。public interface IBlobContainerTContainer : IBlobContainerwhere TContainer: class {} 2.2.2 容器的实现容器的两种实现都存放在 BlobContainer.cs 文件当中标注容器实现内部都会有一个 ContainerName用于标识不同的容器并且和其他的组件作为 关联键 进行绑定。每个容器都会关联 BlobContainerConfiguration、IBlobProvider 两个组件它们分别提供了容器的配置信息和容器的具体实现 Provider在容器构造的时候根据 ContainerName 分别进行初始化。public class BlobContainer : IBlobContainer {protected string ContainerName { get; }protected BlobContainerConfiguration Configuration { get; }protected IBlobProvider Provider { get; }protected ICurrentTenant CurrentTenant { get; }protected ICancellationTokenProvider CancellationTokenProvider { get; }protected IServiceProvider ServiceProvider { get; }// ... 其他代码。 } 可以看到这里还注入了 ICurrentTenant注入该对象的主要作用是用来处理多租户的情况如果当前容器启用了多租户那么会手动 Change()。下面以 SaveAsync() 方法为例。public virtual async Task SaveAsync(string name,Stream stream,bool overrideExisting false,CancellationToken cancellationToken default) {// 变更当前租户信息当启用了多租户时会使用当前租户进行变更。using (CurrentTenant.Change(GetTenantIdOrNull())){// 根据 ContainerName 取得对应的标准化容器名称和对象名称。var (normalizedContainerName, normalizedBlobName) NormalizeNaming(ContainerName, name);// 使用 ContainerName 匹配的 Provider 存储对象数据。await Provider.SaveAsync(new BlobProviderSaveArgs(normalizedContainerName,Configuration,normalizedBlobName,stream,overrideExisting,CancellationTokenProvider.FallbackToProvider(cancellationToken)));} } 这里有两个地方需要单独分析第一个是 NormalizeNaming() 的作用第二个是 BlobProviderSaveArgs 对象。2.2.3.1 名称标准化对象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).AsIBlobNamingNormalizer();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 ITypeListIBlobNamingNormalizer NamingNormalizers { get; }// 当前 BLOB 容器的属性。[NotNull] private readonly Dictionarystring, object _properties;// 当尝试获取某些配置属性但是不存在时会从这个 Configuration 拿取数据。[CanBeNull] private readonly BlobContainerConfiguration _fallbackConfiguration;public BlobContainerConfiguration(BlobContainerConfiguration fallbackConfiguration null){NamingNormalizers new TypeListIBlobNamingNormalizer();_fallbackConfiguration fallbackConfiguration;_properties new Dictionarystring, object();}[CanBeNull]public T GetConfigurationOrDefaultT(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 CreateTContainer(this IBlobContainerFactory blobContainerFactory){// 通过 GetContainerName 方法获取容器的名字。return blobContainerFactory.Create(BlobContainerNameAttribute.GetContainerNameTContainer());} } GetContainerName() 方法也很简单如果容器类型没有指定 BlobContainerNameAttribute特性那么就会默认使用类型的 FullName 作为名称。public static string GetContainerName(Type type) {var nameAttribute type.GetCustomAttributeBlobContainerNameAttribute();if (nameAttribute null){return type.FullName;}return nameAttribute.GetName(type); } 最后的最后看一下这个类型化的 BLOB 容器。public class BlobContainerTContainer : IBlobContainerTContainerwhere TContainer : class {private readonly IBlobContainer _container;public BlobContainer(IBlobContainerFactory blobContainerFactory){_container blobContainerFactory.CreateTContainer();}// ... 其他代码。 } 对应的是模块初始化的工厂方法context.Services.AddTransient(typeof(IBlobContainer),serviceProvider serviceProvider.GetRequiredServiceIBlobContainerDefaultContainer() 这里的 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(IOptionsAbpBlobStoringOptions options){Options options.Value;}public virtual BlobContainerConfiguration Get(string name){return Options.Containers.GetConfiguration(name);} } 这里的 BlobContainerConfigurations 对象核心就是一个键值对键就是 BLOB 容器的名称值就是容器对应的配置对象。public class BlobContainerConfigurations {private BlobContainerConfiguration Default GetConfigurationDefaultContainer();private readonly Dictionarystring, BlobContainerConfiguration _containers;public BlobContainerConfigurations(){_containers new Dictionarystring, BlobContainerConfiguration{// 添加默认的 BLOB 容器。[BlobContainerNameAttribute.GetContainerNameDefaultContainer()] new BlobContainerConfiguration()};}// ... 其他代码public BlobContainerConfigurations Configure([NotNull] string name,[NotNull] ActionBlobContainerConfiguration configureAction){Check.NotNullOrWhiteSpace(name, nameof(name));Check.NotNull(configureAction, nameof(configureAction));configureAction(_containers.GetOrAdd(name,() new BlobContainerConfiguration(Default)));return this;}public BlobContainerConfigurations ConfigureAll(Actionstring, 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 解析的 IEnumerableIBlobProvider 对象我还找了半天是哪个地方进行赋值的。当 ABP 框架自动之后会自动将已经实现的 BLOB Provider 注入到 IoC 容器中如果某个容器在使用时指定了对应的配置参数则会匹配对应的 BLOB Provider。2.3 Provider 的实现2.3.1 File System文件系统作为 BLOB 的最简化实现本质就是通过文件夹进行租户隔离动作所有操作都会将数据持久化到硬盘上。核心代码就一个文件 FileSystemBlobProvider在这个文件内部定义了具体的执行逻辑我们这里大概看一下 SaveAsyn() 的实现。public override async Task SaveAsync(BlobProviderSaveArgs args) {var filePath FilePathCalculator.Calculate(args);if (!args.OverrideExisting await ExistsAsync(filePath)){throw new BlobAlreadyExistsException($Saving BLOB {args.BlobName} does already exists in the container {args.ContainerName}! Set {nameof(args.OverrideExisting)} if it should be overwritten.);}DirectoryHelper.CreateIfNotExists(Path.GetDirectoryName(filePath));var fileMode args.OverrideExisting? FileMode.Create: FileMode.CreateNew;await Policy.HandleIOException().WaitAndRetryAsync(2, retryCount TimeSpan.FromSeconds(retryCount)).ExecuteAsync(async () {using (var fileStream File.Open(filePath, fileMode, FileAccess.Write)){await args.BlobStream.CopyToAsync(fileStream,args.CancellationToken);await fileStream.FlushAsync();}}); } 很简单通过 FilePathCalculator计算出来文件的具体路径然后结合配置参数来判断文件是否存在以及是否进入后续操作。通过 Polly 提供的重试机制来创建文件。2.3.2 DataBase数据库 Provider 是利用数据库的 BLOB 类型将这些大型对象存储到数据库当中不太建议这样操作。这里不再进行详细介绍基本大同小异。2.3.3 各类 OSS (腾讯云为例)OSS 作为云厂商的标配基本概念和操作都与 ABP 的 BLOB 相匹配集成起来也还是比较简单就是将各个 OSS 的 SDK 塞进来就行。这里注意点的是每个 BLOB Provider 都会编写一个基于 BlobContainerConfiguration 类型的静态方法取名都叫做 UseXXX()并在里面对具体的配置进行赋值。public static class TencentCloudBlobContainerConfigurationExtensions {public static TencentCloudBlobProviderConfiguration GetTencentCloudConfiguration(this BlobContainerConfiguration containerConfiguration){return new TencentCloudBlobProviderConfiguration(containerConfiguration);}public static BlobContainerConfiguration UseTencentCloud(this BlobContainerConfiguration containerConfiguration,ActionTencentCloudBlobProviderConfiguration tencentCloudConfigureAction){containerConfiguration.ProviderType typeof(TencentCloudBlobProvider);containerConfiguration.NamingNormalizers.TryAddTencentCloudBlobNamingNormalizer();tencentCloudConfigureAction(new TencentCloudBlobProviderConfiguration(containerConfiguration));return containerConfiguration;} } 可能会对这个 TencentCloudBlobProviderConfiguration 有一些好奇其实就是个套娃因为直接传入了 BlobContainerConfiguration 对象里面的各种属性本质上就是对配置项的那个 Dictionarystring,object 进行操作。public class TencentCloudBlobProviderConfiguration {public string AppId{get _containerConfiguration.GetConfigurationOrDefaultstring(TencentCloudBlobProviderConfigurationNames.AppId);set _containerConfiguration.SetConfiguration(TencentCloudBlobProviderConfigurationNames.AppId, value);}public string SecretId{get _containerConfiguration.GetConfigurationOrDefaultstring(TencentCloudBlobProviderConfigurationNames.SecretId);set _containerConfiguration.SetConfiguration(TencentCloudBlobProviderConfigurationNames.SecretId, value);}// ... 其他代码public TencentCloudBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration){_containerConfiguration containerConfiguration;} } 腾讯云的 BLOB Provider 仓库https://github.com/EasyAbp/Abp.BlobStoring.TencentCloud2.4 回顾开发人员可以在模块的 ConfigureService() 阶段为所有容器或者特定容器指定参数。ABP vNext 框架会注入所有的 BLOB Provider并注入默认的 IBlobContainerDefaultContainer 容器和其他的类型化容器实现。当需要使用 BLOB 时开发人员注入了 IBlobContainer 或 IBlobContainerT。BLOB 容器的工厂会根据容器的名称匹配对应的 BLOB Provider 和配置对象。BLOB Provider 根据 **Args 参数内部附带的配置对象读取对应的配置信息进行自定义的操作。三、总结小型项目直接集成 FileSystem 即可中大型项目可以使用各种 OSS ProviderBLOB 系统可以简化开发人员对于大量二进制文件的管理操作。最近工作相当杂乱繁忙下半年希望有时间继续学习更新吧。相关文章我和ABP vNext 的故事基于 abp vNext 和 .NET Core 开发博客项目 - 终结篇之发布项目[Abp vNext 源码分析] - 19. 多租户abp vnext2.0核心组件之DDD组件之实体结构源码解析基于Abp VNext框架设计 - Masstransit分布式消息ABP vNext中使用开源日志面板 LogDashboard
http://www.yutouwan.com/news/4052/

相关文章:

  • 做电影网站怎样赚钱吗该网站使用的安全设置
  • 大型网站开发用的技术网站订单模板
  • 企业网站开发哪家专业人员优化方案怎么写
  • 网站分站系上海注册公司需要多少钱
  • 物流信息网站有哪些网游大全
  • 做公司网站的多少钱免费的com域名注册
  • 个人怎么做网站页面ps做图软件怎么下载网站
  • 国外网站视觉设计趋势做网站的例子
  • 安徽城乡建设厅官方网站杭州自助建站模板
  • 网页设计中优秀的网站企业网站主要有哪四种类型
  • 很多搜索词网站怎样做烟台开发区网站
  • 重庆网站优化公司怎么样顶格处罚鼠头鸭脖涉事企业
  • 做婚恋网站多少钱电子商城网站建设的实训内容记述
  • 太原电商网站设计百度自媒体怎么注册
  • 网站内部链接的策略wordpress 图片弹出
  • 网站建设系统有哪些十堰网站建设专家
  • 网站设计应该考虑的重要因素自己做网站seo
  • 上海最大的网站建设怎样做公司网站推广
  • 软文网站有哪些买房网
  • 网站开发合同售后服务大理网站建设
  • 盗版小说网站怎么赚钱企业融资的方式有哪几种
  • wordpress站点标题美化网站架构计划书
  • 购物网站开发总结报告清空wordpress数据库
  • excel中批量做网站的超链接商城网站建设框架
  • 建成区违法建设治理网站分销体系搭建
  • 帮一个企业做网站流程广告网站模板下载 迅雷下载安装
  • 成都门户网站有哪些婚纱摄影网站html
  • 搭建网站详细步骤为外国企业做中文网站建设
  • 建设网站编程语言广告效果图设计
  • 塘坑网站建设怎么做公司logo