Browse Source

feat(oss): add public/private file management api

pull/327/head
cKey 4 years ago
parent
commit
a2d478c993
  1. 739
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs
  2. 4
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN.Abp.OssManagement.Application.Contracts.csproj
  3. 24
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationContractsModule.cs
  4. 75
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs
  5. 41
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureNames.cs
  6. 5
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN.Abp.OssManagement.Application.csproj
  7. 50
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationModule.cs
  8. 28
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssManagementApplicationServiceBase.cs
  9. 217
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssObjectAppService.cs
  10. 83
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PublicFileAppService.cs
  11. 5
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN.Abp.OssManagement.Domain.Shared.csproj
  12. 72
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/AbpOssManagementDomainSharedModule.cs
  13. 1
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/en.json
  14. 1
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/zh-Hans.json
  15. 35
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/OssManagementErrorCodes.cs
  16. 49
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementDomainModule.cs
  17. 36
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/AbpOssManagementFileSystemModule.cs
  18. 15
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainer.cs
  19. 96
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainerFactory.cs
  20. 1
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN.Abp.OssManagement.HttpApi.csproj
  21. 68
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiModule.cs
  22. 96
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/FileValidater.cs
  23. 9
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/IFileValidater.cs
  24. 4
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/StaticFilesController.cs
  25. 12
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/UploadOssObjectInput.cs
  26. 20
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.SettingManagement/AbpOssManagementSettingManagementModule.cs
  27. 101
      aspnet-core/modules/oss-management/README.md
  28. 675
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs

739
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Aliyun/LINGYUN/Abp/OssManagement/Aliyun/AliyunOssContainer.cs

