2020年3月26日 星期四

ASP.NET Core - FileUpload 檔案上傳 + NPOI

ASP.NET Core  3.1 — FileUpload 檔案上傳 + NPOI

我把以前NPOI的範例改成 .NET Core版,但在檔案上傳(FileUpload)上遇見一點問題。
ASP.NET Core .31 - FileUpload 檔案上傳跟 .NET完整版(MVC 5)有點不同
改用 IFormFile來做,但大同小異。

原廠文件就很清楚了,請看 https://docs.microsoft.com/zh-tw/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1


上傳 + NPOI讀取 Excel檔

這個範例從 Web Form => MVC 5 => ASP.NET core寫法都差不多。

如果您要用 LinqToExcel,可以把 Excel的 "工作表"當成 DB資料表 那樣讀取,也很簡便。



== 檢視畫面 ==

為了支援檔案上傳,HTML 表單必須指定 multipart/form-data的編碼類型(enctype)。
若要支援上傳多個檔案的 files input 元素,請在 < input > 元素上提供 multiple 屬性。
這些寫法我盡量跟 MVC 5類似,初學者就不會覺得差異太大
   
    @using (Html.BeginForm("Create", "NPOI", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {

               
                這裡需要手動改成 "檔案上傳"的表單元件 type="file"
                <  input type="file" id="FileUpload_FileName" name="FileUpload_FileName" />
                @*     若要支援上傳多個檔案的 files input 元素,請在 < input > 元素上提供 multiple 屬性         *@
               

                <  input type="submit" value="Create(檔案上傳 與 NPOI)" class="btn btn-default" />



                < h3 > @ViewBag.Message < /h3 >

    }


== 控制器 ==

(命名空間)
using System.IO;    //-- FileStream會用到這個命名空間
using System.Text;
using Microsoft.AspNetCore.Http;  //檔案上傳 IFormFile 會用到
// NPOI 2.0的命名空間 --   HSSF(Excel 2003), XSSF(Excel 2007), XWPF(Word 2007)。
using NPOI.XSSF.UserModel;   //-- XSSF 用來產生Excel 2007檔案(.xlsx)
using NPOI.SS.UserModel;    //-- v.1.2.4起 新增的。


        //=========================================
        //== 檔案上傳 與 NPOI -- 對應 Web Form的範例 -- NPOI_20_04_FileUpload.aspx
        //  https://docs.microsoft.com/zh-tw/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1
        //=========================================

        public IActionResult Create()   // 基本款
        {   // 檢視畫面,為了「檔案上傳」,有些地方要自己動手修改。請看上面的「檢視畫面」。
            return View();
        }
        [HttpPost]
        public IActionResult Create(IFormFile FileUpload_FileName)   // 多檔上傳,請用 List
        {   //                                    **************
            try
            {             
                if (FileUpload_FileName.Length > 0)   // 檢查  是否 上傳檔案?
                {
                    XSSFWorkbook workbook;   // NPOI。透過 NuGet安裝,必須裝 DotNETCore專屬的NPOI版本。
                    using (var ms = new MemoryStream())
                    {
                         FileUpload_FileName.CopyTo(ms);
                        //if (ms.Length < 2097152)
                        //{   // 限制上傳檔案必須小於2MB。 https://docs.microsoft.com/zh-tw/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1

                       
                        //}
                        //*** 方法二 ***   上傳檔案,不用存檔。直接讓NOPI 讀取檔案內容(Stream串流)
                        Stream stream = new MemoryStream(ms.ToArray()); 
                     
                        workbook = new XSSFWorkbook(stream);   // 將剛剛的Excel (Stream)讀取到工作表裡面
                        //== XSSFWorkbook() 只能讀取 System.IO.Stream

                    }
                    // 讀取 Excel裡面的工作表(跟以前 MVC 5完全相同)
                    #region
                    XSSFSheet u_sheet = (XSSFSheet)workbook.GetSheetAt(0);  // 0表示:第一個 worksheet工作表
                        StringBuilder SB = new StringBuilder();   // System.Text命名空間
                        XSSFRow headerRow = (XSSFRow)u_sheet.GetRow(0);  //-- Excel 表頭列    
                        // 表頭列,共有幾個 "欄位"?(取得最後一欄的數字)

                        for (int k = headerRow.FirstCellNum; k < headerRow.LastCellNum; k++)
                        {   // 把上傳的 Excel「表頭列」,每一欄位抓到
                            if (headerRow.GetCell(k) != null)   {
                                SB.Append(headerRow.GetCell(k).StringCellValue + "   ");
                            }
                        }
                        // for迴圈的「啟始值」要加一,表示不包含 Excel表頭列
                        for (int i = (u_sheet.FirstRowNum + 1); i <= u_sheet.LastRowNum; i++)
                        {   // 每一列做迴圈
                            XSSFRow row = (XSSFRow)u_sheet.GetRow(i);  //不包含 Excel表頭列的 "其他資料列"
                            for (int j = row.FirstCellNum; j < row.LastCellNum; j++)
                            {  //-- 每一個欄位(行)做迴圈
                                if (row.GetCell(j) != null)   {
                                    SB.Append(row.GetCell(j).ToString() + "   ");  //每一個欄位
                                }
                            }
                            ViewBag.Message = "上傳成功。" + SB.ToString();
                        #endregion
                    }
                }
            }
            catch   {
                ViewBag.Message = "上傳失敗。File upload failed!!";
            }
            return View();
        }

[學員感言] mis2000lab課程評價 - ASP.NET MVC , WebForm

https://www.dotblogs.com.tw/mis2000lab/2023/01/30/mis2000lab_MVC_onlineLearning2023

[ASP.NET Core MVC]第一天 免費課程 3小時完整試聽

https://www.dotblogs.com.tw/mis2000lab/2023/01/30/AspNetCore_MVC_First_Day_Free_20230130

從最早的 75小時MVC課程,目前已經延伸到 115小時,也包含了 .NET Core

.NET Core 6 MVC線上教學 - MIS2000Lab 課程大綱 與 試聽

https://dotblogs.com.tw/mis2000lab/2021/07/18/NET_MVC_Online_Free_Learning_mis2000lab 

購買完整MVC課程(一百小時),限時六折優惠並免費加贈兩萬元「.NET Core升級課程」,請直接來信洽詢

(太便宜!太划算,不能公開) mis2000lab (at) yahoo.com.tw ; school (at) mis2000lab.net



2020年2月5日 星期三

ASP.NET Core - (DB-First) Scaffold-DbContext的錯誤訊息

在MVC課程中,有一段補充教材
把原本 ASP.NET MVC 5的範例,改用 ASP.NET Core專案來做,基本上大同小異。
唯獨 DB-First「資料庫連結(DB Connection)」的地方,需要自己下指令。

當初錄影時,是VS 2019 +.NET Core 2.x版
但我把範例重新在 .NET Core 3.1重做一次,都是正常的。請放心。

有位學員發生了錯誤,

(1)  Scaffold-DbContext : 無法辨識 'Scaffold-DbContext' 詞彙是否為 Cmdlet、函數、指令檔或可執行程式的名稱。請檢查名稱拼字是否正確,如果包含路徑的話,請確認路徑是否正確,然後再試一次。
位於 線路:1 字元:1
+ Scaffold-DbContext 'Data Source=.\SqlExpress;Initial Catalog=xxxxxxx ...
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Scaffold-DbContext:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException



解決方法:

在VS 2019新增一個 ASP.NET Core 2.x 或 3.1專案後
務必先透過NuGet安裝兩個套件
-- 「Microsoft.EntityFrameworkCore.Tools」套件
-- 「Microsoft.EntityFrameworkCore.SqlServer」套件  註解:因為我用MS SQL Server來搭配

(課程中有講,如果您發生錯誤,可以先檢查一下,是不是自己漏了哪些步驟?     影片重播、回頭自己看一下,比對一下)




(2) Visual Studio 上方的功能列   「工具」 =>「Nuget套件管理器」=>「套件管理器主控台」
輸入指令  Scaffold-DbContext 'Server=.\sqlexpress;Database=xxxx' Microsoft.EntityFrameworkCore.SqlServer
出現這樣的錯誤:
A connection was successfully established with the server, but then an error occurred during the login process. (provider: Shared Memory Provider, error: 0 - 管道的另一端上無任何處理程序。)
與伺服器的連接已成功建立,但在登入程序時發生錯誤。 (provider: 共用記憶提供者, error: 0 - 管道的另一端上無任何處理程序。)

解決方法:

我上課使用的指令是
Scaffold-DbContext 'Server=.\sqlexpress;Database=資料庫名稱;Trusted_Connection=True;MultipleActiveResultSets=true' Microsoft.EntityFrameworkCore.SqlServer

(課程中有講,如果您發生錯誤,可以先檢查一下,是不是自己漏了哪些步驟?     影片重播、回頭自己看一下,比對一下)

之前上課介紹的微軟文件,現在找不到了(可能改版或是刪除)
所以他找到類似的網頁,照著做,卻發生錯誤  https://docs.microsoft.com/zh-tw/ef/core/managing-schemas/scaffolding

我也找不到當初的官方文件了,比較類似的是這個網頁介紹 Code-First,請參閱 https://docs.microsoft.com/zh-tw/aspnet/core/data/ef-mvc/intro?view=aspnetcore-3.1



[學員感言] mis2000lab課程評價 - ASP.NET MVC , WebForm

https://www.dotblogs.com.tw/mis2000lab/2023/01/30/mis2000lab_MVC_onlineLearning2023

[ASP.NET Core MVC]第一天 免費課程 3小時完整試聽

https://www.dotblogs.com.tw/mis2000lab/2023/01/30/AspNetCore_MVC_First_Day_Free_20230130

從最早的 75小時MVC課程,目前已經延伸到 115小時,也包含了 .NET Core

.NET Core 6 MVC線上教學 - MIS2000Lab 課程大綱 與 試聽

https://dotblogs.com.tw/mis2000lab/2021/07/18/NET_MVC_Online_Free_Learning_mis2000lab 

購買完整MVC課程(一百小時),限時六折優惠並免費加贈兩萬元「.NET Core升級課程」,請直接來信洽詢

(太便宜!太划算,不能公開) mis2000lab (at) yahoo.com.tw ; school (at) mis2000lab.net

2020年2月4日 星期二

[會員登入] 不使用ASP.NET Core Identity 的 Cookie 驗證 (ClaimsIdentity)

ASP.NET Core 3.1與 2.x 搭配 System.Security.Claims 命名空間的 ClaimsIdentity來做

輕鬆簡單,很快就能上手。Forms Authentication with cookie


使用沒有 ASP.NET Core 身分識別的 cookie 驗證(不使用ASP.NET Core Identity的 cookie 驗證)


ASP.NET Core 3.1與 2.x ,搭配 System.Security.Claims 命名空間 的 ClaimsIdentity來做

我建議先閱讀這一篇文章,簡短有力,淺顯易懂。完成以後,再來看微軟官方說明。

(2018/8/2)  Forms Authentication in .NET Core (AKA Cookie Authentication)
http://www.nogginbox.co.uk/blog/forms-authentication-in-net-core-aka-cookie-authentication

或是參考我錄好的教學影片 - https://youtu.be/eRa-hdsDfB4

微軟的文件(中文) .NET Core 2.1與 3.1差異不大。

但 3.1版的範例採用 Razor Page來示範。
https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/security/authentication/cookie/samples/3.x/CookieSample

每一個檢視畫面(網頁)跟以前WebForm(.aspx)一樣,分成兩個檔案(.cshtml 與 .cshtml.cs)。

我覺得比較不好懂。所以建議參閱 .NET Core 2.1的範例。
https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/security/authentication/cookie/samples/2.x/CookieSample

** 步驟如下 **

第一,打開一個 ASP.NET Core 的 MVC專案

第二,透過 Nuget安裝「Microsoft.AspNetCore.Authentication.Cookies


第三,Startup.cs裡面有些設定:
請參閱  https://github.com/aspnet/AspNetCore.Docs/blob/master/aspnetcore/security/authentication/cookie/samples/3.x/CookieSample/Startup.cs

(3-1) ConfigureServices這個區域,請加入這兩段
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
           .AddCookie();

         

(3-2) Configure這個區域,請加入這兩段
            app.UseAuthentication();   // 這一句話需要手動加入,後面幾句是原本就有的
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                // endpoints.MapRazorPages();   // 如果您不使用 RazorPage來做,這一句可以註解掉、不用
            });




