1、附属文件对象定义

一般情况下,系统里面的文件都会附属一个对象存在,例如用户的头像文件,会附属用户对象存在。邮件中的文件会附属邮件存在。所以在系统里面,我们会创建一个附属文件对象,命名为AttachedFileEntity。其定义如下所示。

/// <summary>
/// 附属文件实体对象
/// </summary>
public class AttachedFileEntity
{ /// <summary>
/// 实体对象GUID
/// </summary>
public string GUID { get; set; } = ""; /// <summary>
/// 所属对象的GUID
/// </summary>
public string EntityGUID { get; set; } = ""; /// <summary>
/// 名称
/// </summary>
public string Name { get; set; } = ""; /// <summary>
/// 关键字
/// </summary>
public string KeyWord { get; set; } = ""; /// <summary>
/// 文件大小
/// </summary>
public int FileSize { get; set; } = 0; /// <summary>
/// 服务器存储路径
/// </summary>
public string ServerPath { get; set; } = ""; /// <summary>
/// 描述信息
/// </summary>
public string Description { get; set; } = ""; }

EntityGUID属性的作用是,定义该文件属于哪个实体对象,例如某个用户的头像文件,该属性就是这个用户对象的GUID值。

KeyWord属性用来标识文件。例如UserEntity有两个文件,头像和一个自我介绍的视频文件。这两个文件的EntityGUID都是UserEntity的GUID,那么就可以通过KeyWord来区分两个文件是做什么用的。

2、小文件上传服务

如果一个文件比较小,例如3M以内,那么我们就可以一次性把文件上传上来,上传的时候,要把AttachedFileEntity对象传进来,并添加到数据库中。

代码如下所示。

 /// <summary>
/// 上传文件
/// </summary>
/// <param name="pEntity"></param>
/// <returns></returns>
[HttpPost]
[Route("UploadFile")]
public IActionResult UploadFile()
{
//获取客户端传来的数据
var myEntityJosnString = Request.Form["pEntity"].ToString();
var myEntity = JsonSerializer.Deserialize<AttachedFileEntity>(myEntityJosnString);
var myFile = Request.Form.Files[0]; //设置新的文件路径
string myFileEx = Path.GetExtension(myFile.FileName);
string myServerFilePath = DateTime.Now.ToString("yyyy_MM_dd") + "\\" + Guid.NewGuid().ToString() + myFileEx;
myEntity!.ServerPath = myServerFilePath; //创建目录
string myFullServerPath = AppDomain.CurrentDomain.BaseDirectory + "\\Files\\" + myServerFilePath;
string myFullFolder = Path.GetDirectoryName(myFullServerPath)!;
if (Directory.Exists(myFullFolder) == false)
{
Directory.CreateDirectory(myFullFolder);
} Stream? myStream = null;
FileStream? myFileStream = null;
BinaryWriter? myBinaryWriter = null;
try
{
myStream = myFile.OpenReadStream();
byte[] myBytes = new byte[myStream.Length];
myStream.Read(myBytes, 0, myBytes.Length);
myStream.Seek(0, SeekOrigin.Begin); myFileStream = new FileStream(myFullServerPath, FileMode.Create);
myBinaryWriter = new BinaryWriter(myFileStream);
myBinaryWriter.Write(myBytes);
}
finally
{
myBinaryWriter?.Close();
myFileStream?.Close();
myStream?.Close();
} //把附属文件对象保存到数据库中
//代码略 return this.Ok(myEntity);
}

因为我们要传入两个复杂的对象AttachedFileEntity和File,所以就不能用参数接了,就需要用代码从Request里面读取。文件其本质就是二进制数据,我们获取这个二进制之后,把数据保存成文件就可以了。然后把pEntity写入到数据库中。

3、前端调用

先用桌面端测试,界面是用C#写的WPF桌面软件,入下图所示。

调用代码入下所示。

var myFilePath = this.UI_SmallFile_TextBox.Text.Trim();
if (myFilePath.Length == 0)
{
MessageBox.Show("请选择一个文件。");
return;
}
if (File.Exists(myFilePath) == false)
{
MessageBox.Show("文件不存在,请重新选择。");
return;
} //定义AttachedFileEntity
var myAttachedFileEntity = new AttachedFileEntity()
{
GUID = Guid.NewGuid().ToString(),
Name = "用户头像",
KeyWord = "UserProfilePhoto",
Description = "",
EntityGUID = "AAAA"
}; //定义请求内容
var myFileStream = new FileStream(myFilePath, FileMode.Open);
myAttachedFileEntity.FileSize = (int)myFileStream.Length;
var myFileName = Path.GetFileName(myFilePath);
var myFileStreamContent = new StreamContent(myFileStream);
var myMultipartFormDataContent = new MultipartFormDataContent
{
{ JsonContent.Create(myAttachedFileEntity), "pEntity" },
{ myFileStreamContent, "pFormFile", myFileName }
}; //请求服务
var myHttpClientEx = new HttpClientEx(new HttpClient())
{
Url = "http://localhost:5000/api/AttachedFile/UploadFile",
HttpContent = myMultipartFormDataContent
};
await myHttpClientEx.PostAsync();
myFileStream.Close(); //解析结果
if (myHttpClientEx.IsSuccess == false)
{
MessageBox.Show(("上传文件失败," + myHttpClientEx.ResponseContenString));
return;
}
var myEntity = myHttpClientEx.GetResponseObject<AttachedFileEntity>();
var myEntityJosnString = JsonSerializer.Serialize(myEntity);
MessageBox.Show(myEntityJosnString);