@ -1,369 +1,370 @@
using Aliyun.OSS;
using LINGYUN.Abp.BlobStoring.Aliyun;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.OssManagement.Aliyun
{
/// <summary>
/// Oss容器的阿里云实现
/// </summary>
internal class AliyunOssContainer : IOssContainer
{
protected ICurrentTenant CurrentTenant { get; }
protected IOssClientFactory OssClientFactory { get; }
public AliyunOssContainer(
ICurrentTenant currentTenant,
IOssClientFactory ossClientFactory)
{
CurrentTenant = currentTenant;
OssClientFactory = ossClientFactory;
}
public virtual async Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request)
{
var ossClient = await CreateClientAsync();
var path = GetBasePath(request.Path);
var aliyunRequest = new DeleteObjectsRequest(request.Bucket, request.Objects.Select(x => x += path).ToList());
ossClient.DeleteObjects(aliyunRequest);
}
public virtual async Task<OssContainer> CreateAsync(string name)
{
var ossClient = await CreateClientAsync();
if (BucketExists(ossClient, name))
{
throw new BusinessException(code: OssManagementErrorCodes.ContainerAlreadyExists);
}
var bucket = ossClient.CreateBucket(name);
return new OssContainer(
bucket.Name,
bucket.CreationDate,
0L,
bucket.CreationDate,
new Dictionary<string, string>
{
{ "Id", bucket.Owner?.Id },
{ "DisplayName", bucket.Owner?.DisplayName }
});
}
public virtual async Task<OssObject> CreateObjectAsync(CreateOssObjectRequest request)
{
var ossClient = await CreateClientAsync();
var objectPath = GetBasePath(request.Path);
var objectName = objectPath.IsNullOrWhiteSpace()
? request.Object
: objectPath + request.Object;
if (!request.Overwrite && ObjectExists(ossClient, request.Bucket, objectName))
{
throw new BusinessException(code: OssManagementErrorCodes.ObjectAlreadyExists);
}
// 当一个对象名称是以 / 结尾时,不论该对象是否存有数据,都以目录的形式存在
// 详情见:https://help.aliyun.com/document_detail/31910.html
if (objectName.EndsWith("/") &&
request.Content.IsNullOrEmpty())
{
var emptyStream = new MemoryStream();
var emptyData = System.Text.Encoding.UTF8.GetBytes("");
await emptyStream.WriteAsync(emptyData, 0, emptyData.Length);
request.SetContent(emptyStream);
}
// 没有bucket则创建
if (!BucketExists(ossClient, request.Bucket))
{
ossClient.CreateBucket(request.Bucket);
}
var aliyunObjectRequest = new PutObjectRequest(request.Bucket, objectName, request.Content)
{
Metadata = new ObjectMetadata()
};
if (request.ExpirationTime.HasValue)
{
aliyunObjectRequest.Metadata.ExpirationTime = DateTime.Now.Add(request.ExpirationTime.Value);
}
var aliyunObject = ossClient.PutObject(aliyunObjectRequest);
var ossObject = new OssObject(
!objectPath.IsNullOrWhiteSpace()
? objectName.Replace(objectPath, "")
: objectName,
objectPath,
DateTime.Now,
aliyunObject.ContentLength,
DateTime.Now,
aliyunObject.ResponseMetadata,
objectName.EndsWith("/") // 名称结尾是 / 符号的则为目录:https://help.aliyun.com/document_detail/31910.html
)
{
FullName = objectName
};
if (!Equals(request.Content, Stream.Null))
{
request.Content.Seek(0, SeekOrigin.Begin);
ossObject.SetContent(request.Content);
}
return ossObject;
}
public virtual async Task DeleteAsync(string name)
{
var ossClient = await CreateClientAsync();
if (BucketExists(ossClient, name))
{
ossClient.DeleteBucket(name);
}
}
public virtual async Task DeleteObjectAsync(GetOssObjectRequest request)
{
var ossClient = await CreateClientAsync();
var objectPath = GetBasePath(request.Path);
var objectName = objectPath.IsNullOrWhiteSpace()
? request.Object
: objectPath + request.Object;
if (BucketExists(ossClient, request.Bucket) &&
ObjectExists(ossClient, request.Bucket, objectName))
{
var objectListing = ossClient.ListObjects(request.Bucket, objectName);
if (objectListing.CommonPrefixes.Any() ||
objectListing.ObjectSummaries.Any())
{
throw new BusinessException(code: OssManagementErrorCodes.ObjectDeleteWithNotEmpty);
// throw new ObjectDeleteWithNotEmptyException("00201", $"Can't not delete oss object {request.Object}, because it is not empty!");
}
ossClient.DeleteObject(request.Bucket, objectName);
}
}
public virtual async Task<bool> ExistsAsync(string name)
{
var ossClient = await CreateClientAsync();
return BucketExists(ossClient, name);
}
public virtual async Task<OssContainer> GetAsync(string name)
{
var ossClient = await CreateClientAsync();
if (!BucketExists(ossClient, name))
{
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
// throw new ContainerNotFoundException($"Can't not found container {name} in aliyun blob storing");
}
var bucket = ossClient.GetBucketInfo(name);
return new OssContainer(
bucket.Bucket.Name,
bucket.Bucket.CreationDate,
0L,
bucket.Bucket.CreationDate,
new Dictionary<string, string>
{
{ "Id", bucket.Bucket.Owner?.Id },
{ "DisplayName", bucket.Bucket.Owner?.DisplayName }
});
}
public virtual async Task<OssObject> GetObjectAsync(GetOssObjectRequest request)
{
var ossClient = await CreateClientAsync();
if (!BucketExists(ossClient, request.Bucket))
{
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
// throw new ContainerNotFoundException($"Can't not found container {request.Bucket} in aliyun blob storing");
}
var objectPath = GetBasePath(request.Path);
var objectName = objectPath.IsNullOrWhiteSpace()
? request.Object
: objectPath + request.Object;
if (!ObjectExists(ossClient, request.Bucket, objectName))
{
throw new BusinessException(code: OssManagementErrorCodes.ObjectNotFound);
// throw new ContainerNotFoundException($"Can't not found object {objectName} in container {request.Bucket} with aliyun blob storing");
}
var aliyunOssObjectRequest = new GetObjectRequest(request.Bucket, objectName, request.Process);
var aliyunOssObject = ossClient.GetObject(aliyunOssObjectRequest);
var ossObject = new OssObject(
!objectPath.IsNullOrWhiteSpace()
? aliyunOssObject.Key.Replace(objectPath, "")
: aliyunOssObject.Key,
request.Path,
aliyunOssObject.Metadata.LastModified,
aliyunOssObject.Metadata.ContentLength,
aliyunOssObject.Metadata.LastModified,
aliyunOssObject.Metadata.UserMetadata,
aliyunOssObject.Key.EndsWith("/"))
{
FullName = aliyunOssObject.Key
};
if (aliyunOssObject.IsSetResponseStream())
{
var memoryStream = new MemoryStream();
await aliyunOssObject.Content.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
ossObject.SetContent(memoryStream);
}
return ossObject;
}
public virtual async Task<GetOssContainersResponse> GetListAsync(GetOssContainersRequest request)
{
var ossClient = await CreateClientAsync();
var aliyunRequest = new ListBucketsRequest
{
Marker = request.Marker,
Prefix = request.Prefix,
MaxKeys = request.MaxKeys
};
var bucketsResponse = ossClient.ListBuckets(aliyunRequest);
return new GetOssContainersResponse(
bucketsResponse.Prefix,
bucketsResponse.Marker,
bucketsResponse.NextMaker,
bucketsResponse.MaxKeys ?? 0,
bucketsResponse.Buckets
.Select(x => new OssContainer(
x.Name,
x.CreationDate,
0L,
x.CreationDate,
new Dictionary<string, string>
{
{ "Id", x.Owner?.Id },
{ "DisplayName", x.Owner?.DisplayName }
}))
.ToList());
}
public virtual async Task<GetOssObjectsResponse> GetObjectsAsync(GetOssObjectsRequest request)
{
var ossClient = await CreateClientAsync();
var objectPath = GetBasePath(request.Prefix);
var marker = !objectPath.IsNullOrWhiteSpace() && !request.Marker.IsNullOrWhiteSpace()
? request.Marker.Replace(objectPath, "")
: request.Marker;
var aliyunRequest = new ListObjectsRequest(request.BucketName)
{
Marker = !marker.IsNullOrWhiteSpace() ? objectPath + marker : marker,
Prefix = objectPath,
MaxKeys = request.MaxKeys,
EncodingType = request.EncodingType,
Delimiter = request.Delimiter
};
var objectsResponse = ossClient.ListObjects(aliyunRequest);
var ossObjects = objectsResponse.ObjectSummaries
.Where(x => !x.Key.Equals(objectsResponse.Prefix))// 过滤当前的目录返回值
.Select(x => new OssObject(
!objectPath.IsNullOrWhiteSpace() && !x.Key.Equals(objectPath)
? x.Key.Replace(objectPath, "")
: x.Key, // 去除目录名称
request.Prefix,
x.LastModified,
x.Size,
x.LastModified,
new Dictionary<string, string>
{
{ "Id", x.Owner?.Id },
{ "DisplayName", x.Owner?.DisplayName }
},
x.Key.EndsWith("/"))
{
FullName = x.Key
})
.ToList();
// 当 Delimiter 为 / 时, objectsResponse.CommonPrefixes 可用于代表层级目录
if (objectsResponse.CommonPrefixes.Any())
{
ossObjects.InsertRange(0,
objectsResponse.CommonPrefixes
.Select(x => new OssObject(
x.Replace(objectPath, ""),
request.Prefix,
null,
0L,
null,
null,
true)));
}
// 排序
// TODO: 是否需要客户端来排序
ossObjects.Sort(new OssObjectComparer());
return new GetOssObjectsResponse(
objectsResponse.BucketName,
request.Prefix,
marker,
!objectPath.IsNullOrWhiteSpace() && !objectsResponse.NextMarker.IsNullOrWhiteSpace()
? objectsResponse.NextMarker.Replace(objectPath, "")
: objectsResponse.NextMarker,
objectsResponse.Delimiter,
objectsResponse.MaxKeys,
ossObjects);
}
protected virtual string GetBasePath(string path)
{
string objectPath = "";
if (CurrentTenant.Id == null)
{
objectPath += "host/";
}
else
{
objectPath += "tenants/" + CurrentTenant.Id.Value.ToString("D");
}
objectPath += path ?? "";
return objectPath.EnsureEndsWith('/');
}
protected virtual bool BucketExists(IOss client, string bucketName)
{
return client.DoesBucketExist(bucketName);
}
protected virtual bool ObjectExists(IOss client, string bucketName, string objectName)
{
return client.DoesObjectExist(bucketName, objectName);
}
protected virtual async Task<IOss> CreateClientAsync()
{
return await OssClientFactory.CreateAsync<AbpOssManagementContainer>();
}
}
}
using Aliyun.OSS;
using LINGYUN.Abp.BlobStoring.Aliyun;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.OssManagement.Aliyun
{
/// <summary>
/// Oss容器的阿里云实现
/// </summary>
internal class AliyunOssContainer : IOssContainer
{
protected ICurrentTenant CurrentTenant { get; }
protected IOssClientFactory OssClientFactory { get; }
public AliyunOssContainer(
ICurrentTenant currentTenant,
IOssClientFactory ossClientFactory)
{
CurrentTenant = currentTenant;
OssClientFactory = ossClientFactory;
}
public virtual async Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request)
{
var ossClient = await CreateClientAsync();
var path = GetBasePath(request.Path);
var aliyunRequest = new DeleteObjectsRequest(request.Bucket, request.Objects.Select(x => x += path).ToList());
ossClient.DeleteObjects(aliyunRequest);
}
public virtual async Task<OssContainer> CreateAsync(string name)
{
var ossClient = await CreateClientAsync();
if (BucketExists(ossClient, name))
{
throw new BusinessException(code: OssManagementErrorCodes.ContainerAlreadyExists);
}
var bucket = ossClient.CreateBucket(name);
return new OssContainer(
bucket.Name,
bucket.CreationDate,
0L,
bucket.CreationDate,
new Dictionary<string, string>
{
{ "Id", bucket.Owner?.Id },
{ "DisplayName", bucket.Owner?.DisplayName }
});
}
public virtual async Task<OssObject> CreateObjectAsync(CreateOssObjectRequest request)
{
var ossClient = await CreateClientAsync();
var objectPath = GetBasePath(request.Path);
var objectName = objectPath.IsNullOrWhiteSpace()
? request.Object
: objectPath + request.Object;
if (!request.Overwrite && ObjectExists(ossClient, request.Bucket, objectName))
{
throw new BusinessException(code: OssManagementErrorCodes.ObjectAlreadyExists);
}
// 当一个对象名称是以 / 结尾时,不论该对象是否存有数据,都以目录的形式存在
// 详情见:https://help.aliyun.com/document_detail/31910.html
if (objectName.EndsWith("/") &&
request.Content.IsNullOrEmpty())
{
var emptyStream = new MemoryStream();
var emptyData = System.Text.Encoding.UTF8.GetBytes("");
await emptyStream.WriteAsync(emptyData, 0, emptyData.Length);
request.SetContent(emptyStream);
}
// 没有bucket则创建
if (!BucketExists(ossClient, request.Bucket))
{
ossClient.CreateBucket(request.Bucket);
}
var aliyunObjectRequest = new PutObjectRequest(request.Bucket, objectName, request.Content)
{
Metadata = new ObjectMetadata()
};
if (request.ExpirationTime.HasValue)
{
aliyunObjectRequest.Metadata.ExpirationTime = DateTime.Now.Add(request.ExpirationTime.Value);
}
var aliyunObject = ossClient.PutObject(aliyunObjectRequest);
var ossObject = new OssObject(
!objectPath.IsNullOrWhiteSpace()
? objectName.Replace(objectPath, "")
: objectName,
objectPath,
DateTime.Now,
aliyunObject.ContentLength,
DateTime.Now,
aliyunObject.ResponseMetadata,
objectName.EndsWith("/") // 名称结尾是 / 符号的则为目录:https://help.aliyun.com/document_detail/31910.html
)
{
FullName = objectName
};
if (!Equals(request.Content, Stream.Null))
{
request.Content.Seek(0, SeekOrigin.Begin);
ossObject.SetContent(request.Content);
}
return ossObject;
}
public virtual async Task DeleteAsync(string name)
{
// 阿里云oss在控制台设置即可,无需改变
var ossClient = await CreateClientAsync();
if (BucketExists(ossClient, name))
{
ossClient.DeleteBucket(name);
}
}
public virtual async Task DeleteObjectAsync(GetOssObjectRequest request)
{
var ossClient = await CreateClientAsync();
var objectPath = GetBasePath(request.Path);
var objectName = objectPath.IsNullOrWhiteSpace()
? request.Object
: objectPath + request.Object;
if (BucketExists(ossClient, request.Bucket) &&
ObjectExists(ossClient, request.Bucket, objectName))
{
var objectListing = ossClient.ListObjects(request.Bucket, objectName);
if (objectListing.CommonPrefixes.Any() ||
objectListing.ObjectSummaries.Any())
{
throw new BusinessException(code: OssManagementErrorCodes.ObjectDeleteWithNotEmpty);
// throw new ObjectDeleteWithNotEmptyException("00201", $"Can't not delete oss object {request.Object}, because it is not empty!");
}
ossClient.DeleteObject(request.Bucket, objectName);
}
}
public virtual async Task<bool> ExistsAsync(string name)
{
var ossClient = await CreateClientAsync();
return BucketExists(ossClient, name);
}
public virtual async Task<OssContainer> GetAsync(string name)
{
var ossClient = await CreateClientAsync();
if (!BucketExists(ossClient, name))
{
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
// throw new ContainerNotFoundException($"Can't not found container {name} in aliyun blob storing");
}
var bucket = ossClient.GetBucketInfo(name);
return new OssContainer(
bucket.Bucket.Name,
bucket.Bucket.CreationDate,
0L,
bucket.Bucket.CreationDate,
new Dictionary<string, string>
{
{ "Id", bucket.Bucket.Owner?.Id },
{ "DisplayName", bucket.Bucket.Owner?.DisplayName }
});
}
public virtual async Task<OssObject> GetObjectAsync(GetOssObjectRequest request)
{
var ossClient = await CreateClientAsync();
if (!BucketExists(ossClient, request.Bucket))
{
throw new BusinessException(code: OssManagementErrorCodes.ContainerNotFound);
// throw new ContainerNotFoundException($"Can't not found container {request.Bucket} in aliyun blob storing");
}
var objectPath = GetBasePath(request.Path);
var objectName = objectPath.IsNullOrWhiteSpace()
? request.Object
: objectPath + request.Object;
if (!ObjectExists(ossClient, request.Bucket, objectName))
{
throw new BusinessException(code: OssManagementErrorCodes.ObjectNotFound);
// throw new ContainerNotFoundException($"Can't not found object {objectName} in container {request.Bucket} with aliyun blob storing");
}
var aliyunOssObjectRequest = new GetObjectRequest(request.Bucket, objectName, request.Process);
var aliyunOssObject = ossClient.GetObject(aliyunOssObjectRequest);
var ossObject = new OssObject(
!objectPath.IsNullOrWhiteSpace()
? aliyunOssObject.Key.Replace(objectPath, "")
: aliyunOssObject.Key,
request.Path,
aliyunOssObject.Metadata.LastModified,
aliyunOssObject.Metadata.ContentLength,
aliyunOssObject.Metadata.LastModified,
aliyunOssObject.Metadata.UserMetadata,
aliyunOssObject.Key.EndsWith("/"))
{
FullName = aliyunOssObject.Key
};
if (aliyunOssObject.IsSetResponseStream())
{
var memoryStream = new MemoryStream();
await aliyunOssObject.Content.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
ossObject.SetContent(memoryStream);
}
return ossObject;
}
public virtual async Task<GetOssContainersResponse> GetListAsync(GetOssContainersRequest request)
{
var ossClient = await CreateClientAsync();
var aliyunRequest = new ListBucketsRequest
{
Marker = request.Marker,
Prefix = request.Prefix,
MaxKeys = request.MaxKeys
};
var bucketsResponse = ossClient.ListBuckets(aliyunRequest);
return new GetOssContainersResponse(
bucketsResponse.Prefix,
bucketsResponse.Marker,
bucketsResponse.NextMaker,
bucketsResponse.MaxKeys ?? 0,
bucketsResponse.Buckets
.Select(x => new OssContainer(
x.Name,
x.CreationDate,
0L,
x.CreationDate,
new Dictionary<string, string>
{
{ "Id", x.Owner?.Id },
{ "DisplayName", x.Owner?.DisplayName }
}))
.ToList());
}
public virtual async Task<GetOssObjectsResponse> GetObjectsAsync(GetOssObjectsRequest request)
{
var ossClient = await CreateClientAsync();
var objectPath = GetBasePath(request.Prefix);
var marker = !objectPath.IsNullOrWhiteSpace() && !request.Marker.IsNullOrWhiteSpace()
? request.Marker.Replace(objectPath, "")
: request.Marker;
var aliyunRequest = new ListObjectsRequest(request.BucketName)
{
Marker = !marker.IsNullOrWhiteSpace() ? objectPath + marker : marker,
Prefix = objectPath,
MaxKeys = request.MaxKeys,
EncodingType = request.EncodingType,
Delimiter = request.Delimiter
};
var objectsResponse = ossClient.ListObjects(aliyunRequest);
var ossObjects = objectsResponse.ObjectSummaries
.Where(x => !x.Key.Equals(objectsResponse.Prefix))// 过滤当前的目录返回值
.Select(x => new OssObject(
!objectPath.IsNullOrWhiteSpace() && !x.Key.Equals(objectPath)
? x.Key.Replace(objectPath, "")
: x.Key, // 去除目录名称
request.Prefix,
x.LastModified,
x.Size,
x.LastModified,
new Dictionary<string, string>
{
{ "Id", x.Owner?.Id },
{ "DisplayName", x.Owner?.DisplayName }
},
x.Key.EndsWith("/"))
{
FullName = x.Key
})
.ToList();
// 当 Delimiter 为 / 时, objectsResponse.CommonPrefixes 可用于代表层级目录
if (objectsResponse.CommonPrefixes.Any())
{
ossObjects.InsertRange(0,
objectsResponse.CommonPrefixes
.Select(x => new OssObject(
x.Replace(objectPath, ""),
request.Prefix,
null,
0L,
null,
null,
true)));
}
// 排序
// TODO: 是否需要客户端来排序
ossObjects.Sort(new OssObjectComparer());
return new GetOssObjectsResponse(
objectsResponse.BucketName,
request.Prefix,
marker,
!objectPath.IsNullOrWhiteSpace() && !objectsResponse.NextMarker.IsNullOrWhiteSpace()
? objectsResponse.NextMarker.Replace(objectPath, "")
: objectsResponse.NextMarker,
objectsResponse.Delimiter,
objectsResponse.MaxKeys,
ossObjects);
}
protected virtual string GetBasePath(string path)
{
string objectPath = "";
if (CurrentTenant.Id == null)
{
objectPath += "host/";
}
else
{
objectPath += "tenants/" + CurrentTenant.Id.Value.ToString("D");
}
objectPath += path ?? "";
return objectPath.EnsureEndsWith('/');
}
protected virtual bool BucketExists(IOss client, string bucketName)
{
return client.DoesBucketExist(bucketName);
}
protected virtual bool ObjectExists(IOss client, string bucketName, string objectName)
{
return client.DoesObjectExist(bucketName, objectName);
}
protected virtual async Task<IOss> CreateClientAsync()
{
return await OssClientFactory.CreateAsync<AbpOssManagementContainer>();
}
}
}