第四,HomeController控制器,您需要加入這些命名空間

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using System.Security.Claims;    // Claims會用到
using Microsoft.AspNetCore.Authorization;  


(4-1) Login登入,輸入帳號、密碼。
        public IActionResult Login()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken] 
        public ActionResult Login(db_user _User)
        {
            if (ModelState.IsValid)
            {   // 入門版,先不連結DB,固定帳號密碼來做(微軟範例也是這樣)
                //
線上課程 裡會有連結資料庫,比對帳號與密碼的教材。  初學者不要急,一步一步學習。
                if (_User.UserName != "123" && _User.UserPassword != "123")
                {
                    ViewData["ErrorMessage"] = "帳號與密碼有錯";
                    return View();
                }
                #region ***** 不使用ASP.NET Core Identity的 cookie 驗證 *****
                var claims = new List   // 搭配 System.Security.Claims; 命名空間
                {
                    new Claim(ClaimTypes.Name, _User.UserName),
                    // new Claim(ClaimTypes.Role, "Administrator"),
                    // 如果要有「群組、角色、權限」,可以加入這一段

                };

                // 底下的 ** 登入 Login ** 需要下面兩個參數 (1) claimsIdentity  (2) authProperties
                var claimsIdentity = new ClaimsIdentity(
                                           claims, CookieAuthenticationDefaults.AuthenticationScheme);
                var authProperties = new AuthenticationProperties
                {
                    //AllowRefresh = ,
                    // Refreshing the authentication session should be allowed.

                    //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10), 
                    // The time at which the authentication ticket expires. A
                    // value set here overrides the ExpireTimeSpan option of
                    // CookieAuthenticationOptions set with AddCookie.

                    //IsPersistent = true,
                    // Whether the authentication session is persisted across
                    // multiple requests. When used with cookies, controls
                    // whether the cookie's lifetime is absolute (matching the
                    // lifetime of the authentication ticket) or session-based.

                    //IssuedUtc = ,
                    // The time at which the authentication ticket was issued.

                    //RedirectUri =
                    // The full path or absolute URI to be used as an http redirect response value.

                };
                // *** 登入 Login *********
                HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
                                                        new ClaimsPrincipal(claimsIdentity),
                                                        authProperties);
                #endregion
                return Content("

恭喜您,登入成功

");
            }
            // Something failed. Redisplay the form.
            return View();
        }

