好久没写篇像样的随笔了,昨天晚上看了老赵的随笔,又由于这段时间这方面技术用的比较多,可能大家已经在用了.这里且与大家分享.
一.纯数据输出
1.早在看ActionScript的时候便接触到了这种写法,直到ajax很火的时候,才知道这种格式叫json.
json数据格式是供前端javascript进行操作的暂时性的数据格式,由于javascript语言的原因,访问json数据非常方便,灵活.本来由后端负责产生Ui的,现在全部由javascript操作dom来产生.避免重复,请大家参考此文JSON简介,同时推荐看看IBM的掌握 Ajax系列.
为了产生json格式的数据,asp.net ajax框架提供了一个JavaScriptSerializer类用于将数据转换成json.
分析下此做法的优点与缺点
优点:
1.后台传输数据量会比较小,减轻服务器压力
2.前端操作非常灵活,可以做很多事情
3.适用于交互性比较强的应用.
缺点:
1.必须要操作dom才能产生ui,无法与美工配合工作,需要熟悉javascript和dom的人来参与
2.大数据量下,前端javascript对json数据的解析和dom的生成会明显减慢.
豪无疑问的,直接产生html比解析要速度来的快.这是一点,要是在后端直接输出html的话,可能会由于产生的字符串太多,直接拖垮IE,挂掉.
我想唯一的做法就是尽量避免大数据量,这便要看大家的创意了,还有就是输出json,然后对json分批操作解析,这样也会有所缓解.
3.灵活的同时,降低了通用性(我有一个需求,某一天我用ajax用到我不想用了,我想回到传统的网页上去,啊噢,这种开发模式做不到)
4.前端开发人员必须了解json数据格式
二.与Ui一起输出
这是我们一贯的做法,如asp.net ajax中的UpdatePanel,其会去后端请求其Panel中所有的UI,然后返回给前端,前端不需要解析,直接得到数据输出便可.
分析下此做法的优点与缺点
优点:
1.可以与美工配合,避免动态产生dom的错误
2.前端开发人员不再需要了解后端传回什么数据格式,直接输出
3.复用性比较强,可以同时满足ajax和传统网页的浏览模式
缺点:
1.大大降低了数据的交互性,前端有时候无法得到想要的对象,只能依赖于后端产生的html数据.
2.后端数据传输量稍微变大,不过影响不大.(相对而言,后端把对象解析成json格式需要时间,前端解析json数据也是需要时间的,主要的速度瓶颈还是在数据库连接访问这里)
三.选择你想要的开发模式
上面两种模式没有谁好谁不好之说,追求效率的人可能会选第一种,这种模式与语言无端,可以套用在php,jsp,asp,都可以.
第二种开发模式比较适合asp.net,为什么呢?因为asp.net本身便存在着控件这一用法,而且效率并不低.
大家可以先看看老赵这篇技巧:使用User Control做HTML生成
四.我的做法
1.我有一个白老鼠程序,自己写的blog程序,我会在其上面应用一些新技术,然后思考一些问题.
初期阶段,我用ajax去加载UserControl中产生的html,开始感觉很好.后来我又想做成传统的网页形式,去掉ajax的加载方式,所以,我需要这么写(很高兴,终于看到代码了)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
@ Page ContentType="text/html" Language="C#" EnableViewState="true" MasterPageFile="~/Templete.Master" AutoEventWireup="true" CodeBehind="default.aspx.cs" Inherits="NLBS._default" Title="无标题页" %>
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
@ Register Src="Control/content.ascx" TagName="content" TagPrefix="uc11" %>
![](/Images/OutliningIndicators/None.gif)
<asp:Content ID="Content1" runat="server" contentplaceholderid="ContentPlaceHolder1">
![](/Images/OutliningIndicators/None.gif)
<uc11:content ID="content" runat="server" />
</asp:Content>
content用户控件,用于显示文章列表.大家可以看看我的白老鼠程序
http://www.clingingboy.cn
然后我做着做着...看到别人的blog有ajax应用,那个酷啊,而且我的虚拟主机便宜,访问数据速度慢.我又想把它换成ajax模式爽一把(我的天),或者说我想随意变换数据的加载模式.这种模式采用json数据格式的话根本无法满足需求,修改太大.怎么办怎么办?
由于本人偷偷的看了下ComponentArt的CallBack控件的源码(其实很早就看了),所以本人也仿照其做了一个自己的CallBack控件.我需要一个容器放content用户控件,然后再异步加载.现在现实的问题,这个页面便是content用户控件的容器.我们通过改变url参数来加载不同数据.(控件呈现是在Render方法中实现)
看下面代码.现在你可以访问诸如
http://www.clingingboy.cn/default.aspx?singleArticle_param=true&ID=70 这样的url来获取content数据
protected override void Render(HtmlTextWriter writer)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
//得到一个querystring参数
string[] requestParams = this.GetCallbackParameters();
if (requestParams != null && requestParams.Length > 0)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
//输出控件数据
this.HandleCallback(requestParams);
return;
}
base.Render(writer);
}
private void HandleCallback(string[] arParams)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
try
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
//try render the HtmlTextWriter
StringWriter oStringWriter = new StringWriter();
HtmlTextWriter oWriter = new HtmlTextWriter(oStringWriter, string.Empty);
![](/Images/OutliningIndicators/InBlock.gif)
CallBackEventArgs oArgs = new CallBackEventArgs(oWriter);
oArgs.Parameter = arParams[0];
oArgs.Parameters = arParams;
![](/Images/OutliningIndicators/InBlock.gif)
this.OnCallback(oArgs);
![](/Images/OutliningIndicators/InBlock.gif)
oWriter.Close();
![](/Images/OutliningIndicators/InBlock.gif)
Context.Response.Clear();
Context.Response.Write(oStringWriter.ToString().Trim());
![](/Images/OutliningIndicators/InBlock.gif)
}
catch (Exception ex)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
//render ther error
this.HandleCallbackError(ex);
}
![](/Images/OutliningIndicators/InBlock.gif)
try
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Context.Response.End();
}
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
catch
{ }
}
小心:如果此时,你在本页面来请求content用户控件,呈现出来的会是2个content控件的ui.所以我们需要另建一个空白页面。使用此模式你不旦可以加载用户控件,同时也可以加载asp.net的内置控件。
2.ajax数据加载与传统url同在
我要访问一篇:博客园的一篇随笔,如http://www.cnblogs.com/JeffreyZhao/archive/2007/12/30/usercontrol_as_an_template.html,那在ajax模式下,我们不是要去掉此url,换成javascript的一个数据请求函数?我们可以用preventDefault()方法把链接给屏蔽掉,或者用stopPropagation()方法把事件给阻截下来.(上面两个方法都是firefox下的方法,ie也有此功能方法,asp.net ajax框架进行了封装)
三.ajax加载用户控件在MVC中的应用
相信有部分人已经在开始研究asp.net ajax了,请看此文Ajax with the ASP.NET MVC Framework。作者写了一个Script#,所以其前端javascript代码也是通过用其生成了。我们不管前端,我们只来谈加载方式。让我们看一个Control中的Add方法
[ControllerAction]
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
public void Add(string name)
{
Task task = null;
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (String.IsNullOrEmpty(name) == false)
{
task = _taskDB.AddTask(name);
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (IsAjaxRequest)
{
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (task != null)
{
![](/Images/OutliningIndicators/InBlock.gif)
RenderView("TaskView", task);
![](/Images/OutliningIndicators/InBlock.gif)
}
}
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (task != null)
{
RedirectToAction("List");
}
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
Dictionary<string, object> viewData = new Dictionary<string, object>();
viewData["Tasks"] = _taskDB.GetTasks();
viewData["ShowAddTaskError"] = true;
![](/Images/OutliningIndicators/InBlock.gif)
RenderView("List", viewData);
}
}
}
RenderView会呈现控件的ui,(page,usercontrol都是控件).此代码我们可以看到如果用ajax模式,则会转到TaskView用户控件这里,其本质还是输出UserControl的数据,然后前端得到数据并呈现。但这种做法个人认为不好,每个Action都需要去写if else的语句。我想应该分离出来。
四。控件Id与Name
上次发的随笔篇幅太小,被刷了下来,希望这次没这么倒霉。但我还是希望大家看看
修改服务器控件的ID和Name ,解决大家的痛,我们是有办法解决。最后阿门,愿MVC模式与控件同在,呵呵。我可不想
<% %> 横行霸道。
五.让数据绑定控件代码更漂亮
让我们来看个Repater控件的传统应用
<asp:Repeater ID="normalArticleList" runat="server">
<ItemTemplate>
<div class="textbox">
<div class="textbox-title">
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
<h4><a onclick="<%# urlFormats.ArticleConent(Convert.ToInt32(Eval("ArticleID").ToString()))%>" href="#"><span runat=server visible=<%# Eval("IsTop")%>>[置顶]</span><%
# Eval("Title")%></a>
</h4>
<div class="textbox-label">
[
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
# Eval("PostTime")%>
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
| <%=lang["author"]%>: <a onclick="<%# urlFormats.UserDetail(int.Parse(Eval("AuthorID").ToString()))%>" href="#"><%
# Eval("Author") %></a> ]</div>
</div>
<div class="textbox-content">
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
<%
# GetContent(Eval("Content0").ToString(), Eval("Content1").ToString())%><%
--<%# Eval("Content1") %>--%></div>
<div class="textbox-bottom">
<asp:PlaceHolder ID="actionLinkPanel" runat="server">
<a href="articleManage.aspx?act=edit&id=<%# Eval("ArticleID") %>" title="<%=lang["edit"]%>">
<img src="/styles/default/images/icon_edit.gif" alt="<%=lang["edit"]%>" />
</a>| <a href="/articleManage.aspx?act=delete&id=<%# Eval("ArticleID") %>" title="<%=lang["delete"]%>">
<img src="/styles/default/images/icon_del.gif" alt="<%=lang["delete"]%>" /></a> |
</asp:PlaceHolder>
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
<a onclick="<%# urlFormats.ArticleCategoryUrl(Convert.ToInt32(Eval("categoryID").ToString()))%>" href="#"><%=lang["category"]%>:<%
# Eval("CategoryName")%></a> | <a href="?id=<%# Eval("ArticleID") %>"><%=lang["permalink"]%></a> | <a onclick="<%# urlFormats.ArticleConent(Convert.ToInt32(Eval("ArticleID").ToString()))%>" href="#commentbox" title="评论"><%=lang["comments"]%>:<%
# Eval("CommentCount") %></a> | <a href="#"><%=lang["trackbacks"]%>:<%
# Eval("TrackbackCount") %></a> | <%=lang["views"]%>:<%
# Eval("ViewCount") %>
</div>
</div>
</ItemTemplate>
</asp:Repeater>
很好的完成了工作,通过数据绑定语法。可这界面太烦,字段多,金黄色语法就更多,那个心里烦啊,我们还是无法逃避这个问题,而且我们偶尔还会对一些字段进行逻辑判断。我的做法:用
Literal控件代替绑定语法,在
ItemDataBound事件中完成数据的填充。现在前端
<asp:Repeater ID="normalArticleList" runat="server">
<ItemTemplate>
<div class="textbox">
<div class="textbox-title">
<asp:Literal ID="articleTitle" runat="server"></asp:Literal>
<div class="textbox-label">
<asp:Literal ID="articleLabel" runat="server"></asp:Literal>
</div>
</div>
<div class="textbox-content">
<asp:Literal ID="articleContent" runat="server"></asp:Literal>
</div>
<div class="textbox-bottom">
<asp:Literal ID="articleBottom" runat="server"></asp:Literal>
</div>
</div>
</ItemTemplate>
</asp:Repeater>
后端
void normalArticleList_ItemDataBound(object sender, RepeaterItemEventArgs e)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Article item = (Article)e.Item.DataItem;
Literal title = (Literal)e.Item.FindControl("articleTitle");
Literal articleLabel = (Literal)e.Item.FindControl("articleLabel");
Literal articleContent = (Literal)e.Item.FindControl("articleContent");
Literal articleBottom = (Literal)e.Item.FindControl("articleBottom");
title.Text = RenderNormalTitle(item);
articleLabel.Text = RenderNormalLabel(item);
articleContent.Text = RenderNormalContent(item);
articleBottom.Text = RenderNormalBottom(item);
}
}
这样的写法会漂亮很多,而且数据绑定是通过反射机制的,听过会损失性能。。。
写了5点了,打住。不好意思,赖,没提供什么代码给大家下载,希望对大家有帮助。祝:元旦快乐,工作顺利。