不用asp.net MVC,用WebForm照样可以实现MVC

cownew 2015-12-25 10:29:28
加精
《避开WebForm天坑,拥抱ASP.Net MVC吧》这篇博客中我讲到了ASP.net WebForm由于一些先天的“诱导犯罪”的缺陷,现在用ASP.net MVC的公司越来越多。但是根据那篇文章末尾的"ASP.net MVC的免费网络公开课"调查表的统计,我们发现有一大半的人还没有使用过ASP.Net MVC,而没用过ASP.net MVC的人中竟然有很多人人是因为感觉ASP.Net 难、没时间学。调查表分析数据如下:


初看ASP.net确实难:复杂的路由机制、 ViewData/ViewBag/TempData、过滤器、Razor、Layout、XXXHelper、验证、WebAPI、依赖注入、单元测试……光看这一堆概念头就晕了,“还是拖控件简单”。

其实学习一个新的框架,只要搞清他的原理就会“豁然开朗”,再看其他的东西就不会感觉恐惧了。

这篇文章我将会带着大家搞明白什么叫MVC模式,并且带着大家用大家熟悉的Asp.Net WebForm实现MVC!

对!你没听错!

用Asp.Net WebForm实现MVC!



再次感受一下ASP.net WebForm吧。

假设有一个Person对象的集合,我们要在网页中以html渲染,那么要如下编写

<table>
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate><tr><td><%#Eval("Name") %></td><td><%#Eval("Age") %></td></tr></ItemTemplate>
</asp:Repeater>
</table>
  

C#代码:

复制代码
if(!IsPostBack)
{
List<Person> list = new List<Person>();
list.Add(new Person { Name = "rupeng", Age = 8 });
list.Add(new Person { Name = "qq", Age = 18 });
Repeater1.DataSource = list;
Repeater1.DataBind();
}


这样做的缺点是C#代码中访问了apsx中的控件Repeater1,也就是在aspx中必须要有一个Repeater类型、Id为Repeater1的控件,这样aspx就和C#代码耦合在了一起。麻烦在哪儿呢?

1)如果aspx有两个地方都要用list了,那么就要写两组DataSource=list;DataBind();

2)如果aspx中突然不想要Repeater了,把Repeater1删掉C#代码就会报错

3)Aspx中忽然不想用Repeater进行数据的显示了,想换别的控件,那么C#代码也要改


再比如,在ASP.Net WebForm中,实现加法计算器会如下实现:

<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
+<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="=" />
<asp:TextBox ID="TextBox3" runat="server"></asp:TextBox>
  

protected void Button1_Click(object sender, EventArgs e)
{
int i1 = Convert.ToInt32(TextBox1.Text);
int i2 = Convert.ToInt32(TextBox2.Text);
int i3 = i1 + i2;
TextBox3.Text = i3.ToString();
}


后台的C#代码和aspx的耦合要求aspx视图中必须有三个名字各为TextBox1、TextBox2、TextBox3的TextBox类型的服务器控件。如果我想把计算的结果从TextBox改成span就不行。前端设计人员看到TextBox绝对没有input亲切,前端人员对input 的把控能力会被TextBox更好。另外不必再说WebForm引入的ViewState、页面生命周期、ClientID等令人作呕的问题。

有同学会说了:你有病吗,开发时候aspx怎么可能总是变来变去,即使aspx变了,你C#代码也就变呗,有什么大不了的?

如果说系统小的话可能无所谓,对于比较复杂的系统,如果aspx和C#这样紧密的耦合,维护还会特别麻烦。而且如果实现像一些CMS系统那样可以动态修改模板文件的话就是存在着“C#无法预测、无法强制要求aspx到底怎么写”的问题。



这还仅仅是展示一个集合的问题,如果要展示复杂的扁平化数据或者需要从用户输入中获取数据,用这种方式更灾难。

那么MVC思想怎么解决呢?逻辑代码(Controller)不直接和页面视图(View)进行交互,他们之间用Model(数据模型)作为沟通的通道。当需要展示数据的时候由Controller收集到数据(Model),然后把数据交给View去展示;当Controller需要读取View中用户输入内容的时候,框架会把View中的数据映射到Model中,然后Controller读取Model中的数据进行后续的逻辑处理。这样就把逻辑代码(俗称C#代码)和视图(俗称页面)进行解耦了。

光说概念没用,还是先看代码把。下面使用MVC模式改造的“显示Person集合”:



View视图PersonsView.aspx

<%@ Page Language="C#"%>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="WebApplication1" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<table>
<%
var persons = (List<Person>)Context.Items["persons"];
foreach(var person in persons)
{
%>
<tr><td><%=person.Name %></td><td><%=person.Age %></td></tr>
<%
}
%>
</table>
</body>
</html>

注意,我把aspx相关的两个自动生成的.cs文件删掉了,并且把<%@Page%>标签的AutoEventWireup、CodeBehind、Inherits等几个属性也都干掉了,这样aspx就变成了一个纯粹的“模板引擎”



作为Controller的Index.ashx的代码如下:
public void ProcessRequest(HttpContext context)
{
List<Person> list = new List<Person>();
list.Add(new Person { Name="rupeng",Age=8});
list.Add(new Person { Name = "qq", Age = 18 });
context.Items["persons"] = list;
context.Server.Transfer("PersonsView.aspx");
}

这里借鉴了JSP中“request.getRequestDispatcher("index.jsp").forward(request,response)”一样的思路。

context.Server.Transfer是在服务器内部把请求处理权转交给"PersonsView.aspx"处理。HttpContext中的Items的生命周期是整个请求响应,这样我们在一般处理程序中把数据放到context.Items中,然后在"PersonsView.aspx"中就可以可以通过Context.Items["persons"]拿到这个数据从而进行数据的展示。

为什么把数据放到HttpContext.Items中呢。由于Transfer仅仅是服务器内部处理权的转接,但是仍然是在一个请求中的,所以放到Context.items是最好的。如果放到Session、Application等中会有并发的问题。

这样Controller(一般处理程序)和View(aspx)之间只要维持一个“要传递一个名字为persons类型的List<Person>”这样一个弱耦合关系即可,至于aspx用不用这个persons、用几次persons、怎么用persons,你Controller都不用管。

按照同样方法改造加法计算器



下面是视图AddView.aspx的代码
<%@ Page Language="C#"%>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<%dynamic viewBag = Context.Items["ViewBag"]; %>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>加法计算器</title>
</head>
<body>
<form id="form1">
<input type="hidden" name="action" value="addSubmit" />
<input type="text" name="i1" value="<%=viewBag.i1 %>" />+<input type="text" name="i2" value="<%=viewBag.i2%>" />
<input type="submit" value="=" /><input type="text" value="<%=viewBag.i3 %>" />
</form>
</body>
</html>

而AddHandler.ashx的主体代码如下:
public void ProcessRequest(HttpContext context)
{
string action = context.Request["action"];
dynamic viewBag = new System.Dynamic.ExpandoObject();
if(string.IsNullOrEmpty(action))
{
viewBag.i1 = "";
viewBag.i2 = "";
viewBag.i3 = "";
}
else if(action=="addSubmit")
{
int i1 = Convert.ToInt32(context.Request["i1"]);
int i2 = Convert.ToInt32(context.Request["i2"]);
int i3 = i1 + i2;
viewBag.i1 = i1;
viewBag.i2 = i2;
viewBag.i3 = i3;
}
context.Items["ViewBag"] = viewBag;
context.Server.Transfer("AddView.aspx");
}

由于View和Controller之间传递的数据比较复杂、比较多,为了简化开发,这样用了dynamic 动态类型。熟悉ASP.Net MVC的同学是不是感觉这个和ASP.net MVC中的ViewBag异曲同工呢。

在这个加法计算器中如果我想把结算结果用span显示,那么只要把<input type="text" name="i2" value="<%=viewBag.i2%>" />改成<span><%=viewBag.i2%></span>就可以了。美工也容易介入页面美化。

如果我想把页面的Title从“加法计算器”改成“3和5相加的结果”,那么只要这样改就可以:<title><%=viewBag.i1 %>和<%=viewBag.i2 %>相加的结果</title> 这样model里的数据我aspx想用几次用几次,想怎么用就怎么用。有没有感觉到和WebForm不一样的地方呢?

所以只要思想想通了,其实实现MVC模式不一定要用ASP.net MVC,我见过很多项目都是自己搞的MVC机制。

当然既然ASP.net MVC已经这么优秀了,一般情况没必要像我这样重新自己发明一个轮子用。

这里给大家讲ASPX实现MVC只是用大家熟悉的东西让大家明白原理,工程项目应用还是直接用ASP.Net MVC吧。
...全文
4281 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_34583875 2016-04-08
  • 打赏
  • 举报
回复
招聘:2年及以上ASP.Net开发经验,熟悉.NET平台架构,熟悉HTML、CSS、JAVASCRIPT、XML等 工资面议。有意向的可以电话:0731-83298636
Hikey 2016-04-07
  • 打赏
  • 举报
回复
感谢楼主。webform时代离开的人 感觉开始对mvc有点概念了
epui2008 2016-03-19
  • 打赏
  • 举报
回复
通俗易懂,最好能有人在性能上做个比较给出数据。。。
Frog1228 2016-01-14
  • 打赏
  • 举报
回复
我很想知道,在Winform下模仿MVC的好方法。
本拉灯 2016-01-02
  • 打赏
  • 举报
回复
杨杨杨复活了。。。
  • 打赏
  • 举报
回复
我是业余玩玩.net,想学mvc,但真的觉得有难
无涯大者 2016-01-02
  • 打赏
  • 举报
回复
感谢杨老师的分享!!
threenewbee 2015-12-31
  • 打赏
  • 举报
回复
支持下原创分享。
Frog1228 2015-12-31
  • 打赏
  • 举报
回复
引用 22 楼 roboot 的回复:
引用 15 楼 mjjackey 的回复:
ASP.NET MVC 很难吗,那不用这个的用什么做.NET开发呢。
你猜
不做这个的,还真不知道,大概知道MVC是很通用的架构模式,所以很好奇。
Lightning-McQueen 2015-12-31
  • 打赏
  • 举报
回复
引用 15 楼 mjjackey 的回复:
ASP.NET MVC 很难吗,那不用这个的用什么做.NET开发呢。
你猜
by_封爱 2015-12-31
  • 打赏
  • 举报
回复
有个卵用....
llyj3385 2015-12-31
  • 打赏
  • 举报
回复
.net的MVC看着有点晕
wisdom1 2015-12-31
  • 打赏
  • 举报
回复
引用 17 楼 qq_25223941 的回复:
[quote=引用 16 楼 yekongswz 的回复:] MVC太复杂了吗,呵呵
不要嘲讽人。。自己很NB?[/quote] 月入多少W呢 ~~
Cx_轩 2015-12-30
  • 打赏
  • 举报
回复
引用 16 楼 yekongswz 的回复:
MVC太复杂了吗,呵呵
不要嘲讽人。。自己很NB?
yekongswz 2015-12-29
  • 打赏
  • 举报
回复
MVC太复杂了吗,呵呵
joyhen 2015-12-28
  • 打赏
  • 举报
回复
Microsoft.AspNet.FriendlyUrls
Frog1228 2015-12-28
  • 打赏
  • 举报
回复
ASP.NET MVC 很难吗,那不用这个的用什么做.NET开发呢。
缪军 2015-12-26
  • 打赏
  • 举报
回复
楼主基本概念不清, 你这只是用asp.net webform模仿asp.net MVC, 而不是用asp.net webform实现MVC设计模式
吴太乙 2015-12-26
  • 打赏
  • 举报
回复
杨校长玩的66666666666
全栈极简 2015-12-25
  • 打赏
  • 举报
回复
不纠结,根据项目以及人员实际情况灵活选择。
加载更多回复(9)

62,072

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