瀏覽標籤:

ASP.NET MVC

[轉載] 系統架構設計

來源:[鐵人30天]當ASP.NET MVC 遇見 Angular.js MVC 客戶管理系統(3) – 系統架構設計

* 為何要分層架構規劃

分層的重要性,也是寫程式幾年後才真的領悟,ASP時代那種義大利麵式的寫法(html、Script、後端程式、SQL程式全混再一起),接著WebForm CodeBind將前後端拆後,再到現在慣用的MVC,深深覺得”關注點分離”這的確是一件很重要的事,目前開發習慣,即使專案在小,也會整理出自己的三層架構起手式,如果是更大型專案,就會再更細分。

架構圖:

_thumb3

各分層介紹:

  • DAL(Data Access Layer) : 有關SQL語法、EntityFream資料庫溝通,都會在此層。
  • BLL(Business Login Layer):資料流從DB或從User輸入後,一定會有一些邏輯判斷,該商業邏輯流程都會寫在此層
  • UI(User Interface):有關Web專案、Web API(Web Service)、Apps 都會在此層
  • Domain Entity : 裡面會有定義ViewModel Class,用來貫穿三個分層
  • Resources:用來放一些資源檔 … e.g 多國語系檔
  • Utility : 用來放置一些共用函示庫 … 如加解密

整個專案建立完如下圖:

1_thumb4

       