(4-2) LogOut 登出。微軟範例以非同步(異步)的寫法來做 -- Async. Await
可以參閱這一則影片  https://youtu.be/8vcrjhaF1zE   ( [ASP.NET].NET 4.5 非同步程式,從一張圖知道原來如此 (async & await) )
        public async Task Logout()
        {
            // 自己宣告 Microsoft.AspNetCore.Authentication.Cookies; 命名空間
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            return View();  // 回 首頁。 return RedirectToAction("Index", "Home");
        }


** 範例下載 **

    我整理了一份 "PDF檔" 當作說明,也分享了這個範例

    專案名為 WebApplication2019_MVC_Core_LoginCookie

    這個範例為了搭配我的MVC課程,所以經過修改。
    已經購買 ASP.NET MVC 5線上教學的朋友,可以發現跟原本範例的差異不大
    主要是上述(第四部分)的修改而已。

請由此下載  https://onedrive.live.com/?id=6F7F668080F24B20%212586&cid=6F7F668080F24B20

***************************************************

[學員感言] mis2000lab課程評價 - ASP.NET MVC , WebForm

https://www.dotblogs.com.tw/mis2000lab/2023/01/30/mis2000lab_MVC_onlineLearning2023

[ASP.NET Core MVC]第一天 免費課程 3小時完整試聽

