[Silverlight][C#] 上傳檔案到Server

2012-10-05


這是模擬跟ASP.net 時代一樣的檔案上傳方式, 跟大家分享一下..
這問題我超級常被問到的..
其實做法跟傳統都一樣... 將FileStream傳給一個ashx ,

之後透過ashx將檔案寫入在Server指令目錄中.

一.首先先製作.ashx 我們開一個方案叫做 FileUploadMemo 為Silverlight 專案..





這時候我們在預設的FileUploadMemo.Web 中加入一個upload.ashx




用來服務client 上傳檔案上來...

其中他預設的Code 我們把他改成這樣…
說明我寫在註解之中…
using System;
using System.IO;
using System.Web;

namespace FileUploadMemo.Web
{

    public class upload : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            try
            {
                //取得副檔名
                string fileextname = context.Request.QueryString["ext"].ToString();
                //製作一個新的檔名
                string newFilename = Guid.NewGuid().ToString().Replace("-", "");

                //儲存路徑
                DirectoryInfo FileDir = new DirectoryInfo(System.AppDomain.CurrentDomain.BaseDirectory.ToString() + "source\\");

                //如果檔案夾沒有建立則自行建立
                if (FileDir.Exists == false)
                {
                    FileDir.Create();
                }
                using (FileStream fs = File.Create((System.AppDomain.CurrentDomain.BaseDirectory.ToString() + "source\\" + newFilename + fileextname)))
                {
                    SaveFile(context.Request.InputStream, fs);
                }

            }
            catch (Exception ex)
            {

            }
        }

        //將收到的stream 寫入檔案
        private void SaveFile(Stream stream, FileStream fs)
        {
            try
            {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    fs.Write(buffer, 0, bytesRead);
                }
            }
            catch (Exception ex)
            {
                //這邊可以放入錯誤的Log
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

其中值得一提的…
因為是範例 所以我設定他
1.上傳時候必須要給已知的副檔名,並且透過get方式 傳ext這參數 進來..
2.他會將檔案寫到source 檔案夾下面
3.如果要控管安全機制,可以在參數中加入token設定一組密碼,不然大家都亂上傳一些怪東西就不好了..

好了之後我們就執行一下…取得服務路徑..之後會用到…



我們就取得執行的路徑…會一片空白是正常的…

二. 接下來就是Silverlight 這一端了..



我們盡量讓程式簡單..
放一個按鈕為button1 使用者點下去之後..
就會選檔->上傳->顯示完成.

XAML Code :

<UserControl x:Class="FileUploadMemo.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">

    <Grid x:Name="LayoutRoot" Background="White">
        <Button Content="選擇檔案" Height="23" HorizontalAlignment="Left" Margin="304,110,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" FontSize="14" />
        <sdk:Label Height="28" HorizontalAlignment="Left" Margin="35,110,0,0" Name="label1" VerticalAlignment="Top" Width="243" Content="請選擇上傳檔案,選擇完後即上傳" FontSize="14" />
    </Grid>
</UserControl>

接下來我們來看C# Code
記得要先using
using System.IO;
using System.Net;

C# Code (註解裡面有說明):
        private void button1_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Multiselect = false;
            //這邊可以設定過副檔名過濾器
            dlg.Filter = "jpeg檔 (*.jpg)|*.jpg";

            bool? retval = dlg.ShowDialog();
            if (retval != null && retval == true)
            {
                UploadFile(dlg.File.Name, dlg.File.OpenRead());

            }
        }


        //上傳檔案
        private void UploadFile(string fileName, Stream data)
        {
          
            //下面敘述網址必須輸入服務的ashx 網址
            UriBuilder ub = new UriBuilder("http://localhost:1209/upload.ashx");
            //取得並將副檔名取出傳送
            ub.Query = string.Format("ext={0}", Path.GetExtension(fileName));
            WebClient c = new WebClient();
            c.OpenWriteCompleted += (sender, e) =>
            {
                PushData(data, e.Result);
                e.Result.Close();
                data.Close();
                MessageBox.Show("上傳完畢");
            };
            c.OpenWriteAsync(ub.Uri);
        }
        private void PushData(Stream input, Stream output)
        {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = input.Read(buffer, 0, buffer.Length)) != 0)
            {
                output.Write(buffer, 0, bytesRead);
            }
        }
這樣就大功告成了…

請注意上傳後 … 因為source 是程式建立出來的..
所以Visual Studio 會熊熊看不到…
要記得打開顯示全部檔案..




打開上傳檔案後…



完成…

請注意:
這邊是把案例簡化到很簡單,其實關於IO存取,很多小細節需要注意..
像是 權限控管,檔案位置規劃,重複寫檔問題,上傳進度等候時間,檔案大小限制。

這都是需要注意的,這不是本文重點,所以這些都是需要注意的 ..^^

讚一下:


檔案下載:


當麻許的超技八 2014 | Donma Hsu Design.