4
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN.Abp.OssManagement.Application.Contracts.csproj

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Application" Version="4.4.0" />
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="4.4.0" />
</ItemGroup>
<ItemGroup>

24
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationContractsModule.cs

@ -1,12 +1,12 @@
using Volo.Abp.Application;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpOssManagementDomainSharedModule),
typeof(AbpDddApplicationModule))]
public class AbpOssManagementApplicationContractsModule : AbpModule
{
}
}
using Volo.Abp.Application;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpOssManagementDomainSharedModule),
typeof(AbpDddApplicationContractsModule))]
public class AbpOssManagementApplicationContractsModule : AbpModule
{
}
}

75
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureDefinitionProvider.cs

@ -1,75 +0,0 @@
using LINGYUN.Abp.OssManagement.Localization;
using Volo.Abp.Features;
using Volo.Abp.Localization;
using Volo.Abp.Validation.StringValues;
namespace LINGYUN.Abp.OssManagement.Features
{
public class AbpOssManagementFeatureDefinitionProvider : FeatureDefinitionProvider
{
public override void Define(IFeatureDefinitionContext context)
{
var featureGroup = context.AddGroup(
name: AbpOssManagementFeatureNames.GroupName,
displayName: L("Features:OssManagement"));
var ossFeature = featureGroup.AddFeature(
name: AbpOssManagementFeatureNames.OssObject.Default,
defaultValue: true.ToString(),
displayName: L("Features:DisplayName:OssObject"),
description: L("Features:Description:OssObject"),
valueType: new ToggleStringValueType(new BooleanValueValidator()));
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.DownloadFile,
defaultValue: false.ToString(),
displayName: L("Features:DisplayName:DownloadFile"),
description: L("Features:Description:DownloadFile"),
valueType: new ToggleStringValueType(new BooleanValueValidator()));
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.DownloadLimit,
defaultValue: "1000",
displayName: L("Features:DisplayName:DownloadLimit"),
description: L("Features:Description:DownloadLimit"),
valueType: new FreeTextStringValueType(new NumericValueValidator(0, 100_0000))); // 上限100万次调用
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.DownloadInterval,
defaultValue: "1",
displayName: L("Features:DisplayName:DownloadInterval"),
description: L("Features:Description:DownloadInterval"),
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 12))); // 上限12月
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.UploadFile,
defaultValue: true.ToString(),
displayName: L("Features:DisplayName:UploadFile"),
description: L("Features:Description:UploadFile"),
valueType: new ToggleStringValueType(new BooleanValueValidator()));
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.UploadLimit,
defaultValue: "1000",
displayName: L("Features:DisplayName:UploadLimit"),
description: L("Features:Description:UploadLimit"),
valueType: new FreeTextStringValueType(new NumericValueValidator(0, 100_0000))); // 上限100万次调用
ossFeature.CreateChild(
name: AbpOssManagementFeatureNames.OssObject.UploadInterval,
defaultValue: "1",
displayName: L("Features:DisplayName:UploadInterval"),
description: L("Features:Description:UploadInterval"),
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 12))); // 上限12月
// TODO: 此功能需要控制器协同,暂时不实现
//fileSystemFeature.CreateChild(
// name: AbpOssManagementFeatureNames.OssObject.MaxUploadFileCount,
// defaultValue: 1.ToString(),
// displayName: L("Features:DisplayName:MaxUploadFileCount"),
// description: L("Features:Description:MaxUploadFileCount"),
// valueType: new FreeTextStringValueType(new NumericValueValidator(1, 10)));
}
protected ILocalizableString L(string name)
{
return LocalizableString.Create<AbpOssManagementResource>(name);
}
}
}

41
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application.Contracts/LINGYUN/Abp/OssManagement/Features/AbpOssManagementFeatureNames.cs

@ -1,41 +0,0 @@
namespace LINGYUN.Abp.OssManagement.Features
{
public class AbpOssManagementFeatureNames
{
public const string GroupName = "AbpOssManagement";
public class OssObject
{
public const string Default = GroupName + ".OssObject";
/// <summary>
/// 下载文件功能
/// </summary>
public const string DownloadFile = Default + ".DownloadFile";
/// <summary>
/// 下载文件功能限制次数
/// </summary>
public const string DownloadLimit = Default + ".DownloadLimit";
/// <summary>
/// 下载文件功能限制次数周期
/// </summary>
public const string DownloadInterval = Default + ".DownloadInterval";
/// <summary>
/// 上传文件功能
/// </summary>
public const string UploadFile = Default + ".UploadFile";
/// <summary>
/// 上传文件功能限制次数
/// </summary>
public const string UploadLimit = Default + ".UploadLimit";
/// <summary>
/// 上传文件功能限制次数周期
/// </summary>
public const string UploadInterval = Default + ".UploadInterval";
/// <summary>
/// 最大上传文件
/// </summary>
public const string MaxUploadFileCount = Default + ".MaxUploadFileCount";
}
}
}

5
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN.Abp.OssManagement.Application.csproj

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
@ -9,9 +9,12 @@
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="4.4.0" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="4.4.0" />
<PackageReference Include="Volo.Abp.Caching" Version="4.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\common\LINGYUN.Abp.Settings\LINGYUN.Abp.Settings.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.OssManagement.Application.Contracts\LINGYUN.Abp.OssManagement.Application.Contracts.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.OssManagement.Domain\LINGYUN.Abp.OssManagement.Domain.csproj" />
</ItemGroup>

50
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/AbpOssManagementApplicationModule.cs

@ -1,23 +1,27 @@
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
using Microsoft.Extensions.DependencyInjection;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpAutoMapperModule),
typeof(AbpOssManagementDomainModule),
typeof(AbpOssManagementApplicationContractsModule))]
public class AbpOssManagementApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpOssManagementApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<OssManagementApplicationAutoMapperProfile>(validate: true);
});
}
}
}
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Application;
using Volo.Abp.AutoMapper;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpOssManagementDomainModule),
typeof(AbpOssManagementApplicationContractsModule),
typeof(AbpCachingModule),
typeof(AbpAutoMapperModule),
typeof(AbpDddApplicationModule))]
public class AbpOssManagementApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpOssManagementApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<OssManagementApplicationAutoMapperProfile>(validate: true);
});
}
}
}

28
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssManagementApplicationServiceBase.cs

@ -1,14 +1,14 @@
using LINGYUN.Abp.OssManagement.Localization;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.OssManagement
{
public class OssManagementApplicationServiceBase : ApplicationService
{
protected OssManagementApplicationServiceBase()
{
LocalizationResource = typeof(AbpOssManagementResource);
ObjectMapperContext = typeof(AbpOssManagementApplicationModule);
}
}
}
using LINGYUN.Abp.OssManagement.Localization;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.OssManagement
{
public abstract class OssManagementApplicationServiceBase : ApplicationService
{
protected OssManagementApplicationServiceBase()
{
LocalizationResource = typeof(AbpOssManagementResource);
ObjectMapperContext = typeof(AbpOssManagementApplicationModule);
}
}
}