https://www.dotblogs.com.tw/mis2000lab/2023/01/30/AspNetCore_MVC_First_Day_Free_20230130

從最早的 75小時MVC課程,目前已經延伸到 115小時,也包含了 .NET Core

.NET Core 6 MVC線上教學 - MIS2000Lab 課程大綱 與 試聽

https://dotblogs.com.tw/mis2000lab/2021/07/18/NET_MVC_Online_Free_Learning_mis2000lab 

購買完整MVC課程(一百小時),限時六折優惠並免費加贈兩萬元「.NET Core升級課程」,請直接來信洽詢

(太便宜!太划算,不能公開) mis2000lab (at) yahoo.com.tw ; school (at) mis2000lab.net


2019年10月22日 星期二

[範例下載 & 團購] ASP.NET專題實務 / 博碩出版

ASP.NET專題實務,上下兩集,書本範例下載


上集 - ASP.NET專題實務 (I) / 博碩出版

https://onedrive.live.com/?id=6F7F668080F24B20%212411&cid=6F7F668080F24B20

      ( 資料庫的範例:   https://onedrive.live.com/?id=6F7F668080F24B20%21200&cid=6F7F668080F24B20 )

      ( 教學影片 https://youtu.be/hAYzo53KUKM )

下集 - ASP.NET專題實務 (II)  / 博碩出版

https://onedrive.live.com/?id=6F7F668080F24B20%211731&cid=6F7F668080F24B20

ASP.NET專題實務 / 博碩出版 上下兩集的範例,由此下載

含郵資(郵局便利箱),全台最便宜,只有二十套!
作者提供的優惠團購價 1,280元(含郵資)。應該是全台灣最便宜吧!因為是我拿錢補貼各位了
僅限二十套!   上班時間,立即出貨!

另外跟您報告一個好消息:
參加這次團購的好朋友,在 2020/6/30 以前,繳費報名我的課程 (不管是實體班上課或是遠距教學)
  • ASP.NET (Web Form) 遠距教學、課程完整內容 影片上網! 
  • 歡迎在家自修、學習     *** 本課程是「事先錄影」的影片。繳費後就能觀賞!*** 

  一律折價「三千」學費!(以姓名、手機、E-Mail,作為識別,需跟本次團購為同一人)
      一律折價「三千」學費!各種優惠 "不"共用!只能任選一種
            一律折價「三千」學費!

參加本次團購      務必填寫報名表,來信報名 。我會回信通知下列資訊:
      若非以下資料,皆屬詐騙,請小心!
      我的「銀行帳號」--     台北富邦銀行(012),帳號後六碼是xxx-xxx-388-785
    (怕有詐騙集團出面劫標,我先公佈一部份。請大家留意!)

  請來信  mis2000lab (at) yahoo.com.tw  或是 school (at) mis2000lab.net

== 天瓏書局 ==
== 博客來 ==
== PChome 24h ==
我將思想傳授他人, 他人之所得,亦無損於我之所有;
猶如一人以我的燭火點燭,光亮與他同在,我卻不因此身處黑暗。 — — Thomas Jefferson




寫信給我,不要私訊 — mis2000lab (at) yahoo.com.台灣 或 school (at) mis2000lab.net
…. YouTube (ASP.NET) 線上教學影片 http://goo.gl/rGLocQ
*************************************************
************************(歡迎索取,免費申請)*****

2019年10月15日 星期二

ASP.NET -IIS與檔案上傳的安全設定

ASP.NET專題實務(I),博碩出版
** IIS 與 檔案上傳 (FileUPload)的安全設定 **
18–13–1 要求篩選(Request Filtering)
新版本IIS都提供了「要求篩選(Request Filtering)」的功能。但需要您手動安裝、增加這功能到IIS裡面。您的作業系統必須具備IIS才能安裝,例如Win10專業版或Windows Server。
18–13–2 限制執行
檔案上傳也可能是網站的一個大漏洞,如果有人把病毒或是木馬程式上傳並執行,那就糟了。有三個建議:
第一,除了前面說過最基本的「副檔名」檢驗以外,建議您也限制上傳目錄的權限,讓它只能讀寫卻無法執行。
第二,以下圖為例,針對「網站底下的子目錄」做設定,例如4_BigControl_Manual這個資料夾是用來存放上傳檔案的。千萬不允許它有「執行」的權限,以免有人上傳木馬程式或病毒後去執行它。當然,做了IIS任何設定以後,您最好重新測試一遍,以免影響到其他功能。
第三,Web Server也得安裝防毒軟體。如果真的被上傳病毒或是木馬程式,也能被檢查出來。大部分的防毒軟體,當對方上傳以後,通常會有即時掃描的功能。但仍建議每天在離峰時段進行全機掃描
在IIS 7.x版(Windows Server 2008)起有另一個設定「處理常式對應(Handle Mapping)」(如下圖,畫面上不太好找)。
針對「網站底下的子目錄」做設定,例如4_BigControl_Manual這個資料夾是用來存放上傳檔案的。千萬不允許它有「指令碼」\「執行」的權限,務必留白(如下圖,不打勾)。做了IIS任何設定以後,建議重新啟動網站服務並重新測試一遍,以免影響到其他功能。
以上來自 — ASP.NET 專題實務 (I) / 博碩出版

2019年9月19日 星期四

ASP.NET (WebForm) 防範 CSRF攻擊

ASP.NET (WebForm) 防範 CSRF攻擊
關鍵字  AntiForgery Token / cross-site request forgery (CSRF攻擊) 

從 NuGet安裝「Microsoft.AspNet.WebPages」套件
使用AntiForgery.GetHtml() 來生成一個隱藏的token
下面的影片,是寫在 Page_Init事件中。

https://youtu.be/-DswQCwVqxk 


相關文章 --  ASP.NET WebForm中異步請求防止XSRF攻擊的方法

https://read01.com/zh-tw/D5kj44.html

其他作法 -- 採用  System.Web.Helpers