[C#][ASP.NET MVC5] 繼承 ValidationAttribute 簡單實作表單欄位驗證

有用過MVC的人一定都知道只要在Model上面加標籤[Required],即可達到前後端驗證欄位必填的效果,無聊研究了一下來簡單實作自定義的表單欄位驗證 !!

 

  1. 首先建立一個類別,繼承ValidationAttribute,宣告m_BaseText變數來儲存預設禁止的文字,而m_Text則是用來儲存禁止其他文字用的變數。
    public class ExampleAttribute : ValidationAttribute
    {
    	private string[] m_Text;
    	private string[] m_BaseText = new string[] { @"\", @"/", @"<", @">" };
    }
  2. 接下來利用多載宣告兩個建構子,一個是不帶參數的,另一則是型別為string[]Text變數,並放到剛剛宣告的m_Text裡面。
    public ExampleAttribute()
    {
    	m_Text = new string[] { };
    }
    
    public ExampleAttribute(string[] Text)
    {
    	this.m_Text = Text;
    }
  3. 接下來把IsValid方法override掉,並實作驗證機制。
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
    	string strValue = (string)value;
    	string[] strBaseError = m_BaseText.Where(x => strValue.Contains(x)).ToArray();
    	string[] strCustomError = m_Text.Where(x => strValue.Contains(x)).ToArray();
    
    	if (strBaseError.Count() == 0 && strCustomError.Count() == 0)
    	{
    		return ValidationResult.Success;
    	}
    	else
    	{
    		List<string> temp = new List<string>();
    		temp.AddRange(m_BaseText.ToList());
    		temp.AddRange(m_Text.ToList());
    		string errorMsg = $"禁止輸入 [{string.Join(", ", temp.ToArray())}] !!";
    		return new ValidationResult(errorMsg);
    	}
    }
    
  4. 完成 !!
    2016-09-26-23_22_37-example-%e6%88%91%e7%9a%84-asp-net-%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f

    2016-09-26-23_29_45-example-%e6%88%91%e7%9a%84-asp-net-%e6%87%89%e7%94%a8%e7%a8%8b%e5%bc%8f

原始碼:https://github.com/shuangrain/WebApplication_CustomAttribute

       

[C#][ASP.NET MVC5] 繼承 AuthorizeAttribute 來實作自訂驗證

有時候會需要頁面會需要依照使用者權限的不同,可以進入的頁面也不同,在MVC裡面有預設Role與User的方式來篩選使用者,不過有時候權限分細一點時就沒辦法應付了,這個時候就需要自訂驗證了。

 

權限表單的結構資料如下:

01

  1. 先在登入成功的地方放入一段程式,來把使用者有權限進入的頁面以字串的方式存入Session
    using (var db = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
    
    {
    	String account = HttpContext.User.Identity.Name.ToString();
    	var list = db.Query<int>(@"
    SELECT 
    [a].[List_Id]
    FROM [dbo].[Permissions] AS [a]
    WHERE [a].[User_Id] = 
    (	SELECT [Id]
    FROm [dbo].[AspNetUsers] AS [z]
    WHERE [z].Email = @Email)", new { Email = model.Email }).ToList<int>();
    
    	Session["Permissions"] = string.Join(",", list.ToArray());
    }

     

  2. 再來新建一個檔案名為CustomAuthorize.cs,程式碼如下:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    namespace WebApplication_CustomVerification.Verification
    {
        public class CustomAuthorize : AuthorizeAttribute
        {
            public int ListId { get; set; }
    
            protected override bool AuthorizeCore(HttpContextBase httpContext)
            {
                if (httpContext == null)
                {
                    throw new ArgumentNullException("httpContext");
                }
    
                //判斷是否已驗證
                if (httpContext.User.Identity.IsAuthenticated == false)
                {
                    return false;
                }
    
                bool boolIsRight = false;
    
                //Session過期,要求重新登入
                HttpSessionStateBase session = httpContext.Session;
                if (session.Count != 0 &&
                    session["Permissions"] != null &&
                    session["Permissions"].ToString() != "")
                {
                    List<string> list = session["Permissions"].ToString().Split(',').ToList();
                    foreach (var item in list)
                    {
                        if (item == ListId.ToString())
                        {
                            boolIsRight = true;
                            break;
                        }
                    }
                }
    
                return boolIsRight;
            }
        }
    }

    這邊覆寫了原本驗證的機制,改成判斷先前存入Session內的字串。

  3. 這樣就可以在Action上面加上標籤來驗證使用者權限囉!
    using System.Web.Mvc;
    using WebApplication_CustomVerification.Verification;
    
    namespace WebApplication_CustomVerification.Controllers
    {
        public class HomeController : Controller
        {
    
            public ActionResult Index()
            {
                return View();
            }
    
            public ActionResult About()
            {
                ViewBag.Message = "Your application description page.";
    
                return View();
            }
    
            public ActionResult Contact()
            {
                ViewBag.Message = "Your contact page.";
    
                return View();
            }
    
            [CustomAuthorize(ListId = 1111)]
            public ActionResult List_01()
            {
    
                return View();
            }
    
            [CustomAuthorize(ListId = 1112)]
            public ActionResult List_02()
            {
    
                return View();
            }
    
            [CustomAuthorize(ListId = 1113)]
            public ActionResult List_03()
            {
    
                return View();
            }
        }
    }

 

 

範例程式:https://github.com/shuangrain/WebApplication_CustomVerification

參考:[C#][ASP.NET MVC]自訂AuthorizeAttribute

       

[C#][ASP.NET MVC5] 使用 jQuery Form Plugin 與 HttpPostedFileBase 檔案上傳

先前提到過 [C#][ASP.NET MVC5] 使用 HttpPostedFileBase 檔案上傳 ,這次我要使用Ajax的方式上傳檔案,但研究了Ajax.BeginForm許久都無法上傳檔案,最後找到使用jQuery Form Plugin來實作此功能。

來源:

  1. ASP.NET MVC – 使用 jQuery Form Plugin 做檔案上傳
  2. ASP.NET MVC – 使用 jQuery Form Plugin 做檔案上傳之加點東西

 

使用NuGet安裝所需套件

  1. 安裝jQuery Form Plugin
    01
  2. 安裝Javascript Alert:toastr
    02

 

View

@{
    ViewBag.Title = "Upload";
}
<h2>Upload</h2>
<hr />
@using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <div class="form-horizontal">
        <div class="form-group">
            <label class="control-label col-sm-2">選擇檔案</label>
            <div class="col-sm-10">
                <input type="file" name="file">
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <input type="submit" value="提交" class="btn btn-primary" />
            </div>
        </div>
    </div>
}
@section css
{
    @Styles.Render("~/Content/toastr")
}
@section scripts
{
    @Scripts.Render("~/bundles/jqueryajax")
    @Scripts.Render("~/bundles/jqueryform")
    @Scripts.Render("~/bundles/toastr")
    <script>
        $("form").ajaxForm({
            iframe: true,
            dataType: "json",
            success: function (result) {
                $("form").resetForm();
                if (result.success) {
                    toastr.success(result.message, 'Success Message')
                }
                else {
                    toastr.error(result.message, 'Error Message')
                }
            },
            error: function (xhr, textStatus, errorThrown) {
                $("form").resetForm();
                toastr.error('檔案上傳錯誤.', 'Error Message')
            }
        });
    </script>
}

HTML的部分可以不用更動,無須使用Ajax.BeginForm,只需要在JavaScript的地方使用ajaxForm即可將表單轉換成Ajax模式。

Controller

[HttpPost]
public JsonResult Upload(HttpPostedFileBase file)
{
	if (file != null && file.ContentLength > 0)
	{
		var fileName = Path.GetFileName(file.FileName);
		var path = Server.MapPath("~/App_Data/FileUploads");
		//若該資料夾不存在,則新增一個
		if (!Directory.Exists(path))
		{
			Directory.CreateDirectory(path);
		}
		path = Path.Combine(path, fileName);
		file.SaveAs(path);
		return Json(new
		{
			success = true,
			message = fileName,
			ContentLenght = file.ContentLength
		}, "text/html");
	}
	else {
		return Json(new
		{
			success = false,
			message = "請上傳正確的檔案."
		}, "text/html");
	}
}

由於前端使用Ajax所以後台回傳資訊則必須從ActionResult修改成JsonResult,這樣才能強制回傳Json格式,需要注意的一點是在IE底下若無指定contentType的話則會出現問題如下圖,必須指定回傳的contentTypetext/html才能在IE底下正常接收資訊。

03

       

[C#][ASP.NET MVC5] MySQL Entity Framework 學習筆記(一) – 環境設定

剛開始在碰ASP.NET MVC的時候,查詢該如何連結資料庫時常常會聽到Entity Framework這個方法,但由於那時沒有太多時間,沒去查太多資料都用SQL自幹,現在閒下來了,就來玩玩看這個東西,首先是環境設定:

  1. NuGet安裝MySQL使用Entity Framework時所需要的套件
    01
     
  2. 總共有三個東西要安裝,分別是
    • MySql.Data
    • MySql.Data.Entity
    • MySql.Web

    01

  3. 安裝完畢後就要開始設定連結字串,打開Web.config新增連結字串
    <connectionStrings>
    	<add name="MySqlConnectionString" providerName="MySql.Data.MySqlClient" connectionString="Server=server;Database=dbname;UID=username;Password=password" />
    </connectionStrings>

    02

  4. 建立MySqlContext.cs並繼承DbContext供後續使用
    public class MySqlContext : DbContext
    {
    	public MySqlContext() : base("MySqlConnectionString") { }
    }

 

結論:

這樣環境就建置完成囉,後續就可以開始使用Entity Framework了!

 

參考:

  1. ASP.NET MVC, ENTITY FRAMEWORK CODE FIRST與MYSQL筆記
  2. Entity Framework 快速上手與學習資源整理
       

[C#][ASP.NET MVC5] FileUpload 上傳檔案大小的限制

ASP.NET為防止駭客利用大檔案進行DOS(Denial Of Service)攻擊,所以把上傳檔案大小限制在4096KB(4MB),因此當上傳檔案超過4MB時,就會收到System.Web.HttpException 超出最大的要求長度的錯誤訊息如下:

01

那如果需要上傳超過4MB的檔案怎麼辦?那就必須修改Web.configsystem.web讓該站自訂大小,修改內容如下:

<system.web>
	<httpRuntime targetFramework="4.5" maxRequestLength="102400" executionTimeout="600"/>
</system.web>
  • maxRequestLength 檔案大小(KB)
  • executionTimeout 上傳時間(秒)

修改完後雖然不會跳出上面的錯誤了,不過卻跳出另外一個訊息:
04

拜了Google才發現,原來 Windows Server 2008 (IIS 7.0) 上又多了一個 maxAllowedContentLength 屬性 (單位為 Byte),於是乎又打開了Web.config找到system.webServer,修改內容如下:

<system.webServer>
	<security>
		<requestFiltering>
			<requestLimits maxAllowedContentLength="1073741824" />
		</requestFiltering>
	</security>
</system.webServer>

其預設值為 30000000 Bytes (~28.6 MB),所以上傳 30 MB 的檔案就會產生錯誤了。這邊我是修改為1 GB (1024 x 1024 x 1024)可視情況調整。


綜合以上的修改結果為:

02

 

如果使用者上傳超過設定的最大上限怎麼辦?是不是又會跳出錯誤訊息?不要害怕,只要在Global.asax裡面處理這項錯誤即可,處理方式如下:

protected void Application_BeginRequest(object sender, EventArgs e)
{
	HttpRuntimeSection section = (HttpRuntimeSection)ConfigurationManager.GetSection("system.web/httpRuntime");
	int maxFileSize = section.MaxRequestLength * 1024;
	if (Request.ContentLength > maxFileSize)
	{
		try
		{
			Response.Redirect("~/SizeError.aspx");
		}
		catch (Exception ex)
		{
			Logger logger = LogManager.GetCurrentClassLogger();
			logger.Warn(ex.Message);
		}
	}
}

03

 

結論:

一個簡單的上傳功能,想不到有這麼多眉眉角角需要注意,做這行真是不容易QQ

 

參考:

  1. ASP.NET如何設定檔案上傳大小可超過預設4096KB(4MB)
  2. FileUpload 上傳檔案大小的限制
       

[C#][ASP.NET MVC5] 使用 HttpPostedFileBase 檔案上傳

檔案上傳功能在網頁中常常出現,在ASP.NET MVC裡面要上傳檔案非常簡單,這裡簡單筆記一下有關 ASP.NET MVC 的檔案上傳基本操作方法。

  • Controller
    [HttpPost]
    public ActionResult Upload(HttpPostedFileBase file)
    {
    	if (file != null && file.ContentLength > 0)
    	{
    		var fileName = Path.GetFileName(file.FileName);
    		var path = Server.MapPath("~/App_Data/FileUploads");
    		//若該資料夾不存在,則新增一個
    		if (!Directory.Exists(path))
    		{
    			Directory.CreateDirectory(path);
    		}
    		path = Path.Combine(path, fileName);
    		file.SaveAs(path);
    	}
    	return RedirectToAction("Upload");
    }
  • View
    @using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        <div class="form-horizontal">
            <div class="form-group">
                <label class="control-label col-sm-2">選擇檔案</label>
                <div class="col-sm-10">
                    <input type="file" name="file">
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <input type="submit" value="提交" class="btn btn-primary" />
                </div>
            </div>
        </div>
    }

    這邊要注意的是,如需要使用HttpPostedFileBase上傳檔案的話,則必須添加enctype = "multipart/form-data",不然怎麼樣都沒辦法正常收到資料!
    另外如果使用下列語法是無法接收資料的,因這樣表單並沒有含enctype = "multipart/form-data"這項

    @using (Html.BeginForm("Upload", "Home", new { enctype = "multipart/form-data" }))

    一定要用改為下面的方法

    @using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))

 

範例程式:https://github.com/shuangrain/WebApplication_Upload

       

[C#][ASP.NET MVC5] 使用Ajax.BeginForm時無法正常運作

在ASP.NET MVC裡面,表單提交方法有兩種,一種是傳統的Html.BeginForm另外一種是利用JQuery實現的Ajax.BeginForm,平常我都是使用Html.BeginForm在處理表單,最近在寫上傳檔案功能的時候想玩Ajax.BeginForm看看,於是乎發生了Ajax無法正常運作的問題,拜了Google大神很久發現了原因是Visual Studio新建專案的時候沒有幫我加入Microsoft jQuery Unobtrusive Ajax這個套件,多虧這個原因讓我撞牆撞了好久,最後裝上去才解決問題。

解決步驟如下:

  1. 對著專案點選右鍵選擇管理NuGet套件
    01
  2. 搜尋unobtrusive找到Microsoft.jQuery.Unobtrusive.Ajax選擇安裝
    02
  3. /App_Start/BundleConfig.cs裡面新增套件
    03

    bundles.Add(new ScriptBundle("~/bundles/jqueryajax").Include(
                "~/Scripts/jquery.unobtrusive-ajax*"));
  4. 在要使用的頁面加入以下語法使用
    @Scripts.Render("~/bundles/jqueryajax")