217
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/OssObjectAppService.cs

@ -1,116 +1,101 @@
using LINGYUN.Abp.Features.LimitValidation;
using LINGYUN.Abp.OssManagement.Features;
using LINGYUN.Abp.OssManagement.Permissions;
using LINGYUN.Abp.OssManagement.Settings;
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Features;
using Volo.Abp.IO;
using Volo.Abp.Settings;
using Volo.Abp.Validation;
namespace LINGYUN.Abp.OssManagement
{
[Authorize(AbpOssManagementPermissions.OssObject.Default)]
public class OssObjectAppService : OssManagementApplicationServiceBase, IOssObjectAppService
{
protected IOssContainerFactory OssContainerFactory { get; }
public OssObjectAppService(
IOssContainerFactory ossContainerFactory)
{
OssContainerFactory = ossContainerFactory;
}
[Authorize(AbpOssManagementPermissions.OssObject.Create)]
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)]
[RequiresLimitFeature(
AbpOssManagementFeatureNames.OssObject.UploadLimit,
AbpOssManagementFeatureNames.OssObject.UploadInterval,
LimitPolicy.Month)]
public virtual async Task<OssObjectDto> CreateAsync(CreateOssObjectInput input)
{
if (!input.Content.IsNullOrEmpty())
{
// 检查文件大小
var fileSizeLimited = await SettingProvider
.GetAsync(
AbpOssManagementSettingNames.FileLimitLength,
AbpOssManagementSettingNames.DefaultFileLimitLength);
if (fileSizeLimited * 1024 * 1024 < input.Content.Length)
{
ThrowValidationException(L["UploadFileSizeBeyondLimit", fileSizeLimited], nameof(input.Content));
}
// 文件扩展名
var fileExtensionName = FileHelper.GetExtension(input.Object);
var fileAllowExtension = await SettingProvider.GetOrNullAsync(AbpOssManagementSettingNames.AllowFileExtensions);
// 检查文件扩展名
if (!fileAllowExtension.Split(',')
.Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase)))
{
ThrowValidationException(L["NotAllowedFileExtensionName", fileExtensionName], "FileName");
}
}
var oss = CreateOssContainer();
var createOssObjectRequest = new CreateOssObjectRequest(
input.Bucket,
input.Object,
input.Content,
input.Path,
input.ExpirationTime)
{
Overwrite = input.Overwrite
};
var ossObject = await oss.CreateObjectAsync(createOssObjectRequest);
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject);
}
[Authorize(AbpOssManagementPermissions.OssObject.Delete)]
public virtual async Task BulkDeleteAsync(BulkDeleteOssObjectInput input)
{
var oss = CreateOssContainer();
await oss.BulkDeleteObjectsAsync(input.Bucket, input.Objects, input.Path);
}
[Authorize(AbpOssManagementPermissions.OssObject.Delete)]
public virtual async Task DeleteAsync(GetOssObjectInput input)
{
var oss = CreateOssContainer();
await oss.DeleteObjectAsync(input.Bucket, input.Object, input.Path);
}
public virtual async Task<OssObjectDto> GetAsync(GetOssObjectInput input)
{
var oss = CreateOssContainer();
var ossObject = await oss.GetObjectAsync(input.Bucket, input.Object, input.Path);
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject);
}
protected virtual IOssContainer CreateOssContainer()
{
return OssContainerFactory.Create();
}
private static void ThrowValidationException(string message, string memberName)
{
throw new AbpValidationException(message,
new List<ValidationResult>
{
new ValidationResult(message, new[] {memberName})
});
}
}
}
using LINGYUN.Abp.Features.LimitValidation;
using LINGYUN.Abp.OssManagement.Features;
using LINGYUN.Abp.OssManagement.Permissions;
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading.Tasks;
using Volo.Abp.Features;
using Volo.Abp.Validation;
namespace LINGYUN.Abp.OssManagement
{
[Authorize(AbpOssManagementPermissions.OssObject.Default)]
public class OssObjectAppService : OssManagementApplicationServiceBase, IOssObjectAppService
{
protected IFileValidater FileValidater { get; }
protected IOssContainerFactory OssContainerFactory { get; }
public OssObjectAppService(
IFileValidater fileValidater,
IOssContainerFactory ossContainerFactory)
{
FileValidater = fileValidater;
OssContainerFactory = ossContainerFactory;
}
[Authorize(AbpOssManagementPermissions.OssObject.Create)]
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)]
[RequiresLimitFeature(
AbpOssManagementFeatureNames.OssObject.UploadLimit,
AbpOssManagementFeatureNames.OssObject.UploadInterval,
LimitPolicy.Month)]
public virtual async Task<OssObjectDto> CreateAsync(CreateOssObjectInput input)
{
if (!input.Content.IsNullOrEmpty())
{
await FileValidater.ValidationAsync(new UploadFile
{
TotalSize = input.Content.Length,
FileName = input.Object
});
}
var oss = CreateOssContainer();
var createOssObjectRequest = new CreateOssObjectRequest(
input.Bucket,
input.Object,
input.Content,
input.Path,
input.ExpirationTime)
{
Overwrite = input.Overwrite
};
var ossObject = await oss.CreateObjectAsync(createOssObjectRequest);
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject);
}
[Authorize(AbpOssManagementPermissions.OssObject.Delete)]
public virtual async Task BulkDeleteAsync(BulkDeleteOssObjectInput input)
{
var oss = CreateOssContainer();
await oss.BulkDeleteObjectsAsync(input.Bucket, input.Objects, input.Path);
}
[Authorize(AbpOssManagementPermissions.OssObject.Delete)]
public virtual async Task DeleteAsync(GetOssObjectInput input)
{
var oss = CreateOssContainer();
await oss.DeleteObjectAsync(input.Bucket, input.Object, input.Path);
}
public virtual async Task<OssObjectDto> GetAsync(GetOssObjectInput input)
{
var oss = CreateOssContainer();
var ossObject = await oss.GetObjectAsync(input.Bucket, input.Object, input.Path);
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject);
}
protected virtual IOssContainer CreateOssContainer()
{
return OssContainerFactory.Create();
}
private static void ThrowValidationException(string message, string memberName)
{
throw new AbpValidationException(message,
new List<ValidationResult>
{
new ValidationResult(message, new[] {memberName})
});
}
}
}

83
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Application/LINGYUN/Abp/OssManagement/PublicFileAppService.cs

@ -1,89 +1,16 @@
using LINGYUN.Abp.Features.LimitValidation;
using LINGYUN.Abp.OssManagement.Features;
using Microsoft.AspNetCore.Authorization;
using System.IO;
using System.Threading.Tasks;
using System.Web;
using Volo.Abp;
using Volo.Abp.Features;
using Volo.Abp.Users;
namespace LINGYUN.Abp.OssManagement
namespace LINGYUN.Abp.OssManagement
{
/// <summary>
/// 所有登录用户公开访问文件服务接口
/// bucket限制在users
/// path限制在用户id
/// </summary>
[Authorize]
// 不对外公开,仅通过控制器调用
[RemoteService(IsEnabled = false, IsMetadataEnabled = false)]
public class PublicFileAppService : OssManagementApplicationServiceBase, IPublicFileAppService
public class PublicFileAppService : FileAppServiceBase, IPublicFileAppService
{
private readonly IFileValidater _fileValidater;
private readonly IOssContainerFactory _ossContainerFactory;
public PublicFileAppService(
IFileValidater fileValidater,
IOssContainerFactory ossContainerFactory)
: base(fileValidater, ossContainerFactory)
{
_fileValidater = fileValidater;
_ossContainerFactory = ossContainerFactory;
}
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.UploadFile)]
[RequiresLimitFeature(
AbpOssManagementFeatureNames.OssObject.UploadLimit,
AbpOssManagementFeatureNames.OssObject.UploadInterval,
LimitPolicy.Month)]
public virtual async Task<OssObjectDto> UploadAsync(UploadPublicFileInput input)
protected override string GetCurrentBucket()
{
await _fileValidater.ValidationAsync(new UploadFile
{
TotalSize = input.Content.Length,
FileName = input.Object
});
var oss = _ossContainerFactory.Create();
var createOssObjectRequest = new CreateOssObjectRequest(
"users",
HttpUtility.UrlDecode(input.Object),
input.Content,
GetCurrentUserPath(HttpUtility.UrlDecode(input.Path)))
{
Overwrite = input.Overwrite
};
var ossObject = await oss.CreateObjectAsync(createOssObjectRequest);
return ObjectMapper.Map<OssObject, OssObjectDto>(ossObject);
}
[RequiresFeature(AbpOssManagementFeatureNames.OssObject.DownloadFile)]
[RequiresLimitFeature(
AbpOssManagementFeatureNames.OssObject.DownloadLimit,
AbpOssManagementFeatureNames.OssObject.DownloadInterval,
LimitPolicy.Month)]
public virtual async Task<Stream> GetAsync(GetPublicFileInput input)
{
var ossObjectRequest = new GetOssObjectRequest(
"users", // 需要处理特殊字符
HttpUtility.UrlDecode(input.Name),
GetCurrentUserPath(HttpUtility.UrlDecode(input.Path)),
HttpUtility.UrlDecode(input.Process));
var ossContainer = _ossContainerFactory.Create();
var ossObject = await ossContainer.GetObjectAsync(ossObjectRequest);
return ossObject.Content;
}
private string GetCurrentUserPath(string path)
{
path = path.StartsWith("/") ? path.Substring(1) : path;
var userId = CurrentUser.GetId().ToString();
return path.StartsWith(userId) ? path : $"{userId}/{path}";
return "public";
}
}
}

5
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN.Abp.OssManagement.Domain.Shared.csproj

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
@ -18,7 +18,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Validation" Version="4.4.0" />
<PackageReference Include="Volo.Abp.Features" Version="4.4.0" />
<PackageReference Include="Volo.Abp.Validation" Version="4.4.0" />
</ItemGroup>
</Project>

