February 2007 - Posts
最近2年生活过的很动荡,主要是家庭的原因,每隔几个月就有些变化,现在总算稳定下来了。
和技术也有些疏远,可以看到我的blog 两年来都没什么更新,这里要感谢开心同学没有把我的帐号删掉
最近作了一个重要的决定,就是告别PC & windows开发,转向移动和潜入式平台,比如Symbian.
此前几乎没有Symbian 开发经验,一切从头开始,再次回到helloworld,就像我写第一个Turbo C程序那样。
虽然Symbian 也是用C++开发,但是却有很大不同。
今后我会写一些学习的感悟,以及经验和技巧与大家分享。
带着我10年的微软平台的开发经验去观察 Symbian 的世界,我尽量用Windows 的概念通过类比,去解释Symbian的问题。相信会对其他从Windows转向Symbian的人有所帮助。
我胡汉三又回来了!
不过识别两年,技术前沿生疏了许多。看思归的文章犹如读字母天书,WPF, WCP横行,幸好没有WTF。
重回CSDN上混,我的账号居然还在。
现在的考量是把和.NET无关的东西放在我的blogspot英文博客上,这里放CSDN上遇到的问题和解决方法。是该重新收拾对.NET地了解了——“无他,但手熟尔”。
DevExpess在月初发布了免费版的Refactor! for C++。此工具和现存的Refactor! Pro不兼容,但是仍在服务期的用户可以通过升级Refactor! Pro来获得对C++的支持。此工具不仅对于托管C++有效,也适用于非托管的C++。
Refactor! for C++不仅包含了常见的变量更名、抽取方法,也包含了对.Net'类库的支持(例如可以把大量的string+=转化为使用StringBuilder),以及C++独有的内联宏功能。更多信息可以参考DevExpess的在线教程。
希望这可以让你的编码工作变得更加简单。
【原文地址】Tip/Trick: Url Rewriting with ASP.NET
【原文发表日期】 Monday, February 26, 2007 9:27 PM
经常有人请我指导应该如何动态地“重写”URL,以在他们的ASP.NETweb应用中发布比较干净的URL端点。这个博客帖子概述了几个方法,你可以用来在ASP.NET中干净地映射或重写URL,以及按照你自己的需求组织你的URL的结构。
为什么URL映射和重写很重要?
下面是开发人员想要对URL有更大的灵活性的最常见的场景:
1) 处理这样的情形:你要更改你的web应用中网页的结构,但你同时也要确保在你移动网页后,那些被人收藏的老URL不会成为死链接。重写URL允许你透明地将请求转交到新的网页地址而不出错。
2) 在象Google,Yahoo 和 Live 这样的搜索引擎中提高你网站上网页的搜索相关性。具体地来说,URL重写经常能使你在你网站上网页的URL里更加容易地嵌入关键词,这么做往往会增加别人点击你的链接的机会。从使用查询字符串参数到使用完全限定(fully qualified)的URL也能在某些情形下提高你在搜索引擎结果中的优先顺序。使用强制 referring链接使用同样的大小写(same case)和URL入口(譬如,使用weblogs.asp.net/scottgu 而不是 weblogs.asp.net/scottgu/default.aspx)的技术也能避免因多个URL造成的网页排名(pagerank)的降低,从而增加你的搜索结果。
在一个搜索引擎日渐驱动网站访问量的世界里,在你的网页排名上稍微得到一些提高就能给你的业务带来不错的投资回报(ROI)。逐渐地,这驱使开发人员使用URL重写以及其他SEO(搜索引擎优化 )技术来优化网站(注,SEO是个步调很快的空间,增加你的搜索相关性的建议月月在变)。想了解一些关于搜索引擎优化方面好的建议的话,我建议你阅读一下《SSW Rules to Better Google Rankings (SSW的提高Google排名之要领)》,以及MarketPosition关于《how URLs can affect top search engine ranking (URL是如何影响搜索引擎排名的)》的文章。
例程的URL重写场景
为这个博客贴子起见,我将假设我们将在一个应用里建造一套电子商务的产品目录网页,产品是按种类来组织的(譬如,图书,录像,CD,DVD等等)。
让我们假定一开始我们有个网页叫Products.aspx,通过查询字符串参数接受一个类别名称,相应地过滤显示的产品。与这个Products.aspx网页对应类别的URL看上去象这样:
http://www.store.com/products.aspx?category=books
http://www.store.com/products.aspx?category=DVDs
http://www.store.com/products.aspx?category=CDs
但我们不想使用查询字符串来呈示每个类别,我们想修改应用,让每个产品类别对搜索引擎来说看上去象是一个独特的URL,并且在实际的URL中嵌入关键词(而不是通过查询字符串参数)。我们将在这个博客帖子剩下来的篇幅里,讨论一下达成这个目的我们可以采取的4种不同方法。
方法一:使用Request.PathInfo 参数而不是查询字符串
我将示范的第一个方法根本不使用URL重写,而是使用ASP.NET中不太为人所知的一个特性,Request的PathInfo属性。为帮助解释这个属性的有用之处,考虑一下我们电子商店下面这些URL的情形:
http://www.store.com/products.aspx/Books
http://www.store.com/products.aspx/DVDs
http://www.store.com/products.aspx/CDs
你会在上面这些URL中注意到的一个东西是,他们不再含有查询字符串值,取而代之的是,类别参数的值是附加到URL上的,是以Products.aspx网页处理器名称之后的/参数 值的方式出现的。然后,一个自动化的搜索引擎爬虫(search engine crawler)会把这些URL解释成三个不同的URL,而不是一个URL带有三个不同的输入值 (搜索引擎是不理会文件扩展名的,只把它当作URL中的另一个字符而已)。
你也许很想知道怎么在ASP.NET中处理这个附加的参数的情形。好消息是,这非常简单。只要使用Request的PathInfo属性就可以了,该属性返回URL中紧随 products.aspx 后面的那部分内容。所以,对上面这些URL, Request.PathInfo会分别返回 “/Books”, “/DVDs”,和 “/CDs”(万一你想知道的话, Request的Path 属性返回“/products.aspx” )。
然后,你可以轻易地编写一个函数来获取产品类别,象这样(下面这个函数去除前面的斜杠字符,只返回“Books”,“DVDs”,或 “CDs”):
Function GetCategory() As String
If (Request.PathInfo.Length = 0) Then
Return ""
Else
Return Request.PathInfo.Substring(1)
End If
End Function
样例下载:我建立的一个展示这个技术的样例应用可以在这里下载。这个样例和这个技术的很好的地方在于,为部署使用这个方法的ASP.NET应用,不需作任何服务器配置改动。在共享主机的环境里,这个技术也行之有效。
方法二:使用HttpModule实现URL重写
上述Request.PathInfo技术的替换方法是,利用ASP.NET提供的HttpContext.RewritePath方法。这个方法允许开发人员动态地重写收到的URL的处理路径,然后让ASP.NET使用刚重写过后的路径来继续执行请求。
譬如,我们可以选择向大众呈示下列URL:
http://www.store.com/products/Books.aspx
http://www.store.com/products/DVDs.aspx
http://www.store.com/products/CDs.aspx
在外界看来,网站上有三个单独的网页(对搜索爬虫而言,这看上去很棒)。通过使用 HttpContext的RewritePath方法,我们可以在这些请求刚进入服务器时,动态地把收到的URL重写成单个Products.aspx网页接受一个查询字符串的类别名称或者PathInfo参数。譬如,我们可以使用Global.asax中的Application_BeginRequest事件,来这么做:
void Application_BeginRequest(object sender, EventArgs e) {
string fullOrigionalpath = Request.Url.ToString();
if (fullOrigionalpath.Contains("/Products/Books.aspx")) {
Context.RewritePath("/Products.aspx?Category=Books");
}
else if (fullOrigionalpath.Contains("/Products/DVDs.aspx")) {
Context.RewritePath("/Products.aspx?Category=DVDs");
}
}
手工编写象上面这样的编码的坏处是,很枯燥乏味,而且容易犯错。我建议你别自己写,而是使用网上现成的HttpModule来完成这项工作。这有几个你现在就可以下载和使用的免费的HttpModule:
这些模块允许你用声明的方式在你应用的web.config文件里表达匹配规则。譬如,在你应用的web.config文件里使用UrlRewriter.Net模块来把上面的那些URL映射到单个Products.aspx页上,我们只要把这个web.config文件添加到我们的应用里去就可以了(不用任何编码):
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="rewriter"
requirePermission="false"
type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter" />
</configSections>
<system.web>
<httpModules>
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"/>
</httpModules>
</system.web>
<rewriter>
<rewrite url="~/products/books.aspx" to="~/products.aspx?category=books" />
<rewrite url="~/products/CDs.aspx" to="~/products.aspx?category=CDs" />
<rewrite url="~/products/DVDs.aspx" to="~/products.aspx?category=DVDs" />
</rewriter>
</configuration>
上面的HttpModule URL重写模块还支持正则表达式和URL模式匹配(以避免你在web.config 文件里硬写每个URL)。所以,不用写死类别名称,你可以象下面这样重写匹配规则,把类别名称动态地从任何/products/[类别].aspx组合的URL里取出来:
<rewriter>
<rewrite url="~/products/(.+).aspx" to="~/products.aspx?category=$1" />
</rewriter>
这使得你的编码极其干净,并且扩展性非常之好。
样例下载:我建立的一个使用UrlRewriter.Net模块展示这个技术的样例应用可以在这里下载。
这个样例和这个技术的很好的地方在于,为部署使用这个方法的ASP.NET应用,不需作任何服务器配置改动。在设置为中等信任安全等级(medium trust)的共享主机的环境里,这个技术也行之有效 (只要把文件FTP/XCOPY到远程服务器就可以了,不需要安装)。
方法三:在IIS7中使用HttpModule 实现无扩展名的URL重写
上述的HttpModule方法在你要重写的URL含有.aspx 扩展名或者包含另一个被设置为ASP.NET处理的扩展名的情形下一切都工作。你这么做的话,不需要任何特定的服务器配置,你只要把你的应用拷贝到远程服务器,它会正常工作的。
但有的时候,你要重写的URL要么拥有一个不为ASP.NET处理的文件扩展名(譬如, .jpg, .gif, 或 .htm),要么根本没有扩展名。譬如,我们也许要把这些URL呈示成公开的产品目录网页(注意,它们没有 .aspx 扩展名):
http://www.store.com/products/Books
http://www.store.com/products/DVDs
http://www.store.com/products/CDs
在 IIS5 和 IIS6 中,使用ASP.NET处理上面这样的URL不是很容易。 IIS 5/6 使得在ISAPI扩展(ASP.NET就是这样一个扩展)里非常难以重写这些类型的URLS。你需要做的是使用ISAPI过滤器在IIS请求管道(request pipeline)的较早期实现重写。我将在下面的第四个方法里示范如何在 IIS5/6 实现这样的重写。
但好消息是, IIS 7.0使得处理这类情形容易之极。你现在可以在 IIS 请求管道的任何地方执行一个HttpModule,这意味着你可以使用上面的URLRewriter 模块 来处理和重写无扩展名的URL(甚至是带有 .asp,.php,或 .jsp 扩展名的URL)。下面示范了你在IIS7中该如何配置:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<configSections>
<section name="rewriter"
requirePermission="false"
type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter" />
</configSections>
<system.web>
<httpModules>
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter" />
</httpModules>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule" />
</modules>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
<rewriter>
<rewrite url="~/products/(.+)" to="~/products.aspx?category=$1" />
</rewriter>
</configuration>
注意一下<system.webServer>内<modules>部分设置为true的runAllManagedModulesForAllRequests属性。这个属性确保来自Intelligencia的UrlRewriter.Net模块(是在IIS7正式发布前编写的),会被调用,有机会重写到服务器的所有URL请求(包括文件夹)。上面的web.config文件非常酷之处在于:
1) 它在任何IIS7机器上都会工作,你不需要管理员在远程主机上启用任何东西,它也能在设置为中等信任安全等级(medium trust)的共享主机的环境场景下工作。
2) 因为我在<httpModules>和 IIS7 的<modules> 部分同时配置了UrlRewriter,我既能在 VS内置的web服务器(即Cassini)中,也能在IIS7下使用同样的URL重写规则。两者完全支持无扩展名的URL重写。这使得测试和开发非常容易。
IIS 7.0 将在今年的晚些时候作为Windows Longhorn服务器的一部分发布,将在几个星期内随Beta3版本的发布支持go-live许可。由于添加到IIS7中的所有的新宿主(hosting)特性,我们预期主机供应商将会非常快地开始积极提供IIS7账号,这意味着你应该很快就可以开始利用上述的无扩展名的URL重写支持。我们将在 IIS7 RTM 时段里发布一个为微软所支持的URL重写模块,该模板是免费的,你可以在IIS7上使用,并且这模块将对你web服务器上的所有内容的高级URL重写场景提供很好的支持。
样例下载:我建立的一个使用IIS7和UrlRewriter.Net模块展示无扩展名URL重写技术的样例应用可以在这里下载。
方法四:在IIS5和IIS6中使用 ISAPIRewrite 来实现无扩展名的URL重写
如果你不想等到IIS7出来才利用无扩展名的URL重写,那么你最好的措施是使用ISAPI过滤器来重写URL。我知道有2个ISAPI过滤器方案,你也许要去看一下:
我没亲手用过上面的产品,虽然我听过到对这2个产品的好评。Scott Hanselman和 Jeff Atwood 最近都写了精彩的博客贴子讲述使用这些产品的体验,同时提供了一些如何在这些产品中配置匹配规则的例子。Helicon Tech的ISAPI Rewrite的规则使用跟 Apache的mod_rewrite同样的句法,譬如(取自Jeff的博客贴子):
[ISAPI_Rewrite]
# fix missing slash on folders
# note, this assumes we have no folders with periods!
RewriteCond Host: (.*)
RewriteRule ([^.?]+[^.?/]) http\://$1$2/ [RP]
# remove index pages from URLs
RewriteRule (.*)/default.htm$ $1/ [I,RP]
RewriteRule (.*)/default.aspx$ $1/ [I,RP]
RewriteRule (.*)/index.htm$ $1/ [I,RP]
RewriteRule (.*)/index.html$ $1/ [I,RP]
# force proper www. prefix on all requests
RewriteCond %HTTP_HOST ^test\.com

RewriteRule ^/(.*) http://www.test.com/$1 [RP]
# only allow whitelisted referers to hotlink images
RewriteCond Referer: (?!http://(?:www\.good\.com|www\.better\.com)).+
RewriteRule .*\.(?:gif|jpg|jpeg|png) /images/block.jpg [I,O]
一定要去读一下Scott和Jeff的贴子以了解这些ISAPI 模块的详情,以及你都能用它们做些什么。
注:使用ISAPI过滤器的一个坏处是,共享主机环境一般不允许你安装这样的组件,所以你要用它们的话,你要么需要一个专用的虚拟主机服务器,要么需要一个专用的主机服务器。但,如果你有一个主机计划允许你安装ISAPI的话,这会在IIS5/6下会提供最大的灵活性,让你过渡到IIS7推出为止。
在URL重写里处理ASP.NET PostBack
大家在使用ASP.NET和重写URL时经常遇到的一个疑难杂症跟处理postback场景有关。具体地来说,当你在一个网页上放置一个 <form runat="server"> 控件时,ASP.NET 会自动地默认输出标识的action属性指向当前所在页面。当使用URL重写时,会出现这样的问题,<form> 控件显示的URL不是原先请求的URL(譬如,/products/books),而是重写过后的URL(譬如,/products.aspx?category=books)。这意味着,当你做一个postback到服务器时,URL不再是你原先干净利落的那个了。
在 ASP.NET 1.0 和1.1 中,大家经常诉诸于继承<form> 控件生成他们自己的控件,来正确地输出要使用的action属性。虽然这可以工作,但结果有点乱,因为这意味着你需要更新你所有的页面来使用这个另外的表单控件,而且有时在Visual Studio所见即所得设计器里也会遇上问题。
好消息是,在ASP.NET 2.0中,有个比较干净的诀窍你可以用来重写<form>控件的action属性。具体地来说,你可利用新的ASP.NET 2.0控件适配器扩展架构来定制控件的输出,用你提供的值来覆盖action属性的值。这不要求在你的.aspx页面里做任何编码改动,而只要在你的/app_browsers文件夹里添加一个.browser文件,注册使用一个控件适配类即可输出新的action属性。
你可在这里查看一个我创建的样例实现,其展示了该如何实现与URL重写协作的表单控件适配器(Form Control Adapter) 。它在我上面使用的第一个(Request.PathInfo),第二个方法(UrlRewriter.Net 模块)中都工作,它使用Request的RawUrl属性获取原先没改写过的 URL来显示。而在第四个方法(ISAPIRewrite过滤器)中,你可以获取ISAPI过滤器保存在Request.ServerVariables["HTTP_X_REWRITE_URL"] 中的原先的URL值。
我上面的FormRewriter类实现在标准的ASP.NET和ASP.NET AJAX 1.0网页上应该都工作(如果你遇上问题的话,告诉我一声)。
正确地处理CSS和图像引用
不少人在第一次使用URL重写时,有时会遇上一个疑难杂症,就是他们发现他们的图像和CSS样式表引用有时会停止工作。这是因为他们在HTML网页里有对这些文件的相对引用,当你开始在应用里重写URL时,你需要意识到浏览器经常会在不同的逻辑层次结构层上(logical hierarchy levels)请求文件,而不是实际存储在服务器上的东西。
譬如,如果我们上面的/products.aspx网页对.aspx 网页里的logo.jpg有一个相对引用,但是通过 /products/books.aspx这个URL来请求的,那么浏览器在显示网页时,将会发出一个对/products/logo.jpg的请求,而不是对/logo.jpg的请求。要正确地引用这个文件,确认你用根目录限定了(root qualify)CSS和图像引用(“/style.css”,而不是 “style.css”)。对于ASP.NET控件,你也可以使用“~”句法从你应用的根目录来引用文件(譬如,<asp:image imageurl="~/images/logo.jpg" runat="server"/>) 。
希望本文对你有所帮助,
Scott
附注:想学习更多的ASP.NET 2.0技巧和诀窍的话,请查看一下我的ASP.NET 2.0技巧,诀窍和教程网页。
附注2:特别感谢Scott Hanselman 和Michael K. Campbell在他们的网站测试我的表单控件适配器 (Form Control Adapter)。
VS2005中的WebTest工具主对是针对于HTTP协议来做的,所以他不仅能测ASP.net的应用,还可以测任何基于http协议的应用,比如JSP、PHP等等。
WebTest在做数据源绑定时,只能很好地分拆Http的Get、Post请求数据包,这对测试webSite已经够了。但如果测web Service就相对不够用,因为WebTest不能分拆Soap包,没有对Soap包内数据进行绑定操作的界面,这一功能需要手工完成。下面就是一个使用VS2005 WebTest工具对webservice进行数据源绑定测试的例子。
1. 先准备一个WebService,并部署到IIS上。
这里有一个简单的WebService:
[WebMethod]
public int Add(int i,int j)
{
return i + j;
}
服务调用说明如下:
2. 准备测试数据
在数据库中准备了一个Test表,存放一些测试数据。
3. 新建Web测试
a) 新建测试项目
b) 新建Web测试
c) 当出现IE录制界面进,按Stop停止录制。
d) 在webtest1里添加Web service request
e) 在web service request里添加Header,其Name=SOAPActioin, Value=” http://tempuri.org/Add”,也就是服务协议里SOAPActioin的值。
f) 在web测试中添加数据源,指向test表。
g) 在http://localhost:8001/webservice/service.asmx?op=Add中注意SOAP请求中下列数据:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Add xmlns="http://tempuri.org/">
<i>int</i>
<j>int</j>
</Add>
</soap:Body>
将其中的i和j的值改为:{{数据源名.表名.列名}},如下所示:
<i>{{MyComics1.tset.i}}</i>
<j>{{MyComics1.tset.j}}</j>
h) 将上面的信息加到Webservice request的stringbody中,如下图所示:
i) 将Web测试的URL改为所测的URL,如下图所示:
到此,测试设置完成。
4. 运行测试
a) 直接运行测试,结果正常。
b) 修改测试,让数据源中的每一条记录都做一次测试。
c) 结果如下图所示,每条数据都执过。

