ASP.NET MVC4+BootStrap 实战(一)

简介:

好久没有写关于web开发的文章了,进到这个公司一直就是winform和Silverlight,实在是没有实战web项目的机会。大D也辞职了,去搞web app了。自己也该闲暇时间多学习学习,每天进步一点点。


OK,不多说了,看一下Solution的截图

wKiom1SEGYbjvyd9AACadjvVi1Q564.jpg

基本上一看就明白了,控制器调用Biz层,Biz层调用DAL层,DAL层进行数据的CURD。Utility是一些公用的类库。ok,为什么程序集的命名都是以Bruce开头呢,因为我在公司的英文名叫这个。废话不多说,我们先看一下页面

wKiom1SEGqCST0eWAAFI-YZmIi4175.jpg

我们引入了BootStrap,主要是为了页面布局。在Views中Partial下面放的都是部分页。

我们先看一下运行效果,今天主要是讲页面初始化部分。

wKioL1SEHMmQN3aBAAJuC6gCl4I512.jpg

其实查询条件就是婚否,出生日期,姓名的模糊查询。我们先看一下页面Index.cshtml的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<!DOCTYPE html>
< html >
< head >
     < meta  charset = "utf-8"  />
     < meta  http-equiv = "X-UA-Compatible"  content = "IE=edge"  />
     < meta  name = "viewport"  content = "width=device-width;initial-scale=1"  />
     < title >Compare data between Solr and DB</ title >
     < link  rel = "stylesheet"  type = "text/css"  href = "~/BootStrap/css/bootstrap-theme.css"  />
     < link  rel = "stylesheet"  type = "text/css"  href = "~/BootStrap/css/bootstrap.css"  />
           @*@Styles.Render("~/css")*@
           @Scripts.Render("~/bundles/BootStrap")
           @Scripts.Render("~/bundles/Scripts")
     < style  type = "text/css" >
         .pre-Scrollable {
             max-height: 700px;
             overflow-y: scroll;
         }
     </ style >
</ head >
< body >
     < div  class = "container" >
         < form  id = "formsync" >
             < div  class = "row" >
                 < div  class = "col-md-12" >
                     < h1  style = "color:red" >< b >Compare Data Between Solr and DB</ b ></ h1 >
                 </ div >
             </ div >
             < div  class = "row"  id = "divloding"  style = "display:none;text-align:center" >
                 < div  class = "col-md-6" >
                     < img  src = "~/Images/ajaxLoading.gif"  alt = "load failed"  />
                     < label >getting,please wait......</ label >
                 </ div >
             </ div >
             < div  class = "row"  id = "divcompare"  style = "display:none;text-align:center" >
                 < div  class = "col-md-6" >
                     < img  src = "~/Images/ajaxLoading.gif"  alt = "load failed"  />
                     < label >comparing,please wait......</ label >
                 </ div >
             </ div >
             < div  class = "row"  id = "divfix"  style = "display:none;text-align:center" >
                 < div  class = "col-md-6" >
                     < img  src = "~/Images/ajaxLoading.gif"  alt = "load failed"  />
                     < label >fixing,please wait......</ label >
                 </ div >
             </ div >
             < div  class = "row"  style = "margin-top:10px" >
                 < div  class = "col-md-12 form-inline" >
                     < div  class = "form-group input-group" >
                         < span  class = "input-group-addon" >IsMarried:</ span >
                         @Html.DropDownList("ddlMarried", ViewBag.MarriedList as SelectList, null, new { id = "ddlMarried", @class = "form-control" })
                     </ div >
                     < div  class = "form-group"  style = "margin-left:10px" >
                         < label  class = "control-label" >BirthDay:</ label >
                         < input  type = "date"  id = "txtdatestart"  class = "form-control" >
                         < label  class = "control-label" >-</ label >
                         < input  type = "date"  id = "txtdateend"  class = "form-control" >
                     </ div >
                     < div  class = "form-group input-group"  style = "margin-left:10px" >
                         < span  class = "input-group-addon" >Name:</ span >
                         < input  id = "txtusername"  type = "text"  class = "form-control"  placeholder = "input name..."  style = "width:120px"  />
                     </ div >
                     < div  class = "form-group"  style = "margin-left:10px" >
                         < input  id = "btnsearch"  type = "button"  class = "btn btn-info"  value = "Get"  style = "width:70px"  />
                     </ div >
                 </ div >
             </ div >
             < div  class = "row"  style = "margin-top:10px" >
                 < div  id = "divresult"  class = "col-md-7 form-inline  pre-Scrollable" >
                     @{Html.RenderPartial("~/Views/Partial/UserInfoPartial.cshtml");}
                 </ div >
                 < div  class = "col-md-5" >
                     @{Html.RenderPartial("~/Views/Partial/DiffAndSameWithSolrPartial.cshtml");}
                 </ div >
             </ div >
         </ form >
     </ div >