72
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/AbpOssManagementDomainSharedModule.cs

@ -1,36 +1,36 @@
using LINGYUN.Abp.OssManagement.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
using Volo.Abp.Validation.Localization;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(typeof(AbpValidationModule))]
public class AbpOssManagementDomainSharedModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpOssManagementDomainSharedModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<AbpOssManagementResource>("en")
.AddBaseTypes(
typeof(AbpValidationResource)
).AddVirtualJson("/LINGYUN/Abp/OssManagement/Localization/Resources");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace(OssManagementErrorCodes.Namespace, typeof(AbpOssManagementResource));
});
}
}
}
using LINGYUN.Abp.OssManagement.Localization;
using Volo.Abp.Features;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpFeaturesModule),
typeof(AbpValidationModule))]
public class AbpOssManagementDomainSharedModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpOssManagementDomainSharedModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<AbpOssManagementResource>("en")
.AddVirtualJson("/LINGYUN/Abp/OssManagement/Localization/Resources");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace(OssManagementErrorCodes.Namespace, typeof(AbpOssManagementResource));
});
}
}
}

1
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/en.json

@ -1,6 +1,7 @@
{
"culture": "en",
"texts": {
"Abp.OssManagement:010000": "System definition containers cannot be deleted!",
"Abp.OssManagement:010001": "Cannot delete a container that has more than one object!",
"Abp.OssManagement:010402": "The container name already exists!",
"Abp.OssManagement:010404": "The queried container could not be found!",

1
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/zh-Hans.json

@ -1,6 +1,7 @@
{
"culture": "zh-Hans",
"texts": {
"Abp.OssManagement:010000": "不能删除系统定义容器!",
"Abp.OssManagement:010001": "不能删除存在多个对象的容器!",
"Abp.OssManagement:010402": "容器名称已经存在!",
"Abp.OssManagement:010404": "未能找到查询的容器!",

35
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/OssManagementErrorCodes.cs

@ -1,17 +1,18 @@
namespace LINGYUN.Abp.OssManagement
{
public static class OssManagementErrorCodes
{
public const string Namespace = "Abp.OssManagement";
public const string ContainerDeleteWithNotEmpty = Namespace + ":010001";
public const string ContainerAlreadyExists = Namespace + ":010402";
public const string ContainerNotFound = Namespace + ":010404";
public const string ObjectDeleteWithNotEmpty = Namespace + ":020001";
public const string ObjectAlreadyExists = Namespace + ":020402";
public const string ObjectNotFound = Namespace + ":020404";
public const string OssNameHasTooLong = Namespace + ":000405";
}
}
namespace LINGYUN.Abp.OssManagement
{
public static class OssManagementErrorCodes
{
public const string Namespace = "Abp.OssManagement";
public const string ContainerDeleteWithStatic = Namespace + ":010000";
public const string ContainerDeleteWithNotEmpty = Namespace + ":010001";
public const string ContainerAlreadyExists = Namespace + ":010402";
public const string ContainerNotFound = Namespace + ":010404";
public const string ObjectDeleteWithNotEmpty = Namespace + ":020001";
public const string ObjectAlreadyExists = Namespace + ":020402";
public const string ObjectNotFound = Namespace + ":020404";
public const string OssNameHasTooLong = Namespace + ":000405";
}
}

49
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain/LINGYUN/Abp/OssManagement/AbpOssManagementDomainModule.cs

@ -1,17 +1,32 @@
using LINGYUN.Abp.Features.LimitValidation;
using Volo.Abp.Domain;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpDddDomainModule),
typeof(AbpMultiTenancyModule),
typeof(AbpFeaturesLimitValidationModule),
typeof(AbpOssManagementDomainSharedModule)
)]
public class AbpOssManagementDomainModule : AbpModule
{
}
}
using LINGYUN.Abp.Features.LimitValidation;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.Domain;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpOssManagementDomainSharedModule),
typeof(AbpDddDomainModule),
typeof(AbpMultiTenancyModule),
typeof(AbpFeaturesLimitValidationModule)
)]
public class AbpOssManagementDomainModule : AbpModule
{
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
// TODO: 是否有必要自动创建容器
var ossOptions = context.ServiceProvider.GetRequiredService<IOptions<AbpOssManagementOptions>>().Value;
var ossFactory = context.ServiceProvider.GetRequiredService<IOssContainerFactory>();
var ossContainer = ossFactory.Create();
foreach (var bucket in ossOptions.StaticBuckets)
{
_ = ossContainer.CreateIfNotExistsAsync(bucket);
}
}
}
}

36
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/AbpOssManagementFileSystemModule.cs

@ -1,17 +1,19 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.BlobStoring.FileSystem;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.OssManagement.FileSystem
{
[DependsOn(
typeof(AbpBlobStoringFileSystemModule),
typeof(AbpOssManagementDomainModule))]
public class AbpOssManagementFileSystemModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddTransient<IOssContainerFactory, FileSystemOssContainerFactory>();
}
}
}
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.BlobStoring.FileSystem;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.OssManagement.FileSystem
{
[DependsOn(
typeof(AbpBlobStoringFileSystemModule),
typeof(AbpOssManagementDomainModule))]
public class AbpOssManagementFileSystemModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddTransient<IOssContainerFactory, FileSystemOssContainerFactory>();
}
}
}

15
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainer.cs

@ -25,6 +25,7 @@ namespace LINGYUN.Abp.OssManagement.FileSystem
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; }
protected IServiceProvider ServiceProvider { get; }
protected FileSystemOssOptions Options { get; }
protected AbpOssManagementOptions OssOptions { get; }
public FileSystemOssContainer(
ICurrentTenant currentTenant,
@ -32,7 +33,8 @@ namespace LINGYUN.Abp.OssManagement.FileSystem
IServiceProvider serviceProvider,
IBlobFilePathCalculator blobFilePathCalculator,
IBlobContainerConfigurationProvider configurationProvider,
IOptions<FileSystemOssOptions> options)
IOptions<FileSystemOssOptions> options,
IOptions<AbpOssManagementOptions> ossOptions)
{
CurrentTenant = currentTenant;
Environment = environment;
@ -40,6 +42,7 @@ namespace LINGYUN.Abp.OssManagement.FileSystem
FilePathCalculator = blobFilePathCalculator;
ConfigurationProvider = configurationProvider;
Options = options.Value;
OssOptions = ossOptions.Value;
}
public virtual Task BulkDeleteObjectsAsync(BulkDeleteObjectRequest request)
@ -173,6 +176,8 @@ namespace LINGYUN.Abp.OssManagement.FileSystem
public virtual Task DeleteAsync(string name)
{
CheckStaticBucket(name);
var filePath = CalculateFilePath(name);
if (!Directory.Exists(filePath))
{
@ -533,6 +538,14 @@ namespace LINGYUN.Abp.OssManagement.FileSystem
return blobPath;
}
protected virtual void CheckStaticBucket(string bucket)
{
if (OssOptions.CheckStaticBucket(bucket))
{
throw new BusinessException(code: OssManagementErrorCodes.ContainerDeleteWithStatic);
}
}
private void ThrowOfPathHasTooLong(string path)
{
// Windows 133 260

96
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.FileSystem/LINGYUN/Abp/OssManagement/FileSystem/FileSystemOssContainerFactory.cs

@ -1,46 +1,50 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using System;
using Volo.Abp.BlobStoring;
using Volo.Abp.BlobStoring.FileSystem;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.OssManagement.FileSystem
{
public class FileSystemOssContainerFactory : IOssContainerFactory
{
protected ICurrentTenant CurrentTenant { get; }
protected IHostEnvironment Environment { get; }
protected IServiceProvider ServiceProvider { get; }
protected IBlobFilePathCalculator FilePathCalculator { get; }
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; }
protected IOptions<FileSystemOssOptions> Options { get; }
public FileSystemOssContainerFactory(
ICurrentTenant currentTenant,
IHostEnvironment environment,
IServiceProvider serviceProvider,
IBlobFilePathCalculator blobFilePathCalculator,
IBlobContainerConfigurationProvider configurationProvider,
IOptions<FileSystemOssOptions> options)
{
Environment = environment;
CurrentTenant = currentTenant;
ServiceProvider = serviceProvider;
FilePathCalculator = blobFilePathCalculator;
ConfigurationProvider = configurationProvider;
Options = options;
}
public IOssContainer Create()
{
return new FileSystemOssContainer(
CurrentTenant,
Environment,
ServiceProvider,
FilePathCalculator,
ConfigurationProvider,
Options);
}
}
}
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using System;
using Volo.Abp.BlobStoring;
using Volo.Abp.BlobStoring.FileSystem;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.OssManagement.FileSystem
{
public class FileSystemOssContainerFactory : IOssContainerFactory
{
protected ICurrentTenant CurrentTenant { get; }
protected IHostEnvironment Environment { get; }
protected IServiceProvider ServiceProvider { get; }
protected IBlobFilePathCalculator FilePathCalculator { get; }
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; }
protected IOptions<FileSystemOssOptions> Options { get; }
protected IOptions<AbpOssManagementOptions> OssOptions { get; }
public FileSystemOssContainerFactory(
ICurrentTenant currentTenant,
IHostEnvironment environment,
IServiceProvider serviceProvider,
IBlobFilePathCalculator blobFilePathCalculator,
IBlobContainerConfigurationProvider configurationProvider,
IOptions<FileSystemOssOptions> options,
IOptions<AbpOssManagementOptions> ossOptions)
{
Environment = environment;
CurrentTenant = currentTenant;
ServiceProvider = serviceProvider;
FilePathCalculator = blobFilePathCalculator;
ConfigurationProvider = configurationProvider;
Options = options;
OssOptions = ossOptions;
}
public IOssContainer Create()
{
return new FileSystemOssContainer(
CurrentTenant,
Environment,
ServiceProvider,
FilePathCalculator,
ConfigurationProvider,
Options,
OssOptions);
}
}
}

1
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN.Abp.OssManagement.HttpApi.csproj

