2013年12月17日 星期二

C# 透過 WebRequest 傳送資料、檔案

近來專案上有個檔案、照片上傳的需求,
但因為運行的架構為前後台分別獨立於不同的主機上運行,
當使用者從後台上傳檔案或照片時,棘手的問題就產生了,
於後台主機上傳的檔案、照片要怎樣同步傳送至前台主機?
當下我嚐試想要透過網芳共享資料夾的方式,
將使用者傳至後台主機的檔案或照片複製到前台的主機上,
弄了二天還是解決不了權限的問題,
解決不了只能用最原始的方法
用HTTP傳送及接收
下面的方法只能指定單一的本機檔案路徑
寫完後才想到有可能會是檔案是分佈在不同的資料中
當要傳送一次就得再呼叫一次有點麻煩
當需求產生時再補入

使用方法
UploadFilesToRemoteUrl(
"http://www.yousite.com/r.aspx" /*接收檔案的網址*/,
"d:\tmp" /*本機檔案路徑*/,
new[] {"a.png", "b.jpg"} /*傳送的檔案名稱,可傳送多個檔案*/,
new NameValueCollection {{"id","123"}} /*其他要傳送的參數*/)
程式如下 [C# 3.5]


發送端
/// 
/// 將本機檔案上傳到遠端主機上
/// 
///  接收檔案的網址
///  本機檔案路徑
///  傳送的檔案名稱
///  其他要傳送的參數
public void UploadFilesToRemoteUrl(string url, string filePath, IEnumerable fileNames, NameValueCollection param)
{
    var boundary = "----------------------------" + Guid.NewGuid();
    var webRequest = (HttpWebRequest)WebRequest.Create(url);
    webRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
    webRequest.Method = "POST";
    webRequest.KeepAlive = true;
    webRequest.Credentials = CredentialCache.DefaultCredentials;
    var memStream = new MemoryStream();
    var boundarybytes = Encoding.ASCII.GetBytes(string.Format("\r\n--{0}\r\n", boundary));

 var paramrHeader =
        string.Format(
        "\r\n--{0}\r\nContent-Disposition: form-data; name=\"{{0}}\";\r\n\r\n{{1}}",
        boundary);
    foreach (var paramItemBytes in
        from string key in param.Keys
        select string.Format(paramrHeader, key, param[key])
        into paramItem
            select Encoding.UTF8.GetBytes(paramItem))
    {
        memStream.Write(paramItemBytes, 0, paramItemBytes.Length);
    }
    memStream.Write(boundarybytes, 0, boundarybytes.Length);

    const 
string fileHeader =
        "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n";
    foreach (var t in fileNames)
    {
        var header = string.Format(fileHeader, t, t);
        var headerbytes = Encoding.UTF8.GetBytes(header);
        memStream.Write(headerbytes, 0, headerbytes.Length);
        var fileStream = new FileStream(
            string.Format("{0}/{1}", filePath, t),
            FileMode.Open,
            FileAccess.Read);
        var buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
        {
            memStream.Write(buffer, 0, bytesRead);
        }
        memStream.Write(boundarybytes, 0, boundarybytes.Length);
        fileStream.Close();
    }
    webRequest.ContentLength = memStream.Length;
    memStream.Position = 0;
    var memBuffer = new byte[memStream.Length];
    memStream.Read(memBuffer, 0, memBuffer.Length);
    memStream.Close();
    webRequest.GetRequestStream().Write(memBuffer, 0, memBuffer.Length);
} 

接收端

protected void Page_Load(object sender, EventArgs e)
{
    if (string.IsNullOrEmpty(Request["id"])) return;
    var strDirectory =
        string.Format(
            "{0}tmp/{1}",
            Request.PhysicalApplicationPath,
            Request["id"]);
    //建立主機上的檔案路徑
    Directory.CreateDirectory(strDirectory);
    foreach (var file in Request.Files)
    {
        Request.Files[file.ToString()].SaveAs(
            string.Format(
                "{0}/{1}",
                strDirectory,
                Request.Files[file.ToString()].FileName));
    }
} 

沒有留言: