VS2012_MVC4入门例子、代码视图分离办法、需要注意的坑爹问题等_被坑后不断更新此贴,要转载的话,请使用链接,不要转载内容
因为此贴会不断更新,所以,要转载的话,请使用链接,不要转载内容。
---------------------------------------------
题外话:
用C#做网站,目前主要有两种模式:Asp.net网站,基于WebForm,和Mvc4 (mvc3、其他自定义框架就不谈了)。也就是做 xx.aspx页面,并且工具栏有一堆现成的.net服务器控件 和 html控件可用。浏览器直接访问 xx.aspx页面。
1.基于WebForm的:
优点:1. 做小网站方便,现成控件直接拖动
2. VS对aspx提供可视支持,可以像DW(DreamWare)那样看到代码的同时,能看到网页的样子。
缺点:1.不容易实现代码与界面分离,因此程序员之间合作不方便,程序与美工合作也不方便,因此不利于做大型BS项目。
2.面对定制的需求,不容易实现。因为现成的.net服务端控件,可定制性差。比如,客户说,这个按钮,要做成某个图案,甚至图案要能变化。这些要求,会超出.net服务端本身控件的能力范围,因此只能找别的解决方案。比如html控件,js控件,或flash控件等。
2.基于Mvc4 + Razor:
缺点:1.可以混编的Razor页面,做小网站不方便,没有能直接拖动的控件(Mvc4里不仅仅可以创建Razor页面,也可以继续使用WebForm页面,这样就可以拖控件)。
2.VS对Razor页面不提供可是支持,因此你只能写代码,没办法马上就看到网页的样子。比如运行后,才能看到网页的最终效果。
优点:1.非常容易实现代码与界面分离,因为MVC4就是干这个事情的。因此利于大家合作,利于做大型BS项目。
2.Razor可以让html与程序的混编,变得非常优雅,就像PHP一样,可以直接在xx.php里混入程序代码与html/css/js代码。最后,Mvc4提供一种类似于php框架的开发方式,也有利于php程序员的加入。
3.最重要的是,Mvc4工程同时支持Razor 与 WebForm!所以,能用Mvc4,尽量用。当然,有一些第三方控件,最好在Mvc4环境下测一下。对于服务器环境,也做一个mvc4例子,测一下。
---------------------------------------------
正文:
1.创建一个项目
1.1 文件 -> 菜单 -> 新建项目 -> 已安装 -> 模板 -> Visual C# -> Web -> ASP.NET MVC 4 Web 应用程序
1.2 选择“空” (空MVC项目)
2.创建首页。注意,按照业界规范,首页的名字,默认应该为Index,但这里为了说明问题,一律不用规范名字。假设首页名字为 MvcMain。
2.1 对 解决方案资源管理器 -> Controllers 单击鼠标右键,选择 添加 -> 控制器
2.2 控制器名称填“MvcMainController”。注意,这里有一个格式规范问题。控制器名称,一律严格按照 “网页URL节点名称 + Controller”方式来命名。
比如 http://www.baidu.com/Node1/Node2,这里,Node1与Node2,就是网页URL节点名称。如果访问入口为: http://www.baidu.com/ABC/ ,则网页URL节点名称为ABC,因此控制器的名称为“ABCController”。
2.3 该页面其他栏目不填,点“添加”。
此时出现:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 7 namespace Mvc4Test2.Controllers 8 { 9 public class MvcMainController : Controller 10 { 11 // 12 // GET: /MvcMain/ 13 14 public ActionResult Index() 15 { 16 return View(); 17 } 18 19 } 20 }
2.4 说明:
2.4.1 Controller是URL的入口。如果这个项目被部署到 http://www.mvc.com/,则上面创建的这个控制器的URL为 http://www.mvc.com/MvcMain 。
2.4.2 当浏览器访问 http://www.mvc.com/MvcMain 时,读取的是 public ActionResult Index() 这个方法。
2.4.3 你可以添加一个方法:About() 与 MailMe(),这个控制器代码就变成了这个样子:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 7 namespace Mvc4Test2.Controllers 8 { 9 public class MvcMainController : Controller 10 { 11 // 12 // GET: /MvcMain/ 13 14 public ActionResult Index() 15 { 16 return View(); 17 } 18 19 public ActionResult About() 20 { 21 return View(); 22 } 23 24 public ActionResult MailMe() 25 { 26 return View(); 27 } 28 } 29 }
2.4.4 此时,About的入口URL为 http://www.mvc.com/MvcMain/About/ ,MailMe的入口URL为:http://www.mvc.com/MvcMain/MailMe/ ,当浏览器访问这个URL时,实际上是上面这个控制器,执行相应的方法。
2.4.5 既然执行的是方法,那就可以加参数。对于参数,刚好是 GET 格式:http://..../NodeName/?ValueName1=Value2&ValueName2=Value2,这个表达式拆开:
http://..../NodeName/ + ? + ValueName1=Value2 + & + ValueName2=Value2
意思是,访问http://..../NodeName/,并且给入两个参数,第一个参数名字为ValueName1,值为Value2;第二个参数名字为ValueName2,值为Value2。
为了快速说明问题,把控制器的 Index方法修改为:
1 public string Index(string arg_strValue, int arg_intValue = 2) 2 { 3 return "MvcMain Index:arg_strValue = [" + arg_strValue + "], arg_intValue = [" + arg_intValue.ToString() + "]"; 4 }
然后按F5调试。此时,打开的应该是:http://localhost:随机端口号/ ,并且是一个错误页面。不慌,在这个URL后面添加“MvcMain/”,整个URL变成:http://localhost:3343/MvcMain/ ,就可以看到效果了。此时,参数还未赋值,使用的是默认值。注意,你应该观察到,参数为默认值的情况下,string为null,mvc没报错,说明它允许null的string作为参数值。但int就不行。如果把Index方法 public string Index(string arg_strValue, int arg_intValue = 2)
改为 public string Index(string arg_strValue, int arg_intValue) ,不给入参数,则会报错。
现在,测试一下给入参数: http://localhost:3343/MvcMain/?arg_strValue=1235&arg_intValue=999 ,看到效果没?
2.4.6 把Index方法恢复为:
1 public ActionResult Index() 2 { 3 return View(); 4 }
3.为控制器添加网页内容。由于控制器只是一个入口,因此需要添加网页内容View。
3.1 对 解决方案资源管理器 -> Views 单击鼠标右键,选择 添加 -> 新建文件夹,这个文件夹名字,要与控制器的名字相对应。上文建立的控制器名字为 MvcMainController,它的名字就是MvcMain。所以,这个文件夹的名字也应该是MvcMain。如果你建立了一个控制器,名字是ABCController,则这个新建文件夹的名字应该为ABC。
3.2 对这个 MvcMain 文件夹,单机鼠标右键,选择 添加 -> 新建项 -> MVC 4 视图页(Razor),下方的“名称(N):”填Index.cshtml。首先,为什么名字是Index?因为Index刚好对应控制器MvcMainController的Index方法。这个是一一对应关系。你可以为控制器的About方法和MailMe方法,建立 About.cshtml 和 MailMe.cshtml 的视图页。其次,为什么后缀为 .cshtml ?这是微软规定的。
3.3 创建好Index.cshtml后,内容设置为:
1 @{ 2 Layout = null; 3 } 4 5 <!DOCTYPE html> 6 7 <html> 8 <head> 9 <meta name="viewport" content="width=device-width" /> 10 <title></title> 11 </head> 12 <body> 13 <div> 14 这就是传说中的视图页。浏览器先通过URL访问控制器,然后控制器执行里面的Index方法,最后Index方法再执行与控制器同名的MvcMain文件夹内的,与控制器的Index方法同名的Index.cshtml. 15 </div> 16 </body> 17 </html>
3.4 F5执行。URL还是填 http://localhost:随机端口号/MvcMain/ ,看到效果了吧。
3.5 现在,在MvcMain文件夹下,按刚才步骤,创建About.cshtml 和 MailMe.cshtml。内容随便写。然后F5调试,访问 http://localhost:随机端口号/MvcMain/About/ 和 http://localhost:随机端口号/MvcMain/MailMe/ ,看到效果了吧?
4.最后一步,让这个控制器成为首页。刚才F5调试时,打开的是 http://localhost:随机端口号/ ,这个本来应该是首页,但出现的是一个错误页面。必须通过 http://localhost:随机端口号/MvcMain/ 才能打开这个页面。现在,我们希望让 http://localhost:随机端口号/ 直接跳转到这个页面。
4.1 解决方案资源管理器 -> 工程 -> 展开App_Start文件夹 -> 鼠标左键双击 RouteConfig.cs
4.2 在这个文件里,找到 controller = "Home", action = "Index"。把Home改成MvcMain就可以了。如果你有一个叫 ABCController的控制器,你也可以把 Home 改为 ABC。
4.3 后面有一个action = "Index",你也可以把Index改为About或MailMe。
4.4 现在F5试试, http://localhost:随机端口号/ 这个URL,现在不是错误页面了吧?而是MvcMain的界面吧。
----------------------------------------------------------------------------------
开发说明:
1.Razor搞出了一堆名堂,什么母版页、布局页、分部页等完全没有存在的必要,把简单问题搞复杂了。Razor比aspx搞定了include和混编,这就足够了。 内容页(视图页) + include + Razor风格混编,已经搞定所有事情,PHP就是这么做的。
2.事实上,大家可以发现,Razor的母版页、布局页和分部页等,最后生成的都是cshtml后缀,说明他们是同一种东西。aspx至少还把内容页aspx和母版页Master用后缀给区分开了。
3.因此,只要掌握了Razor的@单语句,@{ 多语句 } 以及include指令(@RenderPage( page path ) )就可以了。什么模板啊,布局啊,自己就用命名 + 路径来区分开。
4.以上三点只是让大家清楚,这些概念并不是需要一定使用的。但是,VS搞出这些,规范了命名风格,所以,尽量使用它们来遵守这个命名约定,对于规范化开发还是有好处的。此点与上面3点矛盾。总的来说,微软把这些东西弄复杂,但却给出了命名规范。因此大家没必要特意去墨守成规这些概念,能用尽量用,以提高命名规范性,如果有自己的命名规范,不用也行。
----------------------------------------------------------------------------------
后续资料:(以下代码全部为简写)
1.Razor的控制器与视图传值
2.Razor利用Model,进行更方便的传值:
2.1 建立一个Model,为Info:
class Info
{
InfoID : int;
InfoName : string;
}
2.2 控制器传给视图:
2.2.1 控制器Controller:(参数Arg_info的作用,在后面给出)
1 public ActionResult Index(Info arg_info) 2 { 3 Info newInfo = new Info(); 4 newInfo.InfoID = 2; 5 newInfo.InfoName = "newInfo : 2"; 6 return View(newInfo); 7 }
2.2.2 视图View:
1 @model MvcTest.Models.Info 2 3 @{ 4 Layout = null; 5 } 6 7 <!DOCTYPE html> 8 9 <html> 10 <head> 11 <meta name="viewport" content="width=device-width" /> 12 <title></title> 13 </head> 14 <body> 15 <div> 16 <form method="post" action="~/MvcMain/Index_ReceiveData1"> 17 <p> 18 <input type="text" name="InfoID" id="InfoID" value="@Model.InfoID" /> 19 </p> 20 21 <p> 22 <textarea name="InfoName" id="InfoName" cols="45" rows="5">@Model.InfoName</textarea> 23 </p> 24 25 <p> 26 <input type="submit" name="WebUI_Name_Form_Btn_Submit" id="WebUI_ID_Form_Btn_Submit" value="提交 Form" /> 27 </p> 28 </form> 29 </div> 30 </body> 31 </html>
发现没,html控件的ID和Name,与Info类的属性的名字是一样的。这种高耦合,实现了方便性。WCF也是因为这种耦合,才让开发变得更方便。当然,耦合带来的缺点,我们也应该重视。
2.3 视图View传回给控制器
1 [HttpPost] 2 public ActionResult Index_ReceiveData1(Info arg_info) 3 { 4 if (ModelState.IsValid) 5 { 6 int id = arg_info.InfoID; 7 int name = arg_info.InfoName; 8 } 9 else 10 { 11 throw new Excetion(.....); 12 } 13 return RedirectToAction("Index", arg_info);//把这个东东传回index,当然,不传回,做别的事情也可以。如果传回,则控制器的这个方法就不需要些View视图了。 14 15 }
-------------------------------------------------------------------------------------------------------
路径问题
对于一个网站,令人讨厌的就是路径问题。由于MVC4的路由比较特殊,因此,网页与外码之外的所有资源文件,不要放在Controller、Models以及Views这几个特殊目录下。自己在工程目录下,另建一个Resource文件夹。Resource文件夹应该与Controller、Models以及Views目录为同一级。然后,可以把Resource里的结构,设置为与Views内部结构一致。
比如:主页:
~/Views/Main/Index.cshtml
主页的相关资源,最好是放在
~/Resource/Main/下面
实例:
工程 / Views / Main / LayoutPage_Index.cshtml 母版页
工程 / Views / Main / Index.cshtml 主页的内容页
然后,在 LayoutPage_Index.cshtml 里,使用 @RenderPage("~/Views/Main/Index.cshtml"); 来渲染 Index.cshtml 内容。
-------------------------------------------------------------------------------------------------------
Razor + C#混编问题
1.在PHP中,在xx.php里,把一个php的字符串,输出为html的方法是:echo 'PHPStr'; 或 $phpStr = "PHPStr"; echo $phpStr;
在Razor里,
1.1 单行
1.1.1 输出一个C# string变量(假设 string cSharpStr = "123"):@cSharpStr 这样就可以了
1.1.2 输出一个C# 字符串:@("CSharpString") ,注意这个字符串外面要加括号。
1.2 多行
1.2.1 输出一个C# string变量:
@{
string str = "123";
@str;//这样就在这个位置输出123了
}
1.2.2 输出一个C#字符串:
同上,也是:
@{
@("123");
}
1.2.3 直接嵌入HTML代码:
@{
<div>
@("输出内容");
</div>
}
对于html新手来说,需要注意的是,如果要输出的是用户输入的文本,并且用户会输入比如"<script>"这些会引起浏览器执行的代码,那在输出时就需要做html的Encode处理了(或Url的Encode处理)。
-------------------------------------------------------------------------------------------------------
要注意的坑爹问题 (虽然微软的东西用起来很方便,但基本上它的产品都有一些坑爹的小问题)
1. 混编时,Razor指令,一定要在前面加 "@",即使是在@的代码段里。
比如:单独在Html代码里使用:
1 <p> @RenderPage("~/Views/Main/Index_Login_NotLogin.cshtml")</p>
接着,在代码段里使用:
1 <p> 2 @{ 3 //这里就是Razor代码段 4 int a = 0; 5 //使用Razor的RenderPage指令,依然要在前面加@,否则不起作用 6 @RenderPage("~/Views/Main/Index_Login_NotLogin.cshtml"); 7 } 8 </p>
Razor的指令有一堆,RenderXXX,Html.XXX,Url.XXX,等等...
3.Razor的自动推断功能有各种Bug,导致开发者不得不每次写稍微复杂的内容,都需要用 “@” + “大括号”的方式来使用。
4.在Razor开发环境下,不会有自动引用功能,因此需要手动using,或写明class的绝对路径。比如,如果XX是System.Object.XX,则需要手动写全System.Object.XX。
5.在Razor开发环境下,以下IDE功能变得残缺:
5.1 自动完成
5.2 自动提示
5.3 自动格式化(自动格式化的对齐功能总是出问题)
6.如果Razor里的代码有错误,不会提示,也无法访问,也无法调试。只能通过在浏览器的地址栏,输入该View的绝对URL后(View对应的Controller的方法名字),才能看到报错页面,而且也无法调试。