@ -12,7 +12,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\common\LINGYUN.Abp.Settings\LINGYUN.Abp.Settings.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.OssManagement.Application.Contracts\LINGYUN.Abp.OssManagement.Application.Contracts.csproj" />
</ItemGroup>

68
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiModule.cs

@ -1,21 +1,47 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpOssManagementApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule)
)]
public class AbpOssManagementHttpApiModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementHttpApiModule).Assembly);
});
}
}
}
using LINGYUN.Abp.OssManagement.Localization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Authorization.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Validation.Localization;
using Volo.Abp.AspNetCore.Mvc.DataAnnotations;
using Volo.Abp.AspNetCore.Mvc.Localization;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpOssManagementApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule)
)]
public class AbpOssManagementHttpApiModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementHttpApiModule).Assembly);
});
PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
options.AddAssemblyResource(
typeof(AbpOssManagementResource),
typeof(AbpOssManagementApplicationContractsModule).Assembly);
});
}
//public override void ConfigureServices(ServiceConfigurationContext context)
//{
// Configure<AbpLocalizationOptions>(options =>
// {
// options.Resources
// .Get<AbpOssManagementResource>()
// .AddBaseTypes(
// typeof(AbpAuthorizationResource),
// typeof(AbpValidationResource)
// );
// });
//}
}
}

96
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/FileValidater.cs

@ -1,96 +0,0 @@
using LINGYUN.Abp.OssManagement.Localization;
using LINGYUN.Abp.OssManagement.Settings;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Localization;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.IO;
using Volo.Abp.Settings;
namespace LINGYUN.Abp.OssManagement
{
public class FileValidater : IFileValidater, ISingletonDependency
{
private readonly IMemoryCache _cache;
private readonly ISettingProvider _settingProvider;
private readonly IServiceProvider _serviceProvider;
private readonly IStringLocalizer _stringLocalizer;
public FileValidater(
IMemoryCache cache,
ISettingProvider settingProvider,
IServiceProvider serviceProvider,
IStringLocalizer<AbpOssManagementResource> stringLocalizer)
{
_cache = cache;
_settingProvider = settingProvider;
_serviceProvider = serviceProvider;
_stringLocalizer = stringLocalizer;
}
public virtual async Task ValidationAsync(UploadOssObjectInput input)
{
var validation = await GetByCacheItemAsync();
if (validation.SizeLimit * 1024 * 1024 < input.TotalSize)
{
throw new UserFriendlyException(_stringLocalizer["UploadFileSizeBeyondLimit", validation.SizeLimit]);
}
var fileExtensionName = FileHelper.GetExtension(input.FileName);
if (!validation.AllowedExtensions
.Any(fe => fe.Equals(fileExtensionName, StringComparison.CurrentCultureIgnoreCase)))
{
throw new UserFriendlyException(_stringLocalizer["NotAllowedFileExtensionName", fileExtensionName]);
}
}
protected virtual async Task<FileValidation> GetByCacheItemAsync()
{
var fileValidation = _cache.Get<FileValidation>(FileValidation.CacheKey);
if (fileValidation == null)
{
fileValidation = await GetBySettingAsync();
_cache.Set(FileValidation.CacheKey,
fileValidation,
new MemoryCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(2)
});
}
return fileValidation;
}
protected virtual async Task<FileValidation> GetBySettingAsync()
{
var fileSizeLimited = await _settingProvider
.GetAsync(
AbpOssManagementSettingNames.FileLimitLength,
AbpOssManagementSettingNames.DefaultFileLimitLength);
var fileAllowExtension = await _settingProvider
.GetOrDefaultAsync(AbpOssManagementSettingNames.AllowFileExtensions, _serviceProvider);
return new FileValidation(fileSizeLimited, fileAllowExtension.Split(','));
}
}
public class FileValidation
{
public const string CacheKey = "Abp.OssManagement.FileValidation";
public long SizeLimit { get; set; }
public string[] AllowedExtensions { get; set; }
public FileValidation()
{
}
public FileValidation(
long sizeLimit,
string[] allowedExtensions)
{
SizeLimit = sizeLimit;
AllowedExtensions = allowedExtensions;
}
}
}

9
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/IFileValidater.cs

@ -1,9 +0,0 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.OssManagement
{
public interface IFileValidater
{
Task ValidationAsync(UploadOssObjectInput input);
}
}

4
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/StaticFilesController.cs

@ -1,7 +1,6 @@
using LINGYUN.Abp.OssManagement.Localization;
using LINGYUN.Abp.OssManagement.Permissions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@ -15,9 +14,10 @@ using Volo.Abp.Validation;
namespace LINGYUN.Abp.OssManagement
{
[RemoteService(Name = OssManagementRemoteServiceConsts.RemoteServiceName)]
[Area("oss-management")]
[Route("api/files/static")]
[RemoteService(false)]
[ApiExplorerSettings(IgnoreApi = true)]
public class StaticFilesController : AbpController
{
private readonly IOssObjectAppService _ossObjectAppService;

12
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi/LINGYUN/Abp/OssManagement/UploadOssObjectInput.cs

@ -3,18 +3,13 @@ using System.ComponentModel.DataAnnotations;
namespace LINGYUN.Abp.OssManagement
{
public class UploadOssObjectInput
public class UploadOssObjectInput : UploadFile
{
public string Bucket { get; set; }
public string Path { get; set; }
#region 配合Uplaoder 分块传输
/// <summary>
/// 文件名
/// </summary>
[Required]
public string FileName { get; set; }
/// <summary>
/// 常规块大小
/// </summary>
[Required]
@ -34,11 +29,6 @@ namespace LINGYUN.Abp.OssManagement
/// </summary>
[Required]
public int TotalChunks { get; set; }
/// <summary>
/// 总文件大小
/// </summary>
[Required]
public long TotalSize { get; set; }
#endregion

20
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.SettingManagement/AbpOssManagementSettingManagementModule.cs

@ -1,20 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.OssManagement.SettingManagement
{
[DependsOn(
typeof(AbpOssManagementApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule))]
public class AbpOssManagementSettingManagementModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpOssManagementSettingManagementModule).Assembly);
});
}
}
}

101
aspnet-core/modules/oss-management/README.md