</ body >
</ html >

我们使用html5+BootStrap布局,这里用到了BootStrap的网格系统,将浏览器平分为12份,即12列,很容易构造出响应式布局系统。那么什么是BootStrap的网格系统,看如下的解释

wKiom1SEHgqig1sEAAL6wBcgw9U665.jpg


OK,我们怎么看是否是响应式的布局呢,我们打开谷歌浏览器,现将浏览器缩小到一定程度。

wKioL1SEH9rgdj-jAAHg2oPG2L8475.jpg

看到了吧,即使设备浏览器这么小,我们还是能用。那我们在手机模拟器中测试一下,打开谷歌浏览器,按F12,点击手机模拟器样的东西,然后Device选择iphone6。

wKiom1SEIAngkqOvAAMP1bmprLg719.jpg

我们看到iphone6下面的效果是这样的。说到这里我最近很讨厌两个广告,一个是“这个是iphone6,这个是iphone6 plus,它们都有一个叫健康的东西.....但是好吃啊”,还有一个是“当牛魔王变成一个饺子,我愿意变成一双筷子”。看到这两个广告,我想砸电视。

那为什么不同的设备不同的浏览器都是可以正常浏览的呢,原因就在于这段代码

1
< meta  name = "viewport"  content = "width=device-width;initial-scale=1"  />

这段代码的意思是网页宽度默认等于屏幕宽度,缩放比例默认为1(网页初始比例占屏幕的100%)。

ok,我们接下来看head部分css和js的引用,这里有个新东西叫Bundle,用来打包压缩js或者css的。通过它打包压缩的js或者css客户端只需要下载一次包即可,而且可以在客户端缓存起来,当检测到有更新时,才会重新下载。


下面是Bundle.cs的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using  System.Web;
using  System.Web.Optimization;
 
namespace  Brue.GRLC.Web
{
     public  class  BundleConfig
     {
         // 有关 Bundling 的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkId=254725
         public  static  void  RegisterBundles(BundleCollection bundles)
         {
             bundles.Add( new  ScriptBundle( "~/bundles/BootStrap" ).Include(
                         "~/Scripts/jquery-1.11.1.js" , "~/BootStrap/js/bootstrap.js" ));
 
             bundles.Add( new  ScriptBundle( "~/bundles/Scripts" ).Include( "~/Js/Index.js" ));
 
             bundles.Add( new  StyleBundle( "~/css" ).Include( "~/BootStrap/css/bootstrap-theme.css"
                 "~/BootStrap/css/bootstrap.css" ));
         }
     }
}

注意,在这里引用js的时候不要引用压缩过的js,比如xxx.min.js。当Bundle在遇到这种js命名文件的时候,直接就忽略掉了。那么我们在Head中只需要使用如下代码来引用即可。

1
2
@Scripts.Render( "~/bundles/BootStrap" )
@Scripts.Render( "~/bundles/Scripts" )

OK,在这我碰到一个问题,就是我的css通过这种方式引用,始终提示Index out of range。如果哪位大牛知道原因的话麻烦留个言,谢谢!

OK,我们接下来看一下控制器代码,页面刚进来,会走Home/Index。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  ActionResult Index()
         {
             List< object > marriedList = GRLCBiz.GetInstance().GetMarriedList();
             SelectList selectList =  new  SelectList(marriedList,  "MarriedID" "DisplayContent" "-1" );
             ViewBag.MarriedList = selectList;
 
             DataResponse<UserDBEntity> dataResponse = GRLCBiz.GetInstance().GetUserInfoEntityList();
             UserInfoViewModel userInfoViewModel =  new  UserInfoViewModel();
             userInfoViewModel.DataResponse = dataResponse;
             userInfoViewModel.DataResponse.PageIndex = ConstValues.CONN_DefaultPageIndex;
             userInfoViewModel.DataResponse.PageSize = ConstValues.CONN_DefaultPageSize;
             userInfoViewModel.DataResponse.StartPageIndex = 1;
             return  View(userInfoViewModel);
         }

