[索引頁]
[×××]
精進不休 .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,對數據源控件得到的數據作再檢索
- 其它新特性
示例
一、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
{
void Application_Start() void Application_Start(object sender, EventArgs e)
{
// 關於 Routing 能夠參考之前寫的 http://webabcd.blog.51cto.com/1787395/341116
// 其中 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
{
void Page_Load() 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
{
void Page_Load() 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);
}
}
}
二、自定義 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
{
void Page_Load() void Page_Load(object sender, EventArgs e)
{
}
}
// 重寫 OutputCacheProvider 抽象類,以實現自定義的緩存實現(須要重寫的方法是 Add,
Get, Remove,
Set)
// 本 Demo 演示了,如何開發一個自定義的 CacheProvider,來實現將數據緩存到硬盤的功能
public
class FileCacheProvider : OutputCacheProvider
{
private
string _cachePathPrefix = @"c:\";
string MD5()
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>
string GetPathFromKey()
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>
override object Add() 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>
override object
Get() 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>
override void Remove() 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>
override void
Set() 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
override
string GetOutputCacheProviderName() 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);
}
}
}
三、表達式 <%: 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>
四、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
{
void Page_Load() 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; }
}
}
}
五、其餘新特性的簡單說明
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>
一、Permanent Redirect - 能夠實現 301 跳轉
<ul>
<li>Response.RedirectPermanent() - 永久性重定向(http 301)。</li>
<li>Response.Redirect() - 臨時性重定向(http 302)。</li>
</ul>
</p>
<p>
二、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>
三、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>
四、compilation 節點新增 targetFramework 屬性,用於指定程序運行的目標框架
<br />
<textarea>
<compilation targetFramework=
"4.0" />
</textarea>
</p>
<p>
五、asp.net 4.0 結合 iis 7.5 可以使 web 應用程序自動啓動
<br />
在 web 程序中實現 System.Web.Hosting.IProcessHostPreloadClient 接口,用於被 iis 啓動
</p>
<p>
六、Page 類中新增了兩個屬性,分別是 MetaDescription 和 MetaKeywords
</p>
<p>
七、之前每一個可顯示的控件都有 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>
八、web form 須要在頁面上寫入隱藏域(如爲了保存 ViewState 的隱藏域),在 asp.net 4.0 中系統將在這類的隱藏域外的 div 上標記一個名爲 aspNetHidden 的 css 類,以方便樣式控制
</p>
<p>
九、ASP.NET Chart Control - 實例參考 http://code.msdn.microsoft.com/mschart
</p>
</asp:Content>