@ -1,50 +1,51 @@
# Oss-Management
File-Management更名为Oss-Management
## 模块说明
### 基础模块
* [LINGYUN.Abp.OssManagement.Domain.Shared](./LINGYUN.Abp.OssManagement.Domain.Shared) 领域层公共模块,定义了错误代码、本地化、模块设置
* [LINGYUN.Abp.OssManagement.Domain](./LINGYUN.Abp.OssManagement.Domain) 领域层模块,定义了抽象的Oss容器与对象管理接口
* [LINGYUN.Abp.OssManagement.Application.Contracts](./LINGYUN.Abp.OssManagement.Application.Contracts) 应用服务层公共模块,定义了管理Oss的外部接口、权限、功能限制策略
* [LINGYUN.Abp.OssManagement.Application](./LINGYUN.Abp.OssManagement.Application) 应用服务层实现,实现了Oss管理接口
* [LINGYUN.Abp.OssManagement.HttpApi](./LINGYUN.Abp.OssManagement.HttpApi) RestApi实现,实现了独立的对外RestApi接口
* [LINGYUN.Abp.OssManagement.SettingManagement](./LINGYUN.Abp.OssManagement.SettingManagement) 设置管理模块,对外暴露自身的设置管理,用于网关聚合
### 高阶模块
* [LINGYUN.Abp.OssManagement.Aliyun](./LINGYUN.Abp.OssManagement.Aliyun) Oss管理的阿里云实现,实现了部分阿里云Oss服务的容器与对象管理
* [LINGYUN.Abp.OssManagement.FileSystem](./LINGYUN.Abp.OssManagement.FileSystem) Oss管理的本地文件系统实现,实现了部分本地文件系统的容器(目录)与对象(文件/目录)管理
* [LINGYUN.Abp.OssManagement.FileSystem.ImageSharp](./LINGYUN.Abp.OssManagement.FileSystem.ImageSharp) Oss本地对象的ImageSharp扩展,当前端传递需求处理对象时,此模块用于实现基于图形文件流的处理
### 权限定义
* AbpOssManagement.Container 授权对象是否允许访问容器(bucket)
* AbpOssManagement.Container.Create 授权对象是否允许创建容器(bucket)
* AbpOssManagement.Container.Delete 授权对象是否允许删除容器(bucket)
* AbpOssManagement.OssObject 授权对象是否允许访问Oss对象
* AbpOssManagement.OssObject.Create 授权对象是否允许创建Oss对象
* AbpOssManagement.OssObject.Delete 授权对象是否允许删除Oss对象
* AbpOssManagement.OssObject.Download 授权对象是否允许下载Oss对象
### 功能定义
* AbpOssManagement.OssObject.DownloadFile 用户可以下载文件
* AbpOssManagement.OssObject.DownloadLimit 用户在周期内允许下载文件的最大次数,范围0-1000000
* AbpOssManagement.OssObject.DownloadInterval 用户限制下载文件次数的周期,时钟刻度:月,默认: 1,范围1-12
* AbpOssManagement.OssObject.UploadFile 用户可以上传文件
* AbpOssManagement.OssObject.UploadLimit 用户在周期内允许上传文件的最大次数,范围0-1000000
* AbpOssManagement.OssObject.UploadInterval 用户限制上传文件次数的周期,时钟刻度:月,默认: 1,范围1-12
* AbpOssManagement.OssObject.MaxUploadFileCount 单次上传文件的数量,未实现
### 配置定义
* Abp.OssManagement.DownloadPackageSize 下载分包大小,分块下载时单次传输的数据大小,未实现
* Abp.OssManagement.FileLimitLength 上传文件限制大小,默认:100
* Abp.OssManagement.AllowFileExtensions 允许的上传文件扩展名,多个扩展名以逗号分隔,默认:dll,zip,rar,txt,log,xml,config,json,jpeg,jpg,png,bmp,ico,xlsx,xltx,xls,xlt,docs,dots,doc,dot,pptx,potx,ppt,pot,chm
## 更新日志
*【2021-03-10】 变更FileManagement命名空间为OssManagement
# Oss-Management
File-Management更名为Oss-Management
## 模块说明
### 基础模块
* [LINGYUN.Abp.OssManagement.Domain.Shared](./LINGYUN.Abp.OssManagement.Domain.Shared) 领域层公共模块,定义了错误代码、本地化、模块设置
* [LINGYUN.Abp.OssManagement.Domain](./LINGYUN.Abp.OssManagement.Domain) 领域层模块,定义了抽象的Oss容器与对象管理接口
* [LINGYUN.Abp.OssManagement.Application.Contracts](./LINGYUN.Abp.OssManagement.Application.Contracts) 应用服务层公共模块,定义了管理Oss的外部接口、权限、功能限制策略
* [LINGYUN.Abp.OssManagement.Application](./LINGYUN.Abp.OssManagement.Application) 应用服务层实现,实现了Oss管理接口
* [LINGYUN.Abp.OssManagement.HttpApi](./LINGYUN.Abp.OssManagement.HttpApi) RestApi实现,实现了独立的对外RestApi接口
* [LINGYUN.Abp.OssManagement.SettingManagement](./LINGYUN.Abp.OssManagement.SettingManagement) 设置管理模块,对外暴露自身的设置管理,用于网关聚合
### 高阶模块
* [LINGYUN.Abp.OssManagement.Aliyun](./LINGYUN.Abp.OssManagement.Aliyun) Oss管理的阿里云实现,实现了部分阿里云Oss服务的容器与对象管理
* [LINGYUN.Abp.OssManagement.FileSystem](./LINGYUN.Abp.OssManagement.FileSystem) Oss管理的本地文件系统实现,实现了部分本地文件系统的容器(目录)与对象(文件/目录)管理
* [LINGYUN.Abp.OssManagement.FileSystem.ImageSharp](./LINGYUN.Abp.OssManagement.FileSystem.ImageSharp) Oss本地对象的ImageSharp扩展,当前端传递需求处理对象时,此模块用于实现基于图形文件流的处理
### 权限定义
* AbpOssManagement.Container 授权对象是否允许访问容器(bucket)
* AbpOssManagement.Container.Create 授权对象是否允许创建容器(bucket)
* AbpOssManagement.Container.Delete 授权对象是否允许删除容器(bucket)
* AbpOssManagement.OssObject 授权对象是否允许访问Oss对象
* AbpOssManagement.OssObject.Create 授权对象是否允许创建Oss对象
* AbpOssManagement.OssObject.Delete 授权对象是否允许删除Oss对象
* AbpOssManagement.OssObject.Download 授权对象是否允许下载Oss对象
### 功能定义
* AbpOssManagement.OssObject.DownloadFile 用户可以下载文件
* AbpOssManagement.OssObject.DownloadLimit 用户在周期内允许下载文件的最大次数,范围0-1000000
* AbpOssManagement.OssObject.DownloadInterval 用户限制下载文件次数的周期,时钟刻度:月,默认: 1,范围1-12
* AbpOssManagement.OssObject.UploadFile 用户可以上传文件
* AbpOssManagement.OssObject.UploadLimit 用户在周期内允许上传文件的最大次数,范围0-1000000
* AbpOssManagement.OssObject.UploadInterval 用户限制上传文件次数的周期,时钟刻度:月,默认: 1,范围1-12
* AbpOssManagement.OssObject.MaxUploadFileCount 单次上传文件的数量,未实现
### 配置定义
* Abp.OssManagement.DownloadPackageSize 下载分包大小,分块下载时单次传输的数据大小,未实现
* Abp.OssManagement.FileLimitLength 上传文件限制大小,默认:100
* Abp.OssManagement.AllowFileExtensions 允许的上传文件扩展名,多个扩展名以逗号分隔,默认:dll,zip,rar,txt,log,xml,config,json,jpeg,jpg,png,bmp,ico,xlsx,xltx,xls,xlt,docs,dots,doc,dot,pptx,potx,ppt,pot,chm
## 更新日志
*【2021-03-10】 变更FileManagement命名空间为OssManagement
*【2021-10-22】 增加PublicFilesController用于身份认证通过的用户上传/下载文件,所有操作限定在用户目录下

675
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs

@ -1,333 +1,342 @@
using DotNetCore.CAP;
using LINGYUN.Abp.AspNetCore.HttpOverrides;
using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.ExceptionHandling;
using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Features.LimitValidation.Redis;
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
using LINGYUN.Abp.MultiTenancy.DbFinder;
using LINGYUN.Abp.Notifications;
using LINGYUN.Abp.OssManagement;
using LINGYUN.Abp.OssManagement.FileSystem;
using LINGYUN.Abp.OssManagement.FileSystem.ImageSharp;
using LINGYUN.Abp.OssManagement.SettingManagement;
using LINGYUN.Platform.EntityFrameworkCore;
using LINGYUN.Platform.HttpApi;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using StackExchange.Redis;
using System;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Autofac;
using Volo.Abp.BlobStoring;
using Volo.Abp.BlobStoring.FileSystem;
using Volo.Abp.Caching;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Http.Client.IdentityModel.Web;
using Volo.Abp.Identity;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.Security.Claims;
using Volo.Abp.Security.Encryption;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
using Volo.Abp.Threading;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Platform
{
[DependsOn(
// typeof(AbpOssManagementAliyunModule),
typeof(AbpOssManagementFileSystemModule), // 本地文件系统提供者模块
typeof(AbpOssManagementFileSystemImageSharpModule), // 本地文件系统图形处理模块
typeof(AbpOssManagementApplicationModule),
typeof(AbpOssManagementHttpApiModule),
typeof(AbpOssManagementSettingManagementModule),
typeof(PlatformApplicationModule),
typeof(PlatformHttpApiModule),
typeof(PlatformEntityFrameworkCoreModule),
typeof(AbpIdentityHttpApiClientModule),
typeof(AbpHttpClientIdentityModelWebModule),
typeof(AbpAspNetCoreMultiTenancyModule),
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
typeof(AbpAuditLoggingEntityFrameworkCoreModule),
typeof(AbpTenantManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpLocalizationManagementEntityFrameworkCoreModule),
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(AbpNotificationModule),
typeof(AbpEmailingExceptionHandlingModule),
typeof(AbpCAPEventBusModule),
typeof(AbpFeaturesValidationRedisModule),
// typeof(AbpFeaturesClientModule),// 当需要客户端特性限制时取消注释此模块
// typeof(AbpFeaturesValidationRedisClientModule),// 当需要客户端特性限制时取消注释此模块
typeof(AbpDbFinderMultiTenancyModule),
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpAspNetCoreHttpOverridesModule),
typeof(AbpAutofacModule)
)]
public class AppPlatformHttpApiHostModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
PreConfigure<CapOptions>(options =>
{
options
.UseMySql(configuration.GetConnectionString("Default"))
.UseRabbitMQ(rabbitMQOptions =>
{
configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions);
})
.UseDashboard();
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = hostingEnvironment.BuildConfiguration();
// 配置Ef
Configure<AbpDbContextOptions>(options =>
{
options.UseMySQL();
});
//// 中文序列化的编码问题
Configure<AbpSystemTextJsonSerializerOptions>(options =>
{
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
});
Configure<KestrelServerOptions>(options =>
{
options.Limits.MaxRequestBodySize = null;
options.Limits.MaxRequestBufferSize = null;
});
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureAll((containerName, containerConfiguration) =>
{
containerConfiguration.UseFileSystem(fileSystem =>
{
fileSystem.BasePath = Path.Combine(Directory.GetCurrentDirectory(), "file-blob-storing");
});
});
});
// 加解密
Configure<AbpStringEncryptionOptions>(options =>
{
var encryptionConfiguration = configuration.GetSection("Encryption");
if (encryptionConfiguration.Exists())
{
options.DefaultPassPhrase = encryptionConfiguration["PassPhrase"] ?? options.DefaultPassPhrase;
options.DefaultSalt = encryptionConfiguration.GetSection("Salt").Exists()
? Encoding.ASCII.GetBytes(encryptionConfiguration["Salt"])
: options.DefaultSalt;
options.InitVectorBytes = encryptionConfiguration.GetSection("InitVector").Exists()
? Encoding.ASCII.GetBytes(encryptionConfiguration["InitVector"])
: options.InitVectorBytes;
}
});
// 自定义需要处理的异常
Configure<AbpExceptionHandlingOptions>(options =>
{
// 加入需要处理的异常类型
options.Handlers.Add<Volo.Abp.Data.AbpDbConcurrencyException>();
options.Handlers.Add<AbpInitializationException>();
options.Handlers.Add<ObjectDisposedException>();
options.Handlers.Add<StackOverflowException>();
options.Handlers.Add<OutOfMemoryException>();
options.Handlers.Add<System.Data.Common.DbException>();
options.Handlers.Add<Microsoft.EntityFrameworkCore.DbUpdateException>();
options.Handlers.Add<System.Data.DBConcurrencyException>();
});
// 自定义需要发送邮件通知的异常类型
Configure<AbpEmailExceptionHandlingOptions>(options =>
{
// 是否发送堆栈信息
options.SendStackTrace = true;
// 未指定异常接收者的默认接收邮件
// 指定自己的邮件地址
// options.DefaultReceiveEmail = "colin.in@foxmail.com";
});
Configure<AbpDistributedCacheOptions>(options =>
{
// 最好统一命名,不然某个缓存变动其他应用服务有例外发生
options.KeyPrefix = "LINGYUN.Abp.Application";
// 滑动过期30天
options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30);
// 绝对过期60天
options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60);
});
Configure<RedisCacheOptions>(options =>
{
var redisConfig = ConfigurationOptions.Parse(options.Configuration);
options.ConfigurationOptions = redisConfig;
options.InstanceName = configuration["Redis:InstanceName"];
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AppPlatformHttpApiHostModule>("LINGYUN.Platform");
});
// 多租户
Configure<AbpMultiTenancyOptions>(options =>
{
options.IsEnabled = true;
});
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "Platform";
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
{
options
.EntityHistorySelectors
.AddAllEntities();
}
});
// Swagger
context.Services.AddSwaggerGen(
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Platform API", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName);
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Scheme = "bearer",
Type = SecuritySchemeType.Http,
BearerFormat = "JWT"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
},
new string[] { }
}
});
});
// 支持本地化语言类型
Configure<AbpLocalizationOptions>(options =>
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
options.Resources.AddDynamic();
});
Configure<AbpClaimsMapOptions>(options =>
{
options.Maps.TryAdd("name", () => AbpClaimTypes.UserName);
});
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = false;
options.Audience = configuration["AuthServer:ApiName"];
});
if (!hostingEnvironment.IsDevelopment())
{
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
context.Services
.AddDataProtection()
.PersistKeysToStackExchangeRedis(redis, "Platform-Protection-Keys");
}
}
//public override void OnPostApplicationInitialization(ApplicationInitializationContext context)
//{
// var backgroundJobManager = context.ServiceProvider.GetRequiredService<IBackgroundJobManager>();
// // 五分钟执行一次的定时任务
// AsyncHelper.RunSync(async () => await
// backgroundJobManager.EnqueueAsync(CronGenerator.Minute(5), new NotificationCleanupExpritionJobArgs(200)));
//}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
// http调用链
app.UseCorrelationId();
// 虚拟文件系统
app.UseStaticFiles();
// 本地化
app.UseAbpRequestLocalization();
// 多租户
app.UseMultiTenancy();
//路由
app.UseRouting();
// 认证
app.UseAuthentication();
// jwt
app.UseJwtTokenMiddleware();
// 授权
app.UseAuthorization();
// Swagger
app.UseSwagger();
// Swagger可视化界面
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support Platform API");
});
// 审计日志
app.UseAuditing();
// 路由
app.UseConfiguredEndpoints();
if (env.IsDevelopment())
{
AsyncHelper.RunSync(async () =>
await app.ApplicationServices.GetRequiredService<IDataSeeder>()
.SeedAsync());
}
}
}
}
using DotNetCore.CAP;
using LINGYUN.Abp.AspNetCore.HttpOverrides;
using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.ExceptionHandling;
using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Features.LimitValidation.Redis;
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
using LINGYUN.Abp.MultiTenancy.DbFinder;
using LINGYUN.Abp.Notifications;
using LINGYUN.Abp.OssManagement;
using LINGYUN.Abp.OssManagement.FileSystem;
using LINGYUN.Abp.OssManagement.FileSystem.ImageSharp;
using LINGYUN.Abp.OssManagement.SettingManagement;
using LINGYUN.Platform.EntityFrameworkCore;
using LINGYUN.Platform.HttpApi;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using StackExchange.Redis;
using System;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Autofac;
using Volo.Abp.BlobStoring;
using Volo.Abp.BlobStoring.FileSystem;
using Volo.Abp.Caching;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Http.Client.IdentityModel.Web;
using Volo.Abp.Identity;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.Security.Claims;
using Volo.Abp.Security.Encryption;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
using Volo.Abp.Threading;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Platform
{
[DependsOn(
// typeof(AbpOssManagementAliyunModule),
typeof(AbpOssManagementFileSystemModule), // 本地文件系统提供者模块
typeof(AbpOssManagementFileSystemImageSharpModule), // 本地文件系统图形处理模块
typeof(AbpOssManagementApplicationModule),
typeof(AbpOssManagementHttpApiModule),
typeof(AbpOssManagementSettingManagementModule),
typeof(PlatformApplicationModule),
typeof(PlatformHttpApiModule),
typeof(PlatformEntityFrameworkCoreModule),
typeof(AbpIdentityHttpApiClientModule),
typeof(AbpHttpClientIdentityModelWebModule),
typeof(AbpAspNetCoreMultiTenancyModule),
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
typeof(AbpAuditLoggingEntityFrameworkCoreModule),
typeof(AbpTenantManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpLocalizationManagementEntityFrameworkCoreModule),
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(AbpNotificationModule),
typeof(AbpEmailingExceptionHandlingModule),
typeof(AbpCAPEventBusModule),
typeof(AbpFeaturesValidationRedisModule),
// typeof(AbpFeaturesClientModule),// 当需要客户端特性限制时取消注释此模块
// typeof(AbpFeaturesValidationRedisClientModule),// 当需要客户端特性限制时取消注释此模块
typeof(AbpDbFinderMultiTenancyModule),
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpAspNetCoreHttpOverridesModule),
typeof(AbpAutofacModule)
)]
public class AppPlatformHttpApiHostModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
PreConfigure<CapOptions>(options =>
{
options
.UseMySql(configuration.GetConnectionString("Default"))
.UseRabbitMQ(rabbitMQOptions =>
{
configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions);
})
.UseDashboard();
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = hostingEnvironment.BuildConfiguration();
// 配置Ef
Configure<AbpDbContextOptions>(options =>
{
options.UseMySQL();
});
//// 中文序列化的编码问题
Configure<AbpSystemTextJsonSerializerOptions>(options =>
{
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
});
Configure<KestrelServerOptions>(options =>
{
options.Limits.MaxRequestBodySize = null;
options.Limits.MaxRequestBufferSize = null;
});
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureAll((containerName, containerConfiguration) =>
{
containerConfiguration.UseFileSystem(fileSystem =>
{
fileSystem.BasePath = Path.Combine(Directory.GetCurrentDirectory(), "file-blob-storing");
});
});
});
// 加解密
Configure<AbpStringEncryptionOptions>(options =>
{
var encryptionConfiguration = configuration.GetSection("Encryption");
if (encryptionConfiguration.Exists())
{
options.DefaultPassPhrase = encryptionConfiguration["PassPhrase"] ?? options.DefaultPassPhrase;
options.DefaultSalt = encryptionConfiguration.GetSection("Salt").Exists()
? Encoding.ASCII.GetBytes(encryptionConfiguration["Salt"])
: options.DefaultSalt;
options.InitVectorBytes = encryptionConfiguration.GetSection("InitVector").Exists()
? Encoding.ASCII.GetBytes(encryptionConfiguration["InitVector"])
: options.InitVectorBytes;
}
});
// 自定义需要处理的异常
Configure<AbpExceptionHandlingOptions>(options =>
{
// 加入需要处理的异常类型
options.Handlers.Add<Volo.Abp.Data.AbpDbConcurrencyException>();
options.Handlers.Add<AbpInitializationException>();
options.Handlers.Add<ObjectDisposedException>();
options.Handlers.Add<StackOverflowException>();
options.Handlers.Add<OutOfMemoryException>();
options.Handlers.Add<System.Data.Common.DbException>();
options.Handlers.Add<Microsoft.EntityFrameworkCore.DbUpdateException>();
options.Handlers.Add<System.Data.DBConcurrencyException>();
});
Configure<Volo.Abp.AspNetCore.ExceptionHandling.AbpExceptionHandlingOptions>(options =>
{
// 是否发送错误详情
options.SendExceptionsDetailsToClients = false;
});
// 自定义需要发送邮件通知的异常类型
Configure<AbpEmailExceptionHandlingOptions>(options =>
{
// 是否发送堆栈信息
options.SendStackTrace = true;
// 未指定异常接收者的默认接收邮件
// 指定自己的邮件地址
// options.DefaultReceiveEmail = "colin.in@foxmail.com";
});
Configure<AbpDistributedCacheOptions>(options =>
{
// 最好统一命名,不然某个缓存变动其他应用服务有例外发生
options.KeyPrefix = "LINGYUN.Abp.Application";
// 滑动过期30天
options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30);
// 绝对过期60天
options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60);
});
Configure<RedisCacheOptions>(options =>
{
var redisConfig = ConfigurationOptions.Parse(options.Configuration);
options.ConfigurationOptions = redisConfig;
options.InstanceName = configuration["Redis:InstanceName"];
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AppPlatformHttpApiHostModule>("LINGYUN.Platform");
});
// 多租户
Configure<AbpMultiTenancyOptions>(options =>
{
options.IsEnabled = true;
});
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "Platform";
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
{
options
.EntityHistorySelectors
.AddAllEntities();
}
});
// Swagger
context.Services.AddSwaggerGen(
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Platform API", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName);
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Scheme = "bearer",
Type = SecuritySchemeType.Http,
BearerFormat = "JWT"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
},
new string[] { }
}
});
});
// 支持本地化语言类型
Configure<AbpLocalizationOptions>(options =>
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
options.Resources.AddDynamic();
});
Configure<AbpClaimsMapOptions>(options =>
{
options.Maps.TryAdd("name", () => AbpClaimTypes.UserName);
});
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = false;
options.Audience = configuration["AuthServer:ApiName"];
});
if (!hostingEnvironment.IsDevelopment())
{
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
context.Services
.AddDataProtection()
.PersistKeysToStackExchangeRedis(redis, "Platform-Protection-Keys");
}
}
//public override void OnPostApplicationInitialization(ApplicationInitializationContext context)
//{
// var backgroundJobManager = context.ServiceProvider.GetRequiredService<IBackgroundJobManager>();
// // 五分钟执行一次的定时任务
// AsyncHelper.RunSync(async () => await
// backgroundJobManager.EnqueueAsync(CronGenerator.Minute(5), new NotificationCleanupExpritionJobArgs(200)));
//}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
// http调用链
app.UseCorrelationId();
// 虚拟文件系统
app.UseStaticFiles();
// 本地化
app.UseAbpRequestLocalization();
// 多租户
app.UseMultiTenancy();
//路由
app.UseRouting();
// 认证
app.UseAuthentication();
// jwt
app.UseJwtTokenMiddleware();
// 授权
app.UseAuthorization();
// Swagger
app.UseSwagger();
// Swagger可视化界面
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support Platform API");
});
// 审计日志
app.UseAuditing();
// 工作单元
app.UseUnitOfWork();
// 路由
app.UseConfiguredEndpoints();
if (env.IsDevelopment())
{
AsyncHelper.RunSync(async () =>
await app.ApplicationServices.GetRequiredService<IDataSeeder>()
.SeedAsync());
}
}
}
}

Loading…
Cancel
Save