最近一個項目,用到文件上傳功能,本來簡單地使用upload控件直接post到服務器保存,簡單實現了。后來考慮到分布是部署,靜態附件、圖片等內容要單獨服務器(命名為B服務器,一台,192.168.103.240)存儲,則需要分布式服務器(命名為A服務器,可多台,測試程序就是本地 127.0.0.1)上傳附件到B服務器。
考慮難易程度和易操作,簡單想到的方案是:訪問A服務器應用程序調用B服務器的webservice,將附件直接保存到B服務器。
簡單實驗一下,是可以達成效果的。
步驟一、B服務器的webservice代碼如下:

1 /// <summary> 2 /// Summary description for UploadWebService 3 /// </summary> 4 [WebService(Namespace = "http://tempuri.org/")] 5 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 6 [System.ComponentModel.ToolboxItem(false)] 7 // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 8 // [System.Web.Script.Services.ScriptService] 9 public class UploadWebService : System.Web.Services.WebService 10 { 11 [WebMethod] 12 public string HelloWorld() 13 { 14 return "Hello World"; 15 } 16 17 18 HttpContext _context = null; 19 20 [WebMethod] 21 public string PostFile(Byte[] content, string ext) 22 { 23 _context = this.Context; 24 string text = Convert.ToBase64String(content); 25 return Upload(ext, text); 26 } 27 28 private string Upload(string ext, string content) 29 { 30 if (string.IsNullOrEmpty(ext) || string.IsNullOrEmpty(content)) 31 { 32 return ""; 33 } 34 //保存圖片 35 string dateNum = DateTime.Now.ToString("yyyyMM");//按月存放 36 string fileName = Guid.NewGuid() + ext; 37 string currentPath = HttpContext.Current.Request.PhysicalApplicationPath + "upload\\" + dateNum + "\\"; 38 string fullPath = currentPath + fileName; 39 40 if (!Directory.Exists(currentPath)) 41 Directory.CreateDirectory(currentPath); 42 43 byte[] buffer = Convert.FromBase64String(content); 44 using (FileStream fileStream = new FileStream(fullPath, FileMode.Create)) 45 { 46 fileStream.Write(buffer, 0, buffer.Length); 47 } 48 string host = _context.Request.Url.Host; 49 int port = _context.Request.Url.Port; 50 //ResponseWrite(string.Format("http://" + host + ":" + port + "/upload/{0}/{1}", dateNum, fileName));//返回圖片保存路徑 51 return string.Format("http://" + host + "/" + _context.Request.ApplicationPath + "/upload/{0}/{1}", dateNum, fileName); 52 } 53 }
簡單將其部署到B服務器IIS,訪問驗證通過,如下:
步驟二、A服務新建web項目,A服務器的web項目,添加服務引用,增加對B服務器webservice的引用。
新建上傳頁面,前台頁面代碼如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="school.WebForm1" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server" action="WebForm1.aspx" method="post" enctype="multipart/form-data"> <div> <input type="file" name="upload" id="upload" runat="server" /> <input type="submit" value="upload"/> </div> </form> </body> </html>
后台代碼如下:

protected void Page_Load(object sender, EventArgs e) { if (IsPostBack) { var file = Request.Files["upload"]; Stream data = file.InputStream; int length = (int)data.Length; byte[] content = new byte[length]; data.Read(content, 0, content.Length); string ext = file.FileName.Substring(file.FileName.LastIndexOf('.')); //webservice var client = new UploadService.UploadWebServiceSoapClient(); string url = client.PostFile(content, ext); Response.Write(string.Format("<a href=\"{0}\">下載</a>", url)); } }
步驟三、驗證效果,如下圖,輸出的路徑已經是B服務器的網站路徑了。
步驟四、附件大小限制
上傳小附件時,沒有問題,但是當上傳附件很大時,就會報錯:
1、沒有終結點在偵聽可以接受消息的
2、遠程服務器返回錯誤: (404) 未找到
是因為沒有設置上傳大小的限制,超過了默認值。
在B服務器的webservice的web.config內增加如下配置:

<configuration> <system.web> <compilation targetFramework="4.5" /> <httpRuntime targetFramework="4.5" requestLengthDiskThreshold="256" maxRequestLength="2097151" /> </system.web> <system.webServer> <security> <requestFiltering> <!--限制附件上傳80MB--> <requestLimits maxAllowedContentLength="81920000" /> </requestFiltering> </security> </system.webServer> </configuration>
重新上傳附件,問題解決。
簡單思路:分布式服務器應用程序訪問同一個上傳接口。