想要实现的功能:Post附件到WebApi,WebApi 将文件转发到 ftp服务器。
主要功能已经实现,有一个问题:需要在WebApi服务器,接收流写入WebApi本地文件,然后读取文件流写入 ftp 服务器,然后再删除WebApi 服务器上的本地文件,现在不想在WebApi本地写文件,直接取Request的流写入到 ftp,不知道能不能实现,应该怎样写?
1. Post附件到WebApi 主要代码:
#region 上传文件
/// <summary>
/// 通过multipart/form-data方式上传文件
/// </summary>
/// <returns></returns>
[HttpPost]
public
async Task<HttpResponseMessage> PostFile()
{
MessagesDataCodeModel json =
new
MessagesDataCodeModel(
false
,
"无效参数"
, 401);
try
{
// 是否请求包含multipart/form-data。
if
(!Request.Content.IsMimeMultipartContent())
{
logger.Error(
"上传格式不是multipart/form-data"
);
throw
new
HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string
root = HttpContext.Current.Server.MapPath(
"/UploadFiles/"
);
if
(!Directory.Exists(HttpContext.Current.Server.MapPath(
"~/UploadFiles/"
)))
{
Directory.CreateDirectory(HttpContext.Current.Server.MapPath(
"~/UploadFiles/"
));
}
var
provider =
new
MultipartFormDataStreamProvider(root);
StringBuilder sb =
new
StringBuilder();
// Holds the response body
// 阅读表格数据并返回一个异步任务.
await Request.Content.ReadAsMultipartAsync(provider);
// 如何上传文件到文件名.
foreach
(
var
file
in
provider.FileData)
{
string
orfilename = file.Headers.ContentDisposition.FileName.TrimStart(
'"'
).TrimEnd(
'"'
);
FileInfo fileinfo =
new
FileInfo(file.LocalFileName);
//sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
//最大文件大小
//int maxSize = Convert.ToInt32(SettingConfig.MaxSize);
if
(fileinfo.Length <= 0)
{
json.Success =
false
;
json.Msg =
"请选择上传文件"
;
json.Code = 301;
}
else
if
(fileinfo.Length > ConfigHelper.MaxFileSize)
{
json.Msg =
"上传文件大小超过限制"
;
json.Code = 302;
}
else
{
string
fileExt = orfilename.Substring(orfilename.LastIndexOf(
'.'
));
//定义允许上传的文件扩展名
//String fileTypes = SettingConfig.FileTypes;
//if (String.IsNullOrEmpty(fileExt) || Array.IndexOf(fileTypes.Split(','), fileExt.Substring(1).ToLower()) == -1)
//{
// json.Msg = "图片类型不正确";
// json.Code = 303;
//}
//else
//{
//String ymd = DateTime.Now.ToString("yyyyMMdd", System.Globalization.DateTimeFormatInfo.InvariantInfo);
//String newFileName = DateTime.Now.ToString("yyyyMMddHHmmss_ffff", System.Globalization.DateTimeFormatInfo.InvariantInfo);
fileinfo.CopyTo(Path.Combine(root, fileinfo.Name + fileExt),
true
);
json.Success =
true
;
json.Msg =
"操作成功"
;
json.Code = 200;
sb.Append(
"/UploadFiles/"
+ fileinfo.Name + fileExt);
json.Data = sb.ToString();
//}
}
fileinfo.Delete();
//删除原文件
}
}
catch
(System.Exception e)
{
json.Success =
false
;
json.Msg =
"服务器无响应"
;
json.Code = 500;
logger.Error(
"PostFile()服务器错误"
, e);
}
return
ToJsonTran.ToJson(json);
}
#endregion 上传文件
/// <summary>
/// 上传文件
/// </summary>
/// <param name="fileinfo">需要上传的文件</param>
/// <param name="targetDir">目标路径</param>
/// <param name="hostname">ftp地址</param>
/// <param name="username">ftp用户名</param>
/// <param name="password">ftp密码</param>
public static void UploadFile(FileInfo fileinfo, string targetDir, string hostname, string username, string password)
{
//1. check target
string target;
if (targetDir.Trim() == "")
{
return;
}
target = Guid.NewGuid().ToString(); //使用临时文件名
string URI = "FTP://" + hostname + "/" + targetDir + "/" + target;
///WebClient webcl = new WebClient();
System.Net.FtpWebRequest ftp = GetRequest(URI, username, password);
//设置FTP命令 设置所要执行的FTP命令,
//ftp.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails;//假设此处为显示指定路径下的文件列表
ftp.Method = System.Net.WebRequestMethods.Ftp.UploadFile;
//指定文件传输的数据类型
ftp.UseBinary = true;
ftp.UsePassive = true;
//告诉ftp文件大小
ftp.ContentLength = fileinfo.Length;
//缓冲大小设置为2KB
const int BufferSize = 2048;
byte[] content = new byte[BufferSize - 1 + 1];
int dataRead;
//打开一个文件流 (System.IO.FileStream) 去读上传的文件
using (FileStream fs = fileinfo.OpenRead())
{
try
{
//把上传的文件写入流
using (Stream rs = ftp.GetRequestStream())
{
do
{
//每次读文件流的2KB
dataRead = fs.Read(content, 0, BufferSize);
rs.Write(content, 0, dataRead);
} while (!(dataRead < BufferSize));
rs.Close();
}
}
catch (Exception ex) { }
finally
{
fs.Close();
}
}
ftp = null;
//设置FTP命令
ftp = GetRequest(URI, username, password);
ftp.Method = System.Net.WebRequestMethods.Ftp.Rename; //改名
ftp.RenameTo = fileinfo.Name;
try
{
ftp.GetResponse();
}
catch (Exception ex)
{
ftp = GetRequest(URI, username, password);
ftp.Method = System.Net.WebRequestMethods.Ftp.DeleteFile; //删除
ftp.GetResponse();
throw ex;
}
finally
{
//fileinfo.Delete();
}
// 可以记录一个日志 "上传" + fileinfo.FullName + "上传到" + "FTP://" + hostname + "/" + targetDir + "/" + fileinfo.Name + "成功." );
ftp = null;
#region
/*****
*FtpWebResponse
* ****/
//FtpWebResponse ftpWebResponse = (FtpWebResponse)ftp.GetResponse();
#endregion
}
我记得当初我也有个类似的问题:页面请求服务器下载文件,但文件在微软的云上,这中间就导致一个文件经过服务器的手中转了一次,服务器先从云上下载,然后浏览器再从服务器下载.....
当时是服务器构造一个HttpWebRequest直接请求云上的文件。
但这个情况有点不同,毕竟浏览器是向http服务器上post,不管怎样,文件流已经到了服务器,不论服务器接受不接受(时间已经花费了),当然服务器可以选择不存储在本地,直接将流导向ftp服务器。具体代码我不清楚,没接触ftp相关的东西,思路应该可以借鉴下。
其实存http服务器本地这一步确实有点多余:把文件流写入文件,又读取同一文件的文件流。
肯定可以。直接操作context request 中的stream即可。