VS2005自带了一个所谓"个人网站初学者学习工具"(简称tool了~),实质上这是个个人网站的建站系统,而它虽然不大,却已经包含了绝大多数.net 2.0的新特性,masterpage theme DataSouce Membership等等....在现在看petshop程序还是一头雾水的水平下,学习这个显然是明智的选择 呵呵
新建一个"个人网站学习工具"网站,按要求运行,系统会初始化数据库,按照提示在ASP.NET网站配置里建一个administrator帐户,就可以开始玩了
首先看看网站大体结构:
主页->简历 链接 相册 这个是网站主要功能 其实最主要的就是一个相册!
另外提供一个 注册 和几个管理页面
管理页面都放在admin目录中
从web.config入手~
第一次接触这个,感觉一切都很新鲜(废话~),,先看看网站的配置文件吧
在教程里看到,系统里有一个web.config的模板,里面很详细,但是也很麻烦,头次看很难明白~
这个tool里面的就好懂得多,下面开始分析:
首先是connectionstring
定义了两个connectionstring 一个是Personal一个是LocalSqlServer
Personal里面定义的是网站需要存储的东西,主要是相册和photo
而LocalSqlServer,就是用.net自带的一些服务所需要的数据库~他这里默认是在App_Data下的一个文件,这个文件实质上也是一个数据库了,和上面没什么不同,只是对这个数据库的
(有时候不能运行和这个有关系)
很多操作都可以用现成的方法完成,比如成员服务 个性化信息服务等等,因为访问细节不需要来关心,因此连Provider都不用指定,,,初学情况下用默认的就行了
还有一句<remove name="LocalSqlServer"/>,这个是用来覆盖掉继承的来自上一级的LocalSqlServer的~上一级的定义在服务器上会有,是给没有web.config的网站用的默认配置
,在win目录下
<pages styleSheetTheme="White"/> 因此网站的默认theme就是White了,主题里包括default.css 系统会自动应用,因此不用每一页链接default.css
<customErrors mode="RemoteOnly"/> 这一句是定义出错显示的东西,顾名思义就是用服务器的出错信息
mode可以改为off 或者 on 自定义出错页面 参考这个用法
<customErrors defaultRedirect="http://hostName/applicationName/errorStatus.htm" mode="On">
<error statusCode="404" redirect="filenotfound.htm" />
</customErrors>
<compilation debug="true"/> 可以调试~第一次调试运行弹出的对话框就是说的这个了
然后定义身份验证是forms 基于窗体 具体的先不谈(下面都这样,具体的都先不谈)/
<globalization一句 定义编码~
然后打开Role管理服务
打开Sitemaps服务,并且设置
然后还定义了一个path 叫admin,也就是admin文件存放的目录,并且指定Administrators role可以访问 其他都不行 也就是后台了
就这些了
开始分析每个文件前,先看看网站的前台架构
整个网站都基于了default.master,这个master定义了页头和页角,用了sitemap,实际上所有的导航都是基于sitemap的,因此可以方便的扩展~用了两个menu和一个SiteMapPath,
样式控制都用css~
对了插一句,整个网站全部基于div+css~~~控制,而且也没有盲目使用,该用表格也用了表格(文章列表什么的),这样很不错
首页提供了登陆和每日照片
简历和链接比较基本,没有用到什么技术,就是两个普通页面~
照片提供了一个相册功能,albums.aspx列出了所有相册,通过Handler.ashx?AlbumID=1&Size=M访问相册~这里用了HTTPHandle实际上是photos.aspx?alumniid=**
然后photos.aspx根据alumniid列出照片,点击在通过http://localhost:7301/WebSite2/Handler.ashx?PhotoID=1&Size=S访问(和上面一样 实质上是
http://localhost:7301/WebSite2/Details.aspx?AlbumID=1&Page=1)
注意一下,这里通过HTTPHandle提供了类似一个照片缩略图的功能
还有一块儿就是管理功能,这里提供了创建相册,上传图片等等
不深入了 先开始default.aspx
右边都是静态页面,没什么可研究的,看左边
上面是一块LoginArea,是一个LoginView控件
定义了两个模板,<AnonymousTemplate> 和 <LoggedInTemplate> 很好理解
(涉及MemberShip的东西,暂时先不写 做个标记..............)
左边的下面一块FormView
只用了一个ItemTemplate 实际上显示数据用的
绑定到ObjectDataSoure
绑定了几个值,
照片链接为 Details.aspx?AlbumID=<%# Eval("AlbumID") %>&Page=<%# Container.DataItemIndex %>
照片的src为 Handler.ashx?PhotoID=<%# Eval("PhotoID") %>&Size=M
照片编号为 <%# Eval("PhotoID") %>
先看看ObjectDataSource里的东西
业务逻辑类是PhotoManage 只用了一个GetPhotos方法为SelectMethod
去找到这个GetPhotos (有好几个,这里当然是没有参数的那一个)
GetPhotos的代码,先随机得到一个AlblumID,然后调用哪个需要传入AlbumID的GetPhotos
GetPhotos函数: 这个直接用了ado.net访问Personal数据库,它返回一个List<Photo>,,其实就是一个很多个Photo类组成的集合
也就是,GetPhotos 就是返回这个album里面所有的photo 放在一个集合里面,看看它是怎么工作的
通过SqlCommand调用了 GetPhotos 存储过程,传入的参数有@AlbumID和@IsPublic
@AlbumID是传入的,@IsPublic传入一个bool值,这个值通过当前用户是否在friends或者administrators组得到,在admin组或者在friends组就是false (这个@IsPublic意思是"访问
者是public")
通过DataReader读出,然后写进List<Photo> 三个字段(其实是Photo类的属性),PhotoID,AlbumID,和Caption
最后返回list
这里要看一下GetPhotos存储过程要完成些什么
选出Photos,Photo的AlbumID为传入参数,同时此Photo对应Album的IsPublic为1或者对应Album的IsPublic与传入相同(即要么图片公开,要么图片不公开但是传入的参数是false,
也就是在admin或者friends组)
SELECT *
FROM [Photos] LEFT JOIN [Albums]
ON [Albums].[AlbumID] = [Photos].[AlbumID]
WHERE [Photos].[AlbumID] = @AlbumID
AND ([Albums].[IsPublic] = @IsPublic OR [Albums].[IsPublic] = 1)
返回的应该是n条数 每条数据包含一条图片信息~包括binary
回到GetPhotos函数,List<Photo>包含3个字段,PhotoID AlbumID Caption
顺便再看一下Photo类,这个是所谓的"业务实体"
这个在photo.cs里 相当简单,给了三个属性,就是上面那三个,并不包含图像的二进制数据,只是存储了几个ID和描述
还漏了一个,随机得到一个AlblumID用的函数GetRandomAlbumID()
选出非空的album 加入list,随机一个最大为list.count的数,取AlbumID~SQL存储过程里还是有一不少技巧的~
这部分的绑定差不多就这样了~
下面解决两个问题,注意到,img的src指向那个文件,和Page指向的那个<%# Container.DataItemIndex %>
1 <%# Container.DataItemIndex %>
Container 顾名思义这里表示FormView DataItemIndex表示FormView的数据项,也就是表示第几项数据,绑定的时候,是绑定在一个List<Photo>上的,里面包含若干条photo数据,
具体显示哪一项是随机的
注意到FormView属性里 ondatabound="Randomize" Randomize方法代码里随机指定了FromView的PageIndex,当前的页自然就能通过DataItemIndex得到~
2 关于Handler.ashx?PhotoID=<%# Eval("PhotoID") %>&Size=M
这个东西实现的是传入PhotoID和Size 就返回一个图片,类似直接输入jpg的url一样~理解起来似乎要麻烦一点(不过很有用,特别是到ajax~)
有个东西里面介绍这个,http://msdn.microsoft.com/msdnmag/issues/02/09/HTTPPipelines/
这个比较复杂,慢慢来 详细看看这个东西
要理解这个,首先需要了解一些HTTP Pipelines的东西,一个HTTP请求发出,会有一段Httpcontext,细节不关心,这个请求中间会经过一个HTTP Handlers的环节,这个环节会对请求的
文件进行处理,比如标准的HTTP Handler中有一条,对于扩展名为.aspx的文件,会调用System.Web.UI.PageHandlerFactory来处理,也就是把其当成一个页面,对于.asmx文件,会调用
WebService的Factory来处理,所以服务器认识这些文件(默认设置在本机machine.config和web.config中 win目录下那两个)
关注的是对于.ashx文件,它会调用System.Web.UI.SimpleHandlerFactory
这个Factory没有任何实现,当然就等我们去实现了~
还是先不关心细节,实现的方法就是在.ashx文件里加入<%@ WebHandler Language="C#" Class="Handler" %> 然后实现一个接口IHttpHandler
里面只有两个成员IsReusable和ProcessRequest
MSDN里还看到一种,在任意文件中实现IHttpHandler接口,然后在Web.config里面加入单独声明
<httpHandlers>
<add verb="*" path="handler.aspx" type="HandlerExample.MyHttpHandler,HandlerTest"/>
</httpHandlers>
实际上是把handler.aspx的handler定位到HandlerTest.dll文件的HandlerExample.MyHttpHandler上,只要运行handler.aspx就会被Handle
而用.ashx做法应该是这样 默认.ashx文件是定位到SimpleHandlerFactory,这个类没有实现但是可继承,加入<%@ WebHandler Language="C#" Class="Handler" %>就继承了
这个类到本文件下面的Handler类...然后实现Handler类即可,因此访问此.ashx文件就会用本文件的Handler类来处理,不会影响其他的.ashx文件
IsReusable是一个只读属性,返回true就行,否则其他实例无法调用(实际上这里其他实例不可能调用得到,因为继承和实现都在一个地方
ProcessRequest()方法就是主要的实现了,由一个HTTPContent参数,当然表示当前的HttpContent了
看程序:
设置Content 因为需要把传入的Content变成一个图片,所以做一些处理
然后获取传入的数据,先得到size值,然后得到PhotoID,不存在就用AlbumID,不论如何用PhotoManager里的GetPhoto或者GetFirstPhoto获取照片的二进制数据,放在一个stream
里,确保stream里有数据后,写如HttpContent 这段代码:
// 将图像流写入响应流中
const int buffersize = 1024 * 16;
byte[] buffer = new byte[buffersize];
int count = stream.Read(buffer, 0, buffersize);
while (count > 0) {
context.Response.OutputStream.Write(buffer, 0, count);
count = stream.Read(buffer, 0, buffersize);
}
这样context被改变了,于是返回的时候就会返回stream,前面设置过类型是 image/jpeg 于是就相当于jpg文件了~
加一个 得注意context.Response属性的设置,具体的还得再研究~
还差一个,再去看看GetPhoto和GetFirstPhoto做了些什么(其实就是根据参数返回数据库中的binary)
GetPhoto 如果没有传入PhotoID,也就是HttpContent中没有传入PhotoID,直接按照Size返回现成的jpg,实质就3句话
string path = HttpContext.Current.Server.MapPath("~/Images/");
path += "placeholder-600.jpg";
return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
如果传入了PhotoID,就运行"GetPhoto"存储过程,返回的代码在这里~图片大小居然写在存储过程里了,传一个参数就行
object result = command.ExecuteScalar();
try {
return new MemoryStream((byte[])result);
} catch {
return null;
}
再看看存储过程,其实很简单,存储图片的时候就分别存储了4中不同size的图片,选的时候用就行了~所以说存储过程可以做不少事情........
然后GetFirstPhoto 这个是从album中获取图片,其实差不多,存储过程不一样 本来是where photoid=@photoid现在成了albumid=@albumid 然后加个top 1
这就是数据库读取图片的实现~~~~~~
到这里default.aspx研究的差不多了,在研究到admin之前后面工作会轻松一些
注:PhotoManager.cs的内容穿插其中了,没有分开写
新建一个"个人网站学习工具"网站,按要求运行,系统会初始化数据库,按照提示在ASP.NET网站配置里建一个administrator帐户,就可以开始玩了
首先看看网站大体结构:
主页->简历 链接 相册 这个是网站主要功能 其实最主要的就是一个相册!
另外提供一个 注册 和几个管理页面
管理页面都放在admin目录中
从web.config入手~
第一次接触这个,感觉一切都很新鲜(废话~),,先看看网站的配置文件吧
在教程里看到,系统里有一个web.config的模板,里面很详细,但是也很麻烦,头次看很难明白~
这个tool里面的就好懂得多,下面开始分析:
首先是connectionstring
定义了两个connectionstring 一个是Personal一个是LocalSqlServer
Personal里面定义的是网站需要存储的东西,主要是相册和photo
而LocalSqlServer,就是用.net自带的一些服务所需要的数据库~他这里默认是在App_Data下的一个文件,这个文件实质上也是一个数据库了,和上面没什么不同,只是对这个数据库的
(有时候不能运行和这个有关系)
很多操作都可以用现成的方法完成,比如成员服务 个性化信息服务等等,因为访问细节不需要来关心,因此连Provider都不用指定,,,初学情况下用默认的就行了
还有一句<remove name="LocalSqlServer"/>,这个是用来覆盖掉继承的来自上一级的LocalSqlServer的~上一级的定义在服务器上会有,是给没有web.config的网站用的默认配置
,在win目录下
<pages styleSheetTheme="White"/> 因此网站的默认theme就是White了,主题里包括default.css 系统会自动应用,因此不用每一页链接default.css
<customErrors mode="RemoteOnly"/> 这一句是定义出错显示的东西,顾名思义就是用服务器的出错信息
mode可以改为off 或者 on 自定义出错页面 参考这个用法
<customErrors defaultRedirect="http://hostName/applicationName/errorStatus.htm" mode="On">
<error statusCode="404" redirect="filenotfound.htm" />
</customErrors>
<compilation debug="true"/> 可以调试~第一次调试运行弹出的对话框就是说的这个了
然后定义身份验证是forms 基于窗体 具体的先不谈(下面都这样,具体的都先不谈)/
<globalization一句 定义编码~
然后打开Role管理服务
打开Sitemaps服务,并且设置
然后还定义了一个path 叫admin,也就是admin文件存放的目录,并且指定Administrators role可以访问 其他都不行 也就是后台了
就这些了
开始分析每个文件前,先看看网站的前台架构
整个网站都基于了default.master,这个master定义了页头和页角,用了sitemap,实际上所有的导航都是基于sitemap的,因此可以方便的扩展~用了两个menu和一个SiteMapPath,
样式控制都用css~
对了插一句,整个网站全部基于div+css~~~控制,而且也没有盲目使用,该用表格也用了表格(文章列表什么的),这样很不错
首页提供了登陆和每日照片
简历和链接比较基本,没有用到什么技术,就是两个普通页面~
照片提供了一个相册功能,albums.aspx列出了所有相册,通过Handler.ashx?AlbumID=1&Size=M访问相册~这里用了HTTPHandle实际上是photos.aspx?alumniid=**
然后photos.aspx根据alumniid列出照片,点击在通过http://localhost:7301/WebSite2/Handler.ashx?PhotoID=1&Size=S访问(和上面一样 实质上是
http://localhost:7301/WebSite2/Details.aspx?AlbumID=1&Page=1)
注意一下,这里通过HTTPHandle提供了类似一个照片缩略图的功能
还有一块儿就是管理功能,这里提供了创建相册,上传图片等等
不深入了 先开始default.aspx
右边都是静态页面,没什么可研究的,看左边
上面是一块LoginArea,是一个LoginView控件
定义了两个模板,<AnonymousTemplate> 和 <LoggedInTemplate> 很好理解
(涉及MemberShip的东西,暂时先不写 做个标记..............)
左边的下面一块FormView
只用了一个ItemTemplate 实际上显示数据用的
绑定到ObjectDataSoure
绑定了几个值,
照片链接为 Details.aspx?AlbumID=<%# Eval("AlbumID") %>&Page=<%# Container.DataItemIndex %>
照片的src为 Handler.ashx?PhotoID=<%# Eval("PhotoID") %>&Size=M
照片编号为 <%# Eval("PhotoID") %>
先看看ObjectDataSource里的东西
业务逻辑类是PhotoManage 只用了一个GetPhotos方法为SelectMethod
去找到这个GetPhotos (有好几个,这里当然是没有参数的那一个)
GetPhotos的代码,先随机得到一个AlblumID,然后调用哪个需要传入AlbumID的GetPhotos
GetPhotos函数: 这个直接用了ado.net访问Personal数据库,它返回一个List<Photo>,,其实就是一个很多个Photo类组成的集合
也就是,GetPhotos 就是返回这个album里面所有的photo 放在一个集合里面,看看它是怎么工作的
通过SqlCommand调用了 GetPhotos 存储过程,传入的参数有@AlbumID和@IsPublic
@AlbumID是传入的,@IsPublic传入一个bool值,这个值通过当前用户是否在friends或者administrators组得到,在admin组或者在friends组就是false (这个@IsPublic意思是"访问
者是public")
通过DataReader读出,然后写进List<Photo> 三个字段(其实是Photo类的属性),PhotoID,AlbumID,和Caption
最后返回list
这里要看一下GetPhotos存储过程要完成些什么
选出Photos,Photo的AlbumID为传入参数,同时此Photo对应Album的IsPublic为1或者对应Album的IsPublic与传入相同(即要么图片公开,要么图片不公开但是传入的参数是false,
也就是在admin或者friends组)
SELECT *
FROM [Photos] LEFT JOIN [Albums]
ON [Albums].[AlbumID] = [Photos].[AlbumID]
WHERE [Photos].[AlbumID] = @AlbumID
AND ([Albums].[IsPublic] = @IsPublic OR [Albums].[IsPublic] = 1)
返回的应该是n条数 每条数据包含一条图片信息~包括binary
回到GetPhotos函数,List<Photo>包含3个字段,PhotoID AlbumID Caption
顺便再看一下Photo类,这个是所谓的"业务实体"
这个在photo.cs里 相当简单,给了三个属性,就是上面那三个,并不包含图像的二进制数据,只是存储了几个ID和描述
还漏了一个,随机得到一个AlblumID用的函数GetRandomAlbumID()
选出非空的album 加入list,随机一个最大为list.count的数,取AlbumID~SQL存储过程里还是有一不少技巧的~
这部分的绑定差不多就这样了~
下面解决两个问题,注意到,img的src指向那个文件,和Page指向的那个<%# Container.DataItemIndex %>
1 <%# Container.DataItemIndex %>
Container 顾名思义这里表示FormView DataItemIndex表示FormView的数据项,也就是表示第几项数据,绑定的时候,是绑定在一个List<Photo>上的,里面包含若干条photo数据,
具体显示哪一项是随机的
注意到FormView属性里 ondatabound="Randomize" Randomize方法代码里随机指定了FromView的PageIndex,当前的页自然就能通过DataItemIndex得到~
2 关于Handler.ashx?PhotoID=<%# Eval("PhotoID") %>&Size=M
这个东西实现的是传入PhotoID和Size 就返回一个图片,类似直接输入jpg的url一样~理解起来似乎要麻烦一点(不过很有用,特别是到ajax~)
有个东西里面介绍这个,http://msdn.microsoft.com/msdnmag/issues/02/09/HTTPPipelines/
这个比较复杂,慢慢来 详细看看这个东西
要理解这个,首先需要了解一些HTTP Pipelines的东西,一个HTTP请求发出,会有一段Httpcontext,细节不关心,这个请求中间会经过一个HTTP Handlers的环节,这个环节会对请求的
文件进行处理,比如标准的HTTP Handler中有一条,对于扩展名为.aspx的文件,会调用System.Web.UI.PageHandlerFactory来处理,也就是把其当成一个页面,对于.asmx文件,会调用
WebService的Factory来处理,所以服务器认识这些文件(默认设置在本机machine.config和web.config中 win目录下那两个)
关注的是对于.ashx文件,它会调用System.Web.UI.SimpleHandlerFactory
这个Factory没有任何实现,当然就等我们去实现了~
还是先不关心细节,实现的方法就是在.ashx文件里加入<%@ WebHandler Language="C#" Class="Handler" %> 然后实现一个接口IHttpHandler
里面只有两个成员IsReusable和ProcessRequest
MSDN里还看到一种,在任意文件中实现IHttpHandler接口,然后在Web.config里面加入单独声明
<httpHandlers>
<add verb="*" path="handler.aspx" type="HandlerExample.MyHttpHandler,HandlerTest"/>
</httpHandlers>
实际上是把handler.aspx的handler定位到HandlerTest.dll文件的HandlerExample.MyHttpHandler上,只要运行handler.aspx就会被Handle
而用.ashx做法应该是这样 默认.ashx文件是定位到SimpleHandlerFactory,这个类没有实现但是可继承,加入<%@ WebHandler Language="C#" Class="Handler" %>就继承了
这个类到本文件下面的Handler类...然后实现Handler类即可,因此访问此.ashx文件就会用本文件的Handler类来处理,不会影响其他的.ashx文件
IsReusable是一个只读属性,返回true就行,否则其他实例无法调用(实际上这里其他实例不可能调用得到,因为继承和实现都在一个地方
ProcessRequest()方法就是主要的实现了,由一个HTTPContent参数,当然表示当前的HttpContent了
看程序:
设置Content 因为需要把传入的Content变成一个图片,所以做一些处理
然后获取传入的数据,先得到size值,然后得到PhotoID,不存在就用AlbumID,不论如何用PhotoManager里的GetPhoto或者GetFirstPhoto获取照片的二进制数据,放在一个stream
里,确保stream里有数据后,写如HttpContent 这段代码:
// 将图像流写入响应流中
const int buffersize = 1024 * 16;
byte[] buffer = new byte[buffersize];
int count = stream.Read(buffer, 0, buffersize);
while (count > 0) {
context.Response.OutputStream.Write(buffer, 0, count);
count = stream.Read(buffer, 0, buffersize);
}
这样context被改变了,于是返回的时候就会返回stream,前面设置过类型是 image/jpeg 于是就相当于jpg文件了~
加一个 得注意context.Response属性的设置,具体的还得再研究~
还差一个,再去看看GetPhoto和GetFirstPhoto做了些什么(其实就是根据参数返回数据库中的binary)
GetPhoto 如果没有传入PhotoID,也就是HttpContent中没有传入PhotoID,直接按照Size返回现成的jpg,实质就3句话
string path = HttpContext.Current.Server.MapPath("~/Images/");
path += "placeholder-600.jpg";
return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
如果传入了PhotoID,就运行"GetPhoto"存储过程,返回的代码在这里~图片大小居然写在存储过程里了,传一个参数就行
object result = command.ExecuteScalar();
try {
return new MemoryStream((byte[])result);
} catch {
return null;
}
再看看存储过程,其实很简单,存储图片的时候就分别存储了4中不同size的图片,选的时候用就行了~所以说存储过程可以做不少事情........
然后GetFirstPhoto 这个是从album中获取图片,其实差不多,存储过程不一样 本来是where photoid=@photoid现在成了albumid=@albumid 然后加个top 1
这就是数据库读取图片的实现~~~~~~
到这里default.aspx研究的差不多了,在研究到admin之前后面工作会轻松一些
注:PhotoManager.cs的内容穿插其中了,没有分开写