本地服务器存储
引用RsCode.Storage.LocalStorage
使用服务
services.AddLocalStorage(Configuration);
七牛服务器存储
以客户端上传方式为例,步骤:
1.客户端传递key,向上传API索取上传token信息
2.客户端收到token信息后,处理上传url与key信息
3.客户端执行上传 ,附加额外的参数
json
{"key":"key","token":"上传token"}
引用RsCode.Storage.QiniuStorage
使用服务
csharp
services.AddQiniuStorage(Configuration);
json
//七牛存储配置
"QiniuStorage": {
"UploadTokenUrl":"自定义的token获取地址",
"ManageTokenUrl":"自定义的token获取地址",
"DownloadTokenUrl":"自定义的token获取地址",
"AccessKey": "x",
"SecretKey": "x",
"Domain": "在七牛云存储配置的域名", //上传后资源地址,例:http://res.rscode.cn
"Bucket": "在七牛云存储配置的bucket",
"Zone": "bucket存储区域", //华东 ZONE_CN_East 华北 ZONE_CN_North 华南 ZONE_CN_South 北美 ZONE_US_North
"UploadTokenExpireTime": 30, // 上传token有效时间单位:秒
"DownloadTokenExpireTime": 5,//下载token有效时间
"ManageTokenExpireTime": 5 //管理token有效时间
}
//本地存储配置
"LocalStorage": {
"UploadTokenUrl":"自定义的token获取地址", //例 /storage/uptoken
"UploadUrl": "https://localhost:5001/storage/upload",
"AccessKey": "",//不填
"SecretKey": "",//不填
"Domain": "上传后资源地址", //上传后资源地址,例:http://res.rscode.cn
"Bucket": "", //不填
"Zone": "", //不填
"UploadTokenExpireTime": 30, // 上传token有效时间单位:秒
"DownloadTokenExpireTime": 5,//下载token有效时间
"ManageTokenExpireTime": 5 //管理token有效时间
}
自定义获取uptoken的逻辑 例:
csharp
public class StorageController : Controller
{
public IActionResult UpToken([FromServices]IEnumerable<IStorageProvider> providers,string provider="qiniu")
{
var qiniu = providers.FirstOrDefault(s => s.StorageName == provider);
var tokenInfo= qiniu.GetUploadToken();
return Json(tokenInfo);
}
[HttpPost]
public async Task<IActionResult> Upload([FromServices] IEnumerable<IStorageProvider> providers)
{
var local = providers.FirstOrDefault(s => s.StorageName == "local");
var tokenInfo= await local.UploadAsync();
return Json(tokenInfo);
}
}
获取上传token的返回值:
json
{'domain':'合法域名','token':'上传token','upload_url':'上传地址'}
上传成功后的返回值
json
{'res':'','key':'上传后的key'}
注意:使用本地上传时,在wwwroot文件夹中,确保保存文件的文件夹是存在的 razor页面,使用 @Html.Raw(info.UploadUrl)防止字符被转义
实例:
vue文件上传
html
html
@{
Layout = null;
ViewData["title"] = "上传demo";
var info = ViewBag.TokenInfo as RsCode.Storage.TokenResult;
}
<el-upload class="avatar-uploader"
ref="upload"
:action="upload_url"
:data="upload_data"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:on-error="handleError"
:before-upload="beforeAvatarUpload">
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
js
js
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<!-- import JavaScript -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
imageUrl: '',
// 七牛云上传储存区域的上传域名(华东、华北、华南、北美、东南亚)
upload_url: "@Html.Raw(info.UploadUrl)",
domain:"@info.Domain",
upload_data: {
key: "",
token:"@info.Token"
}
};
},
methods: {
handleAvatarSuccess(res, file) {
console.log('res=' + JSON.stringify(res));
console.log('file=' + JSON.stringify(file));
if (res.key && res.key.length > 0) {
let fileUrl = this.domain + res.key;
//本地url
//this.imageUrl = URL.createObjectURL(file.raw);
this.imageUrl = fileUrl;
} else {
this.handleError(res);
}
},
handleError: function (res) {
this.$message({
message: "上传失败,请重试",
duration: 2000,
type: "warning"
});
if (res.error == "expired token")
{
//重新获取token
}
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
let key = file.name; // 文件资源名
//wwwroot下准备好文件夹file
key = 'file/' + Math.random().toString(36).substr(2) + '.' + key.split(".")[1];
this.upload_data.key = key;
return isJPG && isLt2M;
},
getUploadToken() {
this.http.get("/storage?provider=qiniu&action=uptoken")
.then(ret => {
this.domain = ret.domain;
this.token = ret.token;
})
.catch(err => {
})
}
}
})
</script>
css
css
<style>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
Ant Blazor 上传
html
<Upload Action="@tokenResult.UploadUrl"
Data="@tokenResult.Data"
Name="file"
@bind-FileList="fileList"
ShowButton="fileList?.Count <= FileCount"
ListType="picture-card"
OnPreview="(file)=> {
Console.WriteLine(file.FileName);
Console.WriteLine(file.Url);
previewVisible = true;
previewTitle = file.FileName;
imgUrl = file.Url;
}"
BeforeAllUploadAsync="BeforeUploadAsync"
OnChange="HandleChange"
OnSingleCompleted="OnSingleCompleted"
OnCompleted="Completed">
<div>
<Icon Type="plus"></Icon>
<div className="ant-upload-text">上传图片</div>
</div>
</Upload>
上传前,BeforeUpload 或BeforeAllUploadAsync 如果返回false时会阻止上传 上传中,HandleChange 处理上传过程 上传成功 OnSingleCompleted
事件处理代码
csharp
UploadTokenResult tokenResult { get; set; } = new UploadTokenResult();
List<UploadFileItem> fileList = new List<UploadFileItem>
{
//new UploadFileItem
//{
// Id = "1",
// FileName = "image.png",
// State = UploadState.Success,
// Url = "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
//},
};
bool loading = false;
bool BeforeUpload(UploadFileItem file)
{
var isJpgOrPng = file.Type == "image/jpg" || file.Type == "image/jpeg" || file.Type == "image/png";
if (!isJpgOrPng)
{
_message.Error("只能上传格式为JPG或PNG的图片文件!");
}
var isLt2M = file.Size / 1024 / 1024 < 2;
if (!isLt2M)
{
_message.Error("图片必须小于2MB!");
}
return isJpgOrPng && isLt2M;
}
async Task<bool>BeforeUploadAsync(List<UploadFileItem> items)
{
try
{
foreach (var file in items)
{
if(BeforeUpload(file))
{
await GetUploadTokenAsync(file);
}
}
return true;
}
catch (AppException ex)
{
await _message.Error(ex.Message);
}
catch (Exception e)
{
await _message.Error(e.Message);
}
return false;
}
void HandleChange(UploadInfo file)
{
Console.WriteLine("start handleChange");
Console.WriteLine("tokenResult="+JsonSerializer.Serialize(tokenResult));
if (string.IsNullOrEmpty(tokenResult.UploadUrl))
{
_message.Error("未找到上传服务器");
}else
{
loading = file.File.State == UploadState.Uploading;
if (file.File.State == UploadState.Success)
{
//imgUrl = file.File.ObjectURL;
}
InvokeAsync(StateHasChanged).GetAwaiter().GetResult();
Console.WriteLine("HandleChange=" + JsonSerializer.Serialize(file));
}
}
void OnSingleCompleted(UploadInfo fileinfo)
{
if (fileinfo.File.State == UploadState.Success)
{
var result = fileinfo.File.GetResponse<ResponseModel>();
var res=fileinfo.File.GetResponse<QiniuResponse>();
fileinfo.File.Url = $"{tokenResult.Domain}{res.key}";
}
}
void Completed(UploadInfo info)
{
}
void OnPreview(UploadFileItem file)
{
previewVisible = true;
previewTitle = file.FileName;
imgUrl = file.Url;
OnPreviewImage.InvokeAsync(imgUrl).GetAwaiter().GetResult();
}
async Task<bool> OnRemove(UploadFileItem file)
{
await OnRemoveImage.InvokeAsync(file.Url);
return false;
}
async Task GetUploadTokenAsync(UploadFileItem file)
{
string key = $"{Guid.NewGuid().ToString("N")}{file.Ext}";
tokenResult = await UploadService.GetStorageTokenAsync(UserToken, key);
}
上传成功返回json
json
{
"File": {
"Id": "63e9ded5-c68b-4367-b1a6-717abcb431dc",
"FileName": "e78b1da352e7653031d9bbdc2b07b90b.jpg",
"Percent": 100,
"ObjectURL": "blob:https://localhost:5001/20a473a3-67cc-45c5-9f24-3e4f6d83c031",
"Url": null,
"Response": "{\"hash\":\"FlN6RcwiE9aR-GKN9tSCVeFb4LUG\",\"key\":\"mt_9215508b6c164307ba0a7985450da24b_e878fba96d0a4b38989713b21f1630f3\"}",
"State": 0,
"Size": 460427,
"Ext": ".jpg",
"Type": "image/jpeg"
},
"FileList": [
{
"Id": "63e9ded5-c68b-4367-b1a6-717abcb431dc",
"FileName": "e78b1da352e7653031d9bbdc2b07b90b.jpg",
"Percent": 100,
"ObjectURL": "blob:https://localhost:5001/20a473a3-67cc-45c5-9f24-3e4f6d83c031",
"Url": null,
"Response": "{\"hash\":\"FlN6RcwiE9aR-GKN9tSCVeFb4LUG\",\"key\":\"mt_9215508b6c164307ba0a7985450da24b_e878fba96d0a4b38989713b21f1630f3\"}",
"State": 0,
"Size": 460427,
"Ext": ".jpg",
"Type": "image/jpeg"
}
]
}