首先我们构造了一个SelectList用于下拉列表,Biz层的代码很简单

1
2
3
4
5
6
7
8
9
public  dynamic GetMarriedList()
         {
             IList< object > marriedList =  new  List< object >();
             marriedList.Add( new  { MarriedID = -1, DisplayContent =  "No Selection"  });
             marriedList.Add( new  { MarriedID = 0, DisplayContent =  "Married"  });
             marriedList.Add( new  { MarriedID = 1, DisplayContent =  "UnMarried"  });
 
             return  marriedList;
         }

用匿名类去构造一个List。接下来就是DataReponse的获取,Biz层的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public  DataResponse<UserDBEntity> GetUserInfoEntityList(UserInfoRequest request =  null )
         {
             if (request== null )
             {
                 request =  new  UserInfoRequest();
                 request.PageIndex = ConstValues.CONN_DefaultPageIndex;
                 request.PageSize = ConstValues.CONN_DefaultPageSize;
             }
           
             int  totalCount=0;
 
             List<UserDBEntity> userDBEntityList = GRLCDAL.GetInstance().GetUserInfoEntityList(request,  out  totalCount);
             DataResponse<UserDBEntity> dataResponse =  new  DataResponse<UserDBEntity>();
             dataResponse.DataList = userDBEntityList;
             dataResponse.TotalCount = totalCount;
             return  dataResponse;
         }

没什么可说的,ConstValues类中是一些静态只读属性

1
2
3
4
5
6
7
8
public  class  ConstValues
     {
         public  static  readonly  string  CON_DBConnection = ConfigurationManager.ConnectionStrings[ "DB_ConnectionStr" ].ToString();
         public  static  readonly  string  CON_DbScriptXmlFolder = ConfigurationManager.AppSettings[ "DbScriptXmlFolder" ];
         public  static  readonly  int  CONN_DefaultPageSize =  int .Parse(ConfigurationManager.AppSettings[ "DefaultPageSize" ]);
         public  static  readonly  int  CONN_DefaultPageIndex = 1;
         public  static  readonly  int  CONN_PagerDisplayCount =  int .Parse(ConfigurationManager.AppSettings[ "PagerDisplayCount" ]);
     }

看一下DAL层。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public  List<UserDBEntity> GetUserInfoEntityList(UserInfoRequest request,  out  int  totalCount)
         {
             totalCount = 0;
             string  sqlScript =  string .Empty;
             try
             {
                 sqlScript = DBScriptManager.GetScript( this .GetType(),  "GetUserInfo" );
                 SqlParameter[] sqlParameters = 
                 {
                     new  SqlParameter( "@IsMarried" ,SqlDbType.Char,1),
                     new  SqlParameter( "@StartDate" ,SqlDbType.DateTime),
                     new  SqlParameter( "@EndDate" ,SqlDbType.DateTime),
                     new  SqlParameter( "@UserName" ,SqlDbType.NVarChar,20),
                     new  SqlParameter( "@PageIndex" ,SqlDbType.Int),
                     new  SqlParameter( "@PageSize" ,SqlDbType.Int),
                     new  SqlParameter( "@TotalCount" ,SqlDbType.Int)
                 };
 
                 sqlParameters[0].Value = request.IsMarried;
                 sqlParameters[1].Value = request.StartDate;
                 sqlParameters[2].Value = request.EndDate;
                 sqlParameters[3].Value = request.UserName;
                 sqlParameters[4].Value = request.PageIndex;
                 sqlParameters[5].Value = request.PageSize;
                 sqlParameters[6].Direction = ParameterDirection.Output;
 
                 DataSet ds = SqlHelper.ExecuteDataset(ConstValues.CON_DBConnection, CommandType.Text, sqlScript, sqlParameters);
                 if  (ds !=  null  && ds.Tables.Count > 0)
                 {
                     totalCount = Convert.ToInt32(sqlParameters[6].Value);
                     return  ds.Tables[0].ToEntityList<UserDBEntity>();
                 }
 
                 return  new  List<UserDBEntity>();
             }
             catch  (Exception ex)
             {
                 LogHelper.WriteExceptionLog(MethodBase.GetCurrentMethod(), ex);
                 return  null ;
             }
         }

