首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

用 WinForm 模擬 ASP.NET MVC 架構:從瀏覽器請求到 Controller 執行的完整流程示範

     編輯:關於ASP.NET

本文透過一個 WinForm 應用程式模擬瀏覽器行為,配合自訂 `MyHttpHandler`、`Controller`、`Model`、`View` 類別,完整示範 ASP.NET MVC 核心管線:請求 → 路由 → ControllerFactory → ActionInvoker → Model → View → 回應。適合初學者理解 MVC 內部運作原理。

專案結構

MvcSimulation/
├── Default.cs          # WinForm 主視窗 (模擬瀏覽器)
├── WebBrowser.cs       # 簡易瀏覽器類別 (發送請求、顯示回應)
├── Request.cs          # 請求封裝 (Url, FormCollection)
├── Response.cs         # 回應封裝 (StatusCode, Body)
├── MyHttpHandler.cs    # 處理管線入口 (路由分派 → Controller)
├── ControllerBase.cs   # Controller 基類
├── HomeController.cs   # 範例 Controller
├── Model/              # 領域模型
└── View/               # 視圖渲染 (字串模板)

核心代碼解析

1. 瀏覽器發送請求


public class WebBrowser
{
    public static void SendRequest(string url, Dictionary formCollection)
    {
        var request = new Request { Url = url, FormCollection = formCollection };
        string response = MyHttpHandler.HandleRequest(request);
        
        if (!response.StartsWith("Http 200"))
            MessageBox.Show(response); // 簡易錯誤顯示
        else
            // 解析 HTML 顯示在 WebBrowser 控制項中
            RenderHtml(response);
    }
}

2. HttpHandler 路由分派


public class MyHttpHandler
{
    public static string HandleRequest(Request request)
    {
        // 簡易路由解析:/Controller/Action
        var segments = request.Url.Trim('/').Split('/');
        string controllerName = segments.Length > 0 ? segments[0] : "Home";
        string actionName = segments.Length > 1 ? segments[1] : "Index";

        // ControllerFactory 機制
        var controller = ControllerFactory.Create(controllerName);
        if (controller == null)
            return "Http 404: Controller not found";

        // ActionInvoker 機制
        return controller.InvokeAction(actionName, request);
    }
}

3. ControllerFactory 建立 Controller


public static class ControllerFactory
{
    private static readonly Dictionary _controllers = new()
    {
        ["Home"] = typeof(HomeController),
        ["Product"] = typeof(ProductController)
    };

    public static ControllerBase Create(string name)
    {
        if (_controllers.TryGetValue(name, out var type))
            return (ControllerBase)Activator.CreateInstance(type);
        return null;
    }
}

4. ControllerBase 與 ActionInvoker


public abstract class ControllerBase
{
    public string InvokeAction(string actionName, Request request)
    {
        var method = GetType().GetMethod(actionName);
        if (method == null) return "Http 404: Action not found";

        // 簡易參數繫結
        var parameters = method.GetParameters();
        var args = new object[parameters.Length];
        for (int i = 0; i < parameters.Length; i++)
        {
            var p = parameters[i];
            if (request.FormCollection.TryGetValue(p.Name, out var val))
                args[i] = Convert.ChangeType(val, p.ParameterType);
            else
                args[i] = p.HasDefaultValue ? p.DefaultValue : GetDefault(p.ParameterType);
        }

        var result = method.Invoke(this, args);
        return result?.ToString() ?? "Http 200 OK";
    }

    protected virtual string View(string viewName, object model = null)
    {
        return ViewEngine.Render(viewName, model);
    }
}

5. 具體 Controller 實作


public class HomeController : ControllerBase
{
    public string Index()
    {
        return View("Index", new { Title = "歡迎來到 MVC 模擬器", Time = DateTime.Now });
    }

    public string About(string name = "訪客")
    {
        return View("About", new { Name = name });
    }
}

6. Model (資料存取模擬)


public class ProductRepository
{
    public List GetAll() => new List
    {
        new Product { Id = 1, Name = "筆記型電腦", Price = 30000 },
        new Product { Id = 2, Name = "滑鼠", Price = 500 }
    };
}

public class ProductController : ControllerBase
{
    private readonly ProductRepository _repo = new();

    public string List()
    {
        var products = _repo.GetAll();
        return View("ProductList", products);
    }
}

7. ViewEngine 簡易模板渲染


public static class ViewEngine
{
    private static readonly Dictionary _templates = new()
    {
        ["Index"] = @"

@Model.Title

時間: @Model.Time

", ["About"] = @"

關於 @Model.Name

", ["ProductList"] = @"@foreach(var p in Model){}
@p.Name@p.Price
" }; public static string Render(string viewName, object model) { if (!_templates.TryGetValue(viewName, out var template)) return $"View '{viewName}' not found"; // 極簡模板引擎:替換 @Model.Property var props = model?.GetType().GetProperties(); if (props != null) { foreach (var p in props) { template = template.Replace($"@Model.{p.Name}", p.GetValue(model)?.ToString() ?? ""); } } // 處理 @foreach (簡易實作略) return template; } }

執行流程圖解

WinForm (瀏覽器)
    │ 使用者輸入 /Home/Index 按 Enter
    ▼
WebBrowser.SendRequest(url, form)
    │
    ▼
MyHttpHandler.HandleRequest(Request)
    │ 解析路由 → Home/Index
    ▼
ControllerFactory.Create("Home") → HomeController 實例
    │
    ▼
ControllerBase.InvokeAction("Index", request)
    │ 反射呼叫 HomeController.Index()
    ▼
HomeController.Index() → return View("Index", model)
    │
    ▼
ViewEngine.Render("Index", model) → HTML 字串
    │
    ▼
回傳 "Http 200\n" + HTML
    │
    ▼
WinForm 顯示 HTML

教學重點總結

MVC 概念模擬器對應類別關鍵機制
路由MyHttpHandler.HandleRequestURL 解析 → Controller/Action 名稱
ControllerFactoryControllerFactory.Create字典對應 + Activator.CreateInstance
ActionInvokerControllerBase.InvokeAction反射找方法 + 參數繫結 + 呼叫
ModelProductRepository資料存取邏輯封裝
ViewViewEngine.Render模板 + 模型資料 = HTML
ActionResultstring (HTML)簡化為字串回傳

擴充練習建議

  1. 加入 **Filter Pipeline**:`OnActionExecuting` / `OnActionExecuted` / `OnException`
  2. 實作 **Model Binder**:自動從 `Request.FormCollection` 繫結複雜型別
  3. 支援 **ViewData / ViewBag / TempData** 字典
  4. 整合 **真實 Razor 引擎** (`RazorEngine` NuGet) 替代字串替換
  5. 加入 **依賴注入容器** (Autofac/Unity) 管理 Controller/Repository 生命週期
  6. 實作 **Area / Attribute Routing**

這個極簡模擬器雖缺乏生產級功能 (非同步、安全性、快取、區域化...),但完整呈現了 **MVC 核心三角關係與管線流向**,是理解框架本質的最佳切入點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved