Upload
hocit
View
107
Download
1
Embed Size (px)
DESCRIPTION
tai lieu ASP.NET
Citation preview
ĐẠI HỌC THĂNG LONG
BỘ MÔN TIN HỌC
CHUYÊN ĐỀ TỐT NGHIỆP
TÌM HIỂU VÀ XÂY DỰNG ỨNG DỤNG
WEB SIÊU THỊ TRỰC TUYẾN
VỚI ASP.NET MVC
SINH VIÊN :
ĐẶNG TIẾN LỘC – A07138
GIÁO VIÊN HƢỚNG DẪN :
ĐOÀN QUANG MINH
HÀ NỘI 5/ 2010
BẢNG KÝ HIỆU VIẾT TẮT
MVC Model View Controller Mô hình lập trình ba lớp Model, View, Controller
được sử dụng trong nhiều framework lập trình
web trong đó có ASP.NET MVC, ZEND, J2EE…
API Application
Programming Interface
Giao diện lập trình ứng dụng được sử dụng bởi
một ứng dụng qua đó cho phép nó tương tác với
ứng dụng khác
ACK ACKnowledgement Thừa nhận một trường xác thực trong gói tin
http.
URL Uniform Resource
Locator
Địa chỉ website
LINQ .NET Language
Intergrated Query
Ngôn ngữ truy vấn tích hợp với .NET
CDN Content Delivery
Network
Mạng phân phối nội dung
SMTP Simple Mail Transfer
Protocol
Giao thức gửi thư điện tử đơn giản
SSL Secure Socket Layer Tầng bảo mật Socket
IIS Internet Information
Server
Máy chủ thông tin mạng
EML Electronic Mail Thư điện tử (đuôi của tệp thư điện tử)
DOM Document Object
Model
định nghĩa tập các đối tượng chuẩn cho tất cả tài
liệu có cấu trúc
UI User Interface Giao diện người dùng
HTTP Hyper Text Transfer
Protocol
Giao thức truyền siêu văn bản
CPU Control Processing Unit Bộ điều khiển xử lí trong máy tính
DLL Dynamic Link Library Thư viện liên kết động
ISAPI Internet Server API Giao diện lập trình người dùng của máy chủ
thông tin mạng
SP Store Procedure Thủ tục lưu trữ
SQL Structured Query
Language
Ngôn ngữ truy vấn có cấu trúc
CSDL Cơ sở dữ liệu Chứa các dữ liệu của hệ thống
OOP Object Oriented
Programming
Lập trình hướng đối tượng
TDD Test Driven
Development
Phát triển đi kèm với kiểm thử
MỤC LỤC
i
MỤC LỤC
GIỚI THIỆU CHUNG ......................................................................................................... 1
CHƢƠNG 1: MỞ ĐẦU ........................................................................................................ 4 1.1. Tổng quan về ASP.NET MVC ............................................................................. 4
1.2. Tổng quan về ứng dụng thƣơng mại siêu thị trực tuyến ..................................... 4
2.1. Yêu cầu đặt ra cho kiến trúc hệ thống .................................................................. 5
2.2. Thiết kế kiến trúc hệ thống ................................................................................... 5
2.2.1. Thiết kế kiến trúc phân tầng .......................................................................... 6
2.2.2. Lựa chọn lƣu trữ dữ liệu và thiết kế tầng truy xuất dữ liệu .......................... 6
2.2.3. Thiết kế tầng logic nghiệp vụ ...................................................................... 10
2.2.4. Xây dựng vùng nhớ đệm, sử dụng mạng phân phối nội dung tăng hiệu năng
của hệ thống .............................................................................................................. 11
2.2.5. Tầng trình diễn ............................................................................................ 11
CHƢƠNG 2: TÌM HIỂU ASP.NET MVC VÀ LINQ ..................................................... 13 1.1. ASP.NET MVC là gì? ........................................................................................ 13
1.1.1. Mô hình MVC cơ bản ................................................................................. 13
1.1.2. Một vài đặc tính của ASP.NET MVC ......................................................... 14
1.2. Sự khác biệt so với Web Form ........................................................................... 14
1.3. Quá trình thực thi một ứng dụng nền web ASP.NET MVC .............................. 16
2.1. Linq to SQL là gì? .............................................................................................. 18
2.2. Mô hình hóa CSDL dùng Linq to SQL .............................................................. 18
2.3. Tìm hiểu lớp DataContext .................................................................................. 19
2.4. Các ví dụ Linq to SQL ....................................................................................... 20
2.5. Tổng kết .............................................................................................................. 22
CHƢƠNG 3: PHÂN TÍCH THIẾT KẾ ỨNG DỤNG ..................................................... 23 1.1. Thiết kế hệ thống ................................................................................................ 23
1.1.1. Các module của hệ thống ............................................................................ 23
1.1.2. Mối quan hệ giữa các module ..................................................................... 24
1.2. Đặc tả sơ lƣợc các module ................................................................................. 24
1.2.1. Module hồ sơ và thành viên ........................................................................ 24
1.2.2. Module lấy ý kiến khách hàng .................................................................... 24
1.2.3. Module thƣơng mại ..................................................................................... 24
1.2.4. Module gửi thƣ ............................................................................................ 24
1.2.5. Module diễn đàn.......................................................................................... 24
1.2.6. Module tìm kiếm siêu thị ............................................................................ 24
1.2.7. Module bài báo, tin tức, và blog ................................................................. 25
1.2.8. Module quốc tế hóa ..................................................................................... 25
1.2.9. Module kiểm thử ......................................................................................... 25
2.1. Tổng quan về module ......................................................................................... 26
2.2. Sơ đồ chức năng ................................................................................................. 26
2.3. Các bảng DL của module ................................................................................... 27
2.3.1. Tạo các bảng DL từ module hồ sơ, ngƣời dùng trong ASP.NET 2.0 ......... 27
2.3.2. Tạo bảng language ...................................................................................... 27
2.3. Cấu hình tệp web.config cho membership, role và profile: ............................... 28
2.4. Models ................................................................................................................ 29
2.4.1. Lớp UserInformation .................................................................................. 29
2.4.2. Lớp ProfileInformation ............................................................................... 30
2.5. Controllers .......................................................................................................... 30
2.6. Views .................................................................................................................. 31
2.7. Sử dụng Javascript .............................................................................................. 32
2.8. Cấu hình định tuyến ........................................................................................... 33
3.1. Tổng quan về module ......................................................................................... 34
3.2. Sơ đồ chức năng ................................................................................................. 35
3.3. Tìm hiểu, sử dụng Paypal cho chức năng thanh toán ......................................... 35
3.3.1. Tạo tài khoản ảo cho mục đích kiểm thử .................................................... 35
3.3.2. Quá trình thanh toán với Paypal từ website thƣơng mại ............................. 36
3.4. Các bảng dữ liệu của module ............................................................................. 38
3.5. Lớp thiết lập cấu hình cho module thƣơng mại .................................................. 38
3.6. Model ................................................................................................................. 39
3.7. Controller ........................................................................................................... 40
3.8. View ................................................................................................................... 41
3.9. Sử dụng JavaScript ............................................................................................. 43
3.10. Cấu hình định tuyến ........................................................................................ 47
4.1. Tổng quan về module ......................................................................................... 50
4.2. Các vấn đề cần quan tâm khi xây dựng module: ................................................ 50
4.3. Sơ đồ chức năng ................................................................................................. 53
4.4. Các bảng dữ liệu ................................................................................................. 53
4.5. Thiết kế lớp cấu hình cho module ...................................................................... 54
4.6. Model ................................................................................................................. 54
4.7. Controller ........................................................................................................... 55
4.8. View ................................................................................................................... 55
4.9. Cấu hình định tuyến ........................................................................................... 56
5.1. Tổng quan về module ......................................................................................... 57
5.2. Sơ đồ chức năng ................................................................................................. 57
5.3. Các bảng dữ liệu ................................................................................................. 58
5.4. Thiết kế lớp cấu hình cho module ...................................................................... 59
5.5. Model ................................................................................................................. 59
5.6. Controller ........................................................................................................... 60
5.7. View ................................................................................................................... 61
5.8. Sử dụng javascript .............................................................................................. 61
5.9. Cấu hình định tuyến ........................................................................................... 66
6.1. Tổng quan về module ......................................................................................... 68
6.2. Sơ đồ chức năng ................................................................................................. 68
6.3. Các bảng dữ liệu ................................................................................................. 69
6.4. Xây dựng lớp ForumsElement cho thiết lập cấu hình module ........................... 69
6.5. Model ................................................................................................................. 69
6.6. Controller ........................................................................................................... 70
6.7. View ................................................................................................................... 71
6.8. Sử dụng javascript .............................................................................................. 72
6.9. Cấu hình định tuyến ........................................................................................... 76
6.10. Cấu hình trong tệp web.config........................................................................ 78
7.1. Tổng quan về module ......................................................................................... 79
7.2. Sơ đồ chức năng ................................................................................................. 79
7.3. Các bảng dữ liệu ................................................................................................. 80
7.4. Xây dựng lớp ArticleElement cho thiết lập cấu hình của module ..................... 80
7.5. Model ................................................................................................................. 81
7.6. Controller ........................................................................................................... 82
7.7. View ................................................................................................................... 83
7.8. Sử dụng javascript .............................................................................................. 84
7.9. Cấu hình định tuyến ........................................................................................... 90
8.1. Tổng quan về module ......................................................................................... 94
8.2. Xây dựng module ............................................................................................... 94
8.2.1. Các Service hỗ trợ quốc tế hóa trong Framework của Microsoft ............... 94
8.2.2. Xây dựng các tệp tài nguyên ....................................................................... 95
8.2.3. Controller của module ................................................................................. 97
8.2.4. View tƣơng ứng của module ....................................................................... 97
9.1. Tổng quan về module ......................................................................................... 99
9.2. Code cho module ................................................................................................ 99
CHƢƠNG 4: SỬ DỤNG WEB FORMS TRONG ỨNG DỤNG ASP.NET MVC ...... 101 1.1. Các lí do cho sự kết hợp giữa 2 công nghệ ...................................................... 101
1.2. Tại sao có thể thực hiện đƣợc sự kết hợp này .................................................. 101
1.3. Các bƣớc để kết hợp các trang WebForms vào ứng dụng ASP.NET MVC .... 101
2.1. Tổng quan về module ....................................................................................... 102
2.2. Sơ đồ chức năng ............................................................................................... 102
2.3. Phân tích cách xây dựng chức năng ................................................................. 102
2.4. Bảng CSDL ...................................................................................................... 103
2.5. Các lớp hỗ trợ trong module ............................................................................ 104
2.6. View ................................................................................................................. 107
2.7. Thêm định tuyến cho các trang view của module ............................................ 107
2.8. Vấn đề bảo mật ................................................................................................. 108
CHƢƠNG 5: TRIỂN KHAI ỨNG DỤNG VÀ HƢỚNG PHÁT TRIỂN .................... 110 1.1. Các bƣớc triển khai .......................................................................................... 110
1.2. Triển khai Global Store Site ............................................................................. 110
1.3. Cấu hình IIS 7.0 cho Framework MVC sử dụng Microsoft Web Platform
Installer ....................................................................................................................... 111
1.4. Thêm Global Store site vào IIS 7.0 .................................................................. 113
2.1. Hỗ trợ tìm kiếm sản phẩm mở rộng ................................................................. 115
2.2. Mở rộng chức năng tìm kiếm cửa hàng gần nhất ............................................. 115
2.3. Xây dựng module báo cáo tình hình bán hàng của siêu thị kết xuất ra các tệp
định dạng Execel, Pdf ................................................................................................. 115
KẾT LUẬN ....................................................................................................................... 116
TÀI LIỆU THAM KHẢO ................................................................................................ 117
DANH MỤC HÌNH ẢNH ................................................................................................ 118
1
GIỚI THIỆU CHUNG
Trong chuyên đề tốt nghiệp này tôi thực hiện việc tìm hiểu công nghệ ASP.NET
MVC, mô hình thương mại điện tử trực tuyến của các chuỗi siêu thị lớn trên thế
giới như http://www.bestbuy.com, http://www.walmart.com/ qua đó xây dựng hệ
thống thương mại trực tuyến trên nền tảng công nghệ ASP.NET MVC và ASP.NET
gồm các module như sau:
Module thành viên và hồ sơ
- Đăng kí tài khoản.
- Đăng nhập, đăng xuất.
- Quản lí hồ sơ.
- Quản lí vai trò người dùng trong đó có xem toàn bộ các vai trò có trong hệ
thống, xóa, và tạo vai trò.
- Quản lí người dùng trong đó có xem danh sách những người dùng có trong
hệ thống, tìm kiếm người dùng theo tên và email, xóa người dùng, và sửa
đổi thông tin người dùng.
Moudle thương mại
- Duyệt toàn bộ các gian hàng trong siêu thị.
- Xem một gian hàng theo danh sách các sản phẩm có trong gian hàng, chọn
và đưa một sản phẩm vào giỏ hàng.
- Xem chi tiết một sản phẩm trong gian hàng, đưa sản phẩm vào giỏ hàng.
- Quản lí các gian hàng trong đó có xem toàn bộ các gian hàng trong hệ
thống, chỉnh sửa, và xóa một gian hàng, tạo gian hàng mới.
- Quản lí các sản phẩm trong đó có xem danh sách các sản phẩm trong hệ
thống, chỉnh sửa thông tin sản phẩm, xóa sản phẩm, tạo sản phẩm mới.
- Quản lí các chọn lựa cách giao hàng trong đó có xem danh sách các cách
giao hàng, xóa, thêm cách thức giao hàng.
- Quản lí các đơn đặt hàng trong đó có xem danh sách các đơn hàng có
trong hệ thống, xem chi tiết từng đơn hàng.
Mudule tin tức – bài báo – blog.
- Xem danh sách các bài báo.
- Xem các bài báo theo đầu mục.
2
- Xem chi tiết một bài báo, viết lời bình và đánh giá bài báo.
- Quản lí các đầu mục trong đó có chỉnh sửa đầu mục, xóa đầu mục, và tạo
đầu mục.
- Quản lí các bài báo trong đó có xem các bài báo có trong hệ thống, chỉnh
sửa, xóa, tạo bài báo mới.
- Quản lí các nhận xét bài báo trong đó có xem toàn bộ các nhận xét có trong
hệ thống, chỉnh sửa, xóa một nhận xét.
Module trưng cầu ý kiến khách hàng
- Xem các trưng cầu, cho ý kiến.
- Quản lí các trưng cầu trong đó có chuyển trưng cầu sang trạng thái đã lấy
đủ ý kiến, hiện hành, chỉnh sửa trưng cầu, xóa trưng cầu, tạo trưng cầu
mới.
Module gửi thư từ hệ thống
- Xem toàn bộ các thư đã gửi đi từ hệ thống, xóa các thư đã gửi.
- Tạo và gửi thư.
Module định vị cửa hàng siêu thị gần nhất
- Tìm các siêu thị trong khoảng cách nhất định đối với một địa chỉ cho trước.
- Tìm đường đi tới 1 siêu thị từ địa chỉ đó.
- Thêm vị trí siêu thị mới vào hệ thống.
Module diễn đàn
- Duyệt các diễn đàn.
- Xem các bài thảo luận, tham gia thảo luận, xác nhận thích hay không thích
bài thảo luận, tạo bài thảo luận.
- Quản lí các diễn đàn trong đó có chỉnh sửa, xóa diễn đàn.
- Quản lí các bài thảo luận trong đó có chấp thuận cho bài thảo luận được
hiển thị, đóng luồng thảo luận khi nó quá dài, xóa bài thảo luận.
Module quốc tế hóa
- Hiển thị các thông tin địa phương ứng với địa phương mà người dùng đăng
kí trong hồ sơ của họ như tiền dùng ở địa phương, thời gian, cách viết con
số của địa phương,…
3
Module kiểm thử
- Kiểm thử phần bài báo, blog.
- Kiểm thử phần gửi thư.
4
CHƢƠNG 1: MỞ ĐẦU
1. LÍ DO THỰC HIỆN ĐỀ TÀI
1.1. Tổng quan về ASP.NET MVC
Không phải tự nhiên mà rất nhiều framework xây dựng ứng dụng nền tảng web
phổ biến nhất hiện nay kế thừa các nguyên tắc thiết kế của MVC như Django,
Ruby on Rails, CakePHP, Struts, … Sự thành công của việc kế thừa kiểu mẫu lập
trình này cuối cùng cũng đã khiến Microsoft quyết định đưa các nguyên tắc đó vào
sử dụng trong .NET Framework và rồi hình thành nên ASP.NET MVC đầu năm
2007 với phiên bản lúc đó là 1.0.
Công nghệ lập trình ASP.NET MVC này tuy rằng không phải là công nghệp lập
trình ứng dụng nền tảng web tốt nhất hiện nay của Microsoft cũng không phải
dùng để thay thế công nghệ ASP.NET song nó có những ưu điểm nhất định, được
sử dụng khá phổ biến và đang tiếp tục được hỗ trợ phát triển của Micorosoft.
Chính vì những lí do này mà nó đáng được tìm hiểu để từ đó sử dụng một cách
hiệu quả.
1.2. Tổng quan về ứng dụng thƣơng mại siêu thị trực tuyến
Việc mua bán kinh doanh hiện nay đang ngày càng trở nên dễ dàng hơn với sự hỗ
trợ của công nghệ thông tin. Hiện nay có một số lượng rất lớn các website thương
mại đã được xây dựng và sử dụng. Việc này giúp đa dạng hóa các phương thức
bán hàng và vì vậy hàng hóa được tiêu thụ dễ dàng hơn. Có rất nhiều ích lợi từ
việc kinh doanh trực tuyến có thể thấy được như:
Đối với khách hàng:
Mua hàng ở bất kể đâu miễn là họ có máy tính kết nối mạng.
Nhanh chóng tìm kiếm được mặt hàng cần mua chỉ qua vài click chuột.
Không phải đối mặt với nhân viên bán hàng.
…
Đối với doanh nghiệp:
Có thêm được một kênh quảng bá sản phẩm hiệu quả mà chi phí thấp.
Nắm bắt được thông tin phong phú về thị trường và đối tác.
Thiết lập được mối quan hệ tốt với khách hàng và đối tác.
Đa dạng hóa các kênh bán hàng của doanh nghiệp.
….
Hệ thống siêu thị trực tuyến là một ví dụ điển hình về thương mại điện tử nó có
đầy đủ các module mà một hệ thống thương mại điện tử cần có. Trong chuyên đề
tốt nghiệp của mình tôi sẽ xây dựng hệ thống bán hàng trực tuyến dựa trên công
nghệ ASP.NET MVC là chủ yếu.
5
2. SƠ LƢỢC VỀ YÊU CẦU KIẾN TRÚC CỦA HỆ THỐNG
2.1. Yêu cầu đặt ra cho kiến trúc hệ thống
Xây dựng nên hệ thống siêu thị trực tuyến cấu thành từ các module riêng biệt
đồng thời quản lí nội dung động của hệ thống như bài báo,diễn đàn, phiếu điều tra
và gửi thư từ hệ thống. Ta cần giải quyết các vấn đề chung đặt ra với mỗi module
đó là:
Tách biệt mã lệnh truy cập CSDL với mã lệnh logic nghiệp vụ và mã lệnh
cho giao diện để hệ thống có thể dễ dàng bảo trì và mở rộng. Đây là kiểu
thiết kế phân tầng cho hệ thống.
Cô lập kiến trúc truy cập CSDL để từ đó có thể hỗ trợ việc lưu trữ với công
cụ lưu trữ CSDL quan hệ khác nhau như SQL, MySQL, Oracle,.. mà không
phải thực hiện thay đổi nào với tầng đối tượng nghiệp vụ. Ngược lại việc
thay đổi tầng trình diễn hay tầng đối tượng nghiệp vụ cũng không làm thay
đổi các tầng còn lại. Việc làm này tạo ra sự cách ly giữa các tầng của hệ
thống.
Thiết kế kiến trúc đối tượng nghiệp vụ lấy từ tầng truy cập CSDL theo kiểu
hướng đối tượng bằng cách ánh xạ cơ sở dữ liệu quan hệ vào các lớp
hướng đối tượng.
Xây dựng bộ nhớ đệm lưu các đối tượng nghiệp vụ. Điều này giúp làm giảm
áp lực xử lí yêu cầu người dùng với CPU của máy chủ, nguồn CSDL, băng
thông mạng và như vậy làm tăng hiệu năng chung của hệ thống.
Tạo tệp cấu hình cho từng module để có thể dễ dàng thay đổi chúng.
2.2. Thiết kế kiến trúc hệ thống
Với các dự án ASP.NET truyền thống ta sẽ không bao giờ thực sự tách riêng được
phần giao diện người dùng với logic ứng dụng bởi vì .NET cung cấp sẵn các điều
khiển phía máy chủ mà ta thường sử dụng bằng cách kéo thả vào các trang cung
cấp giao diện ví dụ như GridView. Các control kiểu này giúp chúng ta thực hiện
khá nhiều việc tuy nhiên lại thường làm cho mã lệnh xử lí logic của ứng dụng lẫn
vào với mã lệnh giao diện. Một ví dụ thường thấy đó là việc tạo ra logic để sắp xếp
các GridView hay lọc dữ liệu ứng với một sự kiện nhấn chuột. Khi sử dụng những
control như thế ta luôn cần có các tệp mã lệnh để xử lí logic đằng sau các trang
giao diện.
Chúng ta có thể tự tạo trọn vẹn một ứng dụng có tính module tuy nhiên điều này
dẫn tới việc ta phải tự xây dựng framework cho ứng dụng của mình.
Với sự ra đời của framework asp.net mvc thì mọi thứ đã thay đổi hẳn không còn
các tệp mã lệnh xử lí logic đằng sau các trang giao diện giúp tách biệt hoàn toàn
giữa giao diện với logic nghiệp vụ của ứng dụng và như vậy ứng dụng nền tảng
web của ta đã được xây dựng theo kiến trúc phân tầng.
6
2.2.1. Thiết kế kiến trúc phân tầng
Với ứng dụng siêu thị trực tuyến ta sẽ chia thành các tầng như sau:
Tầng lưu trữ dữ liệu: Nơi lưu trữ CSDL. CSDL của hệ thống siêu thị trực tuyến là
CSDL quan hệ.
Tầng truy cập CSDL (Data Access Layer – DAL): Mã lệnh để lấy dữ liệu, xử lí dữ
liệu thô được lưu trong tầng lưu trữ DL. Nhiệm vụ của tầng này là đưa ra các truy
xuất CSDL theo logic nghiệp vụ và có tính trực quan hơn cho ứng dụng. Che dấu
các chi tiết thâm nhập CSDL ở mức thấp tăng tính an toàn cho CSDL của hệ
thống.
Tầng nghiệp vụ (Business Logic Layer – BLL): Mã lệnh ở tầng này sẽ thực hiện
các nguyên tắc nghiệp vụ, tạo các đối tượng cụ thể thuộc miền nghiệp vụ nhằm
thỏa mãn các yêu cầu của ứng dụng.
Tầng Logic ứng dụng (Application Logic Layer): Mã lệnh thuộc tầng này sẽ xử lí
các tương tác giữa tầng trình diễn với tầng logic nghiệp vụ.
Tầng trình diễn (Presentation Layer – PL) : Là các đoạn mã lệnh tạo nên những gì
mà người dùng thấy ở trên trình duyệt. Nó có thể là các dữ liệu đã được định
dạng, thực đơn duyệt hệ thống, …
Hình 1.1 – Kiến trúc ứng dụng
2.2.2. Lựa chọn lƣu trữ dữ liệu và thiết kế tầng truy xuất dữ liệu
Ở ứng dụng này ta lựa chọn lưu trữ CSDL với máy chủ SQL 2008 tuy nhiên trong
thực tế có thể khách hàng lại muốn sử dụng máy chủ Oracle hay IBM DB2 … vì
nhiều lí do như họ muốn tích hợp ứng dụng của bạn vào một dự án lớn hơn mà dự
án này lại dùng máy chủ Oracle để lưu trữ dữ liệu nên tầng truy xuất dữ liệu cần
được thiết kế sao cho đủ linh hoạt để việc thay đổi diễn ra dễ dàng, nhanh chóng.
Tầng truy xất dữ liệu là mã lệnh thực hiện truy vấn CSDL để lấy dữ liệu, cập nhật,
chèn, hay xóa dữ liệu. Đây là mã lệnh gần với CSDL nhất, sử dụng tất cả những gì
có trong CSDL từ giản đồ các bảng,các thủ tục lưu trữ, các hàm … cho đến các
7
trường. Mã lệnh truy xuất tới CSDL cụ thể phải được tách biệt với mã lệnh các
trang web vì các lí do như:
Người viết mã lệnh cho phần giao diện và người viết mã lệnh cho phần truy
cập CSDL có thể không phải là một. Với những ứng dụng nền tảng web cỡ
vừa và lớn thì thường có nhiều lập trình viên tham gia xây dựng. Người xây
dựng giao diện sẽ hầu như không quan tâm tới CSDL. Tuy nhiên họ vẫn
cung cấp giao diện hiển thị thông tin từ CSDL bởi lẽ tất cả các chi tiết hiển
thị đã được gói gọn trong các đối tượng riêng biệt cung cấp việc truy vấn
CSDL ở mức cao, trừu tượng hơn.
Một vài truy vấn CSDL sẽ được sử dụng ở một số các trang của ứng dụng.
Nếu như ta đặt trực tiếp truy vấn vào các trang này mà sau đó ta muốn thay
đổi một câu lệnh truy vấn như thay đổi cách thức sắp xếp, hoặc thay đổi các
trường dữ liệu ta sẽ phải xem lại toàn bộ mã lệnh xem nơi nào sử dụng
chúng và thực hiện thay đổi. Nếu như ta đưa toàn bộ mã lệnh truy cập
CSDL vào một vài lớp trong tầng truy xuất CSDL ta sẽ chỉ phải thay đổi các
tệp này mà không cần quan tâm tới các trang chứa mã lệnh giao diện.
Mã lệnh truy vấn CSDL mà đặt cùng với mã lệnh giao diện sẽ làm ta khó
khăn trong việc thay đổi sang CSDL quan hệ khác.
Với công nghệ asp.net mvc việc tách biệt tầng truy xuất CSDL là gần như bắt
buộc. Tất cả các đối tượng liên quan tới tầng truy xuất CSDL nên được đặt trong
thư mục tên là Models.
Để xử lí việc hỗ trợ lưu trữ dữ liệu linh động với các máy chủ CSDL khác nhau ta
sẽ sử dụng kiểu mẫu thiết kế Provider Model cụ thể là thay vì việc viết trực tiếp các
lớp truy cập CSDL đầu tiên ta sẽ viết lớp trừu tượng và giao diện công khai của
các lớp đó và cả các phương thức hỗ trợ nếu cần. Mã lệnh thực sự dùng truy vấn
CSDL sẽ nằm ở lớp kế thừa trực tiếp từ lớp trừu tượng và lớp này sẽ đưa ra các
mã lệnh cụ thể cho các phương thức trong giao tiếp của lớp trừu tượng. Lớp trừu
tượng được gọi là lớp cung cấp và đây là lí do vì sao Micorsoft gọi kiểu mẫu thiết
kế này là Provider Model.
Rõ ràng khi thay đổi máy chủ CSDL ta chỉ việc thay đổi CSDL, thay đổi các lớp thứ
2 này là xong. Hơn thế nữa với lớp trừu tượng ta biết rõ được phải xây dựng lớp
thứ 2 như thế nào và chúng ta không hề phải thay đổi các module khác ngoại trừ
module tầng truy cập CSDL. Trong trường hợp buộc phải thêm các lớp cung cấp
mới thì ta có thể biến các lớp cung cấp cũ thành virtual để từ đó cho phép các lớp
provider mới có các hàm quá tải các hàm của các provider cũ.
Hình dưới đây minh họa mối quan hệ giữa các tầng giao diện, logic nghiệp vụ, truy
cập CSDL và lưu trữ CSDL với nhiều công cụ lưu trữ khác nhau.
8
Hình 1.2 – Mối quan hệ giữa các tầng giao diện, logic nghiệp vụ, truy cập
CSDL và lưu trữ CSDL
Sử dụng LINQ ở tầng truy cập CSDL (DAL)
Với .NET Framework 3.5 chúng ta được cung cấp một tính năng mới là LINQ
(Language Intergrated Query). LINQ được thiết kế để cung cấp cách thực hiện truy
vấn trên bất kể kiểu collection nào trong .NET Framework bao gồm mảng,
dictionaries, lists, XML, và các CSDL,…
LINQ có những tính năng đáng để xem xét dù ta có thể đơn giản sử dụng kiểu
typed data sets hay các thực thể ta tạo ra để thực hiện việc xây dựng tầng truy vấn
CSDL theo mong muốn như:
Sử dụng các cấu trúc truy vấn giống với SQL trong mã lệnh .NET hay xem
đoạn code này:
SQL
select c.*
from Customer as c
9
LINQ
var customers = from c in dataContext.Customers
select c;
2 câu lệnh trên thực thi cùng một nhiệm vụ là truy vấn thông tin khách hàng
từ bảng Customers, tuy nhiên trong cách truy vấn sử dụng LINQ thì dữ liệu
được chuyển thành kiểu collection, gọi là Iqueryable<Customer>, giúp ta có
thể sử dụng vòng lặp chuẩn foreach. Trong C# ta thấy có từ khóa mới là
var. Đây là kiểu dữ liệu nạc danh (kiểu dữ liệu này chỉ được xác định khi
biên dịch – trình biên dịch sẽ biết nó có kiểu gì khi biên dịch và thay từ khóa
var với tên kiểu đúng của nó)
Với LINQ có thể sử dụng kiểu dữ liệu an toàn và các truy vấn đa dạng hơn.
Hãy xem câu lệnh truy vấn xem mỗi khách hàng trả bao nhiêu cho các đơn
đặt hàng của họ trong năm 2008 bằng SQL và LINQ:
SQL
select c.CustomerId, c.Name as CustomerName, sum(o.TotalPaid) as TotalPaid
from Customer as c inner join Orders as o
on c.CustomerId = o.CustomerId where o.OrderDate >= ‘1/1/2008’
and o.OrderDate <= ‘12/31/2008’ group by c.CustomerId, c.Name
LINQ
var customers = from c in dataContext.Customers join o in dataContext.Orders on c.CustomerId
equals o.CustomerId where c.OrderDate >= new Date(2008, 1, 1)
&& c.OrderDate <= new Date(2008, 12, 31) group o by new { c.CustomerId, c.Name } into g select new {
CustomerId = c.CustomerId, CustomerName = c.Name, TotalPaid = g.Sum(o => o.TotalPaid) };
Trong ví dụ với LINQ thì trường OrderDate có kiểu là System.DateTime. Vì
vậy nếu ta so sánh nó với dữ liệu kiểu chuỗi, hay bất kể một đối tượng nào
không phải kiểu DateTime thì trình biên dịch sẽ báo lỗi và cho biết chính xác
vị trí lỗi xảy ra đây là một ích lợi khi sử dụng LINQ so với việc sử dụng SQL.
Ví dụ dưới đâu sẽ cho thấy với LINQ ta có các truy vấn tiện ích hơn so với
SQL ví dụ như lấy một oder có ID = 2, lấy OderInformation của oder đó thay
đổi ngày thêm vào rồi lưu oder này lại vào CSDL.
var order = (from o in dataContext.Orders where o.OrderId == 2
10
select o).FirstOrDefault(); foreach(var orderInformation in order.OrderInformation)
orderInformation.DateAdded = DateTime.Now; dataContext.SubmitChanges();
LINQ-to-SQL : Để LINQ có thể được sử dụng ta cần phải khởi tạo model
tương ứng. Việc tạo model này hoàn toàn có thể thực hiện bằng cách kéo
thả các bảng cũng như thủ tục lưu vào giao diện thiết kế của tệp thiết kế
các lớp LINQ to SQL. Các lớp thực thể sẽ được tạo tự động. Việc tạo các
lớp thực thể với LINQ to SQL như vậy giúp xây dựng ứng dụng nhanh
chóng tuy nhiên lại là hạn chế vì cách tạo các lớp thực thể này chỉ có máy
chủ SQL của Microsoft hỗ trợ.
2.2.3. Thiết kế tầng logic nghiệp vụ
Tầng truy cập CSDL được xây dựng với LINQ-to-SQL trả về các tập hợp của các lớp thực thể chứa các trường của dữ liệu từ bảng dư liệu. Tuy nhiên dữ liệu trả về của tầng này vẫn là dữ liệu thô dù chúng được chứa trong các lớp bởi vì chúng được sinh tự động. Chúng chỉ là nơi chứa các dữ liệu có định kiểu mạnh được sử dụng để truyền dữ liệu giữa các tầng lưu trữ dữ liệu và tầng logic nghiệp vụ. Tầng nghiệp vụ logic sử dụng các dữ liệu này chuyển chúng tới tầng giao diện người dùng. Ở tầng này có thể có thêm kiểm định logic, xây dựng các biểu thức tính toán dựa trên các thuộc tính, chuyển một số thuộc tính thành kiểu private hay read-only thêm các phương thức tĩnh, thực thể để xử lí việc xóa, chỉnh sửa, truy xuất dữ liệu. Việc tạo các dữ liệu hướng đối tượng, định kiểu mạnh tạo ra sự trừu tượng hóa mạnh mẽ cô lập tầng lưu trữ CSDL cung cấp cho lập trình viên phát triển giao diện tập hợp các lớp đơn giản, xong hiệu quả khi sử dụng. Với asp.net mvc framework thì tầng logic nghiệp vụ nằm gọn trong các điều khiển và các lớp điều khiển bắt buộc phải được đặt trong thư mục Controllers giúp tách hẳn tệp code behind ra khỏi tệp mã lệnh giao diện. Các lớp này sử dụng các kiểu tập hợp xử lí dữ liệu ứng dụng thông qua các kiểu tập hợp này rồi trả lại view tương ứng. Với việc tạo tầng logic nghiệp vụ ở thư mục controllers trong ứng dụng .net mvc thì ta có được một số ích lợi như:
Tạo được các kiểm định bộ phận cho ứng dụng bởi lẽ tất cả các logic nghiệp vụ được đặt trong thư mục Controllers hoặc các thực thể mà ta tạo ra. Không có các trình điều khiển phía máy chủ và như vậy việc kiểm định bộ phận không bị lỗi.
Bảo mật dễ dàng hơn bởi lẽ tất cả các xử lí được đặt trong các lớp điều khiển ta không còn phải tách biệt các trang cần có cấp phép cao hơn và đưa ra lệnh chứng thực cấp phép với thư mục chứa các trang này.
Ta có thể trả về nhiều giao diện từ một phương thức hành động trong controller.
Với vấn đề bảo mật ta chỉ cần xử lí đơn giản như trong đoạn code sau: [Authorize (Roles = ‚Admin‛)] public ActionResult EditContent (int id, ..) {
11
//logic dùng chỉnh sửa nội dung return View(); }
2.2.4. Xây dựng vùng nhớ đệm, sử dụng mạng phân phối nội dung tăng
hiệu năng của hệ thống
Với những ứng dụng nền tảng web có những dữ liệu ít thay đổi và thường được yêu cầu bởi nhiều người dùng và trong hệ thống siêu thị trực tuyến các dữ liệu như vậy có thể kể tới như danh sách các đầu mục bài báo, đầu mục sản phẩm và các sản phẩm… Để có thể tăng hiệu ứng cho hệ thống với những dữ liệu kiểu này ta có thể tạo vùng nhớ đệm cho chúng và giữ vùng nhớ đệm này ở bộ nhớ trong những khoảng thời gian xác định. Asp.net framework cũng khá mạnh trong việc giúp chúng ta xây dựng, quản lí vùng nhớ đệm ở trong các lớp điều khiển. Hãy xem một ví dụ sau cho thấy việc tạo vùng nhớ đệm và duy trì nó trong 60 giây [OutputCache (Duration = 60)] public ActionResult SomeControllerMethod() { //logic nghiệp vụ } Trong trường hợp hệ thống được truy cập bởi một lượng lớn người dùng mỗi ngày vài ngàn đến vài chục ngàn ta có thể tính tới việc sử dụng các mạng phân phối nội dung (CDN) đây là mạng phát tán của các máy chủ giúp ta giải quyết vấn đề quá tải truy cập nội dung của hệ thống, giúp người dùng truy cập nội dung hệ thống nhanh hơn. Các mạng này thực hiện công việc phôn phối nội dung thông qua mạng của các máy chủ quản lí tên miền (DNS) hướng yêu cầu của người dùng tới một máy chủ có sẵn nội dung người dùng cần và gần người dùng đó nhất. Nội dung cần phân phối có thể là các file ảnh, javascript, css, tài liệu, phim ảnh, âm thanh … với hệ thống siêu thị trực tuyến này thì các tệp nội dung được đặt trong thư mục Content việc đưa tất cả các file nội dung vào thư mục này sẽ rất phù hợp với cơ chế làm việc của CDN ở chỗ để CDN hoạt động ta cần phải cài phần mềm tương ứng vào máy chủ web chứa hệ thống và cấu hình để phần mềm này biết cụ thể vị trí của nội dung cần phân phối việc đưa nội dung cần phân phối vào một thư mục sẽ dễ dàng cho việc cấu hình và quá trình tìm kiếm của phần mềm này. Về mặt giá cả thì giải pháp sử dụng CDN sẽ rẻ hơn nhiều so với việc thuê đường truyền có băng thông lớn hơn.
2.2.5. Tầng trình diễn
Tầng trình diễn tương ứng với các trang giao diện duy chỉ có điều là không có các tệp mã lệnh đằng sau mỗi trang đó. Theo công nghệ ASP.NET MVC thì các tệp mã lệnh đó được thay thế bằng những lớp điều khiển. Tuy nhiên còn các điều khiển phía máy chủ (được cung cấp bởi Microsoft, hoặc các hãng thứ 3) vẫn thường được sử dụng trong các trang chứa mã lệnh giao diện của asp.net trước kia thì
12
sao? Trên thực tế những control kiểu này không còn cần thiết trong các trang đó nữa. ASP.NET MVC framework đem lại rất nhiều lựa chọn thay thế cho các điều khiển phía máy chủ của công nghệ ASP.NET đó mà trong hệ thống siêu thị trực tuyến sử dụng. Framework này có một tập các phương thức mở rộng hỗ trợ HTML giúp tự động tạo và gắn kết dữ liệu của phần lớn các điều khiển phía máy chủ mà ta vẫn sử dụng với các trang chứa mã lệnh ASP.NET. Ví dụ như tạo textbox và tiêu đề của textbox sau được ánh xạ bởi ViewData. <label for =‛title‛> Title </label><br/> <%= Html.Textbox(‚Title‛, ViewData.Model.Title)%> Khi đoạn code trên được chuyển tới trình duyệt thì nó được chuyển thành đoạn code HTML tương ứng sau:
<label for =‛title‛> Title </label><br/> <input id = ‚Title‛ name = ‚Title‛ type = ‚text‛ vale=‛Chief Technology Officer‛/> Đoạn code này đơn giản chỉ có thẻ input mà hoàn toàn không có liên quan tới thuộc tính runat. Đối với trình duyệt input này được viết hoàn toàn bằng HTML điều này giúp tối ưu hóa khả năng tìm kiếm hệ thống của các hệ thống tìm kiếm như google hay bing giúp các khách hàng chưa biết tới hệ thống có thể tìm đến hệ thống thông qua cỗ máy tìm kiếm dễn dàng hơn. Ở tầng này của hệ thống siêu thị trực tuyến có sử dụng javascript ở để xử lí các sự kiện không đồng bộ phía người dùng. Cụ thể ta sẽ sử dụng JQuery – đây là javascript framework ổn định, ra đời cách đây vài năm, có các tài liệu hỗ trợ đầy đủ, dễ sử dụng.
13
CHƢƠNG 2: TÌM HIỂU ASP.NET MVC VÀ LINQ
1. TỔNG QUAN VỀ ASP.NET MVC
1.1. ASP.NET MVC là gì?
1.1.1. Mô hình MVC cơ bản
MVC viết tắt của các chữ cái đầu của Models, Views, Controllers. MVC chia giao
diện UI thành 3 phần tương ứng: đầu vào của controller là các điều khiển thông
qua HTTP request, model chứa các miền logic, view là những gì được sinh ra trả
về cho trình duyệt.
Hình 2.1 – Mô hình MVC cơ bản
Lợi ích của việc dùng phương pháp MVC là sự phân tách rõ ràng giữa models,
views, controllers bên trong ứng dụng. Cấu trúc sạch giúp cho việc kiểm tra lỗi ứng
dụng trở nên dễ dàng hơn.
14
1.1.2. Một vài đặc tính của ASP.NET MVC
Tách rõ ràng các mối liên quan giữa các module, mở ra khả năng kiểm thử theo mô hình TDD. Có thể kiểm thử bộ phận trong ứng dụng mà không cần phải chạy lớp điều khiển cùng với tiến trình của ASP.NET và có thể dùng bất kỳ một framework kiểm thử nào như NUnit, MBUnit, MS Test, v.v…
Mọi thứ trong MVC được thiết kế cho phép dễ dàng thay thế/tùy biến ( ví dụ: có thể lựa chọn sử dụng engine view riêng, engine controller riêng, routing policy, parameter serialization, v.v…).
Có một bộ ánh xạ URL mạnh cho phép xây dựng ứng dụng với những URL sạch, các URL không cần phần mở rộng như aspx ( ví dụ: có thể ánh xạ địa chỉ /Products/Edit/4 để thực hiện hành động “Edit” của lớp điều khiển ProductControllers hoặc ánh xạ địa chỉ /Blog/SomeTopic để thực hiện hành động “Display Topic” của lớp điều khiển BlogEngineController ) và được thiết kế để hỗ trợ kiểu mẫu đặt tên url qua đó hỗ trợ tối ưu hóa của bộ máy tìm kiếm.
ASP.NET MVC Framework cũng hỗ trợ những tệp của ứng dụng ASP.NET như .ASPX .ASCX và .Master, đánh dấu các tập tin này như một “view template” ( có thể dễ dàng dùng các tính năng của ASP.NET như lồng các trang Master, <%= %> snippets, mô tả các điều khiển phía máy chủ, template, data-binding, localization, v.v… ). Tuy nhiên sẽ không còn cơ chế postback và interactive back server và thay vào đó là interactive end-user tới một lớp Controller ( không còn viewstate, page lifecycle )
ASP.NET MVC Framework hỗ trợ đầy đủ các tính năng bảo mật của ASP.NET như xác thực theo forms/windows, URL authorization, membership/roles, output và data caching, session/profile state, configuration system, provider architecture v.v…
1.2. Sự khác biệt so với Web Form
ASP.NET WebForm sử dụng ViewState để quản lý, các trang ASP.NET đều có lifecycle,cơ chế postback và dùng các điều khiển, các sự kiện để thực thi hành động trên giao diện khi có sự tương tác với người dùng nên nếu trang ASP.NET có quá nhiều điều khiển thì việc xử lý yêu cầu người dùng sẽ chậm. ASP.NET MVC Framework chia ra thành 3 phần: Models, Views, Controllers. Mọi tương tác của người dùng với Views sẽ thực hiện hành động trong Controllers, không còn postback, không còn lifecycle hay các sự kiện nữa.
Việc kiểm tra, gỡ lỗi với ASP.NET đều phải chạy tất cả các tiến trình của ASP.NET và mọi sự thay đổi ID của bất kỳ điều khiển nào cũng ảnh hưởng đến ứng dụng. Đối với ASP.NET MVC Framework thì việc có thể sử dụng các unit test có thể kiểm định khá dễ dàng hoạt động của các controller.
15
Tính năng ASP.NET 2.0 ASP.NET MVC
Kiến trúc chương trình Kiến trúc mô hình trang
giao diện Bussiness
Database
Kiến trúc sử dụng việc
phân chia chương trình
thành Controllers, Models,
Views
Cú pháp chương trình Sử dụng cú pháp của
webform. Tất cả các sự
kiện và controls đều do
máy chủ quản lí
Các sự kiện được điều
khiển bởi Controllers, các
controls không do máy
chủ quản lí
Truy cập dữ liệu Sử dụng hầu hết các công
cụ truy cập dữ liệu trong
ứng dụng
Có thể dùng LINQ to SQL
class để tạo mô hình truy
cập đối tượng
Gỡ rối Gỡ rối chương trình phải
thực hiện tất cả bao gồm
các lớp truy cập dữ liệu,sự
hiển thị, các điều khiển
Gỡ rối có thể sử dụng các
unit test để kiểm tra các
phương thức trong
controller
Tốc độ phân tải Tốc độ phân tải chậm trong
khi trang có quá nhiều điều
khiển vì khi đó ViewState
quá lớn
Phân tải nhanh hơn do
không phải sử dụng
ViewState để quản lý các
điều khiển trong trang
Tương tác với javascript Tương tác với javascript
khó khăn vì các điều khiển
bị quản lí bởi máy chủ
Tương tác với javascript
dễ dàng vì các đối tượng
không do máy chủ quản lí
dẫn tới điều khiển không
khó khăn
URL address Cấu trúc địa chỉ URL có
dạng
<filename>.aspx?&<các
tham số>
Cấu trúc địa chỉ URL rành
mạch, dễ hiểu theo dạng
Controllers /Action/ Id
16
1.3. Quá trình thực thi một ứng dụng nền web ASP.NET MVC
Một yêu cầu gửi tới ứng dụng nền tảng web viết bằng ASP.NET MVC đầu tiên sẽ đi qua đối tượng UrlRoutingModule, đây là một module HTTP. Module này sẽ phân tích yêu cầu và thực thi việc chọn lựa định tuyến. Nó sẽ chọn đối tượng route đầu tiên thích hợp với yêu cầu hiện thời.(Đối tượng route mở rộng lớp RouteBase và là một thể hiện cụ thể của lớp Route) Nếu không có định tuyến nào thích hợp đối tượng UrlRoutingModule sẽ không thực hiện việc định tuyến mà trả yêu cầu đó về cho IIS hay ASP.NET xử lí. (Xem hình 2.2) Từ đối tượng Route được chọn, đối tượng UrlRoutingModule lấy đối tượng IRouteHandler tương ứng với đối tượng Route. Cụ thể trong một ứng dụng ASP.NET MVC thì IRouteHandler là một thể hiện của MvcRouteHandler. Thể hiện này sẽ tạo ra một đối tượng IHttpHandler và truyền nó tới đối tượng IHttpContext. Theo mặc định,thể hiện IHttpContext của MVC là đối tượng MvcHandler. Đối tượng này sẽ chọn ra controller xử lí yêu cầu gửi từ ứng dụng. Module nói trên và IIS là các điểm đầu vào đối với ASP.NET MVC framework. Chúng thực hiện những việc sau:
Chọn ra một controller tương ứng xử lí yêu cầu từ ứng dụng MVC.
Có được một thể hiện cụ thể của controller đó.
Gọi phương thức Execute của controller này.
Bảng liệt kê các giai đoạn thực thi của một dự án nền Web ASP.NET MVC
Giai đoạn Chi tiết
Nhận yêu cầu
đầu tiên từ
ứng dụng
Trong file Global.asax, các đối tượng Route được thêm vào đối
tượng RouteTable
Thực thi định
tuyến
Module UrlRoutingTable sử dụng đối tượng Route đầu tiên
thích hợp trong tập RouteTable tạo đối tượng RouteData. Đối
tượng này sau đó lại tạo ra đối tượng RequestContext
(IHttpContext).
Tạo trình xử lí
yêu cầu từ
MVC
Đối tượng MvcRouteHandler tạo ra một thể hiện của lớp
MvcHandler và truyền vào nó thể hiện RequestContext
Tạo controller Đối tượng MvcHandler sử dụng thể hiện của RequestContext
để xách định đối tượng IcontrollerFactory qua đó tạo ra thể
hiện controller
17
Thực thi
controller
Thể hiện MvcHandler gọi phương thức Execute controller.
Gọi phương
thức hành
động từ
controller
tương ứng
Hầu hết các controllers đều kế thừa từ lớp Controller cơ bản.
Đối với các controller như thế đối tượng
ControllerActionInvoker đi kèm với controller đó sẽ xác định
phương thức action của lớp controller đó để gọi, và rồi gọi
phương thức đó.
Thực thi kết
quả
Một phương thức hành động cụ thể nhận dữ liệu từ người dùng
sẽ chuẩn bị dữ liệu trả về thích hợp. Những kiểu dữ liệu trả về
được xây dựng sẵn có thể được trả về gồm có: ViewResult
(Thể hiện một View và là dữ liệu thường được trả về nhất),
RedirectToRouteResult, RedirectResult….
Hình 2.2 – Mô hình xử lí yêu cầu từ ứng dụng ASP.NET MVC
18
2. LINQ TO SQL
2.1. Linq to SQL là gì?
LINQ to SQL là một phiên bản hiện thực hóa của O/RM (object relational mapping) có bên trong .NET Framework bản “Orcas” (nay là .NET 3.5), nó cho phép bạn mô hình hóa một cơ sở dữ liệu dùng các lớp .NET. Sau đó bạn có thể truy vấn cơ sở dữ liệu dùng LINQ, cũng như cập nhật/thêm/xóa dữ liệu từ đó. LINQ to SQL hỗ trợ đầy đủ transaction, view và các thủ tục lưu. Nó cũng cung cấp
một cách dễ dàng để thêm khả năng kiểm tra tính hợp lệ của dữ liệu và các quy
tắc vào trong mô hình dữ liệu của bạn.
2.2. Mô hình hóa CSDL dùng Linq to SQL
Visual Studio “Orcas” đã tích hợp thêm một trình thiết kế LINQ to SQL như một công cụ dễ dàng cho việc mô hình hóa một cách trực quan các CSDL dùng LINQ to SQL. Ta sẽ xem xét cách dùng trình thiết kế này. Bằng cách dùng trình thiết kế LINQ to SQL, ta tạo một mô hình cho CSDL mẫu
“Northwind” giống như dưới đây:
Hình 2.3 – Mô hình LINQ to SQL
19
Mô hình LINQ to SQL ở trên định nghĩa bốn lớp thực thể: Product, Category, Order và OrderDetail. Các thuộc tính của mỗi lớp ánh xạ vào các cột của bảng tương ứng trong CSDL. Mỗi thể hiện của một lớp biểu diễn một dòng trong bảng dữ liệu. Các mũi tên giữa bốn lớp thực thể trên biểu diễn quan hệ giữa các thực thể khác nhau, chúng được tạo ra dựa trên các mối quan hệ khóa chính/khóa ngoại trong CSDL. Hướng của mũi tên chỉ ra mối quan hệ là một – một hay một – nhiều. Các thuộc tính tương ứng sẽ được thêm vào các lớp thực thể trong các trường hợp này. Lấy ví dụ, lớp Category ở trên có một mối quan hệ một nhiều với lớp Product, điều này có nghĩa nó sẽ có một thuộc tính “Categories” là một tập hợp các đối tượng Product trong Category này. Lớp Product cũng sẽ có một thuộc tính “Category” chỉ đến đối tượng ”Category” chứa Product này bên trong. Bảng các phương thức bên tay phải bên trong trình thiết kế LINQ to SQL ở trên
chứa một danh sách các thủ tục lưu để tương tác với mô hình dữ liệu của chúng
ta. Trong ví dụ trên tôi đã thêm một thủ tục có tên “GetProductsByCategory”. Nó
nhận vào một categoryID và trả về một chuỗi các Product. Chúng ta sẽ xem bằng
cách nào có thể gọi được thủ tục này trong một đoạn code bên dưới.
2.3. Tìm hiểu lớp DataContext
Khi ta bấm nút “Save” bên trong màn hình thiết kế LINQ to SQL, Visual Studio sẽ lưu các lớp .NET biểu diễn các thực thể và quan hệ bên trong CSDL mà chúng ta vừa mô hình hóa. Cứ mỗi một tệp LINQ to SQL chúng ta thêm vào solution, một lớp DataContext sẽ được tạo ra, nó sẽ được dùng khi cần truy vấn hay cập nhật lại các thay đổi. Lớp DataContext được tạo sẽ có các thuộc tính để biểu diễn mỗi bảng được mô hình hóa từ CSDL, cũng như các phương thức cho mỗi thủ tục lưu mà chúng ta đã thêm vào. Lấy ví dụ, dưới đây là lớp NorthwindDataContext được sinh ra dựa trên mô hình
chúng ta tạo ra ở trên:
20
Hình 2.4 – Mô hình NorthwindDataContext
2.4. Các ví dụ Linq to SQL
Lấy sản phẩm từ CSDL:
Đoạn lệnh dưới đây dùng cú pháp LINQ để lấy về một chuỗi IEnumerable các đối
tượng Product. Các sản phẩm lấy ra phải thuộc phân loại “Beverages”:
Hình 2.5 – Hình minh họa lấy sản phẩm từ CSDL với LINQ
Cập nhật một sản phẩm trong CSDL:
Đoạn lệnh dưới đây cho thấy cách lấy một sản phẩm,cập nhật giá tiền và lưu lại
vào CSDL.
21
Hình 2.6 – Hình minh họa cập nhật sản phẩm từ CSDL với LINQ
Chèn thêm một phân loại mới và 2 sản phẩm vào CSDL:
Đoạn mã dưới đây biểu diễn cách tạo một phân loại mới, và tạo hai sản phẩm mới,
đưa chúng vào trong phân loại đã tạo rồi đưa vào CSDL.
Chú ý rằng ta không cần phải quản lý các mối quan hệ khóa chính/khóa ngoại,
thay vào đó, chỉ đơn giản thêm các đối tượng Product vào tập hợp Products của
đối tượng category, và rồi thêm đối tượng category vào tập hợp Categories của
DataContext, LINQ to SQL sẽ tự thiết lập các giá trị khóa chính/khóa ngoại một
cách thích hợp.
Hình 2.7 – Chèn sản phẩm mới vào CSDL
Xóa các sản phẩm:
Đoạn mã sau sẽ biểu diễn cách xóa tất cả các sản phẩm Toy khỏi CSDL:
Hình 2.8 – Xóa một sản phẩm
Gọi một thủ tục:
Đoạn mã dưới đây biểu diễn cách lấy các thực thể Product mà không dùng cú
pháp của LINQ, mà gọi đến thủ tục “GetProductsByCategory” chúng ta đã thêm
22
vào trước đây. Nhớ rằng một khi đã lấy về kết quả, ta có thể cập nhật/xóa và sau
đó gọi db.SubmitChanges() để cập nhật các thay đổi trở lại CSDL.
Hình 2.9 – Gọi một thủ tục
Lấy các sản phẩm và phân trang:
Đoạn mã dưới đây biểu diễn cách phân trang trên máy chủ như một phần của câu
truy vấn LINQ. Bằng cách dùng các toán tử Skip() và Take(), chúng ta sẽ chỉ trả về
10 dòng từ CSDL – bắt đầu từ dòng 200.
Hình 2.10 – Lấy các sản phẩm và phân trang
2.5. Tổng kết
LINQ to SQL cung cấp một cách hay, rõ ràng để mô hình hóa lớp dữ liệu trong
ứng dụng của bạn. Một khi đã định nghĩa mô hình dữ liệu, bạn có thể dễ dàng
thực hiện các câu truy vấn cũng như cập nhật, xóa, sửa dữ liệu một cách hiệu
quả.
23
CHƢƠNG 3: PHÂN TÍCH THIẾT KẾ ỨNG DỤNG
1. ĐẶC TẢ CÁC CHỨC NĂNG HỆ THỐNG
1.1. Thiết kế hệ thống
Tham khảo và mô phỏng lại hầu hết các chức năng của các hệ thống như
http://www.bestbuy.com/site/index.jsp,http://www.walmart.com/
Trong quá trình thiết kế hệ thống ta sẽ lần lượt làm rõ các module của hệ thống và
mối quan hệ giữa các module. Quá trình thiết kế của hầu hết các module có các
bước như nhau bao gồm tổng quan về module, sơ đồ chức năng,bảng DL của
module, lớp thực thể dữ liệu,bảng lớp điều khiển,bảng liệt kê giao diện người dùng
của module, thiết lập bảng định tuyến, thiết lập cấu hình cần thiết.
1.1.1. Các module của hệ thống
Hệ thống siêu thị bán hàng trực tuyến về cơ bản hỗ trợ người dùng duyệt,mua và
thanh toán hàng. Bên cạnh đó người dùng với vai trò quản trị hệ thống, nhân viên
siêu thị có thể quản lí được hàng hóa (xem, thêm,xóa,sửa), quản lí thông tin đặt
mua, thanh toán, vận chuyển hàng. Ngoài ra hệ thống còn có thêm một số module
như module diễn đàn, module bài báo tin tức, module lấy ý kiến khách hàng,
module gửi thư từ hệ thống, module định vị siêu thị, module quốc tế hóa.
Hình 3.1 – Các module của hệ thống siêu thị trực tuyến
Hệ thống Global Store
Module quản lí thành viên và
hồ sơ
Module lấy ý kiến khách hàng
Module thƣơng mại
Module gửi thƣ
Module diễn đàn
Module tìm kiếm siêu thị
Module địa phƣơng hóa
Module kiểm thử
Module bài báo, tin tức, blog
TIÊU ĐỀ CHƢƠNG 3
24
1.1.2. Mối quan hệ giữa các module
Tất cả các module của hệ thống là độc lập với nhau ngoại trừ việc chúng sử dụng
module thành viên và hồ sơ cho việc xác thực vai trò người dùng và cho phép sử
dụng chức năng cụ thể của một module ứng với vai trò đó.
Việc tách biệt các module như vậy giúp hệ thống linh hoạt hơn khi nâng cấp, hay
có sửa đổi.
1.2. Đặc tả sơ lƣợc các module
1.2.1. Module hồ sơ và thành viên
Module này với người dùng là khách hàng thì họ có thể sử dụng để tạo tài khoản, đăng nhập, đăng xuất,quản lí hồ sơ còn đối với người quản trị hệ thống thì họ còn dùng vào việc quản lí vai trò người dùng, xóa, tạo vai trò, quản lí người dùng.
1.2.2. Module lấy ý kiến khách hàng
Với module lấy ý kiến khách hàng với vai trò admin người dùng có thể tạo các câu hỏi để lấy ý kiến khách hàng qua đó nắm bắt được các thông tin cần thiết để phát triển việc kinh doanh của công ty, hay phát triển hệ thống để phục vụ khách hàng tốt hơn. Người dùng là khách hàng có thể đóng góp ý kiến của mình để được phục vụ tốt hơn.
1.2.3. Module thƣơng mại
Sử dụng module thương mại người dùng là khách hàng có thể xem, chọn mua sản phẩm, thanh toán qua paypal. Đối với người dùng có vai trò là quản lí siêu thị (store keeper) – người quản lí sẽ quản lí gian hàng mà họ tạo ra như quản lí sản phẩm, quản lí đơn đặt hàng..
1.2.4. Module gửi thƣ
Khi sử dụng module này người dùng là khách hàng có thể đăng kí nhận thư của hệ thống thông qua mục nhận thư trong hồ sơ. Còn với người dùng có vai trò admin thì họ còn có thể tạo thư và gửi thư tới toàn bộ các thành viên có đăng kí nhận thư từ hệ thống.
1.2.5. Module diễn đàn
Người dùng nạc danh có thể duyệt xem bài bình luận trong các diễn đàn, tuy nhiên để gửi bài hay bình luận họ phải đăng nhập vào hệ thống. Chức năng quản lí diễn đàn, quản lí các bài thỏa luận dành cho người dùng có vai trò là editor. (biên tập)
1.2.6. Module tìm kiếm siêu thị
Người dùng có thể sử dụng module này để tìm kiếm các siêu thị gần nơi mình ở theo khoảng cách và tìm đường đi đến một siêu thị nào đó.
TIÊU ĐỀ CHƢƠNG 3
25
Với người dùng có vai trò quản trị thì còn có thêm chức năng thêm vị trí siêu thị mới vào hệ thống.
1.2.7. Module bài báo, tin tức, và blog
Người dùng sử dụng module này có thể xem toàn bộ các bài báo, xem theo đầu mục, xem chi tiết bài báo, viết lời bình luận và cho điểm bài báo. Người dùng với vai trò là biên tập có thêm các chức năng như quản lí các đầu mục báo, tạo đầu mục mới, xóa đầu mục đang có trong hệ thống. Quản lí các bài báo trong đó có xem các bài báo, chỉnh sửa, xóa, tạo bài báo mới.
1.2.8. Module quốc tế hóa
Module này cho người dùng biết thông tin địa phương của người dùng qua thông tin ở hồ sơ đăng kí như thời gian, tiền dùng tại địa phương (chẳng hạn như ở Mĩ là USD, ở Việt nam là VND)
1.2.9. Module kiểm thử
Ở module này với phạm vi thực hiện chuyên đề tốt nghiệp tôi chỉ thực hiện kiểm
thử đơn giản với hai module khác trong hệ thống là module bài báo, tin tức, blog
và module gửi thư.
TIÊU ĐỀ CHƢƠNG 3
26
uc Membership and Profile Management
Administrator
(from Actors)
Login
Register Account
Logout
Manage Profile
Create Role
Manage User
Delete User
Change Password
Delete Role
Forgot Password
Edit User
Anonymous User
(from Actors)
Registered User
(from Actors)
Manage Role
«include»
«include»
«include»
«include»
2. MODULE HỒ SƠ NGƢỜI DÙNG VÀ THÀNH VIÊN
2.1. Tổng quan về module
Module sẽ sử dụng hệ thống quản lí thành viên xây dựng sẵn của ASP.NET 2.0 cung cấp bởi Microsoft cho phép người dùng thực hiện các chức năng như đăng kí tài khoản, đăng nhập, thay đổi mật khẩu, lấy lại mật khẩu, nhập thông tin hồ sơ, cho phép nhà quản trị hệ thống đăng nhập vào hệ thống, quản lí quyền, quản lí người dùng (trong đó có xem toàn bộ người dùng trong hệ thống, tìm người dùng và xóa người dùng, thay đổi vai trò người dùng... Trước khi lưu trữ mật khẩu người dùng vào CSDL để bảo mật tất cả các mật khẩu sẽ được thay đổi thông qua hàm băm bằng cách thiết lập cách lưu trữ mật khẩu sử dụng hàm băm ở tệp web.config trong mục. Ghi chú: Module này được sử dụng bởi hầu hết các module khác như module cộng đồng, module tin tức bài báo, hay module đánh giá và cho điểm các luồng thảo luận trong diễn đàn,..
2.2. Sơ đồ chức năng
Hình 3.2 – Sơ đồ tổng quan chức năng của module theo mô hình UC
TIÊU ĐỀ CHƢƠNG 3
27
2.3. Các bảng DL của module
2.3.1. Tạo các bảng DL từ module hồ sơ, ngƣời dùng trong ASP.NET 2.0
Tạo mới CSDL GlobalStore với SQL Server Management Studio, rồi chạy tệp aspnet_regsql trong thư mục C:\Windows\Microsoft.NET\Framework\v2.0.50727 để tạo các bảng dành cho module mà ASP.NET phiên bản 2.0 đã cung cấp sẵn như hình vẽ. Đây thực chất là việc chạy một đoạn script để tạo CSDL cho việc quản lí hồ sơ và người dùng
Hình 3.3 – Tạo CSDL cho module hồ sơ và người dùng
2.3.2. Tạo bảng language
Bảng language để lưu thông tin ngôn ngữ trong hồ sơ người dùng gồm 2 cột LanguageID (mã ngôn ngữ ), và LanguageName (tên ngôn ngữ) như sau:
Hình 3.4 Bảng Langugage
TIÊU ĐỀ CHƢƠNG 3
28
2.3. Cấu hình tệp web.config cho membership, role và profile:
Để có thể sử dụng module quản lí hồ sơ và thành viên dựng sẵn trong ASP.NET 2.0 ta còn phải thiết lập cấu hình cho module trong thẻ <system.web> của tệp web.config : Mục membership: <membership> <providers> <clear/>
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider,System.Web, Version=2.0.0.0, Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="GlobalStoreConnectionString" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="GlobalStore" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
passwordStrengthRegularExpression=""/> </providers> </membership>
Qua nội dung phần config có thể thấy việc cấu hình để sử dụng module Membership của ASP.NET 2.0 ASPNET. Trong đó mật khẩu trước khi lưu xuống CSDL được thay đổi thông qua hàm băm passwordFormat="Hashed",…
Mục Role: <roleManager enabled="true"> <providers> <clear/>
<add connectionStringName="GlobalStoreConnectionString" applicationName="GlobalStore"name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider,System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/> </providers> </roleManager> Mục Profile:
ASP.NET cung cấp một cơ chế có sẵn để quản lí hồ sơ người dùng. Ta chỉ cần khai báo các thông tin cần thiết lưu trong hồ sơ. Khi ứng dụng chạy thông tin thuộc tính của hồ sơ sẽ được thêm vào lớp Page.
TIÊU ĐỀ CHƢƠNG 3
29
<profile> <properties> <add name="Subscription" type="String"/> <add name="Language" type="String"/> <add name="ShoppingCart" type="GlobalStore.Models.ShoppingCart" serializeAs="Binary" allowAnonymous="true"/> <group name="PersonalInformation"> <add name="FirstName" type="String"/> <add name="LastName" type="String"/> <add name="Gender" type="String"/> <add name="BirthDate" type="DateTime"/> <add name="Occupation" type="String"/> <add name="Website" type="String"/> </group> <group name="ContactInformation"> <add name="Street" type="String"/> <add name="City" type="String"/> <add name="State" type="String"/> <add name="ZipCode" type="String"/> <add name="Country" type="String"/> </group> </properties> </profile>
2.4. Models
2.4.1. Lớp UserInformation
Hệ thống có một số trang mà người dùng sử dụng liên quan với việc đăng nhập và quản lí tài khoản của họ. Để truyền dữ liệu mà không phải tạo một số lượng lớn biến cho mỗi phương trức hành động ta tạo lớp UserInformation để truyền vào các phương thức hành động dưới dạng tham số đầu vào xem danh sách các phương thức hành động trong lớp controller của module.
Hình 3.5 Sơ đồ lớp UserInformation
TIÊU ĐỀ CHƢƠNG 3
30
2.4.2. Lớp ProfileInformation
Lớp này được dùng để quản lí thông tin hồ sơ đồng thời hỗ trợ để tạo các chọn lựa dropdown trong phần điền thông tin trên trang quản lí hồ sơ như nghề nghiệp, nước hiện tại ở, ngôn ngữ, … Các thuộc tính của lớp tương ứng với các thuộc tính khai báo trong web.config và các phương thức tạo dropdown tương ứng cho phần quản lí hồ sơ người dùng gồm có dropdown cho các mục:
Country.
Gender.
Language.
Occupation.
Subscription.
Hình 3.6 Sơ đồ lớp ProfileInformation
2.5. Controllers
Tương ứng với các chức năng của module ta có các phương thức hành động cho controller của module này như sau:
Phương thức hành động Bảo mật
Các tham số
Logout ---- ----
Login ---- ----
Login_OnPost ---- string userName, string password, bool persistent, string returnUrl
TIÊU ĐỀ CHƢƠNG 3
31
ForgotPassword ---- ----
ForgotPassword_OnPost ---- string userName, string secretAnswer
Register ---- ----
Register_OnPost ---- UserInformation userInformation
ChangePassword ---- string resetPassword
ChangePassword_OnPost ---- UserInformation userInformation
UserProfile ---- ----
UserProfile_OnPost ---- ProfileInformation profileInformation
GetErrorMessage ---- MembershipCreateStatus membershipCreateStatus
ManageUser Admin string searchType, string searchInput
DeleteUser Admin string id
ManageRole Admin ----
CreateRole Admin string newRole
DeleteRole Admin string id
EditUser Admin string id
EditUser_OnPost Admin string id, bool approved
2.6. Views
Module này tạo thành từ nhiều view trong đó có những views được sử dụng bởi người dùng không có vai trò quản trị và những views dành cho người dùng có vai trò quản trị. Dưới đây là thể hiện cụ thể của các views trong module này:
Liên kết tới trang đăng nhập được hiển thị trên cùng phía bên phải ngay sau mục tóm lược việc mua hàng – shopping summary của mỗi trang bất kể khi nào mà người dùng là nạc danh. Sau khi người dùng đăng nhập vào hệ thống thì liên kết này sẽ được ẩn đi thay vào đó là các chức năng mà người dùng đã đăng nhập có đó là đăng xuất, quản lí hồ sơ, và thay đổi mật khẩu. View đăng kí cho phép người dùng mới đăng kí tài khoản với hệ thống. Trong quá trình đăng kí người dùng mới sẽ tạo hồ sơ với các thông tin : FirstName (string), LastName (string), Gender (string), BirthDate (datetime), Occupation (sring), và website (string). Nhóm thông tin về địa chỉ trong hồ sơ có các thuộc tính phụ trợ sau: Street, PostCode, City, State và Country tất cả đều có kiểu string. Nhóm cuối cùng về Preferences có các thuộc tính Cultrure và Newsletter. View quên mật khẩu cho phép người dùng thay đổi mật khẩu bằng việc trả lời một câu hỏi bảo mật sau khi đã điền đúng tên người dùng vào ô người dùng. Sau khi trả lời đúng câu hỏi bảo mật lúc này người dùng sẽ được phép tạo mật khẩu mới và dùng tài khoản của mình với mật khẩu mới này. Trang quản lí hồ sơ người dùng sẽ chỉ truy cập được bởi người dùng. Nó cho phép người dùng thay đổi các thông tin trên hồ sơ mà họ thiết lập từ lúc họ tạo tài khoản. Các trang để quản lí người dùng dành cho người dùng có vai trò quản trị như view dành cho quản lí người dùng giúp nhà quản trị tìm kiếm người dùng hoặc bằng tên hoặc bằng địa chỉ, view dành cho việc chỉnh sửa thông tin liên quan tới người dùng
TIÊU ĐỀ CHƢƠNG 3
32
sẽ hiển thị các chi tiết thêm về người dùng và cho phép nhà quản trị để hoặc không để tài khoản đó hoạt động, hay thay đổi cập nhật vai trò người dùng. Ngoài ra còn có view dành cho việc quản lí vai trò được sử dụng để tạo, xóa các vai trò trong hệ thống. Như vậy ta có các views của module này
Tên trang Đặc tả Đường dẫn ảo
ChangePassword.aspx Trang này dùng thay đổi mật khẩu của người dùng
user/changepassword/
EditUser.aspx Trang này cho phép thay đổi quyền người dùng, ngăn hoạt động của tài khoản
user/edituser/{id}
ForgotPassword.aspx Trong trường hợp người dùng quên mật khẩu
user/forgotpassword
Login.aspx Trang đăng nhập user /login
ManageRole.aspx Trang dành cho nhà quản trị tạo / xóa các vai trò áp dụng cho hệ thống
user/managerole
ManageUser.aspx Trang dành cho nhà quản trị xem danh sách người dùng, qua đó xóa người dùng
user/manageruser
Register.aspx Trang này cho phép người dùng nạc danh trở thành người dùng đã đăng kí bằng việc điền thông tin người dùng và đăng kí
user/register
UserProfile.aspx Trang hồ sơ dành cho người dùng thay đổi thông tin hồ sơ của mình
user/profile
Ghi chú: Đường dẫn ảo phục vụ cho việc xây dựng định tuyến cho bảng định tuyến
2.7. Sử dụng Javascript
Trong view của trang quản lí người dùng (ManageUser.aspx) việc xóa người dùng sẽ được xử lí bằng kĩ thuật Ajax với đoạn mã javascript trong tệp manage-user.js tệp này nằm trong thư mục /content/scripts/. Đoạn mã lệnh xóa người dùng sẽ được sử dụng để triệu gọi phương thức xóa người dùng DeleteUser trong UserController. Nội dung của đoạn lệnh: $(".delete-user-button").click(function() { var userId = $(this).attr("meta:id"); $.post( "/User/DeleteUser", { id: userId }, function(data) {
TIÊU ĐỀ CHƢƠNG 3
33
$("#user-" + data.object.id).remove(); }, "json" ); return false; }); Tương tự vậy thì trong view của trang quản lí vai trò (ManageRole.aspx) chức năng xóa vai trò cũng được xử lí bằng kĩ thuật này với đoạn mã xóa nằm trong tệp manage-role.js thuộc thư mục scripts với đường dẫn /content/scripts/manage-role.js.
2.8. Cấu hình định tuyến
Sử dụng định tuyến mặc định routes.MapRoute( "Default", "{controller}/{action}", new { controller = (string)null, action = (string)null} );
TIÊU ĐỀ CHƢƠNG 3
34
3. MODULE THƢƠNG MẠI
3.1. Tổng quan về module
Chuỗi các siêu thị của công ty Golbal Store Pte. đều có chung cấu trúc về các gian hàng như thiết bị âm thanh, đồ cho ô tô và thiết bị định vị, máy tính, điện thoại cố định và đồ văn phòng, âm nhạc, phim và sách truyện. Tuy nhiên có một số gian hàng trống tạo không gian mở cho người dùng thuê. Khách hàng khi thuê gian hàng trống phải đăng kí tài khoản, những khách hàng này có toàn quyền quản lí gian hàng của mình.
Khách hàng khi mua hàng trực tuyến với Global Store Pte họ có thể duyệt các gian hàng của siêu thị - xem danh sách các gian hàng. Danh sách các gian hàng sẽ có tên gian hàng và đặc tả về gian hàng. Khi khách hàng chọn xem một gian hàng hệ thống sẽ hiển thị danh sách các sản phầm có trong gian hàng đó. Danh sách các sản phẩm với mỗi sản phẩm sẽ có kèm theo thông tin vắn tắt về sản phẩm (tên sản phẩm, thông tin vắn tắt về sản phẩm, giá bán, giá bán giảm giá nếu có,số lượng sản phẩm còn trong cửa hàng) ,nút AddToCart cho phép người dùng chọn đưa sản phẩm vào giỏ hàng và một liên kết cho phép xem chi tiết sản phẩm, hình ảnh sản phẩm thường là nhỏ hơn so với hình ảnh trong mục xem chi tiết. Khi khách hàng chọn xem chi tiết sản phẩm thì sẽ được chuyển đến view dành cho xem chi tiết sản phẩm. Trên view này người dùng sẽ thấy được thông tin chi tiết sản phẩm như tên sản phẩm, số hiệu sản phẩm, hình ảnh sản phẩm to hơn nếu có, thông tin chi tiết về sản phẩm nếu có, giá bán, giá bán đã có khuyến mãi giảm giá nếu có, số lượng hàng có trong kho, ô chọn số lượng mua (khách hàng hoàn toàn có thể chọn mua với số lượng mong muốn vì siêu thị có thể điều động hàng), cuối cùng là nút AddtoCart. Nếu người dùng chọn mua sản phẩm thì sẽ thấy được một hoạt cảnh dạng hình ảnh sản phẩm bay vào giỏ hàng. Ở đây là sản phẩm sẽ bay vào vị trí có thông tin tóm tắt mua hàng các thông tin vắn tắt mua hàng sẽ được cập nhật đó là số tiền phải trả và số mặt hàng trong giỏ hàng Trong phần thông tin vắn tắt giỏ hàng cũng có liên kết check out đưa người dùng tới trang thông tin mua sắm chi tiết để qua đó người dùng có thể kiểm tra chi tiết hơn những gì mình đã mua. Khách hàng khi chọn liên kết check out ở mục thông tin mua sắm vắn tắt sẽ được chuyển tới view thông tin chi tiết mua sắm của khác hàng. Người dùng với vai trò quản lí siêu thị - Store Keeper khi đăng nhập vào hệ thống có thể quản lí gian hàng mà mình tạo ra như thêm mới các sản phẩm vào gian hàng, xóa sản phẩm của gian hàng, … Ngoài ra người dùng này còn có thể quản lí cách thức giao hàng như thêm và xóa cách thức giao hàng, quản lí các đơn đặt hàng như xem danh sách các đơn đặt hàng, xem chi tiết một đơn đặt hàng. Ghi chú: Với phần mua hàng thì không bắt buộc người dùng phải có tài khoản và đăng nhập vào hệ thống tránh trường hợp đôi khi người dùng không muốn mất thời gian đăng kí tài khoản
TIÊU ĐỀ CHƢƠNG 3
35
uc ECommerce
View Shopping
Basket
User
(from Actors)
Add To Shopping
Basket
Remov e Item from
Shopping Basket
Checkout
View All Products in
Category
Login not required.
View Prouduct's
Detail
Edit Product
Manage Shipping
Add New Shipping
Option
Manage Oder
Manage Product
Delete Product
View Products by
Category
Create Prouct
View Oders detail
Delete Shipping
Option
Login required. User
can be either admin or
store worker
Manage DepartmentsRemov e Category
Edit Category
Paypal Use Cases
Filling Shipping
DetailsShipping Use Cases
Create Department
StoreKeeper
(from Actors)
«include»
«include»
«include»
«include»
«include»
«include»
«include»
«include»
«include»
«include»
3.2. Sơ đồ chức năng
Hình 3.7 Sơ đồ chức năng theo mô hình UC của module thương mại
3.3. Tìm hiểu, sử dụng Paypal cho chức năng thanh toán
Paypal có 3 loại tài khoản sử dụng tiền thật cho khách hàng, những người buôn
bán trực tuyến và các doanh nghiệp và 1 loại tài khoản dùng tiền ảo và dành cho
các nhà phát triển ứng dụng để thử nghiệm ứng dụng của mình. Ở đây ta quan
tâm tới loại hình tài khoản thứ tư : Sandbox Account vì ứng dụng chỉ ở dạng thử
nghiệm.
3.3.1. Tạo tài khoản ảo cho mục đích kiểm thử
Sandbox Account: Là tài khoản có thể ở dạng dùng cho doanh nghiệp, hoặc cho
người buôn bán trực tuyến hay cho cá nhân tuy nhiên lại chỉ được tạo ra và sử
dụng được trong môi trường thử nghiệm và dĩ nhiên chỉ dùng cho mục đích thử
TIÊU ĐỀ CHƢƠNG 3
36
nghiệm mà thôi. Để kiểm nghiệm chỉ cần 2 tài khoản : 1 doanh nghiệp, 1 cá nhân
là đủ. Trước khi tạo 2 tài khoản này ta cần tạo tài khoản dành cho nhà phát triển
ứng dụng (Dùng Paypal cho website thương mại của mình) sau đó với tài khoản
này có thể tạo bao nhiêu tài khoản Sandbox tùy theo ý muốn. Tạo tài khoản dành
cho lập trình viên tại địa chỉ sau: https://developer.paypal.com/
Sau đó tạo 2 tài khoản Sandbox dành cho người mua và bán như hình vẽ sau
Hình 3.8 – Các tài khoản kiểm thử với sandbox Như vậy là ta đã có tài khoản để thực hiện các giao dịch ảo cho mục đích kiểm thử với website thương mại của mình.
3.3.2. Quá trình thanh toán với Paypal từ website thƣơng mại
Việc tích hợp thanh toán với Paypay cho hệ thống siêu thị trực tuyến là không quá phức tạp chỉ cần tạo ra một form HTML với các tham số tương ứng và điều hướng khách hàng từ website thương mại tới trang thanh toán với paypal. <form id="Paypal" name="Paypal" action="<%= GlobalStoreSection.Current.Commerce.PayPalServer %>" method="post"> <input type="hidden" name="cmd" value="_cart" /> <input type="hidden" name="upload" value="1" />
TIÊU ĐỀ CHƢƠNG 3
37
<input type="hidden" name="business" value="<%= GlobalStoreSection.Current.Commerce.PayPalAccount %>" />
<input type="hidden" name="shipping" value="<%= ViewData.Model.ShippingPrice.ToString("N2") %>" /> <input type="hidden" name="amount" value="<%= ViewData.Model.Total.ToString("N2") %>" /> <% int count = 1; %> <% foreach(ShoppingCartItem shoppingCartItem in ViewData.Model) { %> <%=Html.Hidden("amount_" + count, shoppingCartItem.SalePrice.ToString("N2"))%> <%=Html.Hidden("item_name_" + count, shoppingCartItem.Title) %> <%=Html.Hidden("item_number_" + count, shoppingCartItem.Product.ProductID) %> <%=Html.Hidden("quantity_" + count, shoppingCartItem.Quantity) %> <%count++;%> <% } %> <button type="submit" id="paypal-checkout-button" value="PayPal" >Checkout</button> </form> Đây là bảng các liệt kê các tham số cần biết để xây dựng chức năng thanh toán
Thuộc tính Mô tả
cmd Cho biết ta đang sử dụng trang paypal ở chế độ gì. Ví dụ như khi cmd có giá trị _xclick tức là ta đang sử dụng Paypal ở chế độ thanh toán (Pay now). Như vậy trong hệ thống siêu thị trực tuyến này với chức năng checkout ta sẽ gán giá trị _xclick cho tham số cmd của checkout
upload Với giá trị là 1 cho tham số upload cho biết ta sử dụng giỏ hàng của hệ thống chứ không dùng giỏ hàng tích hợp của Paypal
business Địa chỉ thư xác định tài khoản business với Paypal của ta. Đây chính là tài khoản dùng để nhận thanh toán từ giao dịch của khách hàng. Với hệ thống tài khoản này là : [email protected]
item_name Đây là chuỗi mô tả đơn đặt hàng mà khách hàng sẽ thanh toán ví dụ như Oder #01
item_number Con số hay chuỗi số xác định cho một đơn đặt hàng
amount Số tiền mà khách hàng phải trả theo tiền của một nước nào đó được chỉ định bằng mã tiền (currency_code), định dạng tiền phải ở dạng như sau 33.88
quantity Tổng số sản phẩm đặt mua của một mặt hàng cụ thể
shipping Cước vận chuyển cũng được chỉ định theo tiền của nước được chỉ định ở tham số amount với cùng định dạng tiền như vậy
TIÊU ĐỀ CHƢƠNG 3
38
3.4. Các bảng dữ liệu của module
Module thương mại có tất cả 5 bảng sản phẩm, bảng gian hàng (Deparments), bảng phương thức vận chuyển (ShippingMethods), bảng đơn đặt hàng (Oders), bảng các mặt hàng trong đơn đặt hàng (OderItems). Trong đó quan hệ giữa 2 bảng gian hàng và sản phẩm được thiết lập thông qua khóa ngoại là DepartmentID với updates và deletes là kiểu do đó khi xóa một gian hàng thì các sản phẩm có trong gian hàng cũng bị xóa. Tương tự thì có mối quan hệ giữa bảng đơn đặt hàng và bảng các mặt hàng trong đơn đặt hàng được thiết lập bởi khóa ngoại là OderID với updates và delete cũng là kiểu cascade.
Hình 3.9 Sơ đồ quan hệ các bảng dữ liệu trong module thương mại
3.5. Lớp thiết lập cấu hình cho module thƣơng mại
Lớp CommerceElement này dùng thiết lập các cấu hình thanh toán với Paypal được sử dụng để tạo các thuộc tính sau cho việc thanh toán
Thuộc tính Mô tả
TIÊU ĐỀ CHƢƠNG 3
39
3.6. Model
Model của module này được chia làm 2 phần. Phần thứ 1 là các lớp thực thể LINQ-to-SQL được tạo tự động từ năm bảng DL trên.
Hình 3.10 – Sơ đồ các lớp thực thể LINQ-to-SQL của module
PayPalServer Đây chính là máy chủ Paypal mà khách hàng gửi yêu cầu tới đó có thể là máy chủ Sandbox dành cho thử nghiệm có địa chỉ (https://www.sandbox.paypal.com/cgi-bin/webscr) hoặc là máy chủ thực (https://www.paypal.com/cgi-bin/webscr)
PayPalAccount Đây là ID của PayPal của k hoặc là một địa chỉ thư điện tử tương ứng với tài khoản PayPal. Thư điện tử này cần được xác nhận lại với PayPal trước khi có thể dùng đại diện cho tài khoản đó
PayPalIdentityToken Đây là thẻ token được PayPal sử dụng để xác nhận một tài khoản nào đó. Nó có thể có được thông qua site của Paypal ở mục các tùy chọn trong tài khoản PayPal Vì lí do bảo mật thì token này không được gửi tới chủ tài khoản PayPal tuy nhiên khi chủ tài khoản sử dụng Token này thì nó sẽ xuất hiện ở phía dưới các nút bật tắt kiểu radio của phần truyền dữ liệu thanh toán trên trang tùy chọn phương thức thanh toán.
TIÊU ĐỀ CHƢƠNG 3
40
Phần thứ 2 là các lớp thực thể ta xây dựng thêm hỗ trợ cho việc thực hiện một số chức năng của module ví dụ như phần chức năng với giỏ hàng. Lớp ShoppingCart được sử dụng bởi lớp trừu tượng Profile nhằm duy trì trạng thái giỏ hàng của một người dùng ngay cả khi người dùng này thoát khỏi hệ thống. Ngoài ra còn có lớp ShoppingCartItem và lớp tĩnh CommerceQueries chứa các phương thức mở rộng cho lớp Department, Products, và ShippingMethods
Hình 3.11 – Các lớp xây dựng thêm hỗ trợ cho module
3.7. Controller
Lớp controller xử lí toàn bộ các logic nghiệp vụ ứng với các use case của module và chứa các phương thức hành động như sau
Phương thức hành động Bảo mật Các tham số
Index ---- ----
ViewDepartment ---- int departmentId
ViewProduct ---- int productId
ViewShoppingCart ---- int? shippingMethod
AddShoppingCartItem ---- int productId, int? quantity
DeleteShoppingCartItem ---- int id
CompleteOder ---- string tx, decimal amt
ShoppingSummary ---- ----
ManageStore StoreKeeper ----
ManageDepartment StoreKeeper ----
CreateDepartment StoreKeeper ----
CreateDepartment_OnPost StoreKeeper string title, string imageUrl, string description, int? important
EditDepartment StoreKeeper int departmentId
EditDepartment_OnPost StoreKeeper int id, string title, string imageUrl, string description, int? important
DeleteDepartment StoreKeeper int id
ManageProduct StoreKeeper int id
CreateProduct StoreKeeper int id
CreateProduct_OnPost StoreKeeper int? departmentId, string title, string description, string sku, decimal? unit
TIÊU ĐỀ CHƢƠNG 3
41
Price, int? discountPercentage, int? untisInStock, string smallImageUrl, string fullImageUrl
EditProduct StoreKeeper int productId
EditProduct_OnPost StoreKeeper int? departmentId, string title, string description, string sku, decimal? unit Price, int? discountPercentage, int? untisInStock, string smallImageUrl, string fullImageUrl
DeleteProduct StoreKeeper int id
ManageOders StoreKeeper int id
OderDetails StoreKeeper int id, string trackingId
ManageShipping StoreKeeper int id, string trackingId
CreateShipping StoreKeeper string title, decimal price
DeleteShipping StoreKeeper int id
3.8. View
Đây là một trong số các module có nhiều view nhất trong hệ thống. Gồm có các view dành cho người dùng với vai trò StoreKeeper và các view dành cho người dùng với các vai trò còn lại. Đây là danh sách các view của module
Tên trang Đặc tả Đường dẫn ảo Index.aspx Trang này hiển thị
các gian hàng và đóng vai trò là cổng dành cho việc duyệt các sản phẩm
store
ViewDepartment.aspx Trang này được dùng để hiển thị tất cả các sản phẩm trong một gian hàng
store/deparments/{deparmentId}
ViewProduct.aspx Trang này dùng hiển thị một sản phẩm
store/product/{productId}
ViewShoppingCart.aspx Trang này ngoài việc hiển thị chi tiết việc mua hàng của khách hàng thì nó còn cung cấp một số chức năng như xóa mặt hàng, thực hiện thanh toán với PayPal
store/cart
CompleteOder.aspx Trang này được sử dụng để trở về hệ thống khi khách hàng đã hoàn tất
store/oder/completed
TIÊU ĐỀ CHƢƠNG 3
42
việc thanh toán qua PayPal
TransactionError.aspx Trong trường hợp có lỗi xảy ra trong quá trình giao dịch
Trang này không chứa đường dẫn ảo. Đường dẫn được định nghĩa bởi hệ thống sẽ được sử dụng để đưa ra thông báo lỗi
ManageStore.aspx Trang này hiển thị tất cả các mục trong module cần được quản lí bởi storekeeper
storekeeper/store
ManageDepartment.aspx Trang này hiển thị tất cả các gian hàng mà storekeeper tạo ra, cho phép storekeeper này có thể xóa, hay thực hiện những thay đổi
storekeeper/store/departments
CreateDeparment.aspx Trang này cho phép storekeeper tạo mới gian hàng và thay đổi lại thông tin về gian hàng
storekeeper/store/departments/create storekeeper/store/departments/edit/ {departmentId}
ManageProducts.aspx Trang này storekeeper dùng để thêm sản phẩm mới, thay đổi lại thông tin sản phẩm hiện có
storekeeper/store/products/create storekeeper/store/products/edit/ {productId}
MangeOder.aspx Trang này liệt kê tất cả các đơn đặt hàng của hệ thống
storekeeper/store/oders
OderDetail.aspx Trang này cho phép storekeeper xem chi tiết của đơn đặt hàng
storekeeper/store/oders/{oderId}
ManageShipping.aspx Trang này hiển thị tất cả các tùy chọn trong phương thức vận chuyển và cho phép storekeeper thêm mới hay xóa phương thức vận chuyển
storekeeper/store/shipping
TIÊU ĐỀ CHƢƠNG 3
43
3.9. Sử dụng JavaScript
Mã lệnh javascript xử lí các sự kiện bất đồng bộ dành cho module này nằm trong các tệp commerece.js, manage-product.js, manage-deparment.js manage-department.js được sử dụng để đảm bảo các trường trong form quản lí gian hàng có được sinh ra như yêu cầu hay không: $("#title").focus(function () { ShowMessage(this, "Enter the title for your department."); }); $("#importance").focus(function() { ShowMessage(this, "(optional) Enter the order of importance that you want the departments shown in."); }); $("#imageUrl").focus(function() { ShowMessage(this, "The relative web path of an image you want to be shown with products in this department."); }); $("#description").focus(function() { ShowMessage(this, "Enter a short description of the department to display to your users."); }); function ValidateTitle() { return VerifyRequiredField("#title", "required"); } function ValidateImageUrl() { return VerifyRequiredField("#imageUrl", "required"); } function ValidateDescription() { return VerifyRequiredField("#description", "required"); } function ValidateDepartment() { var validTitle = ValidateTitle(); var validImage = ValidateImageUrl(); var validDescription = ValidateDescription(); return validTitle && validImage && validDescription; } $("form.department-create").validate(ValidateDepartment); Tương tự thì tệp manage-product được sử dụng để đảm bảo các trường thông tin trong form tạo sản phẩm được điền vào đúng theo yêu cầu .. /***************************************************************** Product ******************************************************************/
TIÊU ĐỀ CHƢƠNG 3
44
$("#title").focus(function() { ShowMessage(this, "Enter your product name here."); }); $("#sku").focus(function() { ShowMessage(this, "Enter your SKU number here."); }); $("#unitPrice").focus(function() { ShowMessage(this, "Enter the unit price of this product."); }); $("#discountPercentage").focus(function() { ShowMessage(this, "Enter the percent off you want to give for this product."); }); $("#unitsInStock").focus(function() { ShowMessage(this, "Total number of units of this product you have in stock."); }); $("#smallImageURL").focus(function() { ShowMessage(this, "The url to the thumbnail for this product."); }); $("#fullImageURL").focus(function() { ShowMessage(this, "The url to full sized image of this product."); }); function ValidateTitle() { return VerifyRequiredField("#title", "required"); } function ValidateDescription() { return VerifyRequiredField("#description", "required"); } function ValidateProduct() { return ValidateTitle() && ValidateDescription(); } $("form.product-create").validate(ValidateProduct); /*********************************************************************************** * Rich Text Editor ***********************************************************************************/
var bodyEditor; $(document).ready(function() { bodyEditor = new tinymce.Editor("description", __editorConfig); bodyEditor.onChange.add(function(ed) { bodyEditor.save(); }); bodyEditor.onClick.add(function(ed) { ShowMessage("#description", "Enter the description of your product here."); }); bodyEditor.render(); });
// clears the message from the description when another input gets // focus $(":input") .focus(function() { HideMessage("#description"); }) .blur(function() { HideMessage("#description"); });
TIÊU ĐỀ CHƢƠNG 3
45
Trong tệp commerece.js có các đoạn mã lệnh cho cả quản lí gian hàng, quản lí sản phẩm ,… Đoạn code thực hiện xóa gian hàng không tạo ra việc Post back toàn bộ: $(".delete-department-button").click(function() { var departmentId = $(this).attr("meta:id"); $.post( "/Commerce/DeleteDepartment", { id: departmentId }, function(data) { $("#department-" + data.object.id).remove(); $("#admin-" + data.object.id).remove(); $("#spacer-" + data.object.id).remove(); }, "json" ); return false; }); Đoạn code thực hiện việc xóa sản phẩm khỏi gian hàng không tạo ra việc postback toàn bộ: $(".delete-product-button").click(function () { var productID = $(this).attr("meta:id"); $.post( "/Commerce/DeleteProduct", { id: productID }, function (data) { $("#product-" + data.object.id).remove(); $("#admin-" + data.object.id).remove(); $("#spacer-" + data.object.id).remove(); }, "json" ); return false; }); Đoạn code thực hiện việc các phương thức ứng với cách thức vận chuyển (như xóa cách thức vận chuyển, thêm cách thức vận chuyển) mà không tạo ra postback toàn bộ trang ManageShipping.aspx: $(".delete-shipping-method-button").live("click", function() { var shippingMethodId = $(this).attr("meta:id"); $.post( "/Commerce/DeleteShipping", { id: shippingMethodId }, function(data) { $("#shipping-method-" + data.object.id).remove(); },
TIÊU ĐỀ CHƢƠNG 3
46
"json" ); return false; });
$("#add-shipping-method-button").click(function() { var title = $("#title").val(); var price = $("#price").val(); $.post( "/Commerce/CreateShipping", { title: title, price: price }, function(data) { var html = '<tr id="shipping-method-' + data.object.id + '">'; html += '<td align="center">' + title + '</td>'; html += '<td align="center">' + price + '</td>'; html += '<td align="center"><a href="#" class="delete-shipping-method-button" meta:id="' + data.object.id + '"><img border="0" alt="Delete Role" src="/content/images/DeleteSymbol.png" title="Delete Role" align="middle"/></a></td>'; html += '</tr>'; $("#shipping-table tbody").append(html); $("#title").val(""); $("#price").val(""); }, "json" ); return false; }); Đoạn code thực hiện việc xóa sản phẩm khỏi giỏ hàng $(".delete-item-button").click(function () { var productId = $(this).attr("meta:id"); var form = $(this).parent("form"); $.post( "/Commerce/DeleteShoppingCartItem", { id: productId }, function (data) { $("#item-" + data.object.id).remove(); //Reload whole page location.reload(form); }, "json" ); return false; });
TIÊU ĐỀ CHƢƠNG 3
47
3.10. Cấu hình định tuyến
Định tuyến dành cho các view của người dùng có vai trò là storekeeper: routes.MapRoute( "CommerceManageStore", "storekeeper/store", new { controller = "Commerce", action = "ManageStore" } ); routes.MapRoute( "CommerceManageDepartments", "storekeeper/store/departments", new { controller = "Commerce", action = "ManageDepartments" } ); routes.MapRoute( "CommerceCreateDepartment", "storekeeper/store/departments/create", new { controller = "Commerce", action = "CreateDepartment" } ); routes.MapRoute( "CommerceEditDepartment", "storekeeper/store/departments/edit/{departmentId}", new { controller = "Commerce", action = "EditDepartment", departmentId = (int?)null } ); routes.MapRoute( "CommerceManageProducts", "storekeeper/store/products", new { controller = "Commerce", action = "ManageProducts" } ); routes.MapRoute( "CommerceCreateProduct", "storekeeper/store/products/create", new { controller = "Commerce", action = "CreateProduct" } ); routes.MapRoute( "CommerceEditProduct",
TIÊU ĐỀ CHƢƠNG 3
48
"storekeeper/store/products/edit/{productId}", new { controller = "Commerce", action = "EditProduct", productId = (int?)null } ); routes.MapRoute( "CommerceManageOrders", "storekeeper/store/orders", new { controller = "Commerce", action = "ManageOrders" } ); routes.MapRoute( "CommerceOrderDetail", "storekeeper/store/orders/{orderId}", new { controller = "Commerce", action = "OrderDetail", orderId = (int?)null } ); routes.MapRoute( "CommerceManageShipping", "storekeeper/store/shipping", new { controller = "Commerce", action = "ManageShipping" } ); Định tuyến dành cho những người dùng còn lại: routes.MapRoute( "CommerceIndex", "", new { controller = "Commerce", action = "Index" } ); routes.MapRoute( "CommerceDepartment", "store/departments/{departmentId}", new { controller = "Commerce", action = "ViewDepartment", departmentId = (int?)null } ); routes.MapRoute( "CommerceProduct", "store/products/{productId}", new { controller = "Commerce", action = "ViewProduct", productId = (int?)null } ); routes.MapRoute( "CommerceCart", "store/cart",
TIÊU ĐỀ CHƢƠNG 3
49
new { controller = "Commerce", action = "ViewShoppingCart" } ); routes.MapRoute( "CommerceCompleted", "store/order/completed", new { controller = "Commerce", action = "CompleteOrder" } );
TIÊU ĐỀ CHƢƠNG 3
50
4. MODULE GỬI THƢ
4.1. Tổng quan về module
Hệ thống luôn có những nội dung cập nhật mới như bài báo, diễn đàn, thông tin sản phẩm mới … để tạo sự chú ý cho những người dùng là khách hàng thì hệ thống có module gửi thư thông báo khách hàng biết có những thông tin mới đó để rồi khách hàng sẽ quay trở lại sử dụng hệ thống trong trường hợp khách hàng đăng kí nhận thư từ hệ thống.
4.2. Các vấn đề cần quan tâm khi xây dựng module:
Để lưu trữ thông tin đăng kí nhận thư của người dùng ta chỉ cần lưu các thông tin như địa chỉ thư điện tử của người dùng, tên, họ, định dạng thư nhận. Tất cả các thông tin này có trong các bảng của module hồ sơ và thành viên ta hoàn toàn có thể tận dụng. Việc tạo và gửi thư điện tử của người dùng với vai trò là nhà quản trị có thể được xây dựng sử dụng namespace System.Net.Mail (namespace này được định nghĩa trong thư viện System.dll). Các lớp chính cho việc tạo và gửi thư là lớp MailMessage, và lớp SmtpClient cung cấp các phương thức tạo và gửi thư bằng việc kết nối với máy chủ SMTP đã được cấu hình. Với lớp MailMessage ta có thể tạo toàn bộ thông tin đầy đủ của một thư điện tử như sau: // create the message MailMessage mail = new MailMessage(); // set the sender's address and display name mail.From = new MailAddress("[email protected]", "Loc Dang"); // add a first recipient by specifying only her address mail.To.Add("[email protected]"); // add a second recipient by specifying his address and display name mail.To.Add(new MailAddress("[email protected]", "Dan nguyen")); // add a third recipient, but to the CC field this time mail.CC.Add("[email protected]"); // set the mail's subject and HTML body mail.Subject = "Sample Mail"; mail.Body = "Hello, <b>my friend</b>!<br />How are you?"; mail.IsBodyHtml = true; // set the mail’s priority to high mail.Priority = MailPriority.High; // add a couple of attachments mail.Attachments.Add( new Attachment(@"c:\demo.zip", MediaTypeNames.Application.Octet)); mail.Attachments.Add( new Attachment(@"c:\report.xls", MediaTypeNames.Application.Octet));
TIÊU ĐỀ CHƢƠNG 3
51
Khi đối tượng MailMessage đã được tạo ta có thể gửi nó bằng phương thức Send của lớp SmtpClient. SmtpClient smtpClient = new SmtpClient(); smtpClient.Send(mail); Trước khi có thể gọi phương thức Send ta cần thiết lập các thông tin cấu hình cho hệ thống để phương thức này có thể thực hiện được như địa chỉ của máy chủ SMTP (thuộc tính SmtpClient Host), cổng (thuộc tính port) và giấy chứng thực của máy chủ này (thuộc tính credentials), kết nối được mã hóa với SSL (thuộc tính EnableSsl) và thời gian duy trì từ lúc bắt đầu cho tới khi kết thúc của việc gửi thư ( thuộc tính TimeOut, giá trị mặc định là 100 giây). Một thuộc tính quan trọng là DeliveryMethod (đây là thuộc tính liệt kê của kiểu dữ liệu SmtpDeliveryMethod. Nó có thể nhận một trong các giá trị sau: Network: Thư được gửi thông qua kết nối trực tiếp tới một máy chủ Smtp cụ thể PickupDirectoryFromIs: Thư điện tử này được chuẩn bị và tệp thư này được lưu vào thư mục mặc định là <drive>:\Inetpub\mailroot\Queue. IIS sẽ lấy thư này từ hàng đợi thư để gửi. SpecifedPickupDirectory: Các tệp EML với thư điện tử sẽ được gửi được lưu vào thư mục được chỉ định cho thuộc tính này của đối tượng SmtpClient. Thiết lập này sẽ hữu ích khi ta có một ứng dụng ngoài (không phải IIS) xử lí việc chọn thư và gửi Cấu hình phần gửi thư của hệ thống thương mại trực tuyến <system.net> <mailSettings> <smtp deliveryMethod="Network" from="[email protected]">
<network defaultCredentials="true" host="MailServer" port="25"/>
</smtp> </mailSettings> </system.net> Vấn đề thời gian trong xử lí gửi thư có thể là rất lâu khiến người dùng có thể nghĩ hệ thống có lỗi. Việc gửi thư tới hàng ngàn khách hàng đăng kí nhận thư (subscribers) thường phải mất hàng phút trong khi để xử lí một yêu cầu theo tiêu chuẩn chỉ nên trong vài giây. Một giải pháp được đưa ra trong hệ thống đó là khi người dùng nhấn nút submit (tương đương với hành động gửi thư) thì ở phía máy chủ sẽ sinh ra một tiến trình xử lí nhiệm vụ gửi thư mất nhiều thời gian đó ở chế độ nền (backgroudn running mode) và chuyển hướng người dùng về trang quản lí thư. Và ở trang đó người dùng có thể thấy được trạng thái của tất cả các thư đã gửi trong đó có cả thư mới tạo gần nhất và đang được gửi.
TIÊU ĐỀ CHƢƠNG 3
52
Để tránh việc phải có một nút refresh ở trang quản lí thư đó để biết được trạng thái thư mới gửi gần nhất ta sẽ sử dụng JQuery để yêu cầu dư liệu từ lớp điều khiển việc gửi thư (newsletters controller class) và rồi tạo một đối tượng DOM đưa trực tiếp dữ liệu về tình trạng xử lí thư vừa gửi vào trang quản lí thư. Đoạn code javascript đó như sau: $.ajax({ type: "GET", url: "/Newsletter/UpdateStatus", dataType: "html", sucess: function (result) { var domElement = $(result); $("#Newsletter_Status_Table").replaceWith(domElement); } }); Tạo các luồng tiến trình chạy nền – đa tiến trình Các luồng tiến trình chạy nền hay luồng phụ được sử dụng để xử lí các nhiệm vụ cần nhiều thời gian mà không ảnh hưởng tới tiến trình chính. Với ASP.NET ta có thể tạo 250 tiến trình chạy cùng một thời điểm trên một CPU Việc tạo mới một tiến trình không khó tuy nhiên ta phải quan tâm tới việc các tiến trình có thể truy cập cùng lúc tới cùng một không gian nhớ. Để tạo tiến trình ta cần namespace System.Threading trong thư viện mscorlib.dll. Dưới đây là một đoạn code tạo tiến trình phụ chạy nền // create and start a background thread with some input parameters object[] parameters = new object[]{"val1", 10, DateTime.Now}; ParameterizedThreadStart pts = new ParameterizedThreadStart(ExecuteTask); Thread thread = new Thread(pts); thread.Priority = ThreadPriority.BelowNormal; thread.Start(parameters); // main thread goes ahead immediately … // the method run asynchronously by the background thread void ExecuteTask(object data) { // extract the parameters from the input data object object[] parameters = (object[])data; string val1 = (string)parameters[0]; int val2 = (int)parameters[1]; DateTime val3 = (DateTime)parameters[2]; // execute time consuming processing here … }
TIÊU ĐỀ CHƢƠNG 3
53
uc NewsLetters
Registered User
(from Actors)
Administrator
(from Actors)
SubscribeCreate Newsletters
Edit Newsletters Manage Newsletters
Delete Newsletters
«include»
«include»
4.3. Sơ đồ chức năng
Hình 3.12 – Sơ đồ chức năng của module
4.4. Các bảng dữ liệu
Hình 3.13 – Bảng Newsletters Với việc thông tin về người đăng kí nhận thư có thể sử dụng các bảng trong module hồ sơ và thành viên thì với module này chỉ cần một bảng Newsletters thể hiện nội dung thư gửi từ hệ thống, và các thông tin về thư đó.
TIÊU ĐỀ CHƢƠNG 3
54
4.5. Thiết kế lớp cấu hình cho module
Module này sử dụng thành phần <mailsettings> nằm trong <system.net> của tệp web.config. Để cấu hình cho module ta phải xem các thành phần cấu hình của <system.net> /<mailsettings>/<smtp> ở bảng sau
Tiếp đến là cấu hình <system.net>/<mailSettings>/<smtp>/<network>
Cuối cùng ta sẽ tạo thêm phần cấu hình cho module. Phần này thiết lập địa chỉ thư điện tử được sử dụng để gửi thư
4.6. Model
Với module này ta sẽ chỉ cần model là lớp thực thể LINQ-to-SQL dưới đây:
Thuộc tính SMTP Mô tả
DeliveryMethod Thiết lập thuộc tính này với “network” chỉ ra cho ứng dụng biết rằng có một mảy chủ thư điện tử bên ngoài sẽ được sử dụng để gửi thư điện tử. Để gửi được thư thì thành phần của <network> cần được sử dụng gồm có Nơi chứa - Host,Cổng - Port,Tên người dùng - UserName,Mật khẩu- Password, và Chứng thực mặc định - DefaultCredentials.
From Chỉ ra địa chỉ email sẽ được đặt trong mục “From” khi ứng dụng gửi thư đi
ConfigSource Định nghĩa một nguồn ngoài cho các thiết lập cấu hình thư ví dụ như mail.config
Thuộc tính Network Mô tả
DefaultCredentials Một giá trị kiểu bool chỉ ra rằng các chứng thực của ứng dụng có được dùng hay không. Nếu giá trị đó là true thì UserName và Password là không cần
Host Tên của máy chủ thư điện tử
UserName Tên người dùng được sử dụng để đăng nhập vào máy chủ thư điện tử và gửi thư.
Password Mật khẩu được sử dụng để đăng nhập vào máy chủ thư điện tử để gửi thư
Port Cổng sẽ được sử dụng để gửi SMTP
Thuộc tính Newsletters
Mô tả
FromEmail Địa chỉ thư điện tử thực sẽ xuất hiện trong mục “From” trong thư gửi đi ở phần đầu của thư
FromDisplayName Tên hiển thị được sử dụng kèm với thuộc tính FromEmail
TIÊU ĐỀ CHƢƠNG 3
55
Hình 3.14 – Sơ đồ Model Newsletter
4.7. Controller
Với các chức năng của module như sơ đồ chức năng ta có tương ứng các phương thức hành động của controller của module
Phương thức hành động Bảo mật Các tham số
Index ---- ----
ManageNewsletters Editor ----
UpdateStatus Editor ----
CreateNewletters Editor string subject, string body
EditNewsletters Editor int? newsletterId, string subject, string body
RemoveNewsletter Editor int? newsletterId
4.8. View
Từ các phương thức hành động trong phần controller ta cũng có các view dành cho tương ứng. Dưới đây là danh sách các view của module
Tên trang Đặc tả Đường dẫn ảo Index.aspx Trang này được sử
dụng để đăng kí nhận thư từ hệ thống
newsletter
CreateNewsletter.aspx Trang này cho phép người dùng với vai trò là editor tạo hoặc chỉnh sửa thư
editor/newsletter/create editor/newsletter/edit/{newsletterId}
ManageNewsletter.aspx Trang này liệt kê toàn bộ các thư đã gửi trước đó. Editor có thể nhấn vào
editor/newsletter/remove/{newsletterId}
editor/newsletter
TIÊU ĐỀ CHƢƠNG 3
56
thư và xem lại nội dung thư hoặc xóa thư. Trang được cập nhật sau vài giây xử dụng JQuery
4.9. Cấu hình định tuyến
Định tuyến cho trang index của module: routes.MapRoute( "NewsletterIndex", "newsletters", new { controller = "Newsletter", action = "Index" } ); Định tuyến cho các trang dành cho editor: routes.MapRoute( "NewsletterCreate", "editor/newsletters/create", new { controller = "Newsletter", action = "CreateNewsletter" } ); routes.MapRoute( "NewsletterEdit", "editor/newsletters/edit/{newsletterId}", new { controller = "Newsletter", action = "EditNewsletter", newsletterId = (int?)null }, new { newsletterId = "[0-9]+" } ); routes.MapRoute( "NewsletterRemove", "editor/newsletters/remove/{newsletterId}", new { controller = "Newsletter", action = "RemoveNewsletter", newsletterId = (int?)null }, new { newsletterId = "[0-9]+" } ); routes.MapRoute( "NewsletterManage", "admin/newsletters", new { controller = "Newsletter", action = "ManageNewsletters" } );
TIÊU ĐỀ CHƢƠNG 3
57
uc Polls
Editor
(from Actors)Registered User
(from Actors)
View Polls
Vote
Manage PollsRemov e Poll
Edit Poll
Set Archiv e
Set Make Current
Create Poll
Make Poll Question
Make Poll Options
Update Poll
«include»
«include»
«include»
«include»
«include»
«include»
«include»
5. MODULE LẤY Ý KIẾN KHÁCH HÀNG
5.1. Tổng quan về module
Module lấy ý kiến khách hàng gồm các câu hỏi đi kèm với mỗi câu hỏi là các lựa chọn mà khách hàng có thể chọn để trả lời câu hỏi đó. Module được xây dựng vì những lí do như người quản lí hệ thống muốn nắm bắt thị hiếu khách hàng về nhiều vấn đề từ hệ thống cho đến các sản phẩm bán trong siêu thị …Ngoài ra module được xây dựng cũng đem lại cho khách hàng cảm giác họ là một phần của hệ thống và như vậy họ sẽ sử dụng hệ thống thường xuyên hơn. Về mặt chức năng thì module sẽ cho người dùng xem các trưng cầu có trong hệ thống, cho ý kiến. Với người dùng có vai trò là editor có thể quản lí các trưng cầu (chuyển trưng cầu sang trạng thái đã lấy đủ ý kiến, trưng cầu hiện hành và đưa ra trang chủ, chỉnh sửa trưng cầu, xóa trưng cầu), tạo trưng cầu mới.
5.2. Sơ đồ chức năng
Hình 3.15 – Sơ đồ chức năng của module lấy ý kiến người dùng
TIÊU ĐỀ CHƢƠNG 3
58
5.3. Các bảng dữ liệu
Hình 3.16 – Sơ đồ mối quan hệ giữa 2 bảng DL của module lấy ý kiến người dùng Với module này ta cần 2 bảng một bảng là bảng Polls chứa các câu hỏi lấy ý kiến và các thuộc tính của chúng như câu hỏi trưng cầu là hiện hành, hay đã lấy đủ ý kiến … Bảng thứ 2 là bảng PollOptions chứa các thông tin về những chọn lựa cho câu hỏi đặt ra để lấy ý kiến. Mỗi một chọn lựa tương ứng với một câu trả lời được hệ thống tạo sẵn cho người dùng.Quan hệ giữa 2 bảng này được tạo thông qua khóa
ngoại PollD
Hình 3.17 – Sơ đồ thiết kế bảng PollOptions
TIÊU ĐỀ CHƢƠNG 3
59
Hình 3.18 – Sơ đồ thiết kế bảng Polls
5.4. Thiết kế lớp cấu hình cho module
Với module này cần thiết lập một số thông tin cấu hình như thiết lập thuộc tính archived hay public cho một trưng cầu … (khi thiết lập thuộc tính public hay archived cho poll, cho phép hay không cho phép vote nhiều lần..) Bảng dưới đây sẽ là bảng các thuộc tính thuộc lớp PollElement. Lớp này kế thừa từ lớp ConfigurationElement của framework .net mvc. Nó sẽ đọc các thiết lập của thành phần <polls> nằm trong phần thiết lập cầu hình của <GlobalStore> trong tệp web.config
5.5. Model
Model của module này cũng thiết kế theo kiểu mẫu Provider Model của Microsoft như đã trình bày trong phần lựa chọn kiến trúc hệ thống. Có 2 lớp thực thể LINQ-to-SQL được tạo tự động là:
Thuộc tính SMTP Mô tả
VotingLockInterval Một số nguyên cho biết khi nào thì cookie dành cho phần vote của một người dùng cụ thể nào đó hết hiệu lực (tương ứng với số ngày ngăn ngừa việc vote lại)
VotingLockByCookie Một giá trị kiểu bool chỉ ra rằng liệu cookie có được dùng hay không được dùng cho việc nhớ người dùng đã vote hay chưa
VotingLockByIP Một giá trị kiểu bool cho biết liệu địa chỉ IP của người dùng có được giữ trong bộ nhớ để tránh việc một người với cùng 1 địa chỉ IP trong phiên hiện hành vote cho cùng một poll nhiều lần
ArchiveIsPublic Một giá trị kiểu bool được dùng để cho biết liệu các poll đã được thiết lập archive có được xem bởi tất cả mọi người hay không
TIÊU ĐỀ CHƢƠNG 3
60
Hình 3.19 – Sơ đồ lớp PollOption và Poll Lớp tĩnh PollQueries chứa tất cả các truy vấn cần thiết để lấy thông tin từ CSDL cụ thể nó cung cấp các phương thức mở rộng cho module này.
Hình 3.20 – Sơ đồ lớp PollQueries
5.6. Controller
Ứng với các chức năng của module ta có các phương thức hành động trong controller của module ở bảng dưới đây
Phương thức hành động Bảo mật Các tham số
Index ---- bool? archived, int page
ViewPoll ---- int id, string path
Vote ---- int optionId
ManagePolls Editor int page
CreatePoll Editor string question, bool? Current
RemovePoll Editor int? newsletterId
EditPoll Editor int pollId, string question, bool? current, bool? Archived
AddOption Editor int pollId, string text
RemoveOption Editor int optionId
SetCurrent Editor int pollId
SetArchived Editor int pollId, bool archive
TIÊU ĐỀ CHƢƠNG 3
61
5.7. View
Dưới đây là các trang của module dành cho người dùng có vai trò editor và người dùng khác của hệ thống:
Tên trang Đặc tả Đường dẫn ảo
Index.aspx Trang này được sử dụng để xem các poll ở các trạng thái như công khai (public), đã lấy đủ (archived)
/polls /polls/page{page} /polls?archived=true /polls/ page{page}?archived=true
CreatePoll.aspx Trang này cho phép người dùng với vai trò là editor tạo hoặc chỉnh sửa poll
/editor/polls/create / editor /polls/edit/{pollId}
ManagePolls.aspx Trang này liệt kê toàn bộ các poll có trong hệ thống. Editor có thể thêm, chỉnh sửa, xóa các lựa chọn của poll, thiết lập poll hiện hành (set current), và xem poll hiện hành
/ editor /polls / editor /polls/page{page}
RemovePoll.aspx Trang này dùng thực hiện việc xóa poll khỏi hệ thống
/editor/polls/remove/{pollId}
5.8. Sử dụng javascript
Module này sử dụng 2 tệp javascript trong thư mục Content/script là tệp manage-poll.js : /****************************************************************** * Manage ******************************************************************/ $(document).ready(function() { $("#polls :input").hide("fast"); }); $(".set-current").click(function() { var id = $(this).attr("meta:id"); $.post( "/poll/setcurrent", { pollId: id },
TIÊU ĐỀ CHƢƠNG 3
62
function(data) { var poll = $("#set-current-" + data.object.pollId); poll.remove(); }, "json" ); return false; }); $(".set-archived").click(function() { var id = $(this).attr("meta:id"), archived = $(this).hasClass("archived"); $.post( "/poll/setarchived", { pollId: id, archive: !archived }, function(data) { var poll = $("#set-archived-" + data.object.pollId); poll.removeClass("archived"); if (data.object.isArchived) poll.addClass("archived"); poll.text(data.object.isArchived ? "Allow Voting" : "Archive"); }, "json" ); return false; }); /****************************************************************** * Polls ******************************************************************/ $("#question").focus(function() { ShowMessage(this, "Enter the question you would like to ask in the poll."); }); function ValidateQuestion() { return VerifyRequiredField("#question", "required"); } function ValidatePoll() { return ValidateQuestion(); } $("form.poll-create").validate(ValidatePoll);
TIÊU ĐỀ CHƢƠNG 3
63
function EditOption() { var id = $(this).attr("meta:id"), option = $("#option-" + id), text = option.find(".text").text(); // hide all the childrend option.children().hide(); var optionForm = $("<form><span class=\"field\"><input type=\"text\" id=\"text-" + id + "\" class=\"edit-text\" value=\"" + text + "\" /> <button type=\"button\" class=\"update\" meta:id=\"" + id + "\">Update</button> <button type=\"button\" class=\"cancel\">Cancel</button></span></form>"); // update the form optionForm.find(".update").click(function () { var id = $(this).attr("meta:id"), formText = $(this).prevAll(".edit-text").val(); $.post( "/poll/editoption", { optionId: id, text: formText }, function (data) { var comment = $("#option-" + data.object.optionId); comment.children("form").remove(); comment.children(".text").text(data.object.text); comment.children().show(); }, "json" ); }); // cancel the update optionForm.find(".cancel").click(function () { $(this).parents(".option").children(":hidden").show(); $(this).parents("form").remove(); }); // add the form to the current comment option.append(optionForm); return false; } $(".edit-option-button").click(EditOption); function DeleteOption () { var id = $(this).attr("meta:id");
TIÊU ĐỀ CHƢƠNG 3
64
$.post( "/poll/removeoption", { optionId: id }, function (data) { $("#option-" + data.object.optionId).fadeOut("slow", function () { $(this).remove() }); }, "json" ); return false; } $(".delete-option-button").click(DeleteOption); function AddOptionSuccess(data) { var optionItem = $("<li id=\"option-" + data.object.optionId + "\" class=\"option\"><span class=\"text\">" + data.object.text + "</span> <button type=\"button\" class=\"edit-option-button\" meta:id=\"" + data.object.optionId + "\">Edit</button> <button type=\"button\" class=\"delete-option-button\" meta:id=\"" + data.object.optionId + "\">Delete</button></li>"); optionItem.find(".edit-option-button").click(EditOption); optionItem.find(".delete-option-button").click(DeleteOption); // clear the option box $("#option").val(""); // add the new option to the other options optionItem.appendTo("#poll-options"); } $("form.poll-options-create").submit(function() { var option = $("#option").val(), pollId = $("#pollId").val(); $.post( "/poll/addoption", { pollId: pollId, text: option }, AddOptionSuccess, "json" ); return false; }); Và tệp poll.js /******************************************************************
TIÊU ĐỀ CHƢƠNG 3
65
* Poll ******************************************************************/ function RenderPoll(obj, data) { var poll = $(obj), total = data.object.total, item, percentValue, rightValue, leftValue; // clears all child nodes poll.empty(); poll.append("<h2>" + data.object.question + "</h2>"); poll.append("<ul class=\"poll-options\">"); // go through each option and render it for(var i = 0; i < data.object.options.length; i++) { item = data.object.options[i]; percentValue = Math.round(item.votes / total * 100); poll.append("<li class=\"option\" id=\"option-" + item.optionId + "\">" + "<h3>" + item.text + "</h3>" + "<div class=\"graph\"><img src=\"/Content/images/poll-graph.gif\" height=\"10\" width=\"" + percentValue + "%\" /></div>" + "<div class=\"values\">" + percentValue + "% (" + item.votes + " votes)</div>" + "</li>"); } poll.append("</ul>"); poll.append("<div class=\"total\">There are " + total + " total votes for this poll.</div>"); } $(".poll form").submit(function() { var selection = $(this).find(":checked").val(); if (selection != undefined) { $.post( "/poll/vote", { optionId: selection }, function(data, textStatus) { SetCookie("poll_" + data.object.pollId, selection, 30); // render the poll for the given data RenderPoll($("#poll-" + data.object.pollId), data); }, "json" ); }
TIÊU ĐỀ CHƢƠNG 3
66
return false; });
5.9. Cấu hình định tuyến
Định tuyến của các trang dành cho người dùng không có vai trò editor routes.MapRoute( "PollsIndex", "polls", new { controller = "Poll", action = "Index", page = 1 } ); routes.MapRoute( "PollsIndexPaged", "polls/page{page}", new { controller = "Poll", action = "Index", page = (int?)null }, new { page = "[0-9]+" } ); Định tuyến dành của các trang dành cho người dùng có vai trò là editor routes.MapRoute( "PollCreate", "admin/polls/create", new { controller = "Poll", action = "CreatePoll" } ); routes.MapRoute( "PollEdit", "admin/polls/edit/{pollId}", new { controller = "Poll", action = "EditPoll", pollId = (int?)null }, new { pollId = "[0-9]+" } ); routes.MapRoute( "PollRemove", "admin/polls/remove/{pollId}", new { controller = "Poll", action = "RemovePoll", pollId = (int?)null }, new { pollId = "[0-9]+" } ); routes.MapRoute( "PollManager",
TIÊU ĐỀ CHƢƠNG 3
67
"admin/polls", new { controller = "Poll", action = "ManagePolls", page = 1 } ); routes.MapRoute( "PollManagerPaged", "admin/polls/page{page}", new { controller = "Poll", action = "ManagePolls", page = (int?)null }, new { page = "[0-9]+" } );
TIÊU ĐỀ CHƢƠNG 3
68
uc Forums
Editor
(from Actors)
User
(from Actors)
View All Forums
View Forum
ViewPost
Create Post
Manage Forum
Edit Forum
Remov e Forum
Close Post
Approv e Post
Remov e Post
«include»
«include»
6. MODULE DIỄN ĐÀN
6.1. Tổng quan về module
Là một công ty sở hữu các chuỗi siêu thị có mặt khắp nơi trên thế giới ,Global Store có rất nhiều khách hàng trung thành. Các khách hàng của Global Store có chung nhiều sở thích mà mua sắm tại các siêu thị của công ty là một trong những sở thích đó. Nhu cầu giao lưu trao đổi về những sở thích đó là hết sức tự nhiên. Nắm bắt được điểm này Global Store đã xây dựng diễn đàn tạo một sân chơi cho các khách hàng của công ty giao lưu. Diễn đàn góp phần giữa chân các khách hàng trung thành cũng như biến các khách hàng tiềm năng thành khách hàng thân thiết của công ty. Sử dụng module này người dùng nạc danh có thể duyệt xem bài bình luận trong các diễn đàn, tuy nhiên để gửi bài hay bình luận họ phải đăng nhập vào hệ thống. Chức năng quản lí diễn đàn, quản lí các bài thỏa luận dành cho người dùng có vai trò là editor. (biên tập)
6.2. Sơ đồ chức năng
Hình 3.21 – Sơ đồ chức năng module Forum
TIÊU ĐỀ CHƢƠNG 3
69
6.3. Các bảng dữ liệu
Hình 3.22 – Các bảng dữ liệu của module forum Trong module này ta cần có 3 bảng như hình vẽ. Ngoài 2 bảng Forums và Posts là các bảng cốt lõi cho một diễn đàn thì ta có thêm bảng vote dùng cho cho ý kiến một cho một post là hay hay không để người dùng có thể biết post đó được nhiều hay ít người quan tâm, thích.
6.4. Xây dựng lớp ForumsElement cho thiết lập cấu hình module
Các thiết lập về module Diễn đàn được định nghĩa trong thành phần <forums> trong mục <GlobalStore> của tệp web.config. Lớp này ánh xạ các thiết lập về diễn đàn ứng với các thuộc tính của nó để sử dụng cho module
6.5. Model
Model của module này cũng được thiết kế theo kiểu mẫu Provider Model được trình bày ở phần thiết kế kiến trúc hệ thống gồm có các lớp thực thể LINQ-to-SQL
Thuộc tính SMTP Mô tả
PostReplyPageSize Số các trả lời với mỗi một post trên một trang khi người dùng xem một post
ForumPageSize Số lượng các post liệt kê ở mỗi trang khi xem một diễn đàn
TIÊU ĐỀ CHƢƠNG 3
70
và một lớp ForumQueries chứa các phương thức mở rộng hỗ trợ truy vấn của module như hình vẽ dưới
Hình 3.23 – Sơ đồ các lớp thực thể LINQ-to-SQL Post, Forum, Vote
Hình 3.24 – Sơ đồ lớp ForumQueries
6.6. Controller
Phương thức hành động Bảo mật Các tham số
Index ---- ----
ViewForum ---- int forumId, string path, int page
ViewPost ---- Int postId, string path
Vote ---- int post Id, int direction
TIÊU ĐỀ CHƢƠNG 3
71
ManageForum Editor int? newsletterId, string subject, string body
CreateForum Editor string title, string description, int? order, bool? Moderated
EditForum Editor int forumId, string title, string description, int? order, bool? Moderated
RemoveForum Editor int forumId, string remove
CreatePost ---- int? forumId, int? parentPostId, string title, string body
ClosePost Editor int postId, bool closed
ApprovedPost Editor int postId, bool approved
RemovePost Editor int posted
6.7. View
Tên trang Đặc tả Đường dẫn ảo
Index.aspx Trang này dùng để xem danh sách tất cả các forums có trong hệ thống
/Forum
ViewForum.aspx Thông quan trang này người dùng có thể xem các post có trong một forum
forums/{forumId}/{*path} forums/{forumId}/{path}/page{page}
ViewPost.aspx Đây là trang cung cấp view cho một post và các reply của post đó
forums/posts/{postId}/{*path} forums/posts/{postId}/{path}/page{page}
CreatePost.aspx Đây là trang mà qua đó người dùng có thể tạo post mới hoặc trả lời một post nào đó
forums/posts/{postId}/{*path} forums/posts/{postId}/{path}/page{page}
ManageForums.aspx Đây là trang mà qua đó editor có thể quản lí diễn đàn với chức năng thêm, sửa và xóa nội dung
editor/forums
ManagePosts.aspx Đây là trang mà qua đó người dùng với vai trò editor có thể cho phép hay từ chối một post đang ở trong tình trạng hạn chế
editor/forums/posts
TIÊU ĐỀ CHƢƠNG 3
72
CreateForum.aspx Trang này cho phép editor tạo hay chỉnh sửa một diễn đàn đang tồn tại
editor/forums/create editor/forums/edit/{forumId}
RemoveForum.aspx Trang này dùng để hỏi liệu bạn có muốn xóa điễn đàn khỏi CSDL hay không
editor/forums/remove/{forumId}
6.8. Sử dụng javascript
Trong module này có sử dụng 2 tệp javascript là manage-forum.js và forums.js Tệp manage-forum.js /****************************************************************** * Forum Post ******************************************************************/ $("#title").focus(function() { ShowMessage(this, "Enter the title for your forum."); }); $("#description").focus(function() { ShowMessage(this, "Enter the description of your forum."); }); $("#moderated").focus(function() { ShowMessage(this, "Do you want this forum to be moderated?"); }); $("#order").focus(function() { ShowMessage(this, "The order you want this forum to appear in, compared to the other forums."); }); function ValidateTitle() { return VerifyRequiredField("#title", "required"); } function ValidateDescription() { return VerifyRequiredField("#description", "required"); } function ValidateForum() { return ValidateTitle() && ValidateDescription(); } $("form.forum-create").validate(ValidateForum); /****************************************************************** * Editor Functions ******************************************************************/ $(".post .toggle-body").click(function() { $(this).next(".body").slideToggle("normal");
TIÊU ĐỀ CHƢƠNG 3
73
return false; }); $(".post .admin .close").click(function() { var postId = $(this).attr("meta:id"); $.post( "/forum/closepost", { postId: postId, closed: true }, function(data) { $("#post-" + data.object.postId) .fadeOut("normal", function() { var title = $(this).find("h3"); title.text(title.text() + " [closed]"); $(".admin .close", this).remove(); }) .fadeIn("normal"); }, "json" ); return false; }); $(".post .admin .approve").click(function() { var postId = $(this).attr("meta:id"); $.post( "/forum/approvepost", { postId: postId, approved: true }, function(data) { $("#post-" + data.object.postId).fadeOut("normal", function() { $(this).remove(); }); }, "json" ); return false; }); $(".post .admin .remove").click(function() { var postId = $(this).attr("meta:id"); $.post( "/forum/removepost", { postId: postId }, function(data) {
TIÊU ĐỀ CHƢƠNG 3
74
$("#post-" + data.object.postId).fadeOut("normal", function() { $(this).remove(); }); }, "json" ); return false; }); $(".reply .admin .remove").click(function() { var postId = $(this).attr("meta:id"); $.post( "/forum/removepost", { postId: postId }, function(data) { $("#reply-" + data.object.postId).fadeOut("normal", function() { $(this).remove(); }); }, "json" ); return false; }); Tệp forums.js /********************************************************************************************* * Forum Post *********************************************************************************************/ $("#title").focus(function() { ShowMessage(this, "Enter the title for your post."); }); $("#body").focus(function() { ShowMessage(this, "Enter the body of your post."); }); function ValidateTitle() { return VerifyRequiredField("#title", "required"); } function ValidateBody() { return VerifyRequiredField("#body", "required"); } function ValidatePost() { return ValidateTitle() && ValidateBody();
TIÊU ĐỀ CHƢƠNG 3
75
} $("form.post-create").validate(ValidatePost); /****************************************************************** * Rich Text Editor ******************************************************************/ var bodyEditor; $(document).ready(function() { bodyEditor = new tinymce.Editor("body", __editorConfig); bodyEditor.onChange.add(function(ed) { bodyEditor.save(); }); bodyEditor.onClick.add(function(ed) { ShowMessage("#body", "Enter the body of your article."); }); bodyEditor.render(); }); // clears the message from the description when another input gets focus $(":input") .focus(function() { HideMessage("#body"); }) .blur(function() { HideMessage("#body"); }); /****************************************************************** * Forum ******************************************************************/ function VoteSuccess(data) { if (data.object.error) { alert("You must be logged in to vote."); return; } var button = $(".post .vote-" + (data.object.direction > 0 ? "up" : "down")); var number = $(".post strong"); // remove current selections and select correct button $(".post .vote-button a").removeClass("selected"); button.addClass("selected"); // set new count value number.text(data.object.voteCount); } $(".post .vote-button a").click(function() { var postId = $("#postId").val(); var href = $(this).attr("href"); var direction = (href == "#up") ? 1 : -1;
TIÊU ĐỀ CHƢƠNG 3
76
$.post( "/forum/vote", { postId: postId, direction: direction }, VoteSuccess, "json" ); return false; });
6.9. Cấu hình định tuyến
Định tuyến cho người dùng có vai trò editor: routes.MapRoute( "ForumCreate", "editor/forums/create", new { controller = "Forum", action = "CreateForum" } ); routes.MapRoute( "ForumEdit", "editor/forums/edit/{forumId}", new { controller = "Forum", action = "EditForum", forumId = (int?)null }, new { forumId = "[0-9]+" } ); routes.MapRoute( "ForumRemove", "editor/forums/remove/{forumId}", new { controller = "Forum", action = "RemoveForum", forumId = (int?)null }, new { forumId = "[0-9]+" } ); routes.MapRoute( "ForumPostsManager", "editor/forums/posts", new { controller = "Forum", action = "ManagePosts" } ); routes.MapRoute( "ForumManager", "editor/forums", new { controller = "Forum", action = "ManageForums" } ); Các định tuyến cho người dùng với các vai trò còn lại của hệ thống
TIÊU ĐỀ CHƢƠNG 3
77
routes.MapRoute( "ForumPostCreate", "forums/{forumId}/post", new { controller = "Forum", action = "CreatePost", forumId = (int?)null }, new { forumId = "[0-9]+" } ); routes.MapRoute( "ForumPostReply", "forums/posts/{parentPostId}/reply", new { controller = "Forum", action = "CreatePost", parentPostId = (int?)null }, new { parentPostId = "[0-9]+" } ); routes.MapRoute( "ForumsIndex", "forums", new { controller = "Forum", action = "Index" } ); routes.MapRoute( "Forum", "forums/{forumId}/{*path}", new { controller = "Forum", action = "ViewForum", forumId = (int?)null, path = (string)null, page = 1 }, new { forumId = "[0-9]+" } ); routes.MapRoute( "ForumPaged", "forums/{forumId}/{path}/page{page}", new { controller = "Forum", action = "ViewForum", forumId = (int?)null, path = (string)null, page = (int?)null }, new { forumId = "[0-9]+" } ); routes.MapRoute( "ForumPost", "forums/posts/{postId}/{*path}", new { controller = "Forum", action = "ViewPost", postId = (int?)null, path = (string)null, page = 1 }, new { postId = "[0-9]+" } ); routes.MapRoute( "ForumPostPaged", "forums/posts/{postId}/{path}/page{page}",
TIÊU ĐỀ CHƢƠNG 3
78
new { controller = "Forum", action = "ViewPost", postId = (int?)null, path = (string)null, page = (int?)null }, new { postId = "[0-9]+" } );
6.10. Cấu hình trong tệp web.config
<globalStore> <forums postReplyPageSize="10" forumPageSize="25"/> </globalStore>
TIÊU ĐỀ CHƢƠNG 3
79
uc Articles, News, Blog
Editor
(from Actors)User
(from Actors)
View all categories View all articles of
specific category
View Article Detail
Create Comment
Rate Article
Manage Article
CategoriesRemov e Category
Edit Category
Create Category
Manage Articles
Edit Article
Remov e Article
Create Article
Manage CommentsEdit Comment
Remov e Comment
«include»
«include»
«include»
«include»
«include»
«include»
7. MODULE BÀI BÁO, TIN TỨC, VÀ BLOG
7.1. Tổng quan về module
Global store với mục tiêu tạo một site thương mại tương tác cao nội dung phong phú nên trong hệ thống có module cho phép người dùng viết bài xung quanh các nội dung về sự kiện nào đó tổ chức tại siêu thị, chia sẻ các hình ảnh về siêu thị ,… Người dùng sử dụng module này có thể xem toàn bộ các bài báo, xem theo đầu mục, xem chi tiết bài báo, viết lời bịnh và đánh giá . Người dùng với vai trò là editor có thêm các chức năng như quản lí các đầu mục báo, tạo đầu mục mới, xóa đầu mục đang có trong hệ thống. Quản lí các bài báo (chỉnh sửa, xóa), tạo bài báo mới
7.2. Sơ đồ chức năng
Hình 3.25 – Sơ đồ chức năng của module bài báo, tin tức, và blog
TIÊU ĐỀ CHƢƠNG 3
80
7.3. Các bảng dữ liệu
Với module này ta sẽ cần ba bảng dữ liệu là Articles (chứa các thông tin liên quan đến các bài báo), Categories (Chứa các thông tin liên quan đến đầu mục các bài báo), Comments (Chứa các thông tin liên quan đến bình luận của các bài báo) Mổi quan hệ giữa bảng Articles với bảng Comments được thiết lập thông qua khóa ngoại là ArticleID với updates và deletes là kiểu Cascade do đó khi xóa một Artile thì các Comments tương ứng với Article đó cũng bị xóa. Tương tự quan hệ giữa 2 bảng Categories và Articles được thiết lập thông qua khóa ngoại là CategoryID với updates và deletes là kiểu do đó khi xóa một Category thì các bài báo thuộc Category đó cũng bị xóa.
Hình 3.26 – Sơ đồ bảng Categories, Comments, Articles và quan hệ của chúng
7.4. Xây dựng lớp ArticleElement cho thiết lập cấu hình của
module
Các thuộc tính cấu hình trong thành phần <article> nằm trong phần <globalStore> thuộc tệp web.config sẽ được đọc bởi lớp ArticleElement. Lớp này kế thừa từ namespace System.Configuration.ConfigurationElement với thuộc tính thiết lập cấu hình như trong bảng sau.
TIÊU ĐỀ CHƢƠNG 3
81
Phần cấu hình của module bài báo, tin tức, blog trong tệp web.config <globalStore> <articles pageSize="10"/> </globalStore>
7.5. Model
Từ các bảng DL của module trong CSDL của hệ thống ta tạo được các lớp thực thể tương ứng thông quan LINQ-to-SQL như sau:
Hình 3.27 – Sơ đồ các lớp thực thể Article, Comment, Category Để hỗ trợ cho việc truy vấn các bảng dữ liệu của module. Vì các lớp thực thể Article, Comment, Category đều là các lớp partial do đó có thể thêm các thuộc tính và phương thức vào các lớp này ở một tệp khác tệp chứa định nghĩa của các lớp đó. Như vậy có thể dễ dàng mở rộng các lớp thực thể LINQ-to-SQL được tạo tự động từ các bảng DL trong CSDL của hệ thống.
Thuộc tính Mô tả
PageSize Số các bài báo mặc định có trên mỗi trang.
TIÊU ĐỀ CHƢƠNG 3
82
Như sơ đồ dưới ta có mở rộng cho lớp Article thực thể bằng việc thêm ba thuộc tính AverageRating, Location, Published và 2 phương thức là IncrementViewCount, Rate.Thêm vào đó là một đối tượng ArticleCollectionWrapper
Hình 3.28 – Sơ đồ các lớp mở rộng ArticlesQueries, Article, ArticleCollectionWrapper
7.6. Controller
Phương thức hành động
Bảo mật
Các tham số
Index ---- string category, int page
CategoryIndex ---- ----
ViewArticle ---- int id, string path
RateArticle ---- int articleId, int rating
ManageArticle Editor int page
ManageCategory Editor ----
ManageComment Editor ----
CreateArticle Editor int? categoryId, string title, string summary, string body, string country, string state,string city, DateTime? releaseDate, DateTime? expireDate,
TIÊU ĐỀ CHƢƠNG 3
83
bool? approved, bool? listed, bool? commentsEnabled, bool? onlyForMembers
EditArticle Editor int articleId, int? categoryId, string title, string summary, string body, string country,string state, string city, DateTime? release-Date, DateTime? expireDate, bool? approved, bool? listed, bool? commentsEnabled, bool? onlyForMembers
RemoveArticle Editor int articleId, string remove
CreateCategory Editor string title, int? importance, string imageUrl, string description
EditCategory Editor int categoryId, string title, int? importance, string imageUrl, string description
RemoveCategory Editor int categoryId, int? newCategoryId,string remove
CreateComment ---- int articleId, string name, string email,string body
EditComment Editor int commentId, string name, string body
RemoveComment Editor int commented
7.7. View
Tên trang Đặc tả Đường dẫn ảo Index.aspx Trang này hiển thị
tất cả các bài báo hiện có trong hệ thống
article articles/page{page}} articles/categories/{category} articles/categories/{category}/page{page}
CategoryIndex.aspx Trang này hiển thị những đầu mục các bài báo
articles/categories
ViewArticle.aspx Trang này cho phép xem chi tiết bài báo, viết lời bình luận về bài báo, cho điểm bài báo
articles/{id}/{*path}
ManageArticle.aspx Trang này liệt kê các bài báo hiện có trong hệ thống với hỗ trợ phân trang, và cho phép chỉnh sửa, xóa bài báo
editor/articles editor/articles/page{page}
ManageCategory.aspx Trang này liệt kê các đầu mục báo hiện có trong hệ thống, và cho phép chỉnh sửa, xóa các đầu mục đó
editor/articles/categories
ManageComments.aspx Trang này hiển thị tất cả các lời bình theo thứ tự từ trên xuống từ tính theo thời gian và
TIÊU ĐỀ CHƢƠNG 3
84
cho phép người dùng với vai trò editor xóa các lời bình đó
editor/articles/comments editor/articles/comments/page{page}
CreateArticle.aspx
Trang này cho phép bạn tạo mới hay chỉnh sửa một bài báo có trong hệ thống
editor/articles/create editor/articles/edit/{articleId}
CreateCategory.aspx Trang này cho phép bạn tạo mới hay chỉnh sửa một đầu mục báo có trong hệ thống
editor/articles/categories/create editor/articles/categories/edit/{categoryId}
RemoveArticle.aspx Trang này được dùng để xác nhận lại việc có hay không xóa một bài báo
editor/articles/remove/{articleId}
RemoveCategory.aspx Trang này được dùng để xác nhận lại việc có hay không xóa một đầu mục báo
editor/articles/categories/remove/{categoryId}
7.8. Sử dụng javascript
Tệp manage-category.js được sử dụng để thực thi các hành động phía người dùng trên trang CreateCategory.aspx
Phần đầu của tệp này dùng cho thông điệp thông tin cho các mục trong form Create Category $("#title").focus(function ()
{ ShowMessage(this, "Enter the title for your category."); }); $("#importance").focus(function ()
{ ShowMessage(this, "(optional) Enter the order of importance that you want the categories shown in."); });
$("#imageUrl").focus(function () { ShowMessage(this, "The relative web path of an image you want to be shown with articles in this category."); });
$("#description").focus(function () { ShowMessage(this, "Enter a short description of the category to display to your users."); });
Với đoạn mã lệnh trên thì khi các textbox tittle, importance, imageUrl, hay description được sử dụng thì chúng sẽ hiển thị thông điệp được truyền vào phương thức ShowMessage.
TIÊU ĐỀ CHƢƠNG 3
85
function ValidateTitle () { return VerifyRequiredField("#title", "required"); } function ValidateImageUrl () { return VerifyRequiredField("#imageUrl", "required"); } function ValidateDescription () { return VerifyRequiredField("#description", "required"); } 3 hàm này thực thi việc đảm bảo các trường title, imageUrl, và description có chứa giá trị bởi lẽ chúng buộc phải có để có thể lưu một bản category vào CSDL. function ValidateCategory () { var validTitle = ValidateTitle(); var validImage = ValidateImageUrl(); var validDescription = ValidateDescription(); return validTitle && validImage && validDescription; } $("form.category-create").validate(ValidateCategory); Hàm cuối cùng này của tệp manage-categories.js thực hiện việc đảm bảo cả ba trường đều phải chứa giá trị. Trong trường hơp cả ba trường đều có chứa giá trị nó sẽ trả về giá trị true và như vậy hệ thống sẽ tiếp tục submit Form tạo Category. Trong các trường hợp còn lại hệ thống sẽ không thể tiếp tục thực hiện việc submit Form nói trên.
Tiếp đến là tệp manage-articles.js: Phần đầu của tệp này cũng thực hiện việc tương tự với tệp trên tuy nhiên là cho trang CreateArticles $("#title").focus(function ()
{ ShowMessage(this, "Enter the title for your article."); }); $("#summary").focus(function ()
{ ShowMessage(this, "(optional) Enter a summary for your article to be displayed instead of body."); });
$("#body").focus(function () { ShowMessage(this, "Enter the body of your article."); });
$("#country").focus(function () { ShowMessage(this, "(optional) Enter the country that is associated with this article."); });
$("#state").focus(function () { ShowMessage(this, "(optional) Enter the state that is associated with this article."); });
$("#city").focus(function ()
TIÊU ĐỀ CHƢƠNG 3
86
{ ShowMessage(this, "(optional) Enter the city that is associated with this article."); });
$("#releaseDate").focus(function () { ShowMessage(this, "(optional) This is the date that you want this article to be first show on the site. If left blank todays day is used."); });
$("#expireDate").focus(function () { ShowMessage(this, "(optional) This is the date that you want this article to stop showing on the site."); });
function ValidateTitle () { return VerifyRequiredField("#title", "required"); } function ValidateBody () { return VerifyRequiredField("#body", "required"); } function ValidateArticle () { return ValidateTitle() && ValidateBody(); } $("form.article-create").validate(ValidateArticle); Phần tiếp theo của tệp này được dùng để tạo và gắn một thể hiện của TinyMCE với TextArea có tên là body: var bodyEditor; $(document).ready(function () { bodyEditor = new tinymce.Editor("body", __editorConfig); bodyEditor.onChange.add(function (ed) { bodyEditor.save(); }); bodyEditor.onClick.add(function (ed) { ShowMessage("#body", "Enter the body of your article."); }); bodyEditor.render(); }); Phần code cuối cùng của tệp này dùng để dấu thông điệp của phần body mỗi khi một vùng textbox trên trang CreateArticle được sử dụng: $(":input") .focus(function () { HideMessage("#body"); }) .blur(function () { HideMessage("#body"); });
Tệp manage-comment.js Phần mã lệnh javascript dùng để xóa một comment : $(".remove-comment").click(function () {
TIÊU ĐỀ CHƢƠNG 3
87
var id = $(this).attr("meta:id"); $.post( "/article/removecomment", { commentId: id }, function (data) { $("#comment-" + data.object.commentId).next(".admin").fadeOut("slow", function () { $(this).remove() }); $("#comment-" + data.object.commentId).fadeOut("slow", function () { $(this).remove() }); }, "json" ); return false; }); Phần mã lệnh chỉnh sửa comment: $(".edit-comment").click(function () { var id = $(this).attr("meta:id"), comment = $("#comment-" + id), bodyText = comment.find(".body").text(), nameText = comment.find(".name").text();
// hide all the childrend comment.children().hide(); var commentText = ""; commentText += "<form><div class=\"comment-header field\"><label for=\"name-" + id + "\">Commentor's Name</label><br/><input type=\"text\" id=\"name-" + id + "\" class=\"edit-name\" value=\"" + nameText + "\" /></div>"; commentText += "<div class=\"field\"><label for=\"body-" + id + "\">Comment Body</label><br/><textarea class=\"edit-body\" id=\"body-" + id + "\">" + bodyText + "</textarea><br/><button type=\"button\" class=\"update\" meta:id=\"" + id + "\">Update</button> <button type=\"button\" class=\"cancel\">Cancel</button></div></form>"; var commentForm = $(commentText); // update the form commentForm.find(".update").click(function () { var id = $(this).attr("meta:id"); var nameFormText = $(this).prevAll(".edit-name").val(); var bodyFormText = $(this).prevAll(".edit-body").val(); $.post(
TIÊU ĐỀ CHƢƠNG 3
88
"/article/editcomment", { commentId: id, name: nameFormText, body: bodyFormText }, function (data) { var comment = $("#comment-" + data.object.commentId); comment.children("form").remove(); comment.children(".body").text(data.object.body); comment.children(".name").text(data.object.name); comment.children().show(); }, "json" ); }); // cancel the update commentForm.find(".cancel").click(function () { $(this).parents(".comment").children(":hidden").show(); $(this).parents("form").remove(); }); // add the form to the current comment comment.append(commentForm); return false; });
Tệp article.js Phần code cho điểm một bài báo (rating article). Để cho điểm một bài báo thì việc đầu tiên là phải gắn kết mã lệnh javascript xử lí việc cho điểm với sự kiện submit trên form cho điểm bài báo để mỗi khi người dùng nhấn nút cho điểm thì một yêu cầu AJAX sẽ được gửi tới phương thức hành động /article/ratearticle: $("form.rate-article").submit(function () { $.post( "/article/ratearticle", { articleId: $("#articleId").val(), rating: $("#rating").val() }, RateArticleSuccess, "json" ); // don't allow submit because this is an ajax request return false; });
TIÊU ĐỀ CHƢƠNG 3
89
Bởi lẽ cái yêu cầu cho điểm này là bất đồng bộ nên ta sẽ cung cấp một phương thức callback là RateArticleSuccess. Phương thức này được gọi khi mà việc cho điểm thành công và trả về trình duyệt của người dùng function RateArticleSuccess (data) { var value = data.object.averageRating; var imagePosition = "50"; if (value <= 1.3) imagePosition = "10"; else if (value <= 1.8) imagePosition = "15"; else if (value <= 2.3) imagePosition = "20"; else if (value <= 2.8) imagePosition = "25"; else if (value <= 3.3) imagePosition = "30"; else if (value <= 3.8) imagePosition = "35"; else if (value <= 4.3) imagePosition = "40"; else if (value <= 4.8) imagePosition = "45"; $("#article-rating-value") .replaceWith("<img src=\"/Content/images/stars" + imagePosition + ".gif\" alt=\"" + value + "\" />"); $("form.rate-article :input").attr("disabled", "true"); $("form.rate-article").append("Your rating has been applied!"); } Phần code cho xử lí thêm comment cũng như phần cho điểm bài báo phải thực hiện 2 việc : Một là tạo một yêu cầu bất đồng bộ, hai là thực hiện đáp trả yêu cầu function ValidateCommentName () { return VerifyRequiredField("#comment-name", "required"); } function ValidateCommentEmail () { return VerifyRequiredField("#comment-email", "required"); } function ValidateCommentBody () { return VerifyRequiredField("#comment-body", "required"); } function CreateCommentSuccess (data, textStatus) { $(".new-comment").removeClass("new-comment").show("normal");
TIÊU ĐỀ CHƢƠNG 3
90
var commentText = ""; commentText += "<div id=\"comment-" + data.object.commentId + "\" class=\"comment new-comment\">"; commentText += "<div class=\"comment-header\">Comment posted by " + data.object.name + " 0 sec ago</div>"; commentText += "<blockquote>" + data.object.body + "</blockquote>"; commentText += "</div>"; var comment = $(commentText); // clear the body box $("#comment-body").val(""); // add the new comment to the other comments comment .hide() .appendTo("#article-comments") .slideDown("slow"); } $("form.comment-create").submit(function () { var valid = ValidateCommentName() && ValidateCommentEmail() && ValidateCommentBody(); if (valid) { $.post( "/article/createcomment", { articleId: $("#articleId").val(), name: $("#comment-name").val(), email: $("#comment-email").val(), body: $("#comment-body").val() }, CreateCommentSuccess, "json" ); } // don't allow submit because this is an ajax request return false; });
7.9. Cấu hình định tuyến
Phần cấu hình định tuyến các trang dành cho mọi người dùng: routes.MapRoute( "ArticleView", "articles/{id}/{*path}",
TIÊU ĐỀ CHƢƠNG 3
91
new { controller = "Article", action = "ViewArticle", id = (string)null, path = (string)null }, new { id = "[0-9]+", path = "[a-zA-Z0-9\\-]*" } ); routes.MapRoute( "ArticleCategoryViewIndex", "articles/categories/{category}", new { controller = "Article", action = "Index", category = (string)null, page = 1 }, new { category = "[a-zA-Z0-9\\-]+", page = "[0-9]+" } ); routes.MapRoute( "ArticleCategoryViewIndexPaged", "articles/categories/{category}/page{page}", new { controller = "Article", action = "Index", category = (string)null, page = (int?)null }, new { category = "[a-zA-Z0-9\\-]+", page = "[0-9]+" } ); routes.MapRoute( "ArticleCategoryIndex", "articles/categories", new { controller = "Article", action = "CategoryIndex" } ); routes.MapRoute( "ArticleIndex", "Articles", new { controller = "Article", action = "Index", category = (string)null, page = 1 } ); routes.MapRoute( "ArticleIndexPaged", "articles/page{page}", new { controller = "Article", action = "Index", category = (string)null, page = (int?)null }, new { page = "[0-9]+" } ); Phần cấu hình định tuyến dành riêng cho người dùng có vai trò editor routes.MapRoute( "ArticleCreate",
TIÊU ĐỀ CHƢƠNG 3
92
"editor/articles/create", new { controller = "Article", action = "CreateArticle" } ); routes.MapRoute( "ArticleEdit", "editor/articles/edit/{articleId}", new { controller = "Article", action = "EditArticle", articleId = (int?)null }, new { articleId = "[0-9]+" } ); routes.MapRoute( "ArticleRemove", "editor/articles/remove/{articleId}", new { controller = "Article", action = "RemoveArticle", articleId = (int?)null }, new { articleId = "[0-9]+" } ); routes.MapRoute( "ArticleManage", "editor/articles", new { controller = "Article", action = "ManageArticles", page = 1 } ); routes.MapRoute( "ArticleManagePaged", "editor/articles/page{page}", new { controller = "Article", action = "ManageArticles", page = (int?)null }, new { page = "[0-9]+" } ); routes.MapRoute( "ArticleCategoryCreate", "editor/articles/categories/create", new { controller = "Article", action = "CreateCategory" } ); routes.MapRoute( "ArticleCategoryEdit", "editor/articles/categories/edit/{categoryId}", new { controller = "Article", action = "EditCategory", categoryId = (int?)null }, new { categoryId = "[0-9]+" } );
TIÊU ĐỀ CHƢƠNG 3
93
routes.MapRoute( "ArticleCategoryRemove", "editor/articles/categories/remove/{categoryId}", new { controller = "Article", action = "RemoveCategory", categoryId = (int?)null }, new { categoryId = "[0-9]+" } ); routes.MapRoute( "ArticleCategoryManage", "editor/articles/categories", new { controller = "Article", action = "ManageCategories" } ); routes.MapRoute( "ArticleCommentManage", "editor/articles/comments", new { controller = "Article", action = "ManageComments", page = 1 } ); routes.MapRoute( "ArticleCommentManagePaged", "editor/articles/comments/page{page}", new { controller = "Article", action = "ManageComments", page = (int?)null }, new { page = "[0-9]+" } ); #endregion #endregion #region Polls routes.MapRoute( "PollsIndex", "polls", new { controller = "Poll", action = "Index", page = 1 } ); routes.MapRoute( "PollsIndexPaged", "polls/page{page}", new { controller = "Poll", action = "Index", page = (int?)null }, new { page = "[0-9]+" } );
TIÊU ĐỀ CHƢƠNG 3
94
8. MODULE QUỐC TẾ HÓA
8.1. Tổng quan về module
GlobalStore Pte. có chuỗi các siêu thị có mặt ở nhiều nước vì vậy hệ thống siêu thị trực tuyến của GlobalStore Pte. cần đáp ứng được việc thể hiện hệ thống dưới nhiều ngôn ngữ khác nhau và sử dụng đúng các số liệu như tiền, cách viết ngày tháng, con số theo địa phương của người sử dụng hệ thống. Người sử dụng hệ thống sẽ chọn lựa chức năng này của hệ thống thông qua quá trình đăng kí hồ sơ hoặc chỉnh sửa hồ sơ chọn ngôn ngữ hiển thị của site.
8.2. Xây dựng module
8.2.1. Các Service hỗ trợ quốc tế hóa trong Framework của Microsoft
Namespace System.Globalization cung cấp một số các service hỗ trợ cho việc quốc tế hóa ứng dụng chẳng hạn như lớp CultureInfo được dùng để định dạng ngày và số ứng với những nơi khác nhau.
Tất cả các tiến trình của .NET đều xử lí ,theo dấu đối tượng CurrentCulture ( một đối tượng của lớp CultureInfo xác định các định dạng, các thiết lập sắp xếp) và đối tượng CurrentUICulture (cũng là một đối tượng của lớp CultureInfo xác định ngôn ngữ nào được dùng cho văn bản thể hiện trên giao diện người dùng).
Visual Studio có chương trình soạn thảo tài nguyên sẵn trong nó và giúp ta có thể trực tiếp quản lí việc dịch các chuỗi sang các ngôn ngữ khác. Trong quá trình phát triển ta có thể truy cập tới các chuỗi này thông qua tính năng intelliSense của Visual Studio bởi lẽ mỗi tài nguyên chuỗi khi được tạo ra thì Visual Studio sẽ sinh ra một lớp với các thuộc tính tác biệt cho mỗi chuỗi tài nguyên. Tại thời điểm chạy chương trình, các thuộc tính này gọi System.Resources.ResourceManager (trình quản lí tài nguyên) để trả về phần dịch chuỗi tài nguyên tương ứng với tiến trình hiện thời của đối tượng CurrentUICulture.
Đa số các phương thức định dạng chuỗi đều thực hiện tốt với tiến trình của đối tượng CurrentUICulture có nghĩa là nó sẽ hiển thị chuẩn các thông tin như ngày tháng, con số, và tiền tệ trên giao diện người dùng ứng với Culture hiện hành của UI.
Ta hoàn toàn có thể sử dụng tài nguyên ở cấp độ trang với ASP.NET 2.0 trở lên bằng việc xây dựng tài nguyên cho trang cụ thể bên cạnh tài nguyên toàn cục (global resource)
Ta có thể gắn kết một điều khiển phía máy chủ với các chuỗi tài nguyên bằng việc sử dụng cú pháp sau <asp:Label runat="server" Text="<%$ resources: YourDateOfBirth %>"/>
TIÊU ĐỀ CHƢƠNG 3
95
Lớp Cultural Information
Phương thức Miêu tả
CurrentCulture Trả về một đối tượng CultureInfo cung cấp thông tin về văn hóa được sử dụng trong tiến trình hiện hành
CurrentUICulture Trả về một đối tượng CultureInfo cung cấp thông tin về văn hóa được sử dụng bởi trình quản lí tài nguyên của hệ thống
DateTimeFormat Cung cấp cho bạn đối tượng DateTimeFormatInfo văn hóa cụ thể
InstalledUICulture Trả về một đối tượng CultureInfo cung cấp thông tin văn hóa trên hệ điều hành được cài đặt ở máy chủ
NumberFormat Cung cấp cho bạn đối tượng NumberFormatInfo như vậy bạn sẽ có các con số, tiền tệ, và phần trăm ứng với một văn hóa cụ thể
8.2.2. Xây dựng các tệp tài nguyên
Trong hệ thống siêu thị trực tuyến ta sẽ chỉ xây dựng 3 tệp tài nguyên toàn cục (global resouce files) và 2 tệp tài nguyên cục bộ (local resource files). Mỗi một tệp trong số 3 tệp tương ứng sẽ có một tệp dành cho các thông tin bằng tiếng Anh còn lại là bằng tiếng Việt và một tệp dành cho tiếng Ý. Mỗi một tệp sẽ cung cấp thông tin văn hóa tương ứng như đơn vị tiền tệ,đơn vị phần trăm, cách viết ngày tháng Tạo thư mục App_GlobalResources và trong thư mục này ta sẽ tạo 3 tệp tài nguyên là Message.resx, Message.it-IT.resx và tệp Message.vn-Vn.resx. Việc tạo 3 tệp hết sức đơn giản như hình sau:
Hình 3.29 – Tệp Message.resx
Hình 3.30 – Tệp Message.vn-VN.resx
TIÊU ĐỀ CHƢƠNG 3
96
Hình 3.31 – Tệp Message.it-IT.resx Tạo thư mục localization trong thư mục View,rồi tạo thư mục App_LocalResources trong thư mục localization. Trong thư mục mới tạo này ta sẽ tạo 3 tệp tài nguyên là TestLocalization.resx, TestLocalization.it-IT.resx, Test.Localization.vn-Ve.resx. Việc tạo các tệp các tệp này cũng giống như các tệp trên và được thể hiện như hình vẽ dưới:
Hình 3.32 – Tệp TestLocalization.resx
Hình 3.33– Tệp TestLocalization.vn-VN.resx
Hình 3.34 – Tệp TestLocalization.it-IT.resx Ghi chú: Vậy là ta đã có đủ dữ liệu để xây dựng thử nghiệm module quốc tế hóa
TIÊU ĐỀ CHƢƠNG 3
97
8.2.3. Controller của module
Trong thư mục Controller tạo tệp chứa với tên là LocalizationController.cs chứa controller mới của module. Controller này cho phép ta thiết lập văn hóa hiện hành của một tiến trình dựa trên thông tin trong hồ sơ người dùng và định dạng một vài kiểu thông tin theo định dạng tương ứng của văn hóa hiện hành đó: namespace GlobalStore.Controllers { [HandleError] public class LocalizationController : Controller { public ActionResult TestLocalization() {
Thread.CurrentThread.CurrentCulture = new CultureInfo(HttpContext.Profile.GetPropertyValue("Language") +
"-" +
HttpContext.Profile.GetPropertyValue("ContactInformation.Country"), false); Decimal amount = new Decimal(5);
ViewData["CurrencyExample"] = String.Format(CultureInfo.CurrentCulture.NumberFormat, "{0:c}", amount); ViewData["PercentageExample"] = String.Format(CultureInfo.CurrentCulture.NumberFormat, "{0:p}", amount); ViewData["NumberExample"] = String.Format(CultureInfo.CurrentCulture.NumberFormat, "{0:N}", amount); ViewData["DateExample"] = Convert.ToDateTime(DateTime.Now, CultureInfo.CurrentCulture.DateTimeFormat);
return View("TestLocalization"); } } }
8.2.4. View tƣơng ứng của module
Để tạo view cho module quốc tế hóa có tính minh họa ta sẽ không cần tạo quá nhiều thông tin mà chỉ cần các thông tin như tiền địa phương, cách viết con số của địa phương, cách viết phần trăm của địa phương, cách viết ngày và thời gian địa phương.. Tạo tệp TestLocalization.aspx trong thư mục Views/Localization như sau: <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
TIÊU ĐỀ CHƢƠNG 3
98
Inherits="System.Web.Mvc.ViewPage" culture="auto" meta:resourcekey="PageResource1" uiculture="auto" %> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h1><%= HttpContext.GetLocalResourceObject("~/Views/Localization/TestLocalization", "Title", System.Globalization.CultureInfo.CurrentUICulture)%></h1> <h3><%= HttpContext.GetGlobalResourceObject("Messages", "LocalGreeting", System.Globalization.CultureInfo.CurrentUICulture)%></h3> <p><%= HttpContext.GetLocalResourceObject("~/Views/Localization/TestLocalization", "Message", System.Globalization.CultureInfo.CurrentUICulture)%></p> <p><b>Localized Currency:</b> <%= ViewData["CurrencyExample"] %></p> <p><b>Localized Numbers:</b> <%= ViewData["NumberExample"] %></p> <p><b>Localized Percentages:</b> <%= ViewData["PercentageExample"] %></p> <p><b>Localized Date & Time:</b> <%= ViewData["DateExample"] %></p> <p><b><%= HttpContext.GetLocalResourceObject("~/Views/Localization/TestLocalization", "Copywrite", System.Globalization.CultureInfo.CurrentUICulture)%></b></p> </asp:Content>
TIÊU ĐỀ CHƢƠNG 3
99
9. MODULE KIỂM THỬ
9.1. Tổng quan về module
Việc kiểm soát mã lệnh theo từng phần bộ phận tách biệt luôn là mong muốn của lập trình viên. Với ứng dụng ASP.NET việc thực hiện Unitest là hầu như không thể. Tuy nhiên thực hiện Unit test với ứng dụng ASP.NET MVC lại dễ dàng và dự án xây dựng với công nghệ .NET MVC có thể kiểm tra được toàn bộ. Tuy nhiên với ứng dụng siêu thị trực tuyến ta chỉ thực hiện kiểm thử với module bài báo, tin tức và blog, và module gửi thư.
9.2. Code cho module
Với module Bài báo, Tin tức, và Blog ta sẽ kiểm thử với phương thức hành động Index (xem tất cả các bài báo có trong hệ thống), CategoryIndex (xem tất cả các đầu mục báo) :
- Kiểm thử Index :
[TestMethod] public void IndexTest() { ArticleController target = new ArticleController(); ActionResult actual = target.Index("", 0); Assert.IsNotNull(actual); Assert.IsInstanceOfType(actual, typeof(ViewResult)); ViewResult viewResult = actual as ViewResult; Assert.IsNotNull(viewResult.ViewData); Assert.AreEqual("All Articles", viewResult.ViewData["PageTitle"]); var model = viewResult.ViewData.Model as IEnumerable<Article>; Assert.IsNotNull(model); }
- Kiểm thử Category Index:
[TestMethod] public void CategoryIndexTest() { ArticleController target = new ArticleController(); ActionResult actual = target.CategoryIndex(); Assert.IsNotNull(actual);
TIÊU ĐỀ CHƢƠNG 3
100
Assert.IsInstanceOfType(actual, typeof(ViewResult)); ViewResult viewResult = actual as ViewResult; Assert.IsNotNull(viewResult.ViewData); Assert.AreEqual("All Categories", viewResult.ViewData["PageTitle"]);
var model = viewResult.ViewData.Model as IOrderedQueryable<Category>;
Assert.IsNotNull(model); } Với Module gửi thư ta cũng kiểm thử với phương thức hành động Index của module này và kiểm thử với phương thức hành động ManageNewsleters() trong lớp NewsletterController:
- Kiểm thử với Index: [TestMethod]
public void IndexTest() { NewsletterController target = new NewsletterController(); ActionResult actual = target.Index(); Assert.IsNotNull(actual); Assert.IsInstanceOfType(actual, typeof(ViewResult)); ViewResult viewResult = actual as ViewResult; Assert.IsNotNull(viewResult.ViewData);
Assert.AreEqual("Newsletters", viewResult.ViewData["PageTitle"]);
}
- Kiểm thử với ManageNewsletters: [TestMethod] public void ManageNewslettersTest() { NewsletterController target = new NewsletterController(); ActionResult actual = target.ManageNewsletters(); Assert.IsNotNull(actual); Assert.IsInstanceOfType(actual, typeof(ViewResult)); ViewResult viewResult = actual as ViewResult; Assert.IsNotNull(viewResult.ViewData);
Assert.AreEqual("Manage Newsletters", viewResult.ViewData["PageTitle"]);
var model = viewResult.ViewData.Model as IOrderedQueryable<Newsletter>;
Assert.IsNotNull(model);}
101
CHƢƠNG 4: SỬ DỤNG WEB FORMS TRONG ỨNG DỤNG
ASP.NET MVC
1. TỔNG QUAN VỀ VIỆC KẾT HỢP CÔNG NGHỆ ASP.NET
MVC VÀ WEBFORMS TRONG CÙNG MỘT ỨNG DỤNG
1.1. Các lí do cho sự kết hợp giữa 2 công nghệ
Có 2 trường hợp thường xảy ra nhất khi ta có mong muốn kết hợp 2 công nghệ xây dựng ứng dụng nền tảng web vào một ứng dụng đó là: 1. Xây dựng ứng dụng MVC nhưng lại muốn sử dụng công nghệ WebForms trong
ứng dụng đó: Có thể bạn muốn tận dụng các trang WebForms,các web control, hay các control người dùng từ các dự án trước đó mà không có đủ thời gian để xây dựng lại tất cả từ đầu sử dụng công nghệ .NET MVC
2. Bạn có một ứng dụng WebForms đã hoàn thiện và muốn nâng cấp ứng dụng đó để hỗ trợ công nghệ MVC.
1.2. Tại sao có thể thực hiện đƣợc sự kết hợp này
Kết hợp ASP.NET webforms and ASP.NET MVC vào một ứng dụng là hoàn toàn có thể và thực tế là việc này khá dễ dàng. Lí do là ASP.NET MVC framework được xây dựng dựa trên chính ASP.NET. Thực tế là chỉ có một khác biệt duy nhất đáng quan tâm đó là toàn bộ công nghệ ASP.NET thì gói gọn trong System.Web trong khi ASP.NET MVC thì ngoài nằm trong System.Web nó còn nằm ở System.Web.Routing, System.Web.Abstractions, và System.Web.MVC. Điều này có nghĩa là nếu ta thêm 3 thư viện này vào ứng dụng ASP.NET thì ta có thể kết hợp giữa 2 công nghệ. Với ứng dụng ASP.NET MVC ta có thể trực tiếp thêm các trang webforms vào điều duy nhất ta phải làm là thiết lập thêm định tuyến cho các trang webforms để ASP.NET MVC định tuyến tới các tệp .aspx này.
1.3. Các bƣớc để kết hợp các trang WebForms vào ứng dụng
ASP.NET MVC
Trong chuyên đề này tôi sẽ xây dựng module Store Locator theo công nghệ
ASP.NET để minh họa cho việc kết hợp trang WebForms vào ứng dụng ASP.NET
MVC.
Để thực hiện được trước tiên tôi sẽ xây dựng các trang webforms của module
trong thư mục WebForms sau đó thêm định tuyến cho các trang này vào tệp
Global.asxc.
TIÊU ĐỀ CHƢƠNG 3
102
uc Store Locator
Administrator
(from Actors)
User
(from Actors)
Locate Stores Add new store
2. MODULE TÌM CỬA HÀNG GẦN NHẤT
2.1. Tổng quan về module
Công ty GLOBAL STORE có các chuỗi cửa hàng ở khắp nơi trên thế giới. Các khách hàng khi mua hàng của Global Store họ thường có nhu cầu tìm cửa hàng gần nơi họ ở nhất theo khoảng cách cho trước là 5, 10,15,20,30,40,50 dặm. Việc tìm kiếm này được thực hiện thông qua module store locator. Trong dự án GLOBAL STORE trực tuyến này CSDL dành cho module store locator sử dụng địa chỉ các cửa hàng bất kì làm ví dụ minh họa. Địa chỉ cửa hàng mới được thêm vào bởi người dùng có vai trò quản trị .
2.2. Sơ đồ chức năng
Hệ thống có 2 chức năng như trong phân tích. Một là chức năng tìm kiếm cửa hàng gần nhất dành cho mọi người dùng, một là thêm địa chỉ cửa hàng mới chỉ dành cho người dùng có vai trò quản trị.
Hình 4.1 – Sơ đồ chức năng của module Store Locator
2.3. Phân tích cách xây dựng chức năng
Với chức năng tìm kiếm vị trị cửa hàng gần nhất: - Thông tin đầu vào: Địa chỉ (ở dạng đầy đủ và mã gửi thư – zip code) mà
qua đó người dùng muốn tìm các cửa hàng gần địa điểm (của địa chỉ đó) trong bán kính là một trong các lựa chọn 5, 10,15,20,30,40,50 dặm
- Kết quả : Hiển thị địa chỉ các cửa hàng nằm trong bán kính đó theo thứ tự về khoảng cách, hiển thị bản đồ Google với các Marker đánh dấu các vị trí tìm được trên bản đồ…
ta sẽ phải thực hiện được những việc sau:
- Xác định được (latitude, longtitude) của vị trí từ địa chỉ có được ở ô dành cho việc điền địa chỉ.
- Tính được khoảng cách của các cửa hàng có trong CSDL tới địa điểm của địa chỉ đó từ đó chọn ra các cửa hàng gần địa điểm đó trong bán kính yêu cầu.
TIÊU ĐỀ CHƢƠNG 3
103
- Hiển thị kết quả tìm được. Với chức năng thêm cửa hàng mới :
- Thông tin đầu vào : Tên cửa hàng, địa chỉ đầy đủ, tên thành phố, tên bang, mã gửi thư.
- Kết quả đầu ra: lưu toàn bộ thông tin về cửa hàng vào CSDL gồm các thông tin đầu vào và cả thông tin longitude, latitude. Trong trường hợp địa chỉ cửa hàng không xác định hệ thống sẽ đưa ra thông báo cho người dùng.
Ta sẽ phải thực hiện việc:
- Qua Google map api tìm được (longtitude, latitude) của cửa hàng thông qua các thông tin đầu vào.
- Thực hiện việc lưu thông tin xuống CSDL.
2.4. Bảng CSDL
Theo phân tích chức năng thì ta cần một bảng Location để lưu thông tin vị trí của cửa hàng :
Hình 4.2 – Bảng Locations Thủ tục GetNearByLocations: Tính toán và lọc ra các cửa hàng gần người dùng nhất. Thủ tục InsertLocation: Chèn một vị trí mới vào bảng Locations 3 hàm XAxis, YAxis, và ZAxis, được dùng dành cho việc tính toán của thủ tục GetNearByLocations.
TIÊU ĐỀ CHƢƠNG 3
104
2.5. Các lớp hỗ trợ trong module
Trong chức năng tìm kiếm các cửa hàng gần nhất cũng như chức năng thêm cửa hàng vào CSDL việc xác định ta đều cần thông tin (Latitude, Longtitude ) của địa chỉ người dùng nhập và cả 2 thông tin đó đều cần thiết cho việc tính toán khoảng cách của thủ tục GetNearByLocations cũng như cần thiết cho việc hiển thị Marker trên bản đồ Google vậy để xác định được ta phải sử dụng Google Map API và xây dựng lớp GeoCode như sau: namespace GoogleGeocoder { public interface ISpatialCoordinate { decimal Latitude { get; set; } decimal Longitude { get; set; } } /// <summary> /// Coordiate structure. Holds Latitude and Longitude. /// </summary> public struct Coordinate : ISpatialCoordinate { private decimal _latitude; private decimal _longitude; public Coordinate(decimal latitude, decimal longitude) { _latitude = latitude; _longitude = longitude; } #region ISpatialCoordinate Members public decimal Latitude { get { return _latitude; } set { this._latitude = value; } } public decimal Longitude { get { return _longitude;
TIÊU ĐỀ CHƢƠNG 3
105
} set { this._longitude = value; } } #endregion } public class Geocode { private const string _googleUri = "http://maps.google.com/maps/geo?q="; private const string _outputType = "csv"; // Available options: csv, xml, kml, json /// <summary> /// Returns a Uri of the Google code Geocoding Uri. /// </summary> /// <param name="address">The address to get the geocode for.</param> /// <returns>A new Uri</returns> private static Uri GetGeocodeUri(string address) { string googleKey = ConfigurationManager.AppSettings["googleApiKey"].ToString(); address = HttpUtility.UrlEncode(address); return new Uri(String.Format("{0}{1}&output={2}&key={3}", _googleUri, address, _outputType, googleKey)); } /// <summary> /// Gets a Coordinate from a address. /// </summary> /// <param name="address">An address. /// <remarks> /// <example> /// 3276 Westchester Ave, Bronx, NY 10461 /// /// or /// /// New York, NY /// /// or /// /// 10461 (zipcode) /// </example> /// </remarks>
TIÊU ĐỀ CHƢƠNG 3
106
/// </param> /// <returns>A spatial coordinate that contains the latitude and longitude of the address.</returns> public static Coordinate GetCoordinates(string address) { WebClient client = new WebClient(); Uri uri = GetGeocodeUri(address); /* The first number is the status code, * the second is the accuracy, * the third is the latitude, * the fourth one is the longitude. */ string[] geocodeInfo = client.DownloadString(uri).Split(','); return new Coordinate(Convert.ToDecimal(geocodeInfo[2]), Convert.ToDecimal(geocodeInfo[3])); } } }
Và trước khi tìm địa chỉ các cửa hàng gần nhất ta sẽ gọi tới hàm GetCoorDinates trong lớp Geocode để lấy Latitude và Longtitude của địa chỉ người dùng nhập vào như sau: //Get the coordinate of the address Coordinate coordinate = Geocode.GetCoordinates(addressTextBox.Text);
Ngoài ra ta sẽ phải xây dựng DataSet cho việc chứa các địa chỉ cửa hàng tìm được gần địa chỉ mà khách hàng nhập vào nhất gồm 2 tệp một tệp chứa design của DataSet là LocationsData.xsd ,một tệp chứa code LocationsData.Designer.cs Hình 4.3 – Tệp LocationsData.xsd
TIÊU ĐỀ CHƢƠNG 3
107
2.6. View
Module này có 2 view một dành cho mọi người dùng tìm kiếm siêu thị gần họ nhất, view còn lại chỉ dành cho người dùng có vai trò quản trị để thêm vị trí cửa hàng mới
Tên trang Đặc tả Đường dẫn ảo StoreLocator.aspx Trang này cho
phép người dùng tìm kiếm siêu thị gần họ nhất
Locator/Index
AddStoreLocation.aspx Trang này dành cho người dùng với vai trò quản trị thêm vị trí cửa hàng mới vào CSDL
Locator/AddStore
2.7. Thêm định tuyến cho các trang view của module
Khi mà ta yêu cầu một trang web sử dụng Url tương ứng với trang đó trên ổ đĩa tức là ta đã hoàn toàn tránh không sử dụng hệ thống định tuyến của ASP.NET MVC. Tuy nhiên trong module này ta muốn yêu cầu trang web StoreLocator.aspx và AddStoreLocation.aspx thông qua hệ thống định tuyến đó bằng cách sử dụng phương pháp: Tạo phương thức sinh URL hướng tới thư mục nằm ngoài thư mục Views. Cụ thể thư mục đó là WebForms. Đây là đoạn code của lớp chứa phương thức đó: //Create route class for WebForms public class WebFormsRoute : Route { //Constructor is hard-coded to use the special WebFormsRouteHandler public WebFormsRoute(string url, string virtualPath) : base(url, new WebFormsRouteHandler { VirtualPath = virtualPath }) { } public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { //Only generate outbound URL when "virtual Path" matches this entry string path = ((WebFormsRouteHandler)this.RouteHandler).VirtualPath;
TIÊU ĐỀ CHƢƠNG 3
108
if ((string)values["VirtualPath"] != path) return null; else { // var valuesExceptVirtualPath = new RouteValueDictionary (values); valuesExceptVirtualPath.Remove("virtualPath"); return base.GetVirtualPath(requestContext, valuesExceptVirtualPath); } } private class WebFormsRouteHandler : IRouteHandler { public string VirtualPath { get; set; } //Compiles the ASPX file if needed and instantiates the web form public IHttpHandler GetHttpHandler(RequestContext requestContext) { return (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(IHttpHandler)); } } } Ở đây ta đã sử dụng tới lớp BuildManager để định vị, dịch và tạo thể hiện của các trang webforms. Với lớp này ta có thể tạo ngay định tuyến cho các tệp StoreLocator.aspx và AddStoreLocation.aspx trong thư mục WebForms và thêm các định tuyến này vào bảng định tuyến: #region Locator
routes.Add(new WebFormsRoute("Locator/Index", "~/WebForms/StoreLocator.aspx")); routes.Add(new WebFormsRoute("Locator/AddStore", "~/WebForms/AddStoreLocation.aspx"));
#endregion
2.8. Vấn đề bảo mật
Một vấn đề ở đây là chúng ta cần thêm luật xác thực cho định tuyến Urls mới tạo để bảo vệ các trang khỏi kiểu truy cập trực tiếp sử dụng định tuyến đó: <!-- Configuration Extension For Preventing Direct Access To Web Form Pages-->
TIÊU ĐỀ CHƢƠNG 3
109
<location path="Locator/AddNewStore"> <system.web> <authorization> <allow roles="Admin"/> <deny users="*"/> </authorization> </system.web> </location> <location path="WebForms/AddStoreLocation.aspx"> <system.web> <authorization> <deny users="*"/> </authorization> </system.web> </location>
110
CHƢƠNG 5: TRIỂN KHAI ỨNG DỤNG VÀ HƢỚNG PHÁT
TRIỂN
1. TRIỂN KHAI ỨNG DỤNG
1.1. Các bƣớc triển khai
Công việc triển khai được chia làm 2 bước: Triển khai cơ sở dữ liệu và triển khai gobal store site. Về phần CSDL do IIS hỗ SQL server express cho nên CSDL này sẽ được gắn với ứng dụng GlobalStore khi ta triển khai ứng dụng này. Ở đây GlobalStore site chỉ sử dụng như là một site nhỏ nên ta chỉ cần dùng SQL server express để chứa CSDL.
1.2. Triển khai Global Store Site
Ta sẽ thực hiện triển khai Global Store Site với chức năng Public từ Visual Studio
như hình dưới đây sau khi chạy Visual Studio với vai trò administrator:
Hình 5.1 – Triển khai Global Store Site
111
1.3. Cấu hình IIS 7.0 cho Framework MVC sử dụng Microsoft
Web Platform Installer
Công cụ cài đặt Web Platform này là một công cụ mới của Microsoft hỗ trợ cài đặt trọn bộ Web Platform của Microsoft. Sau khi cài công cụ này khởi động nó ta sẽ thấy trên màn hình :
Hình 5.2 – Màn hình chọn lựa Paltform để cài đặt
112
Ta phải đảm bảo rằng .NET framework và ASP.NET MVC mới nhất được cài đặt bằng cách nhấn vào link Customize mục Framworks and Runtimes như hình dưới đây nếu đã có dấu tích chìm ứng với các mục cần cài thì tức là chúng đã được cài đặt vào máy.
Hình 5.3 – Màn hình kiêm tra các cài đặt của .NET Framework và ASP.NET MVC
113
Kiểm tra xem đã cài SQL Server express 2008 chưa bằng việc chọn liên kết Customize ở mục Database nếu như có dấu tích chìm ở phần SQL Server Express 2008 ở màn hình mới mở ra thì tức là SQL server express 2008 đã được cài đặt.
Hình 5.4 – Màn hình kiểm tra việc cài đặt SQL server express 2008
1.4. Thêm Global Store site vào IIS 7.0
Chạy máy chủ quản lí thông tin Internet của Microsoft – IIS 7.0 như trong hình vẽ
Hình 5.5 – IIS Manager
114
Nhấn vào node của máy chủ rồi nhấn chuột phải chọn Add Web Site ta sẽ thấy màn hình như sau
Hình 5.6 – Add Web Site Dialog Ở đây sẽ cần một số các thiết lập như đặt tên cho site, gán Host header …
115
2. Hƣớng phát triển ứng dụng
Do thời gian và phạm vi làm chuyên đề tốt nghiệp cũng như hiểu biết còn hạn chế nên em đã chỉ có thể đa phần là áp dụng những kĩ thuật cơ bản trong lập trình ứng dụng nền tảng web sử dụng công nghệ .NET MVC và ASP.NET của Microsft. Trên thực tế hệ thống còn có thể mở rộng theo một số hướng như sau để trở nên hữu ích và hiệu quả hơn.
2.1. Hỗ trợ tìm kiếm sản phẩm mở rộng
Với một hệ thống lớn như Global Store việc xây dựng chức năng tìm kiếm sản phẩm mở rộng là cần thiết giúp khách hàng tiết kiệm được thời gian tìm kiếm cũng như khiến cho hệ thống trở nên hữu ích hơn.
2.2. Mở rộng chức năng tìm kiếm cửa hàng gần nhất
Việc tìm kiếm cửa hàng gần nhất là một tiện ích khá thú vị của hệ thống tuy nhiên mục tiêu cần hướng tới là trong trường hợp khách hàng có lựa chọn sản phẩm vào giỏ hàng thì hệ thống cần thiết phải thông báo cho khách hàng biết sản phẩm mà khách hàng muốn mua đó có hay không có ở các siêu thị mà họ định tới. Ngoài ra cũng cần có các thông tin bổ trợ về siêu thị như giờ mở cửa, giờ đóng cửa ,…
2.3. Xây dựng module báo cáo tình hình bán hàng của siêu thị kết
xuất ra các tệp định dạng Execel, Pdf
Đây là một module khá cần thiết cho một ứng dụng kiểu như siêu thị trực tuyến, ông chủ của Global Store Pte luôn có nhu cầu nắm bắt các thông tin bán hàng của từng siêu thị. Để xây dựng được module này ở mức cao như yêu cầu thực tế của những site như www.bestbuy.com hay www.walmart.com không phải là điều dễ dàng xong xây dựng để mô phỏng thì không khó và là cần thiết.
116
KẾT LUẬN
Sau khi thực hiện xong chuyên đề tốt nghiệp xây dựng hệ thống siêu thị trực tuyến
em đã tìm hiểu được một số công nghệ xây dựng ứng dụng nền tảng web của
Microsoft:
- ASP.NET MVC
- ASP.NET
Tìm hiểu và ứng dụng cách kết hợp 2 công nghệ xây dựng ứng dụng web của
Microsoft là ASP.NET MVC và ASP.NET
Tìm hiểu và sử dụng các webservices sử dụng trong chức năng thanh toán với
Paypal, hay chức năng hiển thị bản đồ Google của module định vị cửa hàng gần
nhất.
Tìm hiểu và sử dụng AJAX cho các hành động phía Client, kĩ thuật xây dựng bộ
nhớ đệm,…
117
TÀI LIỆU THAM KHẢO
Tiếng Anh:
Về chức năng tham khảo các trang http://www.walmart.com/,
http://www.bestbuy.com/
ScottGu (5/2007), Using LINQ to SQL, xem trên blog của ScottGu
(http://weblogs.asp.net/scottgu)
How to use Membership in ASP.NET 2.0, trong msdn của microsoft
http://msdn.microsoft.com/en-us / library/ ff648345.aspx#paght000022
_sqlmembershipproviderconfig )
Troy Mageniss (2010), LINQ to Object using C# 4.0, Chapter 3,4
ASP.NET MVC, các bài từ cơ bản đến nâng cao về framework asp.net mvc trên
trang dành cho .NET MVC của microsoft (http://www.asp.net/mvc/fundamentals)
Steven Sanderson (2009), Pro ASP.NET MVC framework, p540 tới p546 –
Internationlization, p555 tới p576 commbination of ASP.NET and ASP.NET MVC
technology in one application.
Bear Bibfault, (11/2008), JQuery in action, Chapter 8 Talk to the server with Ajax
p217 tới p266.
Google developers, Google map API, xem ở (http://code.google.com/apis/maps/)
Paypal developers, Paypal API, xem ở (https://cms.paypal.com/us/cgi-
bin/?cmd=_render-content&content_ID=developer/howto_api_reference )
118
DANH MỤC HÌNH ẢNH
Hình 1.1 – Kiến trúc ứng dụng – Trang 6
Hình 1.2 - Mối quan hệ giữa các tầng giao diện, logic nghiệp vụ, truy cập CSDL và
lưu trữ CSDL – Trang 8
Hình 2.1 – Mô hình MVC cơ bản – Trang 13
Hình 2.2 – Mô hình xử lí yêu cầu từ ứng dụng ASP.NET MVC – Trang 17
Hình 2.3 – Mô hình LINQ to SQL – Trang 18
Hình 2.4 – Mô hình NorthwindDataContext – Trang 20
Hình 2.5 – Hình minh họa lấy sản phẩm từ CSDL với LINQ - Trang 20
Hình 2.6 – Hình minh họa cập nhật sản phẩm từ CSDL với LINQ – Trang 20
Hình 2.7 – Chèn sản phẩm mới vào CSDL – Trang 21
Hình 2.7 – Xóa một sản phẩm – Trang 21
Hình 2.8 – Gọi một thủ tục – Trang 22
Hình 2.9 – Lấy các sản phẩm và phân trang – Trang 22
Hình 3.1 – Các module của hệ thống siêu thị trực tuyến – Trang 23
Hình 3.2 – Sơ đồ tổng quan chức năng của module theo mô hình UC – Trang 26
Hình 3.3 – Tạo CSDL cho module hồ sơ và người dùng – Trang 27
Hình 3.4 Bảng Langugage – Trang 27
Hình 3.5 Sơ đồ lớp UserInformation – Trang 29
Hình 3.6 Sơ đồ lớp ProfileInformation – Trang 30 Hình 3.7 Sơ đồ chức năng theo mô hình UC của module thương mại – Trang 35 Hình 3.8 – Các tài khoản kiểm thử với sandbox – Trang 36 Hình 3.9 Sơ đồ quan hệ các bảng dữ liệu trong module thương mại – Trang 38 Hình 3.10 – Sơ đồ các lớp thực thể LINQ-to-SQL của module – Trang 39 Hình 3.11 – Các lớp xây dựng thêm hỗ trợ cho module – Trang 40 Hình 3.12 – Sơ đồ chức năng của module - Trang 53 Hình 3.13 – Bảng Newsletters – Trang 53 Hình 3.14 – Sơ đồ Model Newsletter – Trang 55
DANH MỤC HÌNH ẢNH
119
Hình 3.15 – Sơ đồ chức năng của module lấy ý kiến người dùng – Trang 57 Hình 3.16 – Sơ đồ mối quan hệ giữa 2 bảng DL của module lấy ý kiến người dùng – Trang 58 Hình 3.17 – Sơ đồ thiết kế bảng PollOptions – Trang 58 Hình 3.18 – Sơ đồ thiết kế bảng Polls – Trang 59 Hình 3.19 – Sơ đồ lớp PollOption và Poll – Trang 60 Hình 3.20 – Sơ đồ lớp PollQueries – Trang 60 Hình 3.21 – Sơ đồ chức năng module Forum – Trang 68 Hình 3.22 – Các bảng dữ liệu của module forum – Trang 69 Hình 3.23 – Sơ đồ các lớp thực thể LINQ-to-SQL Post, Forum, Vote – Trang 70 Hình 3.24 – Sơ đồ lớp ForumQueries – Trang 70 Hình 3.25 – Sơ đồ chức năng của module bài báo, tin tức, và blog – Trang 79 Hình 3.26 – Sơ đồ bảng Categories, Comments, Articles và quan hệ của chúng – Trang 79 Hình 3.27 – Sơ đồ các lớp thực thể Article, Comment, Category – Trang 80 Hình 3.28 – Sơ đồ các lớp mở rộng ArticlesQueries, Article, ArticleCollectionWrapper - Trang 82 Hình 3.29 – Tệp Message.resx – Trang 95 Hình 3.30 – Tệp Message.vn-VN.resx – Trang 95 Hình 3.31 – Tệp Message.it-IT.resx – Trang 96 Hình 3.32 – Tệp TestLocalization.resx – Trang 96 Hình 3.33 – Tệp TestLocalization.vn-VN.resx – Trang 96 Hình 3.34 – Tệp TestLocalization.it-IT.resx – Trang 96 Hình 4.1 – Sơ đồ chức năng của module Store Locator - Trang 102 Hình 4.2 – Bảng Locations – Trang 103 Hình 4.3 – Tệp LocationsData.xsd – Trang 106 Hình 5.1 – Triển khai Global Store Site – Trang 110
DANH MỤC HÌNH ẢNH
120
Hình 5.2 – Màn hình chọn lựa Paltform để cài đặt – Trang 111 Hình 5.3 – Màn hình kiêm tra các cài đặt của .NET Framework và ASP.NET MVC – Trang 112 Hình 5.4 – Màn hình kiểm tra việc cài đặt SQL server express 2008 – Trang 112 Hình 5.5 – IIS Manager – Trang 113 Hình 5.6 – Add Web Site Dialog – Trang 114