OK,我们看一下这个GetUserInfo脚本,在Bruce.GRLC.DbScriptXml程序集下。

wKioL1SELgGinSrUAABc8KMeEz0396.jpg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<? xml  version = "1.0"  encoding = "utf-8"  ?>
< Scripts >
   < Script  Key = "GetUserInfo" >
     <![CDATA[
DECLARE @UserTempTable TABLE
(  
     ID INT IDENTITY(1,1) NOT NULL,
     UserNo CHAR(25) NOT NULL
)
 
INSERT INTO @UserTempTable
(
     UserNo
)
SELECT
     A.UseNo
FROM Bonus.dbo.[User] A WITH(NOLOCK)
LEFT JOIN Bonus.dbo.UerInfo B WITH(NOLOCK)
     ON A.UseNo = B.UseNo
WHERE (@IsMarried IS NULL OR @IsMarried = '' OR B.Temper = @IsMarried)
     AND
     (
         @StartDate IS NULL 
         OR @EndDate IS NULL 
         OR B.BirthDay BETWEEN @StartDate AND @EndDate
     )
     AND 
     (
         @UserName IS NULL 
         OR @UserName = '' 
         OR B.Name LIKE '%' + @UserName + '%'
     )
ORDER BY A.UseNo ASC
     
SELECT @TotalCount = COUNT(1) FROM @UserTempTable
 
SELECT
     UseNo,
     Name,
     Age,
     Married
FROM(
     SELECT
         ID = ROW_NUMBER() OVER(ORDER BY UseNo ASC),
         A.UseNo,
         B.Name,
         B.Age,
         Married = CASE WHEN B.Temper = '1'
                         THEN '已婚'
                        ELSE '未婚'
                   END
         FROM Bonus.dbo.[User] A WITH(NOLOCK)
     LEFT JOIN Bonus.dbo.UerInfo B WITH(NOLOCK)
         ON A.UseNo = B.UseNo
     INNER JOIN @UserTempTable C
         ON C.UserNo = A.UseNo
) N
WHERE ID BETWEEN (@PageIndex - 1)* @PageSize + 1 AND @PageIndex * @PageSize
    ]]>
   </ Script >
</ Scripts >

脚本很简单,就是传入参数查分页数据。

在DAL层我们将DataTable通过ToEntityList转化为了实体List,在Utility中我们定义了一个扩展用来转化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public  static  class  DataTableToEntityExtension
     {
         public  static  List<T> ToEntityList<T>( this  DataTable dt)  where  T :  class , new ()
         {
             List<T> entityList =  new  List<T>();
 
             Type entityType =  typeof (T);
             PropertyInfo[] propertys = entityType.GetProperties();
             DataMappingAttribute mappingAttribute =  null ;
 
             foreach  (DataRow dr  in  dt.Rows)
             {
                 T tEntity =  new  T();
 
                 foreach  (PropertyInfo pi  in  propertys)
                 {
                     mappingAttribute = pi.GetCustomAttribute( typeof (DataMappingAttribute))  as  DataMappingAttribute;
 
                     if  (mappingAttribute !=  null  && dt.Columns.Contains(mappingAttribute.mappingName))
                    
                         if  (!pi.CanWrite)  continue ;
 
                         object  value = dr[mappingAttribute.mappingName];
                         if  (value != DBNull.Value)
                             pi.SetValue(tEntity, value,  null );
                     }
                 }
                 entityList.Add(tEntity);
             }
             return  entityList;
         }
     }

值那么转化的时候是怎么让DataTable的列和实体匹配起来,你可以将列别名和实体定义成一样的,还有一种你可以使用Attribute。那我们使用后者,因为后者更灵活。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[AttributeUsage(AttributeTargets.Property)]
     public  class  DataMappingAttribute : Attribute
     {
         public  string  mappingName;
         public  DbType dbType;
         public  DataMappingAttribute()
         { }
 
         public  DataMappingAttribute( string  mappingName, DbType dbType)
         {
             this .mappingName = mappingName;
             this .dbType = dbType;
         }
     }