HttpClientEx是对.Net定义的HttpClient一些功能的扩展,这样用起来会比较方便,代码定义如下。

/// <summary>
/// HttpClient的自定义扩展类
/// </summary>
public class HttpClientEx
{ /// <summary>
/// HttpClient的自定义扩展类
/// </summary>
/// <param name="pHttpClient"></param>
public HttpClientEx(HttpClient? pHttpClient)
{
this.HttpClient = pHttpClient;
this.ParameterDictionary = new Dictionary<string, string>();
} /// <summary>
/// HttpClient对象
/// </summary>
public HttpClient? HttpClient { get; private set; } /// <summary>
/// 服务地址
/// </summary>
public string Url { get; set; } = ""; /// <summary>
/// 参数字典
/// </summary>
public Dictionary<string, string> ParameterDictionary { get; private set; } /// <summary>
/// 请求内容
/// </summary>
public HttpContent? HttpContent { get; set; } /// <summary>
/// 请求返回的消息
/// </summary>
public HttpResponseMessage? ResponseMessage { get; private set; } /// <summary>
/// 是否执行成功
/// </summary>
public bool IsSuccess { get; private set; } /// <summary>
/// 返回的内容字符串
/// </summary>
public string ResponseContenString { get; private set; } = ""; /// <summary>
/// Get
/// </summary>
/// <returns></returns>
public async Task GetAsync()
{
var myUrlWithParameters = this.GetUrlWithParameters();
this.ResponseMessage = await this.HttpClient!.GetAsync(myUrlWithParameters);
this.IsSuccess = this.ResponseMessage.IsSuccessStatusCode;
this.ResponseContenString = await this.ResponseMessage.Content.ReadAsStringAsync();
} /// <summary>
/// Get
/// </summary>
/// <returns></returns>
public async Task PostAsync()
{
var myUrlWithParameters = this.GetUrlWithParameters();
this.ResponseMessage = await this.HttpClient!.PostAsync(myUrlWithParameters, this.HttpContent);
this.IsSuccess = this.ResponseMessage.IsSuccessStatusCode;
this.ResponseContenString = await this.ResponseMessage.Content.ReadAsStringAsync();
} /// <summary>
/// 得到返回的对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T? GetResponseObject<T>()
{
if (this.ResponseContenString == "")
{
return default;
}
var myJsonSerializerOptions = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
};
return JsonSerializer.Deserialize<T>(this.ResponseContenString, myJsonSerializerOptions);
} /// <summary>
/// 得到带参数的Url
/// </summary>
/// <returns></returns>
private string GetUrlWithParameters()
{
if (this.ParameterDictionary == null)
{
return this.Url;
}
if (this.ParameterDictionary.Count == 0)
{
return this.Url;
} var myParameterList = new List<string>();
foreach (var myItem in this.ParameterDictionary)
{
myParameterList.Add(myItem.Key + "=" + myItem.Value);
}
return this.Url + "?" + string.Join("&", myParameterList);
} }

如果客户端是Js,就需要自己组织服务需要的数据了。代码入下所示。

var myFileReader = new FileReader();
var myFileName = ""; myFileReader.onloadend = function () {
var myFileResult = myFileReader.result;
var myFileLength = myFileResult.byteLength; var myFileEntity = new Object()
{
ServerPath: ""
};
Upload(); function Upload() { var myByteArray = myFileResult.slice(0, myFileLength);
var myBlob = new Blob([myByteArray]);
var myFile = new File([myBlob], myFileName);
var myFormData = new FormData();
myFormData.append("file", myFile)
myFormData.append("pEntity", json.stringify(myFileEntity));
request.post(myUrl, {
data: myFormData
}).then(function (data) {
myFileEntity = json.parse(data);
alert("上传文件结束。");
alert(json.stringify(myFileEntity));
}, function (err) {
alert(err);
return;
});
}
} myFileName = this.files[0].name;
myFileReader.readAsArrayBuffer(this.files[0]);