【原文地址】WPF Text Reading and Flow Document Support, and the new NYTimes, Daily Mail, and Seattle Post-Intelligencer Reader Applications
【原文发表日期】 Thursday, February 22, 2007 12:11 PM
Windows Presentation Foundation (WPF,即Avalon) 对Windows客户端开发来说,向前迈进了巨大的一步,它提供了超丰富的.NET UI 框架,其集成了矢量图形,丰富的流文字支持(flow text support),3D视觉效果和强大无比的控件模型框架。你可以从.NET 3.0 得到WPF 支持,.NET 3.0是内置于Windows Vista 中的,对其他的Windows操作系统版本则可以单独下载得到。
Visual Studio Orcas中将随行发布一个丰富的所见即所得(WYSIWYG)设计器以及相关项目支持,可以让开发人员轻松地开发 WPF应用。Microsoft Expression套版 美工产品也将向美工提供杀手级的支持(killer support),可以让美工对WPF视觉和交互性进行设计 (Expression Blend是这方面的专门产品)。
Visual Studio和Expression两者将共享同样的项目文件格式,意味着开发人员和美工可以天衣无缝地在单个项目上合作,而不用在开发过程中互相打架了(因为基于XML的XAML文件定义了应用的UI和样式,而单独的 .cs/.vb 文件则包含了程序员对XAML编程的后台代码)。你现在就可以下载Microsoft Expression的 Beta 2 版本。下几个星期里,我们将在网上发布Visual Studio Orcas 二月份的CTP版本,该版本将拥有内置的WPF设计器,并提供对WPF的强大的代码编写的支持。
WPF文字阅读和Flow Document特性
WPF包括了大量的丰富排版的支持,将显著改进文字在屏幕上的显示,极大地改进数字文字阅读的体验。排版上的高级特性,象ClearType 对亚像素级(sub-pixel )的定位和Y方向平滑的支持, 象连写(ligature),传统的数字,花体(swash),以及文脉选择 (contextual alternatives)这样的OpenType特性,可以使文字的质量,跟普通的HTML以及其他的Windows客户端图形技术相比,高出很多很多,而且可以极大地提高用户阅读内容的速度。
作为UI布局和控件模型体验的一部分,WPF也提供了对Flow Document的内置支持。Flow Document的功能对随窗口大小,内容语义(semantics),以及应用的设备分辨率之不同而重新流动内容提供了自动支持。譬如,你可以在WPF中的FlowDocumentPageViewer控件中装载文字,图像,录像和任何WPF控件,然后让其自动地改变大小和为你自动地跨越多列/多页来分页显示文字。
下面是纽约时报阅读器程序中的实际例子(帖子后面对该程序还有另述)。注意,文章是自动跨2列换行显示的,并注意屏幕下方的 "Page 1 of 2" 导航和放大UI:
为帮助示范如何在你自己的应用里实现同样的内容流动行为,我在下面使用WPF的内置FlowDocumentPageViewer控件编写了一个简单的样例,下面是该应用的所有内容(全部是XAML,不需要后台代码):
<Window x:Class="WPFApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<FlowDocumentPageViewer>
<FlowDocument>
<Paragraph>
This is a paragraph of text.
</Paragraph>
<Paragraph>
This is another paragraph of text.
</Paragraph>
<Paragraph>
My movers are carrying my TV out right now.
</Paragraph>
<Paragraph>
I hope that loud bang wasn't the TV being dropped.
</Paragraph>
<BlockUIContainer>
<Button Content="Button" />
</BlockUIContainer>
<Paragraph>
This is another paragraph.
</Paragraph>
</FlowDocument>
</FlowDocumentPageViewer>
</Grid>
</Window>
现在我运行这个应用时,我会得到一个窗口,对这个内容,其默认大小为300x300像素 :

就象你预期的,我得到几个文字段落。注意,我也能够在内容里直接内嵌WPF按钮控件(我可以在其中放置任何WPF控件)。也注意一下上面由FlowDocumentPageViewer提供的自动内容分页控件和内容大小滑标器(slider)。
然后,当我改变窗口大小,使它更短,更宽时,你会注意到内容被FlowDocumentPageViewer自动分成两列。我不用写任何编码就得到了这个行为:
我也可以稍微缩窄窗口,放大内容(使用底部的滑标)。注意内容(文字和按钮)在屏幕上是如何变大的,以及FlowDocumentPageViewer 控件是如何自动为我对内容做了分页 (我在下面的适当UI部分用红笔加了圆圈做标记):
你可以看到,这非常容易实现,其结果是个简单但强有力的应用。很明显地,我可以调用一个web-service或者RSS feed来动态地填充内容,而不是在应用里硬写内容。我将得到同样的分页和流机制(semantics)。
WPF应用 纽约时报阅读器,每日邮报阅读器,和 西雅图邮报Intelligencer阅读器可从网上下载
WPF的文字支持真的开启了无穷多的机会来创造更深入,更加个人化的阅读体验(此外,WPF真的可以为一个博客阅读客户端所用)。
我的开发队伍,正与很多报纸和杂志出版商合作,帮他们开发和发布针对他们内容的个人化的阅读器程序。除了提供丰富的文字支持外,这些阅读器都支持离线内容(意味着你在线时同步内容,然后可以在离线不在网络上时阅读所有的东西,当你在飞机,火车或者公车上时,这可是非常理想)。阅读器程序也提供丰富的查询视觉效果,同时提供内容评注支持等:
去年九月纽约时报发布了这个定制的纽约时报阅读器程序(点击这里免费下载和使用):
今天,西雅图邮报Intelligencer也推出了阅读器程序(点击这里免费下载和使用):
英国的每日邮报也推出了阅读器(点击这里免费下载和使用):
更多的知名出版商在将来的几个月内也会陆续推出类似的应用。
我们也将推出一个出版商Reader SDK ,以允许任何人开发类似的定制阅读应用。网站将能够提供带有自定义扩展的RSS feed(以内嵌分页规则,广告放置细节等等),然后,开发人员将能够轻易地建造定制的WPF 阅读器客户端应用来进一步增强体验。
Tim Sneath在他这里的精彩博客上对此做了更详细的讨论。
如何进一步了解WPF
想进一步了解WPF中Flow Document支持的话,我建议你阅读一下MSDN这里的这篇精彩文章。
最近刚出版了几本很好的WPF的书,可以帮助你对WPF上手。Adam Nathan 出版了一本非常好的《 Windows Presentation Foundation Unleashed 》书,目前已在售,在亚马逊书店上获得了好评(十个评语,5星评分):
Chris Sells 和 Chris Anderson两人将在下几个月内出版自己的WPF书,我已经读过初稿,非常喜欢。这里是Chris Anderson的《Essential WPF》在亚马逊书店上的连接,该书将在四月份出版。我刚开始阅读Chris Sell更新的WPF书,也非常喜欢他的书,等该书在亚马逊书店的连接一出来,我会更新这个博客贴子。
希望本文对你有所帮助,
Scott
【原文地址】ASP.NET AJAX and SharePoint
【原文发表日期】 Tuesday, February 20, 2007 11:45 PM
最近在欧洲的一个用户组织会议上我被问到的一个问题是,是否能够在SharePoint 2007 方案里使用 ASP.NET AJAX。这个问题经常问到,为回答这个问题,SharePoint开发队伍最近在他们的博客上讨论了他们关于ASP.NET AJAX的计划。你可以在这里阅读他们的帖子。
总的来说,SharePoint中对ASP.NET AJAX 的正式支持将随SharePoint 2007的第一个服务包推出。这是因为SharePoint 2007是在ASP.NET AJAX 1.0之前发行的,所以SharePoint开发队伍还有一些工作需要完成才能使之很好地集成。
但与此同时,你可以在SharePoint开发队伍这里的博客上阅读一下如何在SharePoint 2007站点上安装ASP.NET AJAX 1.0 ,现在就开始使用ASP.NET AJAX 1.0 的功能。在第一个服务包发行之前,会有一些小问题,但他们博客贴子里的步骤会帮你马上就开始使用。同时,也一定要去看一下Eric Schoonover关于自定义AjaxBasePart web part的帖子,这个web part是他的队伍创建来帮助你在你建立的自定义web part里使用ASP.NET AJAX的。
SharePoint 和ASP.NET 开发人员信息
想了解SharePoint和Web Part的详细信息的话,请看一下我以前的这些帖子:
也看一下SharePoint 2007的SmartPart 控件插件,该插件允许你在SharePoint 2007中把任何ASP.NET 2.0用户控件当作web part来部署。
SharePoint和ASP.NET Web Part开发类书籍
既然说到SharePoint开发人员和ASP.NET Web Parts,有2本关于SharePoint开发的书,我最近听到了很多好评。第一本是Todd Bleeker的《Windows SharePoint第三版平台上开发人员之向导(Developer's Guide to the Windows SharePoint Services v3 Platform)》,在亚马逊(Amazon)网上书店上,有11个评论,得到五个星的评分,在过去的几个月内名列亚马逊的畅销榜:

第二本是 Darren Neimke 的《实战ASP.NET 2.0 Web Parts:建造动态门户网站(ASP.NET 2.0 Web Parts in Action: Building Dynamic Web Portals)》,提供了一个非常不错的方式来学习如何使用ASP.NET 2.0 Web Parts来建造网站,以及如何建造你自己的自定义Web Parts :
Web part的美妙之处在于,使用ASP.NET 2.0,你现在可以建造的web part,可以在任何ASP.NET网站/应用(不需SharePoint)中使用以及能被用户所定制,而且这些同样的web part在SharePoint 2007 中也能使用和运行(无论是免费的Windows SharePoint Services版本还是微软Office SharePoint服务器版本)。这可提供了无穷的开发人员威力,打开了很多选项。这可是赋予了开发人员极其强大的能力,开启了许多开发选项。
Windows SharePoint Services 3.0免费应用模板
过去的几个月内,SharePoint开发队伍集中精力在做的一件事情是聚集一堆免费应用模板,你可以下载来与Windows SharePoint Services 3.0一起使用,该版本是你可以下载和安装在任何Windows服务器机器上的免费SharePoint版本。
你可以在这里了解关于这些应用模板的更多细节。下面是一些现在就可下载的带有自定义web part的免费模板的列单:
- 董事会(Board of Directors)
- 业务表现报表(Business Performance Reporting)
- 政府部门案例管理(Case Management for Government Agencies)
- 课堂管理(Classroom Management)
- 临床试验提议和管理(Clinical Trial Initiation and Management)
- 竞争分析网站(Competitive Analysis Site)
- 讨论数据库(Discussion Database)
- 有争议发票管理(Disputed Invoice Management)
- 员工活动网站(Employee Activities Site)
- 员工自服务福利(Employee Self-Service Benefits)
- 员工培训日程和材料(Employee Training Scheduling and Materials)
- Equity 研究(Research)
- 集成市场调查追踪(Integrated Marketing Campaign Tracking)
- 制造过程管理(Manufacturing Process Management)
- 新店开张(New Store Opening)
- 产品和市场需求计划(Product and Marketing Requirements Planning)
- 征求建议书(Request for Proposal)
- 体育联盟(Sports League)
- 团队网站(Team Work Site)
- 工时系统管理(Timecard Management)
这些模板很棒之处在于,你下载/安装它们之后,你可以往里添加自定义的ASP.NET web parts,然后使用标准的ASP.NET 2.0技术对它们做进一步的定制。这可以极大地简化建造和部署常见的应用方案。
最后,是一些对想提供SharePoint服务的主机供应商的信息
对那些想向客户提供基于SharePoint的解决方案的主机供应商,请去看一下上星期一微软刚发布的精彩方案指引:《在Windows SharePoint Services 3.0上创建共享主机方案(Creating Shared Hosting Solutions on Windows SharePoint Services 3.0)》。该指引提供了详尽的说明和具体指导你如何在共享主机的环境里以最佳方式部署和管理SharePoint,允许成千上万的客户在单一共享主机服务器上运行。
希望本文对你有所帮助,
Scott
在VS2005里有源代码切换的设置,但在VS2003里没有。VS2003的源代管理器的配置依赖于注册表中的一条记录。
[HKEY_LOCAL_MACHINE\SOFTWARE\SourceCodeControlProvider]
"Microsoft Team Foundation Server MSSCCI Provider"="SOFTWARE\\Microsoft\\Team Foundation Server MSSCCI Provider"
"ProviderRegKey"="SOFTWARE\\Microsoft\\Team Foundation Server MSSCCI Provider"
[HKEY_LOCAL_MACHINE\SOFTWARE\SourceCodeControlProvider\InstalledSCCProviders]
"Microsoft Team Foundation Server MSSCCI Provider"="SOFTWARE\\Microsoft\\Team Foundation Server MSSCCI Provider"
"Microsoft Visual SourceSafe"="Software\\Microsoft\\SourceSafe"
当providerRegkey指到msscci时,就用TFS,指向VSS时就用的VSS。
网上有一个小工具SCPSelector.exe可以很方便地做providerRegkey切换,不用每次改注册表。每次切换过后要重启一下VS2003。
SQL Server 2005 SP2 出来后,Vista 下安装 SQL Server 2005 就很容易了,忽略掉所有提示,一直安装,安装完成了,直接打SP2的补丁就可以了。
这样简单的过程,是没必要写博客的。但我(郭红俊)仍然要写一篇博客,是因为我忘记了一点,费了一上午才在Vista上安装好 SQL 2005。
这点就是:
Vista 上不支持安装 Enterprise 版的 SQL 2005 数据库服务
但是却支持安装 SQLEXPRESS 版本, 以及 Developer 版本的数据库服务。
至于SQL Server 2005 的其他几个版本,是否 Vista 支持安装数据库服务,由于我没测试,就不提了。
如果你想在Vista 上装 Enterprise 版的 SQL 2005 数据库服务,在安装选项的时候,就会看到下面的情况,数据库服务没法选择中,是灰色的。
郭红俊整理出这篇博客,就是为了提醒大家,如果发现类似上面的问题,可能你这个版本的SQL 2005 不支持在Vista 上安装,在Vista 上安装 SQL 2005 ,我还是强烈建议你安装 开发人员版本的 SQL 2005。
相关下载:
英文版 Microsoft SQL Server 2005 Service Pack 2 下载地址:
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=d07219b2-1e23-49c8-8f0c-63fa18f26d3a
中文版 Microsoft SQL Server 2005 Service Pack 2 下载地址:
http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&FamilyID=d07219b2-1e23-49c8-8f0c-63fa18f26d3a
SQL Server 2005 SP2 的新增功能
http://download.microsoft.com/download/e/2/b/e2baa171-0995-42f9-befc-526ae4683ea2/WhatsNewSQL2005SP2.htm
RSS博客镜像是CommunityServer在较高级版本中(好像是从2.1开始)推出的功能,其主要的作用是,将其它博客(博客软件或者博客服务提供商)中的日志通过解析RSS方式自动发布到CommunityServer中。
这是一个相当实用的功能,有了RSS博客镜像,就不需要在多处同时发布博客日志了。比如你同时在新浪上有自己的博客,又同时有自己的个人博客站点,那么你只需要在新浪上发布博客日志,而个人博客站点通过RSS博客镜像功能将新浪博客上发布的新日志自动更新到站点中。
我们在肥猫博客中,也提供了这样的一个功能,在这里就此介绍下实现方法,这个实现方式是针对ASP.NET的,至于asp,由于其天生的局限性,可能无法直接在Web应用程序中完成这一功能,而需要额外的Windows应用程序的支持。
1. 管理RSS博客镜像
首先我们需要在肥猫博客软件系统中管理好RSS博客镜像,需要管理的内容有:
l RSS地址
l 更新频率
l 最后更新的时间

需要管理的内容如图所示,这里所列出的3个是必须的字段,当然根据你自己系统的需要,你可能需要更多的字段。
这部分工作由于和肥猫博客系统相关性比较强,如果你需要自己实现RSS博客镜像,和你本身的系统也是比较相关的,这里就不再多做介绍,你根据自己系统的需要去实现就行。
2. 通过ASP.NET的定时器来抓取RSS源
有了上面的对每个RSS种子定时更新的信息,就需要在ASP.NET中设置一个定时器来定时更新这些RSS种子内容了。
这部分内容请主要参考如下文章《在 ASP.NET 中使用计时器(Timer)》,根据这篇文章实现定时器就足够了。下面我主要介绍下在肥猫博客中的实现方式:
这下面的代码都在Global.ascx.cs中实现。
protected void Application_Start(Object sender, EventArgs e)
{
SetApplicationStatus(RssMirror, true);
// 设置定时器
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += new System.Timers.ElapsedEventHandler(this.RefressRssMirror);
timer.Interval = 300000; // 每5分钟中触发定时器
timer.AutoReset = true;
timer.Enabled = true;
}
private void SetApplicationStatus(string keyword, object result)
{
Application.Lock();
Application[keyword] = result;
Application.UnLock();
}
private void UpdateRssMirror(fmRssMirror item, fmblog.Data.DataProviders.DataProvider provider)
{
try
{
DateTime now = DateTime.Now;
XmlDocument doc = new XmlDocument();
// 载入RSS种子
doc.Load(item.FeedUrl);
// 解析RSS种子内容
fmPostCollection list = fmFeedParser.GetPosts(item.UserName, doc, item.LastUpdateTime);
for(int i=list.Count-1; i>=0; i--)
{
// 根据标题,判断博客日志是否已经存在
if(provider.GetPost(item.UserName, list
.Title)==null)
{
provider.NewPost(list
, string.Empty);
}
}
// 设置最后更新时间
provider.SetRssMirrorLastUpdateTime(item.Id, now, item.UserName);
}
catch(Exception)
{
}
}
protected void RefressRssMirror(object sender, System.Timers.ElapsedEventArgs e)
{
// 判断上次触发的定时器是否已经完成
if((bool)Application[RssMirror])
{
SetApplicationStatus(RssMirror, false);
try
{
fmblog.Data.DataProviders.DataProvider provider = fmblog.Data.DataProviders.DataProvider.CreateInstance(Application);
provider.OpenConnection();
try
{
fmRssMirrorCollection list = provider.GetAllRssMirrors();
DateTime now = DateTime.Now;
// 更新RSS博客镜像里的所有RSS种子
foreach(fmRssMirror item in list)
{
TimeSpan span = now - item.LastUpdateTime;
if(span.Hours>=item.UpdateInterval)
{
UpdateRssMirror(item, provider);
}
}
}
&nbs