定义好Attribute之后,我们设置其能使用的目标只能是Property。然后我们在实体类里面的属性上加上这个Attribute。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace  Bruce.GRLC.Model.Entity
{
     public  class  UserDBEntity
     {
         [DataMapping( "UseNo" , DbType.AnsiString)]
         public  string  UserID {  get set ; }
 
         [DataMapping( "Name" , DbType.AnsiString)]
         public  string  UserName {  get set ; }
 
         [DataMapping( "Age" , DbType.Int32)]
         public  int  Age {  get set ; }
 
         [DataMapping( "Married" , DbType.String)]
         public  string  Married {  get set ; }
     }
}

在DataTableToEntityExtension这个扩展中我们得到属性的Attribute去和DataTable的列名去匹配,反射赋值。

OK,拿到数据后,我们在控制器构造viewModel,传递给界面来绑定。我们看一下部分页UserInfoPartial.cshtml的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@using Bruce.GRLC.Model.ViewModel;
@model UserInfoViewModel
< table  id = "tabuserinfo"  class = "table table-bordered table-hover" >
     < thead >
         < tr  style = "background-color: #2aabd2;color:white" >
             < th >帐号</ th >
             < th >姓名</ th >
             < th >年龄</ th >
             < th >婚否</ th >
         </ tr >
     </ thead >
     < tbody >
         @if (Model != null && Model.DataResponse != null && Model.DataResponse.DataList != null)
         {
             foreach (var userEntity in Model.DataResponse.DataList)
             {
                 < tr >
                     < td >
                         @userEntity.UserID
                     </ td >
                     < td >
                         @userEntity.UserName
                     </ td >
                     < td >
                         @userEntity.Age
                     </ td >
                     < td >
                         @userEntity.Married
                     </ td >
                 </ tr >
             }
         }
     </ tbody >
</ table >
< div  id = "divpagination" >
     @{Html.RenderPartial("~/Views/Partial/PaginationPartial.cshtml", Model.DataResponse);}
</ div >

其实也就是一个应用了BoootStrap样式的表格,有边框和鼠标经过的样式。关于BootStrap的样式的使用,请参考BootStrap官网。代码很简单,就是循环遍历,展示数据。



本文转自 BruceAndLee 51CTO博客,原文链接:http://blog.51cto.com/leelei/1587301,如需转载请自行联系原作者

相关文章
|
2月前
|
开发框架 .NET 中间件
七天.NET 8操作SQLite入门到实战 - (2)第七天Blazor班级管理页面编写和接口对接
七天.NET 8操作SQLite入门到实战 - (2)第七天Blazor班级管理页面编写和接口对接
|
2月前
|
开发框架 .NET C#
使用C#进行.NET框架开发:深入探索与实战
【5月更文挑战第28天】本文探讨了C#在.NET框架中的应用,展示了其作为强大编程语言的特性,如类型安全、面向对象编程。C#与.NET框架的结合,提供了一站式的开发环境,支持跨平台应用。文中介绍了C#的基础知识,如数据类型、控制结构和面向对象编程,以及.NET的关键技术,包括LINQ、ASP.NET和WPF。通过一个实战案例,展示了如何使用C#和ASP.NET开发Web应用,包括项目创建、数据库设计、模型和控制器编写,以及视图和路由配置。本文旨在揭示C#在.NET开发中的深度和广度,激发开发者探索更多可能性。
|
26天前
|
设计模式 存储 前端开发
【设计模式】MVC与MVVM详尽解读与实战指南
【设计模式】MVC与MVVM详尽解读与实战指南
69 0
|
2月前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
44 0
|
2月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
166 5
|
2月前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
|
2月前
mvc.net分页查询案例——mvc-paper.css
mvc.net分页查询案例——mvc-paper.css
|
缓存 前端开发 .NET
ASP.NET MVC Bootstrap极速开发框架
原文:ASP.NET MVC Bootstrap极速开发框架 前言 每次新开发项目都要从头开始设计?有木有一个通用的快速开发框架?并且得是ASP.NET MVC  And Bootstrap?数据库不要手工创建?框架对未来业务支持的扩展性好?这么简单的功能还需要一天搭建基础环境?能不能只关心我所需要的业务? 有这样的一个项目,基于ASP.NET MVC、EntityFramework、Memcached、Bootstrap的快速项目开发框架,只需3秒钟即可创建一个带有简单用户管理的项目。
1262 0
|
2月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
111 0
|
11月前
|
存储 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(五)
经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,banner条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情等功能的开发,今天继续讲解购物车功能开发,仅供学习分享使用,如有不足之处,还请指正。
139 0