iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 28
0
Modern Web

ASP.NET Web Form 入門30天系列 第 28

[ASP.NET] 新增泛型處理常式(.ashx)及瀏覽上傳圖片的範例

本篇擷取重點:

  1. 泛型處理常式(.ashx)及ASPX在使用上的粗略比較
  2. 如何新增泛型處理常式
  3. 瀏覽上傳圖片的範例

這篇"無法"要告訴大家,泛型處理常式(.ashx)是什麼或是關於他的底層學理,因為我也還看不懂嗚嗚嗚嗚,只能提供一個使用範例及大概使用的方向,讓大家也許在需要用時能夠暫時應急應急,但正確觀念的確立及其底層學理的意義,就需要讀者再去翻翻書或看其他大大的文章。


一、泛型處理常式(.ashx)及ASPX在使用上的粗略比較

泛型處理常式(.ashx)與ASPX皆可當作httphandler来使用,他們在使用上的差異在於:

  • ASPX除實現了IHttpHandler接口,還繼承了System.Web.UI.Page,也就是說ASPX還多了要負責前端頁面處理的過程
  • 而(.ashx)可以讓我們單純專注於程式編程的部分

使用條件上,ASPX較強調使用者及後端之間的互動性而(.ashx)則多用來處理無須顯示頁面且無須持續來回處理互動的部分,例如同一頁面中進行動態的圖片展示或連接資料庫比對帳號是否重複...等。

也有人說,「(.ashx)就是沒有畫面的ASPX」,例如,檔案下載服務,透過傳遞參數給.ashx,來決定要下載那一個檔案,這個下載的動作是不需UI畫面的。又或者,提供給AJAX上傳檔案用.ashx,因為AJAX來上傳檔案,接收端的.ashx是不需要UI畫面。

參考資料:
https://blog.csdn.net/thinker28754/article/details/4552040
https://blog.kkbruce.net/2013/12/.ashx-vs-aspnet-web-api.html#.XZBeTEYzZEY


二、如何新增泛型處理常式

檔案總管 - 專案 - 滑鼠右鍵 - 加入 - 新增項目

https://ithelp.ithome.com.tw/upload/images/20190929/20120056aqpA7nDKx6.png

選擇泛型處理常式 - 命名 - 確定

https://ithelp.ithome.com.tw/upload/images/20190929/20120056Zar8UvU7EO.png

預設內容

https://ithelp.ithome.com.tw/upload/images/20190929/20120056fJqkq4RnYX.jpg


三、瀏覽上傳圖片的範例

在設計頁面(.aspx)拖引出所需的工具箱控制項,

  • FileUpload 上傳檔案用
  • Button 確認用
  • Label 提示用
  • Image 預覽用

<form id="form1" runat="server">
    <div>
        <asp:FileUpload runat="server" ID="FileUpload1" />
        <asp:Button Text="Click" ID="Button1" UseSubmitBehavior="false" runat="server" OnClick="Button_Click" />
        <asp:Label ID="Message" runat="server" Text=""></asp:Label>
        <br />
        <asp:Image runat="server" ID="Image1" />
    </div>
</form>

後置程式碼部分(.aspx.cs)分為兩部分,

  • 存入session,並設定Image控制項的圖片來源,來自Handler1.ashx網址(API)
  • 將上傳的檔案進行確認並下載至伺服器中

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack)
    {

    }
}
protected void Button_Click(object sender, EventArgs e)
{
    // 存入session
    if (FileUpload1.PostedFile != null)
    {                 
        HttpPostedFile myFile = FileUpload1.PostedFile;
        Session["myFile"] = myFile;
        // Set ImageUrl
        Image1.ImageUrl = "Handler1.ashx";
    }
    //存入伺服器中
    string fileName;
    if (FileUpload1.HasFile)
    {
        if (FileUpload1.PostedFile.ContentType.IndexOf("image") == -1)
        {
            Message.Text = "檔案型態錯誤!";
            return;
        }
        //取得副檔名
        string Extension = FileUpload1.FileName.Split('.')[FileUpload1.FileName.Split('.').Length - 1];
        //新檔案名稱
        fileName = String.Format("{0:yyyyMMddhhmmsss}.{1}", DateTime.Now, Extension);
        //上傳目錄為/Images/
        FileUpload1.SaveAs(Server.MapPath(String.Format("~/images/{0}", fileName)));
        //
    }
    else
    {
        Message.Text = "沒有上傳檔案";
        return;
    }
}

在(.ashx)中,使用session有兩個重點:

  • 須於上方引用 using System.Web.SessionState;
  • HttpHandler 的類別一定要繼承 System.Web.SessionState.IRequiresSessionState 介面(讓 context.Session 可讀可寫)或 System.Web.SessionState.IReadOnlySessionState 介面(讓 context.Session 唯讀)

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.SessionState; //因為有使用到session,故須引用

namespace ShareTwo
{
    /// <summary>
    /// Handler1 的摘要描述
    /// </summary>
    public class Handler1 : IHttpHandler, IRequiresSessionState //因為有使用到session
    {

        public void ProcessRequest(HttpContext context)
        {
            if (context.Session["myFile"] != null)
            {
                HttpPostedFile myFile = (HttpPostedFile)context.Session["myFile"];
                int myFile_Length = myFile.ContentLength;
                //設定緩衝區大小
                byte[] myData = new byte[myFile_Length];
                //myFile檔案的內容讀取到位元組陣列
                myFile.InputStream.Read(myData, 0, myFile_Length);
                context.Response.Clear();
                //告訴瀏覽器檔案為image/jpeg的MIME類型
                context.Response.ContentType = "image/jpeg";
                //將二進位字元的字串寫入 HTTP 輸出資料流
                context.Response.BinaryWrite(myData);
            }
        }

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

顯示頁面的上傳圖檔預覽

https://ithelp.ithome.com.tw/upload/images/20190929/20120056Qf5TRUEbpU.jpg

參考資料:
https://blog.miniasp.com/post/2008/03/09/Using-contextSession-object-in-HttpHandler
https://dotblogs.com.tw/mis2000lab/archive/2013/08/20/ashx_beginner_02_fileupload_picture_preview.aspx


此篇內容整理自多篇網路文章、PPT及自己的理解,但筆者也仍處在初階的學習過程,對程式概念的理解及判斷都尚不足,若有錯誤的地方,也煩請各位大大提點,先謝謝大家惹!!


上一篇
[ASP.NET] 工具箱常用的伺服器控制項 - CheckBox (全選的JS?)
下一篇
[ASP.NET] Master Pages 主版頁面 (上)
系列文
ASP.NET Web Form 入門30天30

1 則留言

1
小朱
iT邦新手 4 級 ‧ 2019-09-29 20:33:27

ashx不難懂,因為System.Web.UI.Page類別本身就是一個很大號的ashx (HTTP Handler),只是它在web.config中被設定對應.aspx由它來處理而己,這也就是說HTTP Handler可以改掉原本的副檔名 (只要在web.config登錄),而IIS/aspnet_wp.exe會將要求導向到指定的HTTP Handler,這時程式就可以接手處理,可得到完整的要求內容,並且要自己輸出回應的資料 (aspx是回應HTML),也就是說即便是ashx一樣可以產生畫面,只要自己組出必要的HTML的話。

ashx所要賦與的是程式開發上的彈性,而且不用受到Web Form Page Lifecycle那麼多的動作影響,輸出又可以自己決定,速度也會比aspx要快 (因為沒有走Page Lifecycle),但缺點 (也是優點) 就是所有的輸出,包含類型 (ContentType) 以及內容 (Content) 都要自己處理輸出,這樣更看出程式員對.NET Framework的熟悉度了。

PS: 文中的範例實務上一般不會這樣做,因為將檔案放在Session是很耗記憶體的作法,實務上的作法多半是寫入一個暫存檔,ashx再去讀這個暫存檔,這樣就只會耗磁碟空間,磁碟的價格比記憶體便宜太多了。

好的,謝謝朱大的詳細講解,我再研究一下暫存檔,我好像還沒碰過XDDD

我要留言

立即登入留言