ASP.NET WebForm 雖提供事件驅動模型,但許多開發者仍沿用腳本式寫法,導致邏輯與呈現耦合。本文透過簡單的「Portal-Subject」主從資料查詢範例,對比傳統 WebForm 寫法與模式化架構 (Repository、Service、Controller),展示關注點分離帶來的可測試性與維護性。
// WebForm.aspx.cs
private void Page_Load(...) {
if (!IsPostBack) {
using (var conn = new SqlConnection(cfg["ConnStr"])) {
var da = new SqlDataAdapter("SELECT * FROM Portal", conn);
var ds = new DataSet(); da.Fill(ds);
dropDownList.DataSource = ds;
dropDownList.DataTextField = "PortalName";
dropDownList.DataValueField = "PortalId";
dropDownList.DataBind();
}
}
}
private void button_Click(...) {
using (var conn = new SqlConnection(cfg["ConnStr"])) {
string sql = string.Format("SELECT * FROM Subject WHERE PortalId = {0}", dropDownList.SelectedValue);
var da = new SqlDataAdapter(sql, conn);
var ds = new DataSet(); da.Fill(ds);
dataGrid.DataSource = ds; dataGrid.DataBind();
}
}
缺點:SQL 散落事件中、連線字串硬編碼、無法單元測試、邏輯無法重用、修改 Schema 需改多處。
public class Portal { public int Id { get; set; } public string Name { get; set; } }
public class Subject { public int Id { get; set; } public string Title { get; set; } public int PortalId { get; set; } }
public interface IPortalRepository { IEnumerable GetAll(); }
public interface ISubjectRepository { IEnumerable GetByPortal(int portalId); }
public class SqlPortalRepository : IPortalRepository {
private readonly string _connStr;
public SqlPortalRepository(string connStr) { _connStr = connStr; }
public IEnumerable GetAll() {
using (var conn = new SqlConnection(_connStr))
using (var cmd = new SqlCommand("SELECT Id, Name FROM Portal", conn)) {
conn.Open();
using (var rd = cmd.ExecuteReader())
while (rd.Read()) yield return new Portal { Id = rd.GetInt32(0), Name = rd.GetString(1) };
}
}
}
public class PortalService {
private readonly IPortalRepository _repo;
public PortalService(IPortalRepository repo) { _repo = repo; }
public IEnumerable GetPortals() => _repo.GetAll();
}
// Global.asax 或 IoC 容器註冊
// Application["PortalService"] = new PortalService(new SqlPortalRepository(cfg["ConnStr"]));
// WebForm.aspx.cs
private PortalService Service => (PortalService)Application["PortalService"];
protected void Page_Load(...) {
if (!IsPostBack) {
dropDownList.DataSource = Service.GetPortals();
dropDownList.DataTextField = "Name";
dropDownList.DataValueField = "Id";
dropDownList.DataBind();
}
}
protected void btnQuery_Click(...) {
var subjectRepo = (ISubjectRepository)Application["SubjectRepo"];
dataGrid.DataSource = subjectRepo.GetByPortal(int.Parse(dropDownList.SelectedValue));
dataGrid.DataBind();
}