22/5/56
Action Filter with HTTP-Compression
ในการรับส่งข้อมูลโดยทั่วไปเริ่มต้นจากการเกิด HTTP Request ข้อมูลไปยัง Web Server ซึ่งถ้า Request มีขนาดใหญ่ก็จะเกิดปัญหาตามมาก็คือใช้เวลาในการทำงานนาน อีกวิธีที่ช่วยลดขนาดของ Request ก็คือ HTTP-Compression พูดง่ายๆก็คือ การบีบอัดข้อมูลให้มีขนาดเล็กลงก่อนที่จะทำการส่ง Request ไปยัง Web Servers จึงช่วยลดขนาดของ Bandwidth และเพิ่มประสิทธิภาพความเร็วในการรับ-ส่งข้อมูลระหว่าง Web Servers และ Clients ซึ่งมีรูปแบบของการ Compress 3 รูปแบบ คือ GZip , Compress , Deflate ในส่วนของการพัฒนาด้วย C# ต้อง Run ผ่าน Internet Information Service (IIS) ซึ่งรองรับทั้ง GZip ละ Deflate ตัวอย่างนี้จะลองประยุกต์ใช้ HTTP-Compression ผ่านการทำ AcionFilter ของ MVC นะครับ
เริ่มแรกสร้างโปรเจค MVC ขึ้นมา สร้าง Folder Filters สร้าง Class ชื่อ CompressFilter ในส่วนบนสุดให้ทำการ using System.Web.Mvc; เพื่อให้สามารถ Inherit ActionFilterAttribute ได้ ดังรูป
จากนั้นจะได้ให้เขียน Code ดังนี้
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO.Compression;
namespace MvcApplication1.Filters
{
/// <summary>
/// Compresiion Filter Request
/// </summary>
public class CompressFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpRequestBase request = filterContext.HttpContext.Request;
string acceptEncoding = request.Headers["Accept-Encoding"];
if (string.IsNullOrEmpty(acceptEncoding)) return;
acceptEncoding = acceptEncoding.ToUpperInvariant();
HttpResponseBase response = filterContext.HttpContext.Response;
if (acceptEncoding.Contains("GZIP"))
{
response.AppendHeader("Content-encoding", "gzip");
response.Filter = new GZipStream(response.Filter
, CompressionMode.Compress);
}
else if (acceptEncoding.Contains("DEFLATE"))
{
response.AppendHeader("Content-encoding", "deflate");
response.Filter = new DeflateStream(response.Filter
, CompressionMode.Compress);
}
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
}
}
}
เท่านี้เราก็สร้าง HTTP-Compression เสร็จเรียบร้อย แต่เมื่อ Run ทดสอบแล้ว จะเกิด Request ดังรูป
สังเกตว่ายังไม่มีการ Compress เกิดขึ้น โดยดูจาก Request ยังมีขนาดเท่าเดิมเพราะว่าเรายังไม่ได้กำหนด CompressFilter ให้กับ Action ที่ต้อการการ Compress ในตัวอย่างนี้จะทดสอบโดยกำหนดที่ Index ใน Controller Home โดยเขียน Code ดังนี้
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication1.Filters;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
[CompressFilter]
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
}
เมื่อ Run ทดสอบแล้วสังเกตว่าขนาดของ Request จะเล็กลงจาก 1.3 KB เหลือ 853B และมีเวลาในการทำงานน้อยลงจาก 22 ms เหลือ 20 ms
20/5/56
Loading and save data with Knockout
วันนี้ขอแนะนำเรื่อง Knockout นะครับ เป็น Library ขนาดเล็กที่ช่วยให้งานสร้าง dynamic UI ง่ายขึ้น ด้วย (Model-View-ViewModel) MVVM Pattern ประกอบด้วยส่วนหลักๆคือ Declarative Binding, Automatic UI Refresh, Dependency Tracking, และ Templating น่าสนใจดีนะครับ
เริ่มแรกสร้างโปรเจค MVC ขึ้นมาก่อน จากนนั้น Reference Knockout.js
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"
type="text/javascript"></script>
จากนั้นเขียน HTML ดังนี้
<h3>Loading and save data with Knockout</h3>
<form data-bind="submit: addTask">
Add task:
<input data-bind="value: newTaskText"
placeholder="What needs to be done?" />
<button type="submit">Add</button>
</form>
<ul data-bind="foreach: tasks, visible: tasks().length > 0">
<li>
<input type="checkbox" data-bind="checked: isDone" />
<input data-bind="value: title, disable: isDone" />
<a href="#" data-bind="click: $parent.removeTask"
class='button-list'>Delete</a>
</li>
</ul>
<br /><br />
You have <b data-bind="text: incompleteTasks().length"> </b>
incomplete task(s)
<span data-bind="visible: incompleteTasks().length == 0"></span>
ในตัวอย่างผมได้สร้าง CSS ไว้แสดงหน้าจอด้วย เพราะอยากให้ปุ่ม Delete ในตัวอย่างออกมาในรูปแบบที่ต้องการ
<style>
html,body{ background:#ffffff;}
.button-list
{
text-decoration:none;
background:#696969;
border:1px soid #000000;
font-size:11px;
color:#ffffff!important;
padding:3px 8px 3px 8px;
}
</style>
จากนั้นเมื่อ Run จะได้หน้าจอ ดังนี้
ตอนนี้หน้าจอจะยังไม่สามารถทำงานได้ ต้องเขียน Javascript นี้ก่อน เพื่อกำหนดส่วนของ Data และ Opeation ดังนี้
<script>
function Task(data) {
this.title = ko.observable(data.title);
this.isDone = ko.observable(data.isDone);
}
function TaskListViewModel() {
// Data
var self = this;
self.tasks = ko.observableArray([]);
self.newTaskText = ko.observable();
self.incompleteTasks = ko.computed(function () {
return ko.utils.arrayFilter(self.tasks(),
function (task) {
return !task.isDone()
});
});
// Operations
self.addTask = function () {
self.tasks.push(new Task({
title: this.newTaskText()
}));
self.newTaskText("");
};
self.removeTask = function (task) {
self.tasks.remove(task)
};
}
ko.applyBindings(new TaskListViewModel());</script>
จากนั้นเมื่อ Run แล้วกรอกข้อมูลที่ TextBox กดปุ่ม Add จะทำงานโดยบันทึกข้อมูลแล้วโหลดแสดงรายการ
credit : http://learn.knockoutjs.com/#/?tutorial=loadingsaving
เริ่มแรกสร้างโปรเจค MVC ขึ้นมาก่อน จากนนั้น Reference Knockout.js
type="text/javascript"></script>
จากนั้นเขียน HTML ดังนี้
<h3>Loading and save data with Knockout</h3>
<form data-bind="submit: addTask">
Add task:
<input data-bind="value: newTaskText"
placeholder="What needs to be done?" />
<button type="submit">Add</button>
</form>
<ul data-bind="foreach: tasks, visible: tasks().length > 0">
<li>
<input type="checkbox" data-bind="checked: isDone" />
<input data-bind="value: title, disable: isDone" />
<a href="#" data-bind="click: $parent.removeTask"
class='button-list'>Delete</a>
</li>
</ul>
<br /><br />
You have <b data-bind="text: incompleteTasks().length"> </b>
incomplete task(s)
<span data-bind="visible: incompleteTasks().length == 0"></span>
ในตัวอย่างผมได้สร้าง CSS ไว้แสดงหน้าจอด้วย เพราะอยากให้ปุ่ม Delete ในตัวอย่างออกมาในรูปแบบที่ต้องการ
<style>
html,body{ background:#ffffff;}
.button-list
{
text-decoration:none;
background:#696969;
border:1px soid #000000;
font-size:11px;
color:#ffffff!important;
padding:3px 8px 3px 8px;
}
</style>
จากนั้นเมื่อ Run จะได้หน้าจอ ดังนี้
ตอนนี้หน้าจอจะยังไม่สามารถทำงานได้ ต้องเขียน Javascript นี้ก่อน เพื่อกำหนดส่วนของ Data และ Opeation ดังนี้
<script>
function Task(data) {
this.title = ko.observable(data.title);
this.isDone = ko.observable(data.isDone);
}
function TaskListViewModel() {
// Data
var self = this;
self.tasks = ko.observableArray([]);
self.newTaskText = ko.observable();
self.incompleteTasks = ko.computed(function () {
return ko.utils.arrayFilter(self.tasks(),
function (task) {
return !task.isDone()
});
});
// Operations
self.addTask = function () {
self.tasks.push(new Task({
title: this.newTaskText()
}));
self.newTaskText("");
};
self.removeTask = function (task) {
self.tasks.remove(task)
};
}
ko.applyBindings(new TaskListViewModel());</script>
จากนั้นเมื่อ Run แล้วกรอกข้อมูลที่ TextBox กดปุ่ม Add จะทำงานโดยบันทึกข้อมูลแล้วโหลดแสดงรายการ
credit : http://learn.knockoutjs.com/#/?tutorial=loadingsaving
17/5/56
Improving Performance with Output Caching
Output Caching เป็นอีกวิธีหนึงในการเพิ่มประสิทธิภาพของ ASP.NET MVC โดย Output Cache จะช่วยให้ Content ที่ถูก Return จาก Controller Action ที่มีเนื้อหาเดียวกันจะไม่ถูกสร้างทุกครั้ง
ยกตัวอย่าง ASP.NET MVC ต้องการแสดงข้อมูลจาก Database ผ่าน View Index โดยทั่วไปต้องมีการ Execute เพื่อดึงข้อมูลที่ Controller Action แล้ว Retun ข้อมูลมาที่ View Index เท่ากับว่าจะมีการ Retrieve ข้อมูลทุกครั้ง ซึ่งบางทีข้อมูลที่ Retrieve มาไม่ได้มีการเปลี่ยนแปลงทำให้เกิดการทำงานซ้ำซ้อนบน Server
ในการเพิ่มประสิทธิภาพ ASP.NET MVC จึงใช้ Ouput Cache เพื่อหลีกเลี่ยงการ Execute Database ทุกครั้ง ดังนั้นเมื่อผู้ใช้ Request ไปที่ Controlller Action เดิม View index จะ Retrieve ข้อมูลจาก Cache แทน
Enabling Output Caching
เราสามารถใช้งาน Output Caching ได้โดยการกำหนด Attribute [OutputCache] บน Controller Action
using System.Web.Mvc; namespace MvcApplication1.Controllers { [HandleError] public class HomeController : Controller { [OutputCache(Duration=10, VaryByParam="none")] public ActionResult Index() { return View(); } } }
จาก Code ข้างบนจะเป็นการกำหนดว่าถามีการเรียก Controller Action Index จะมีการเก็บ Cache โดยมี Parameters คือ Duration บอกว่าเราต้องการเก็บข้อมูล Cache ไว้กี่วินาที ในตัวอย่างจะมีการเก็บ Cache ไว้ 10 วินาที ส่วน VaryByParam ช่วยให้เราสามารถสร้าง Cache Version จาก Parameter หรือ Query String ที่ต่างกัน มีค่า Default เป็น "none" โดยมี Parameters ต่างๆดังนี
Location="Any | Client | Downstream | Server | None | ServerAndClient "
Shared="True | False"
VaryByControl="controlname"
VaryByCustom="browser | customstring"
VaryByHeader="headers"
VaryByParam="parametername"
VaryByContentEncoding="encodings"
CacheProfile="cache profile name | ''"
NoStore="true | false"
SqlDependency="database/table name pair | CommandNotification"
สมัครสมาชิก:
บทความ (Atom)