.Net Web API 005 Controller上传小文件的更多相关文章

  1. Wince 6.0适用 .NET 使用HttpRequest的Post上传文件,服务端的Web API接收Post上传上来的文件 代码

    //调用的示例 private string fileName = "InStorageData.csv"; string filePath = parentPath + Comm ...

  2. SharePoint REST API - 使用REST API和jQuery上传一个文件

    博客地址:http://blog.csdn.net/FoxDave 本篇主要通过两个代码示例来展示如何应用REST API和jQuery上传文件到SharePoint. 示例会使用REST接口和j ...

  3. Windows Azure 系列-- 使用Azure + Web API实现图片上传

    1. 创建1个Azure账号,登录之后创建1个AzureStorage.左下方点Manage Access会看到Primary Access Key和Storage Account,记住它们的位置,等 ...

  4. web api 2.0 上传文件超过4M时,出现404错误

    客户端代码 string path = "C:\\text.txt"; WebClient client = new WebClient(); Uri _address = new ...

  5. C# WEB.API 多图上传

    using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Ne ...

  6. windows上在linux客户端上传小文件lrzsz

    yum install lrzsz 即可 rz上传,会打开本地图形化界面直接上传 基于centos系统,其他系统请找对应 的源码包编译 一下

  7. web项目使用fastdsf上传|下载文件

    在上传代码中添加一下代码 suffix=suffix.substring(1); fast.FastDFSFile file = new fast.FastDFSFile(mFile.getBytes ...

  8. Azure VM上传小文件

    因为需要传一些脚本到Azure的VM里,有个简单方法可以实现,如下 编辑这个rdp文件 点击确定,连接远程计算机 可以在我的电脑里看到本地硬盘

  9. webAPI文件上传时文件过大404错误的问题

    背景:最近公司有个需求,外网希望自动保存数据到内网,内网有2台服务器可以相互访问,其中一台服务器外网可以访问,于是想在 这台服务器上放个中转的接口.后来做出来以后测试发现没有问题就放线上去了,不顾发现 ...

  10. Asp.net MVC利用WebUploader上传大文件出现404解决办法。

    刚开始我上传小文件都是比较顺利的,但是上传了一个大文件大约有200M的压缩包就不行了.在chrome里面监视发现网络状态是404,我分析可能不是WebUploader的限制,应该是WebConfig限 ...

随机推荐

  1. TCP/IP网络模型

    在网络模型中有分为7层模型(OSI模型)和5层模型和TCP/IP模型 OSI模型将应用层和表示层作为独立的两层,而TCP/IP模型将它们合并为一个应用层. 两种对比来说,TCP/IP模型更符合实际开发 ...

  2. QUIC在京东直播的应用与实践

    作者:京东零售 周凯 一. 前言与背景 国内的互联网直播技术从2005年前后兴起,彼时最具代表性的直播产品是由PPLive创始人姚欣在华中科技大学就读期间发起的校园直播项目PPLive.当时的直播技术 ...

  3. SqliLabs 第二关 ,数字型注入!!!

    首先打开网页,进行注入点的测试 输入?id=1 and 1=1发现1=2的时候出现了报错,说明服务器接收了我们的指令,并且进行了反馈,说明了有注入点的存在,然后对注入点进行测试 然后输入order b ...

  4. vue项目使用rem布局刷新页面瞬间元素尺寸由小变大,页面闪现错乱样式

    vue项目使用px2remLoader插件,在index.html自定义设置font-size的大小,尤其是在首屏加载的时候,会出现页面各个元素尺寸由小变大的一个过程,很难看 刚开始一直在想是不是因为 ...

  5. 2022-08-26:用一个大小为 m x n 的二维网格 grid 表示一个箱子 你有 n 颗球。箱子的顶部和底部都是开着的。 箱子中的每个单元格都有一个对角线挡板,跨过单元格的两个角, 可以将球导

    2022-08-26:用一个大小为 m x n 的二维网格 grid 表示一个箱子 你有 n 颗球.箱子的顶部和底部都是开着的. 箱子中的每个单元格都有一个对角线挡板,跨过单元格的两个角, 可以将球导 ...

  6. 2021-02-15:给定一个整型数组arr,代表数值不同的纸牌排成一条线。玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿。但是每个玩家每次只能拿走最左或最右的纸牌,玩家A和玩家B都绝顶聪明。请返回最后获胜者的分数。

    2021-02-15:给定一个整型数组arr,代表数值不同的纸牌排成一条线.玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿.但是每个玩家每次只能拿走最左或最右的纸牌,玩家A和玩家B都绝顶聪 ...

  7. 2021-03-05:go中,io密集型的应用,比如有很多文件io,磁盘io,网络io,调大GOMAXPROCS,会不会对性能有帮助?为什么?

    2021-03-05:go中,io密集型的应用,比如有很多文件io,磁盘io,网络io,调大GOMAXPROCS,会不会对性能有帮助?为什么? 福哥答案2021-03-05: 这是面试中被问到的.实力 ...

  8. .NET 创建无边框的跨平台应用

    .NET 创建无边框的跨平台应用 在创建了Photino应用程序以后我们发现它自带了一个标题栏,并且非常丑,我们现在要做的就是去掉这个很丑的自带标题栏,并且自定义一个更好看的,下面我们将用Masa B ...

  9. STM32F429 Discovery开发板应用:实现SPI-SD Card文件写入(搭载FatFS文件系统)

    MCU:STM32F429ZIT6 开发环境:STM32CubeMX+MDK5 外购了一个SPI接口的SD Card模块,想要实现SD卡存储数据的功能. 首先需要打开STM32CubeMX工具.输入开 ...

  10. Oracle Users表空间重命名

    需求:默认无法直接删除Oracle的users表空间,直接尝试删除会有报错如下: SQL> drop tablespace users including contents and datafi ...