继我的Ajax服务端框架完成后, 也花了些时间学习了一Asp.net MVC,感觉我的Ajax框架也能玩MVC开发, 于是乎,在又加了点功能后,现在也能像Asp.net MVC那样写aspx和ascx了。

先来点代码来看看,具体的页面呈现效果请参考通用数据访问层及Ajax服务端框架的综合示例,展示与下载

<%@ Page Title="商品管理" Language="C#" MasterPageFile="~/MasterPage.master" 
     Inherits="FishWebLib.Mvc.MyPageView<ProductsPageData, ProductsModelLoader>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
    <script type="text/javascript" src="/js/MyPage/Products.js"></script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">

<table cellpadding="4" border="0">
<tr><td>当前分类</td><td>
        <select id="ddlCurrentCategory" onchange="<%= UiHelper.DropDownListAutoRedir("ddlCurrentCategory")%>"  
            combobox="not-editable" style="width:300px;">
<%= Model.Categories.ToHtmlOptions("categoryId", false, "searchWord", "page")%>
</select>
    </td><td>
        <a id="btnCreateItem" href="#" class="easyui-linkbutton" iconCls="icon-add">添加商品</a>
    </td></tr>
</table>
<div style="height: 10px"></div>


<table class="GridView" cellspacing="0" cellpadding="4" border="0" style="border-collapse:collapse;">
    <tr align="left">
        <th style="width:20px;">&nbsp;</th>
        <th style="width:550px;">商品名称</th>
        <th style="width:120px;">单位</th>
        <th style="width:120px;">单价</th>
        <th style="width:50px;">数量</th>
    </tr>
<% foreach( Product product in Model.Products ) { %>
    <tr>
        <td><a href="/AjaxProduct.Delete.cs?id=<%= product.ProductID %>&returnUrl=<%= this.CurrentRequestRawUrl %>" 
                title="删除" class="easyui-linkbutton" plain="true">
            <img src="/Images/delete.gif" alt="删除" /></a>
        </td>
        <td style="white-space:nowrap;">
            <a href="#" rowId="<%= product.ProductID %>" class="easyui-linkbutton" plain="true" iconCls="icon-open" >
                <%= product.ProductName.HtmlEncode()%></a>
        </td><td>
            <span name="Unit"><%= product.Unit.HtmlEncode() %></span>
        </td><td>
            <span name="UnitPrice"><%= product.UnitPrice.ToText() %></span>
        </td><td>
            <input type="text" pid="<%= product.ProductID %>" value="<%= product.Quantity %>" class="quantityTextbox" />
        </td>
    </tr>
<% } %>

<%= Model.PagingInfo.PaginationBar(5)%>
</table>

<input type="hidden" id="hfCurrentCategoryId" value="<%= Model.CurrentCategoryId %>" />


<div id="divProductInfo" title="商品" style="padding: 8px; display: none">
<%= FishWebLib.Ajax.UcExecutor.Execute("~/Controls/ProductInfo.ascx", Model.ProductInfoViewData)%>
</div>

</asp:Content>


再来个ascx

<%@ Control Language="C#" Inherits="FishWebLib.Mvc.MyUserControlView<OrderListViewData>" %>

<table class="GridView" cellspacing="0" cellpadding="4" border="0" style="border-collapse:collapse; width: 99%">
    <tr align="left">
        <th style="width:100px;">订单编号</th>
        <th style="width:160px;">时间</th>
        <th style="width:300px;">客户</th>
        <th style="width:100px;">订单金额</th>
        <th style="width:60px;">已处理</th>
    </tr>
<% foreach( var item in Model.List ) { %>
<tr>
    <td>
        <a href="#" OrderNo="<%= item.OrderID %>" class="easyui-linkbutton" plain="true" iconCls="icon-open">
        <%= item.OrderNo %></a>
    </td>
    <td><%= string.Format("{0:yyyy-MM-dd HH:mm:ss}", item.OrderDate) %></td>
    <td>
        <a href="#" Customer='<%= item.ValidCustomerId %>' class="easyui-linkbutton" plain="true" iconCls="icon-open">
        <%= item.CustomerName.HtmlEncode() %></a>
    </td>
    <td><%= item.SumMoney.ToText() %></td>
    <td>
        <%= item.Finished.ToCheckBox(null, "chk_Finished", true) %>
    </td>
</tr>
<% } %>

<%= Model.PagingInfo.PaginationBar(5) %>
</table>


与Asp.net MVC的aspx,ascx一样:没有与之对应的CodeFile

再来看看"商品管理"页面加载数据的C#代码吧。注意类型的名称与方法的签名,它们在上面Page指令中有引用。

