[索引页]
[源码下载]
精进不休 .NET 4.0 (2) - asp.net 4.0 新特性之url路由, 自定义CacheProvider, 新增的表达式<%: expression %>, QueryExtender控件, 其它新特性
作者:
webabcd
介绍
asp.net 4.0 的新增功能
- 在 web form 中做 url 路由
- 通过实现自定义的 CacheProvider ,来实现自定义的页面缓存逻辑
- 新增的表达式 <%: expression %> 相当于 <%= HttpUtility.HtmlEncode(expression) %>
- 控件 QueryExtender,对数据源控件获得的数据做再检索
- 其它新特性
示例
1、web form 中的 url 路由的 demo
Global.asax.cs
代码
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.Security;
using
System.Web.SessionState;
using
System.Web.Routing;
namespace
AspDotNet
{
public
class
Global : System.Web.HttpApplication
{
protected
void
Application_Start(
object
sender, EventArgs e)
{
//
关于 Routing 可以参考以前写的
http://www.cnblogs.com/webabcd/archive/2009/04/21/1440149.html
//
其中 PageRouteHandler 类的作用是将 URL 路由的功能集成到 Web Form 中
RouteTable.Routes.Add(
"
myRoute
"
,
new
Route(
"
user/{userName}/{age}
"
,
new
PageRouteHandler(
"
~/UrlRouting/Default.aspx
"
)));
/*
对应的配置如下,在 machine.config 中
<system.web>
<httpmodule>
<add name="RoutingModule" type="System.Web.Routing.UrlRoutingModule"/>
</httpmodule>
<system.web>
*/
}
}
}
UrlRouting/Default.aspx
代码
<%
@ Page Title
=
""
Language
=
"
C#
"
MasterPageFile
=
"
~/Site.Master
"
AutoEventWireup
=
"
true
"
CodeBehind
=
"
Default.aspx.cs
"
Inherits
=
"
AspDotNet.UrlRouting.Default
"
%>
<
asp:Content
ID
="Content1"
ContentPlaceHolderID
="head"
runat
="server"
>
</
asp:Content
>
<
asp:Content
ID
="Content2"
ContentPlaceHolderID
="ContentPlaceHolder1"
runat
="server"
>
<!--
在页面上获取 url 路由而来的数据的方法
配合以下逻辑的路由规则是:"user/{userName}/{age}"
-->
<
asp:Literal
runat
="server"
Text
="<%$ RouteValue:userName%>"
/>
<
br
/>
<
asp:Literal
runat
="server"
Text
="<%$ RouteValue:age%>"
/>
<!--
另外,对于数据源控件来说,也多了一种参数类型 RouteParameter
-->
</
asp:Content
>
<%
--
对应的配置如下,在 machine.config 中
<
system.web
>
<
compilation debug
=
"
true
"
targetFrameworkMoniker
=
"
.NETFramework,Version=v4.0
"
>
<
expressionBuilders
>
<
add expressionPrefix
=
"
RouteValue
"
type
=
"
System.Web.Compilation.RouteValueExpressionBuilder
"
/>
</
expressionBuilders
>
</
compilation
>
<
system.web
>
--
%>
UrlRouting/Default.aspx.cs
代码
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.UI;
using
System.Web.UI.WebControls;
namespace
AspDotNet.UrlRouting
{
public
partial
class
Default : System.Web.UI.Page
{
protected
void
Page_Load(
object
sender, EventArgs e)
{
//
获取 url 路由而来的数据
//
配合以下逻辑的路由规则是:"user/{userName}/{age}"
Response.Write(
"
userName:
"
+
RouteData.Values[
"
userName
"
].ToString());
Response.Write(
"
<br />
"
);
Response.Write(
"
age:
"
+
RouteData.Values[
"
age
"
].ToString());
}
}
}
UrlRouting/RouteUrlExpressionBuilderDemo.aspx
代码
<%
@ Page Title
=
""
Language
=
"
C#
"
MasterPageFile
=
"
~/Site.Master
"
AutoEventWireup
=
"
true
"
CodeBehind
=
"
RouteUrlExpressionBuilderDemo.aspx.cs
"
Inherits
=
"
AspDotNet.UrlRouting.RouteUrlExpressionBuilderDemo
"
%>
<
asp:Content
ID
="Content1"
ContentPlaceHolderID
="head"
runat
="server"
>
</
asp:Content
>
<
asp:Content
ID
="Content2"
ContentPlaceHolderID
="ContentPlaceHolder1"
runat
="server"
>
<!--
在页面上构造 url 路由的方式
-->
<
asp:HyperLink
ID
="lnk1"
runat
="server"
NavigateUrl
="<%$ RouteUrl:RouteName=myRoute, userName=webabcd, age=30 %>"
Text
="goto"
/>
<
br
/><
br
/>
<
asp:HyperLink
ID
="lnk2"
runat
="server"
Text
="goto"
/>
</
asp:Content
>
<%
--
对应的配置如下,在 machine.config 中
<
system.web
>
<
compilation debug
=
"
true
"
targetFrameworkMoniker
=
"
.NETFramework,Version=v4.0
"
>
<
expressionBuilders
>
<
add expressionPrefix
=
"
RouteUrl
"
type
=
"
System.Web.Compilation.RouteUrlExpressionBuilder
"
/>
</
expressionBuilders
>
</
compilation
>
<
system.web
>
--
%>
UrlRouting/RouteUrlExpressionBuilderDemo.aspx.cs
代码
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
System.Web.Compilation;
namespace
AspDotNet.UrlRouting
{
public
partial
class
RouteUrlExpressionBuilderDemo : System.Web.UI.Page
{
protected
void
Page_Load(
object
sender, EventArgs e)
{
//
在代码中构造 url 路由的方式
string
expression
=
String.Format(
"
RouteName={0}, userName={1}, age={2}
"
,
"
myRoute
"
,
"
webabcd
"
,
"
30
"
);
lnk2.NavigateUrl
=
RouteUrlExpressionBuilder.GetRouteUrl(
this
, expression);
}
}
}
2、自定义 CacheProvider
CachingEnhancement.aspx
代码
<%
--
OutputCache 目前不支持直接设置 providerName 属性
--
%>
<%
@ OutputCache Duration
=
"
30
"
VaryByParam
=
"
None
"
%>
<%
@ Page Title
=
""
Language
=
"
C#
"
MasterPageFile
=
"
~/Site.Master
"
AutoEventWireup
=
"
true
"
CodeBehind
=
"
CachingEnhancement.aspx.cs
"
Inherits
=
"
AspDotNet.CachingEnhancement
"
%>
<
asp:Content
ID
="Content1"
ContentPlaceHolderID
="head"
runat
="server"
>
</
asp:Content
>
<
asp:Content
ID
="Content2"
ContentPlaceHolderID
="ContentPlaceHolder1"
runat
="server"
>
<%
=
DateTime.Now.ToString()
%>
</
asp:Content
>
CachingEnhancement.aspx.cs
代码
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
System.Web.Caching;
using
System.Security.Cryptography;
using
System.Text;
using
System.IO;
using
System.Runtime.Serialization.Formatters.Binary;
namespace
AspDotNet
{
public
partial
class
CachingEnhancement : System.Web.UI.Page
{
protected
void
Page_Load(
object
sender, EventArgs e)
{
}
}
//
重写 OutputCacheProvider 抽象类,以实现自定义的缓存实现(需要重写的方法是 Add, Get, Remove, Set)
//
本 Demo 演示了,如何开发一个自定义的 CacheProvider,来实现将数据缓存到硬盘的功能
public
class
FileCacheProvider : OutputCacheProvider
{
private
string
_cachePathPrefix
=
@"
c:\
"
;
private
string
MD5(
string
s)
{
var provider
=
new
MD5CryptoServiceProvider();
var bytes
=
Encoding.UTF8.GetBytes(s);
var builder
=
new
StringBuilder();
bytes
=
provider.ComputeHash(bytes);
foreach
(var b
in
bytes)
builder.Append(b.ToString(
"
x2
"
).ToLower());
return
builder.ToString();
}
///
<summary>
///
将指定的 key ,做md5 加密后,拼出一个路径,做为保存此 key 对应的对象的文件(此例只做演示用)
///
</summary>
///
<param name="key">
缓存 key
</param>
///
<returns></returns>
private
string
GetPathFromKey(
string
key)
{
return
_cachePathPrefix
+
MD5(key)
+
"
.txt
"
;
}
///
<summary>
///
将对象放入自定义的缓存中
///
</summary>
///
<param name="key">
缓存 key
</param>
///
<param name="entry">
缓存对象
</param>
///
<param name="utcExpiry">
缓存的过期时间
</param>
///
<returns></returns>
public
override
object
Add(
string
key,
object
entry, DateTime utcExpiry)
{
var path
=
GetPathFromKey(key);
//
指定的 key 已被缓存了,则不做任何处理
if
(File.Exists(path))
return
entry;
//
将对象缓存到硬盘上的指定文件
using
(var file
=
File.OpenWrite(path))
{
var item
=
new
CacheItem { Expires
=
utcExpiry, Item
=
entry };
var formatter
=
new
BinaryFormatter();
formatter.Serialize(file, item);
}
return
entry;
}
///
<summary>
///
在缓存中,根据指定的 key 获取缓存对象
///
</summary>
///
<param name="key">
缓存 key
</param>
///
<returns></returns>
public
override
object
Get(
string
key)
{
var path
=
GetPathFromKey(key);
//
未找到缓存
if
(
!
File.Exists(path))
return
null
;
CacheItem item
=
null
;
//
如果有缓存的话,则取出缓存对象
using
(var file
=
File.OpenRead(path))
{
var formatter
=
new
BinaryFormatter();
item
=
(CacheItem)formatter.Deserialize(file);
}
//
缓存过期或缓存中无数据,则删除此缓存所对应的硬盘上的物理文件
if
(item
==
null
||
item.Expires
<=
DateTime.Now.ToUniversalTime())
{
Remove(key);
return
null
;
}
return
item.Item;
}
///
<summary>
///
根据指定的 key 删除缓存对象
///
</summary>
///
<param name="key">
缓存 key
</param>
public
override
void
Remove(
string
key)
{
var path
=
GetPathFromKey(key);
if
(File.Exists(path))
File.Delete(path);
}
///
<summary>
///
更新缓存
///
</summary>
///
<param name="key">
缓存 key
</param>
///
<param name="entry">
缓存对象
</param>
///
<param name="utcExpiry">
缓存的过期时间
</param>
public
override
void
Set(
string
key,
object
entry, DateTime utcExpiry)
{
var item
=
new
CacheItem { Expires
=
utcExpiry, Item
=
entry };
var path
=
GetPathFromKey(key);
using
(var file
=
File.OpenWrite(path))
{
var formatter
=
new
BinaryFormatter();
formatter.Serialize(file, item);
}
}
///
<summary>
///
封装了需要被缓存的对象的一个可序列化的对象
///
</summary>
[Serializable]
internal
class
CacheItem
{
///
<summary>
///
缓存对象
///
</summary>
public
object
Item;
///
<summary>
///
缓存对象的过期时间
///
</summary>
public
DateTime Expires;
}
}
}
Web.config
代码
<!--
缓存配置
-->
<
caching
>
<!--
默认的缓存实现是 AspNetInternalProvider(即 asp.net 自带的基于内存的缓存实现方式)
-->
<
outputCache
defaultProvider
="AspNetInternalProvider"
>
<
providers
>
<!--
新增一个缓存的 provider 配置
具体实现见 CachingEnhancement.aspx.cs
-->
<
add
name
="FileCache"
type
="AspDotNet.FileCacheProvider, AspDotNet"
/>
</
providers
>
</
outputCache
>
</
caching
>
Global.asax.cs
代码
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.Security;
using
System.Web.SessionState;
using
System.Web.Routing;
namespace
AspDotNet
{
public
class
Global : System.Web.HttpApplication
{
//
根据 HttpContext 的不同,可以为其指定不同的 CacheProvider
public
override
string
GetOutputCacheProviderName(HttpContext context)
{
//
符合此条件的,则缓存的实现使用自定义的 FileCacheProvider
//
自定义缓存实现见 CachingEnhancement.aspx.cs
//
CacheProvider 的配置见 web.config
//
页面的缓存时间见 CachingEnhancement.aspx
if
(context.Request.Path.ToLower().EndsWith(
"
cachingenhancement.aspx
"
))
return
"
FileCache
"
;
else
return
base
.GetOutputCacheProviderName(context);
}
}
}
3、表达式 <%: expression %> 的 demo
HtmlEncodedCodeExpressions.aspx
代码
<%
@ Page Title
=
""
Language
=
"
C#
"
MasterPageFile
=
"
~/Site.Master
"
AutoEventWireup
=
"
true
"
CodeBehind
=
"
HtmlEncodedCodeExpressions.aspx.cs
"
Inherits
=
"
AspDotNet.HtmlEncodedCodeExpressions
"
%>
<
asp:Content
ID
="Content1"
ContentPlaceHolderID
="head"
runat
="server"
>
</
asp:Content
>
<
asp:Content
ID
="Content2"
ContentPlaceHolderID
="ContentPlaceHolder1"
runat
="server"
>
<%
--
新增的一个表达式
<
%: expression
%>
相当于
<%
=
HttpUtility.HtmlEncode(expression)
%>
--%>
<%
=
"
<strong>strong</strong>
"
%>
<
br
/>
<%
:
"
<strong>strong</strong>
"
%>
<
br
/>
<%
=
HttpUtility.HtmlEncode(
"
<strong>strong</strong>
"
)
%>
</
asp:Content
>
4、QueryExtender 控件的 demo
QueryExtenderDemo.aspx
代码
<%
@ Page Title
=
""
Language
=
"
C#
"
MasterPageFile
=
"
~/Site.Master
"
AutoEventWireup
=
"
true
"
CodeBehind
=
"
QueryExtenderDemo.aspx.cs
"
Inherits
=
"
AspDotNet.QueryExtenderDemo
"
%>
<
asp:Content
ID
="Content1"
ContentPlaceHolderID
="head"
runat
="server"
>
</
asp:Content
>
<
asp:Content
ID
="Content2"
ContentPlaceHolderID
="ContentPlaceHolder1"
runat
="server"
>
<
asp:GridView
ID
="GridView1"
runat
="server"
AutoGenerateColumns
="False"
DataSourceID
="LinqDataSource1"
>
<
Columns
>
<
asp:BoundField
DataField
="ProductId"
HeaderText
="ProductId"
SortExpression
="ProductId"
/>
<
asp:BoundField
DataField
="ProductName"
HeaderText
="ProductName"
SortExpression
="ProductName"
/>
<
asp:BoundField
DataField
="ProductPrice"
HeaderText
="ProductPrice"
SortExpression
="ProductPrice"
/>
</
Columns
>
</
asp:GridView
>
<
asp:LinqDataSource
ID
="LinqDataSource1"
runat
="server"
ContextTypeName
="AspDotNet.QueryExtenderDemo"
EntityTypeName
="AspDotNet.Product"
TableName
="Data"
>
</
asp:LinqDataSource
>
<!--
QueryExtender - 和数据源控件结合使用,以对数据源控件中检索到的数据做再次检索
SearchExpression - 根据指定的字段查找指定的数据
RangeExpression - 在指定字段中查找指定范围的数据
PropertyExpression - 查找某字段的值为某指定的值的数据
OrderByExpression - 用于排序数据
CustomExpression - 自定义查询表达式
-->
<
asp:QueryExtender
ID
="QueryExtender1"
runat
="server"
TargetControlID
="LinqDataSource1"
>
<
asp:SearchExpression
DataFields
="ProductName"
SearchType
="EndsWith"
>
<
asp:Parameter
Type
="String"
DefaultValue
="0"
/>
</
asp:SearchExpression
>
</
asp:QueryExtender
>
</
asp:Content
>
QueryExtenderDemo.aspx.cs
代码
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.UI;
using
System.Web.UI.WebControls;
namespace
AspDotNet
{
public
partial
class
QueryExtenderDemo : System.Web.UI.Page
{
protected
void
Page_Load(
object
sender, EventArgs e)
{
}
//
为 GridView 提供数据
public
List
<
Product
>
Data
{
get
{
Random random
=
new
Random();
List
<
Product
>
products
=
new
List
<
Product
>
();
for
(
int
i
=
0
; i
<
100
; i
++
)
{
products.Add(
new
Product { ProductId
=
i
+
1
, ProductName
=
"
名称
"
+
i.ToString().PadLeft(
2
,
'
0
'
), ProductPrice
=
random.NextDouble() });
}
return
products;
}
}
//
为 GridView 提供数据的实体类
public
class
Product
{
public
int
ProductId {
get
;
set
; }
public
string
ProductName {
get
;
set
; }
public
double
ProductPrice {
get
;
set
; }
}
}
}
5、其他新特性的简单说明
Others.aspx
代码
<%
@ Page Title
=
"
其它,一笔带过
"
Language
=
"
C#
"
MasterPageFile
=
"
~/Site.Master
"
AutoEventWireup
=
"
true
"
CodeBehind
=
"
Others.aspx.cs
"
Inherits
=
"
AspDotNet.Others
"
%>
<
asp:Content
ID
="Content1"
ContentPlaceHolderID
="head"
runat
="server"
>
<
style
>
body
{
font-size
:
12px
;
}
textarea
{
width
:
99%
;
}
</
style
>
</
asp:Content
>
<
asp:Content
ID
="Content2"
ContentPlaceHolderID
="ContentPlaceHolder1"
runat
="server"
>
<
p
>
1、Permanent Redirect - 可以实现 301 跳转
<
ul
>
<
li
>
Response.RedirectPermanent() - 永久性重定向(http 301)。
</
li
>
<
li
>
Response.Redirect() - 临时性重定向(http 302)。
</
li
>
</
ul
>
</
p
>
<
p
>
2、Session 压缩(设置 sessionState 节点的 compressionEnabled 属性)
<
br
/>
对于使用进程外会话状态服务器的会话状态提供程序,或者将会话状态保存在 sqlserver 数据库中的会话状态提供程序,现在为提高其效率新增了压缩 Session 数据的功能(使用System.IO.Compression.GZipStream来压缩数据),像如下这样的配置
<
br
/>
<
textarea
rows
="6"
>
<
sessionState
mode
="SqlServer"
sqlConnectionString
="data source=dbserver;Initial Catalog=aspnetstate"
allowCustomSqlDatabase
="true"
compressionEnabled
="true"
/>
</
textarea
>
</
p
>
<
p
>
3、httpRuntime 节点的新增配置
<
ul
>
<
li
>
maxRequestPathLength - url 路径的最大长度(基于NTFS文件路径的最大长度就是 260)
</
li
>
<
li
>
maxQueryStringLength - url 的最大长度
</
li
>
<
li
>
requestPathInvalidChars - 指定 url 路径的无效字符
</
li
>
<
li
>
requestValidationType - 继承 System.Web.Util.RequestValidator 抽象类,重写其 IsValidRequestString() 方法,以实现自定义的请求验证。在 requestValidationType 可以指定使用这个自定义的类
</
li
>
<
li
>
encoderType - 重写 System.Web.Util.HttpEncoder,可以实现自定义的 html编码, url编码, http header编码。在 encoderType 指定这个自定义编码的类后,程序中所用到的 System.Web.HttpUtility 或 System.Web.HttpServerUtility 的相关方法将会使用自定义的编码实现
</
li
>
</
ul
>
<
br
/>
<
textarea
rows
="2"
>
<
httpRuntime
maxRequestPathLength
="260"
maxQueryStringLength
="2048"
requestPathInvalidChars
="<,>,*,%,&,:,\,?"
requestValidationType
="Samples.MyValidator, Samples"
encoderType
="Samples.MyEncoder, Samples"
/>
</
textarea
>
</
p
>
<
p
>
4、compilation 节点新增 targetFramework 属性,用于指定程序运行的目标框架
<
br
/>
<
textarea
>
<
compilation
targetFramework
="4.0"
/>
</
textarea
>
</
p
>
<
p
>
5、asp.net 4.0 结合 iis 7.5 可使 web 应用程序自动启动
<
br
/>
在 web 程序中实现 System.Web.Hosting.IProcessHostPreloadClient 接口,用于被 iis 启动
</
p
>
<
p
>
6、Page 类中新增了两个属性,分别是 MetaDescription 和 MetaKeywords
</
p
>
<
p
>
7、以前每个可显示的控件都有 Enabled 属性(如果 Enabled="false" 则对应的 HTML 为 disabled="disabled"),但是 HTML 4.01 的标准是只有 input 才能有 disabled 属性
<
ul
>
<
li
>
在 pages 节点中设置 controlRenderingCompatibilityVersion="3.5",则所有可显示控件都会输出 disabled="disabled"
</
li
>
<
li
>
在 pages 节点中设置 controlRenderingCompatibilityVersion="4.0",则只有 input 元素才会输出 disabled="disabled",非 input 元素将会自动标记一个名为 aspnetdisabled 的 css 类
</
li
>
</
ul
>
</
p
>
<
p
>
8、web form 需要在页面上写入隐藏域(如为了保存 ViewState 的隐藏域),在 asp.net 4.0 中系统将在这类的隐藏域外的 div 上标记一个名为 aspNetHidden 的 css 类,以方便样式控制
</
p
>
<
p
>
9、ASP.NET Chart Control - 实例参考 http://code.msdn.microsoft.com/mschart
</
p
>
</
asp:Content
>
OK
[源码下载]