public class ProductsModelLoader
{
    public static ProductsPageData LoadModel()
    {
        ProductsPageData result = new ProductsPageData();
        result = new ProductsPageData();
        result.Categories = BllFactory.GetCategoryBLL().GetList();

        if( result.Categories.Count == 0 ) {
            //HttpContext.Current.Response.Redirect("/Categories.aspx", true);    // 不建议使用这个方法,不利于测试
            FishWebLib.HttpContextHelper.RequireRedirect("/Categories.aspx");
            return null;
        }

        // 获取当前用户选择的商品分类ID
        result.CurrentCategoryId = FishWebLib.FishUrlHelper.GetIntegerFromQueryString("categoryId", 0);
        if( result.CurrentCategoryId == 0 )
            result.CurrentCategoryId = result.Categories[0].CategoryID;

        result.ProductInfoViewData = new ProductInfoViewData(result.Categories, 
					new Product { CategoryID = result.CurrentCategoryId });

        result.PagingInfo.PageIndex = result.PagingInfo.GetPageIndex();
        result.PagingInfo.PageSize = AppHelper.DefaultPageSize;

        // 加载商品列表,并显示
        result.Products = BllFactory.GetProductBLL().GetProductByCategoryId(result.CurrentCategoryId, result.PagingInfo);
        return result;
    }
}


public class ProductsPageData
{
    public PagingInfo PagingInfo;
    public List<Category> Categories;
    public int CurrentCategoryId;
    public List<Product> Products;

    public ProductInfoViewData ProductInfoViewData { get; set; }


    public ProductsPageData()
    {
        this.PagingInfo = new PagingInfo();
    }
}

上面那个ascx是供JS调用的,C#的实现代码如下:(注意是如何执行用户控件的)

/// <summary>
/// 搜索订单,并以HTML代码的形式返回给客户端
/// </summary>
/// <returns></returns>
public static string Search()
{
    // 从查询字符串中读取客户端发过的日期范围。
    QueryDateRange range = QueryDateRange.GetDateRangeFromQueryString("StartDate", "EndDate");

    OrderListViewData data = new OrderListViewData();
    data.PagingInfo.PageIndex = data.PagingInfo.GetPageIndex();
    data.PagingInfo.PageSize = AppHelper.DefaultPageSize;

    // 搜索数据库
    data.List = BllFactory.GetOrderBLL().Search(range, data.PagingInfo);

    // 执行用户控件,并传递所需的呈现数据。
    return FishWebLib.Ajax.UcExecutor.Execute("~/Controls/OrderList.ascx", data);
}

public class OrderListViewData
{
    public List<OrderItem> List;
    public PagingInfo PagingInfo = new PagingInfo();
}

与Asp.net MVC框架一样,页面数据的加载和呈现彻底地分开了。

JS调用上面那个ascx的代码如下:

function btnQuery_Click(){
    var dateRange = GetDateRange("txtStartDate", "txtEndDate");
    if( dateRange == null ) return false;
    var url = '/AjaxOrder.Search.cs?' 
				+ $.param({StartDate: dateRange.StartDate, EndDate: dateRange.EndDate});
    ShowPickerPage(url, 'divResultList_inner', ShowResultSuccess);
    return false;
}

代码回顾

学过Asp.net MVC的朋友应该能发现,前面示例代码中的 aspx, ascx的写法,与Asp.net MVC的写法是100%的兼容的。 但我肯定没有使用Asp.net MVC,您可以下载示例代码去看。

当初学习Asp.net MVC是因为有些人把Asp.net MVC说得太过于神话了,好像用Asp.net做开发,非它不可。但是,学了之后才发现, 确实,这个东西有很多优点,但没那么神奇。我认它最出色的地方还是在于它的思想:MVC,这种思想能够让我们在开发时, 尽量去分离一些可分离的东西,比如:呈现与获取数据的过程,从而可以在一个地方只关注一件事情,也就是它所提倡的:分离关注点。

正如前面所说,我认为Asp.net MVC的优点在于它的设计体现了MVC的思想。但让人不解的是:微软在实现时,不知为何, 非要把MVC搞得与WebForms差别巨大。这种区别尤其是在加入了Route和一堆Html扩展之后。 对于Route和一堆Html扩展,我对它们没多大的兴趣,因为它们于MVC无关,对于代码的维护和性能根本没什么改善。 所以也不打算在这个山寨版本上采用,反而认为现在的代码更容易理解了。

至于在Ajax方面的实现,我的框架也完全是符合MVC思想的。 而且在生成HTML片段时,仍然可以使用MVC的思想:先准备数据,然后交给ascx来呈现。

我的MVC框架与Asp.net MVC的不同之处:
1. 简单了很多,抛弃了许多与MVC无关的东西。因此,学习成本更低。
2. Controller少了很多限制,可以在单独的类库中实现。为了方便安全检查,建议放在一个命名空间中,或者取个前缀或后缀,这也符合:约定胜于配置。
3. 由于没有Route,页面是由Asp.net框架所调用的,而不是先经过Controller,但页面的数据加载是由一个辅助的类来完成的, 这个类一定要实现一个名为“LoadModel”的方法(签名不限,框架会识别),同样,也是采用约定胜于配置的原则。

点击此处进入下载页面

posted on 2011-05-02 21:26  Fish Li  阅读(14274)  评论(13编辑  收藏