<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>简单生活 —— Kevin Yang的博客 &#187; Silverlight</title> <atom:link href="http://www.imkevinyang.com/tags/silverlight/feed" rel="self" type="application/rss+xml" /><link>http://www.imkevinyang.com</link> <description>It&#039;s all about sharing</description> <lastBuildDate>Mon, 06 Sep 2010 08:00:00 +0000</lastBuildDate> <generator>http://wordpress.org/?v=2.9.1</generator> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <item><title>Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</title><link>http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html</link> <comments>http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html#comments</comments> <pubDate>Mon, 03 May 2010 16:37:42 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[RIA]]></category> <category><![CDATA[SEO]]></category> <category><![CDATA[Silverlight SEO]]></category> <category><![CDATA[Sitemap]]></category> <category><![CDATA[优化]]></category> <category><![CDATA[搜索引擎]]></category> <category><![CDATA[深层链接]]></category> <category><![CDATA[网站地图]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html</guid> <description><![CDATA[继续我们的系列文章，接着来看一下Silverlight和SEO。互联网上大部分流量都是搜索驱动的。搜索引擎通常是很多用户在公共互联网上的第一站，企业环境上的情况也在朝这个趋势发展。搜索也是很多广告获得收益的关键因素。所以无须多讲，SEO非常重要。但对于Silverlight程序来说，很多有意思的内容都是动态生成的，怎么做SEO呢？接下来我会给大家展示一个只需耗费最小工作的应用模式来实现Silverlight应用程序的SEO优化。]]></description> <content:encoded><![CDATA[<div class="statement"><p>作者：Brad Abrams</p><p>译者：Kevin Yang</p><p>英文链接：<a title="Silverlight 4 + RIA Services - Ready for Business: Search Engine Optimization (SEO)" href="http://blogs.msdn.com/brada/archive/2010/03/17/silverlight-4-ria-services-ready-for-business-search-engine-optimization-seo.aspx" target="_blank">Silverlight 4 + RIA Services - Ready for Business: Search Engine Optimization (SEO)</a></p></div><p>继续我们的系列文章，接着来看一下Silverlight和SEO。互联网上大部分流量都是搜索驱动的。搜索引擎通常是很多用户在公共互联网上的第一站，企业环境上的情况也在朝这个趋势发展。搜索也是很多广告获得收益的关键因素。所以无须多讲，SEO非常重要。但对于Silverlight程序来说，很多有意思的内容都是动态生成的，怎么做SEO呢？接下来我会给大家展示一个只需耗费最小工作的应用模式来实现Silverlight应用程序的SEO优化。</p><p>要实现Silverlight应用程序的SEO优化，需要按照以下三个有趣而又简单的步骤来实施：</p><ul><li>步骤1：做好重要的页面的深层链接</li><li>步骤2：使用网站地图(Sitemap)让搜索引擎知道你网站的所有深层链接</li><li>步骤3：对于重要内容，提供一个备选版本</li></ul><p>下面我会用例子来讲解以上这三个步骤的具体含义。我会继续沿用我在PDC209上的“美食浏览器”的演示。你可能需要看一下我之前的演示(<a href="http://blogs.msdn.com/brada/archive/2009/11/19/pdc09-talk-building-amazing-business-applications-with-silverlight-4-ria-services-and-visual-studio-2010.aspx">PDC09 Talk: Building Amazing Business Applications with Silverlight 4, RIA Services and Visual Studio 2010</a>)，这样可以在正式开始下面的讲解之前，能够熟悉一些背景。</p><p><a href="http://brad_abrams.members.winisp.net/Projects/Mix10/MyApp.SEO.zip">下载完整的示例</a>。</p><h2>步骤1: 做好重要的页面的深层链接</h2><p>对于你网站上的任何内容，如果你想让搜索引擎能够爬取到，那么必须给这份内容起一个独特的Url。例如如果我想在Bing（或者Google，或者其他搜索引擎）上搜索“乡村炸牛排（Country Fried Steak）”，能看到我网站上这个列举了很多乡村炸牛排图片的页面，那么我需要为这个页面提供一个Url，从而引导你来到这个页面。http://foo.com/foodieExplorer.aspx这个Url还不够好，我需要提供一个类似于http://foo.com/foodieExplorer.aspx?food=CountryFriedsteak这样的Url。注意，使用这种格式的Url还有很多其他的好处，例如用户可以在Twitter上传播，通过电子邮件或者即时通讯软件去讨论这些内容。</p><p>幸运的是，Silverlight的导航特性使到实现内容的深层链接变得非常简单。我们来看看具体是怎么做的。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0016.png"><img style="display: inline; border-width: 0px;" title="clip_image001[6]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0016_thumb.png" border="0" alt="clip_image001[6]" width="275" height="212" /></a></p><p>我们首先需要做的就是提供一个Url来唯一标识一个特定的餐馆，或者一个特定的餐馆加特定的美食。出于SEO或者用户友好的角度考虑，我们希望Url的格式类似于http://www.hanselman.com/abrams/restaurant/25/plate/4，这表示餐馆编号=25，美食编号=4。要实现这个，我们需要在Web工程的global.aspx文件中定义导航路径（Routes）。</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Global : HttpApplication
{
    <span class="kwrd">void</span> Application_Start(<span class="kwrd">object</span> sender, EventArgs e)
    {
        RegisterRoutes(RouteTable.Routes);
    }

    <span class="kwrd">void</span> RegisterRoutes(RouteCollection routes)
    {
        routes.MapPageRoute(
            <span class="str">"deepLinkRouteFull"</span>,
            <span class="str">"restaurant/{restaurantId}/plate/{plateId}"</span>,
            <span class="str">"~/default.aspx"</span>,
            <span class="kwrd">false</span>,
            <span class="kwrd">new</span> RouteValueDictionary { { <span class="str">"restaurant"</span>, <span class="str">"-1"</span> },
            { <span class="str">"plate"</span>, <span class="str">"-1"</span> } });

        routes.MapPageRoute(
            <span class="str">"deepLinkRoute"</span>,
            <span class="str">"restaurant/{restaurantId}"</span>,
            <span class="str">"~/default.aspx"</span>,
            <span class="kwrd">false</span>,
            <span class="kwrd">new</span> RouteValueDictionary { { <span class="str">"restaurant"</span>, <span class="str">"-1"</span> } });</pre><p>在上面代码中，我们定义了深层链接的Url模板，支持Url中添加餐馆编号（restaurantId）和美食编号（plateId）的参数。我们定义的导航路径的顺序是从最复杂到不那么复杂。如果这两个编号在Url中都缺失的话，那么将使用上面设置的默认值。</p><p>现在，我们来看看Silverlight客户端怎么解析这个Url的。在Plates.xaml.cs文件中：</p><pre class="csharpcode"><span class="rem">// Executes when the user navigates to this page.</span>
<span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)
{
    <span class="kwrd">int</span> plateID = -1;
    <span class="kwrd">int</span> restaurantId  =-1;
    var s = HtmlPage.Document.DocumentUri.ToString().Split(<span class="kwrd">new</span> <span class="kwrd">char</span>[] {<span class="str">'/'</span>,<span class="str">'#'</span>});
    <span class="kwrd">int</span> i = Find(s, <span class="str">"plate"</span>);
    <span class="kwrd">if</span> (i != -1)
    {
         plateID = Convert.ToInt32(s[i + 1]);
         plateDomainDataSource.FilterDescriptors.Add(
             <span class="kwrd">new</span> FilterDescriptor(<span class="str">"ID"</span>,
                 FilterOperator.IsEqualTo, plateID));
    }
    i = Find(s, <span class="str">"restaurant"</span>);
    <span class="kwrd">if</span> (i != -1) restaurantId = Convert.ToInt32(s[i + 1]);
    <span class="kwrd">else</span> restaurantId = Convert.ToInt32(NavigationContext.QueryString[<span class="str">"restaurantId"</span>]);
    plateDomainDataSource.QueryParameters.Add(
        <span class="kwrd">new</span> Parameter()
        {
           ParameterName = <span class="str">"resId"</span>,
           Value = restaurantId
        }
    );
}</pre><p>基本上，上面代码所做的事情就是获取完整的Url，然后将其结构化，再提取出其中的餐馆编号和美食编号。在18-23行中，我们将餐馆编号作为参数传给查询方法，但是在11-14行中，我们并没有这么干，而是应用了一个过滤器，这就相当于最终发给服务器的LINQ查询就多了一个“where”子句。这样，我们就无需修改服务端的代码了。</p><p>我们还需要做一点小工作，那就是保证客户端最终导航到美食（Plates）的页面。这在Silverlight的导航框架中是通过锚点“#/Plates”来实现的。但由于锚点只是一个客户端特性，而搜索引擎并不能很好的处理锚点，因此我们需要在客户端动态添加锚点。我发现用一点点Javascript脚本就可以很好的完成这个工作。我在服务端的Default.aspx页面上加入了这段脚本：</p><pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">void</span> Page_Init(<span class="kwrd">object</span> sender, EventArgs e)
{
    <span class="kwrd">string</span> resId = Page.RouteData.Values[<span class="str">"restaurant"</span>] <span class="kwrd">as</span> <span class="kwrd">string</span>;
    <span class="kwrd">if</span> (resId != <span class="kwrd">null</span>) { Response.Write(<span class="str">"&lt;script type=text/javascript&gt;window.location.hash='#/Plates';&lt;/script"</span>+<span class="str">"&gt;"</span>); }
}</pre><p>还有一个小事情需要注意的，由于我们启用了路径导航的功能，现在就可以通过不同的Url来访问default.aspx页面了，因此如果使用相对路径去引用Silverlight.js以及MyApp.xap包的时候就会出现问题。例如我们会看到浏览器去请求http://www.hanselman.com/abrams/restaurant/25/plate/4/Silverlight.js，而不是http://www.hanselman.com/abrams/silverlight.js，这会导致下面错误：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0018.png"><img style="display: inline; border-width: 0px;" title="clip_image001[8]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0018_thumb.png" border="0" alt="clip_image001[8]" width="244" height="169" /></a></p><blockquote><p>行: 56</p><p>错误: Unhandled Error in Silverlight Application</p><p>异常代码: 2104</p><p>类别: InitializeError</p><p>消息: 无法下载Silverlight程序，请检查Web服务器的设置</p></blockquote><p>要解决这个问题，我们需要修改脚本的src属性：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">script </span><span class="attr">src</span><span class="kwrd">='&lt;%= this.ResolveUrl("~/Silverlight.js") %&gt;'</span></pre><p>还有Silverlight插件参数：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">param</span> <span class="attr">name</span><span class="kwrd">="source"</span> <span class="attr">value</span><span class="kwrd">="&lt;%= this.ResolveUrl("</span>~/<span class="attr">ClientBin</span>/<span class="attr">MyApp</span>.<span class="attr">xap</span><span class="kwrd">") %&gt;"</span><span class="kwrd">/&gt;</span></pre><p>现在我们再通过http://localhost:30045/restaurant/48/plate/119#/Plates这个包含美食编号的Url来访问，就能直接来到相应的美食页面了：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00110.png"><img style="display: inline; border-width: 0px;" title="clip_image001[10]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00110_thumb.png" border="0" alt="clip_image001[10]" width="408" height="322" /></a></p><h2>步骤2：使用网站地图让搜索引擎知道你网站的所有深层链接</h2><p>现在我们有了一个已经做好深层链接的应用程序了，每一个有趣的内容都被赋予了一个唯一的Url。但搜索引擎怎么知道这些Url呢？我们当然希望别人在社交网络上多谈论（谈论的时候通常会留下链接），然后搜索引擎能够发现其中的一部分Url，但我们更希望能够把这事做完整了。我们想给搜索引擎提供一个应用程序内部所有深层链接的Url列表。这可以使用网站地图（Sitemap）来实现。</p><p>网站地图的格式是所有主流搜索引擎都认可的。你可以在<a href="http://sitemap.org">http://sitemap.org</a>网站找到相关的信息。</p><p>为了更好的了解这其中的原理，我们来看看亚马逊，<a href="http://amazon.com">http://amazon.com</a>，这个以数据驱动的网站是如何被搜索引擎索引的。当搜索引擎第一次来到这个网站，它会去读取网站根目录下的robots.txt文件。在这个例子中，robots.txt文件的绝对地址是<a href="http://www.amazon.com/robots.txt">http://www.amazon.com/robots.txt</a>。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00112.png"><img style="display: inline; border-width: 0px;" title="clip_image001[12]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00112_thumb.png" border="0" alt="clip_image001[12]" width="222" height="341" /></a></p><p>在这个例子中，我们可以看到，文件上半部分列举了一些目录，这些目录是不允许搜索引擎爬取的，文件下半部分列举的sitemap清单，是希望搜索引擎去爬取这些网站内容。</p><p>注意，严格来说，你不是必须使用Robots文件来声明你的网站地图（译者注：原文写的是“你不是必须使用网站地图”）。你可以使用主流搜索引擎提供的网站管理员工具直接登记网站地图地址。</p><p>如果我们导航到上面其中一个网址，我们将看到一个网站地图文件，如下面所示：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00114.png"><img style="display: inline; border-width: 0px;" title="clip_image001[14]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00114_thumb.png" border="0" alt="clip_image001[14]" width="244" height="190" /></a></p><p>在这个例子中，因为亚马逊网站很庞大，这些链接被放到多个网站地图中去了（上面这个文件被称为网站地图索引文件）。当我们钻进子网站地图文件中，就能看到实际产品的链接了。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00116.png"><img style="display: inline; border-width: 0px;" title="clip_image001[16]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00116_thumb.png" border="0" alt="clip_image001[16]" width="396" height="293" /></a></p><p>格式就如你看到的：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">urlset</span> <span class="attr">xmlns</span><span class="kwrd">="http://www.google.com/schemas/sitemap/0.84"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">url</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">loc</span><span class="kwrd">&gt;</span>http://www.amazon.com/GAITHER-COMMITTEE-EISENHOWER-COLD-WAR/dp/081425005X<span class="kwrd">&lt;/</span><span class="html">loc</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">url</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">url</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">loc</span><span class="kwrd">&gt;</span>http://www.amazon.com/CONTROLLING-VICE-REGULATING-PROSTITUTION-CRIMINAL/dp/0814250076<span class="kwrd">&lt;/</span><span class="html">loc</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">url</span><span class="kwrd">&gt;</span></pre><p>有意思的是，当亚马逊产品目录中添加或者移除商品的时候，这里的链接也会经常发生变更。</p><p>我们接着来看看如何为我们的网站建立一个网站地图。在Web工程中，打开VS的添加条目对话框，往我们工程添加一个“Search sitemap”  。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image002.png"><img style="display: inline; border-width: 0px;" title="clip_image002" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image002_thumb.png" border="0" alt="clip_image002" width="366" height="247" /></a></p><p>确认你机器上已经安装了<a href="http://silverlight.net/riaservices">RIA Services Toolkit</a> ，否则是没有这个条目模板的。</p><p>添加成功之后，我们会得到一个robots.txt文件：</p><blockquote><p># This file provides hints and instructions to search engine crawlers.</p><p># For more information, see <a href="http://www.robotstxt.org/">http://www.robotstxt.org/</a>.</p><p># Allow all</p><p>User-agent: *</p><p># Prevent crawlers from indexing static resources (images, XAPs, etc)</p><p>Disallow: /ClientBin/</p><p># Register your sitemap(s) here.</p><p>Sitemap: /Sitemap.aspx</p></blockquote><p>还有一个sitemap.aspx的文件。</p><p>更多信息，请参考：<a href="http://www.bing.com/community/blogs/webmaster/archive/2009/08/15/uncovering-web-based-treasure-with-sitemaps-sem-101.aspx">Uncovering web-based treasure with Sitemaps</a>。</p><p>但这个sitemap.aspx文件还是空的，要建立实际可用的网站地图，我们需要基于PlateViewDomainService创建另外的视图。在这个例子，这个视图的消费者是一个Asp.Net页面。这里我们要用到asp:DomainDataSource。在设计器拖放一个Repeater控件到表单中，如下所示：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image003.png"><img style="display: inline; border-width: 0px;" title="clip_image003" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image003_thumb.png" border="0" alt="clip_image003" width="244" height="157" /></a></p><p>在Repeater控件上右键配置数据源：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image004.png"><img style="display: inline; border-width: 0px;" title="clip_image004" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image004_thumb.png" border="0" alt="clip_image004" width="436" height="117" /></a></p><p>选择一个数据源</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image005.png"><img style="display: inline; border-width: 0px;" title="clip_image005" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image005_thumb.png" border="0" alt="clip_image005" width="369" height="294" /></a></p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image006.png"><img style="display: inline; border-width: 0px;" title="clip_image006" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image006_thumb.png" border="0" alt="clip_image006" width="244" height="192" /></a></p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image007.png"><img style="display: inline; border-width: 0px;" title="clip_image007" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image007_thumb.png" border="0" alt="clip_image007" width="244" height="192" /></a></p><p>最后，我们的网站地图文件中就会得到两个链接集合。</p><pre class="csharpcode"> <span class="kwrd">&lt;</span><span class="html">asp:DomainDataSource</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">ID</span><span class="kwrd">="RestaurauntSitemapDataSource"</span>
 <span class="attr">DomainServiceTypeName</span><span class="kwrd">="MyApp.Web.DishViewDomainService"</span>
 <span class="attr">QueryName</span><span class="kwrd">="GetRestaurants"</span> <span class="kwrd">/&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">asp:Repeater</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">id</span><span class="kwrd">="repeater"</span> <span class="attr">DataSourceID</span><span class="kwrd">="RestaurauntSitemapDataSource"</span> <span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">HeaderTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">urlset</span> <span class="attr">xmlns</span><span class="kwrd">="http://www.sitemaps.org/schemas/sitemap/0.9"</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">HeaderTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">url</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">loc</span><span class="kwrd">&gt;</span><span class="asp">&lt;%</span>= Request.Url.AbsoluteUri.ToLower().Replace(<span class="str">"sitemap.aspx"</span>,<span class="kwrd">string</span>.Empty) + <span class="str">"restaurant/"</span><span class="asp">%&gt;</span><span class="asp">&lt;%</span># HttpUtility.UrlEncode(Eval(<span class="str">"ID"</span>).ToString()) <span class="asp">%&gt;</span><span class="kwrd">&lt;/</span><span class="html">loc</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">url</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">asp:Repeater</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">asp:DomainDataSource</span> <span class="attr">ID</span><span class="kwrd">="PlatesSitemapDataSource"</span> <span class="attr">runat</span><span class="kwrd">="server"</span>
 <span class="attr">DomainServiceTypeName</span><span class="kwrd">="MyApp.Web.DishViewDomainService"</span>
 <span class="attr">QueryName</span><span class="kwrd">="GetPlates"</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">asp:DomainDataSource</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">asp:Repeater</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">id</span><span class="kwrd">="repeater2"</span> <span class="attr">DataSourceID</span><span class="kwrd">="PlatesSitemapDataSource"</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">url</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">loc</span><span class="kwrd">&gt;</span><span class="asp">&lt;%</span>= Request.Url.AbsoluteUri.ToLower().Replace(<span class="str">"sitemap.aspx"</span>,<span class="kwrd">string</span>.Empty) + <span class="str">"restaurant/"</span><span class="asp">%&gt;</span><span class="asp">&lt;%</span># HttpUtility.UrlEncode(Eval(<span class="str">"RestaurantID"</span>).ToString()) + <span class="str">"/plate/"</span> + HttpUtility.UrlEncode(Eval(<span class="str">"ID"</span>).ToString()) <span class="asp">%&gt;</span><span class="kwrd">&lt;/</span><span class="html">loc</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">url</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">FooterTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">urlset</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">FooterTemplate</span><span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">asp:Repeater</span><span class="kwrd">&gt;</span></pre><p>在第3行和第20行，我们是直接调用在DomainService中定义的GetRestaurant 和GetPlates方法。</p><p>现在，对于一个具有相当规模数据量的网站来说，这个页面将会耗费很长的时间去执行。它需要扫描数据库中的每一行。这当然可以保证数据永远最新的，但是我们希望平衡一下服务器的负载。一个简单的做法就是通过设置一个小时的输出缓存。具体操作参考<a href="http://msdn.microsoft.com/en-us/library/aa478965.aspx">ASP.NET Caching: Techniques and Best Practices</a>。</p><pre class="csharpcode"><span class="asp">&lt;%@ OutputCache Duration="3600" VaryByParam="None" %&gt;</span></pre><p>另外一个处理这种大数据集的策略是将数据分割到多个网站地图中去，就像我们上面看到的亚马逊网站的例子。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image008.png"><img style="display: inline; border-width: 0px;" title="clip_image008" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image008_thumb.png" border="0" alt="clip_image008" width="311" height="372" /></a></p><p>随便取其中的一个Url，导航到此网址，OK，现在我们得到正确的页面了。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image009.png"><img style="display: inline; border-width: 0px;" title="clip_image009" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image009_thumb.png" border="0" alt="clip_image009" width="444" height="261" /></a></p><h2>步骤3：对于重要内容，提供一个备选版本</h2><p>太棒了，现在我们有了深层链接，我们也能让搜索引擎发现所有这些链接，不过，当搜索引擎来到这个页面的时候，它会看到什么？多数搜索引擎只会解析HTML，所以通过菜单"页面&gt;查看源代码"，我们就能够看到搜索引擎眼中我们页面的面目了:</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00118.png"><img style="display: inline; border-width: 0px;" title="clip_image001[18]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00118_thumb.png" border="0" alt="clip_image001[18]" width="358" height="207" /></a></p><p>或者我们在禁用Silverlight插件（工具 &gt; 管理加载项）后去访问此页面，我们会看到：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00120.png"><img style="display: inline; border-width: 0px;" title="clip_image001[20]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image00120_thumb.png" border="0" alt="clip_image001[20]" width="275" height="158" /></a></p><p>我们会看到一个巨大的白屏！</p><p>Silverlight生成的动态内容根本没有显示。事实上，要显示这些动态内容，必须得执行Silverlight代码。但我敢肯定，搜索引擎在任何时候都不会在他们的数据中心上去执行我们的Silverlight（或者Flash或者Ajax）代码的。所以我们需要的是一些备选的内容。</p><p>幸运的是，要做到这一点非常简单。首先让所有备选的内容展示出来。需要特别注意的是，这些内容并不单单是给搜索引擎看。制作只给搜索引擎看的内容是“糊弄搜索引擎”，或者是垃圾网页。这些内容通常用来迷惑搜索引擎，掩盖网站的真实内容（<a href="http://www.bing.com/community/blogs/webmaster/archive/2010/02/11/the-pernicious-perfidy-of-page-level-web-spam-sem-101.aspx">the pernicious perfidy of page-level web spam</a>) 。而这里的备选内容是给那些没有安装Silverlight插件的用户看的。它可能不拥有所有Silverlight的特性，但却提供了一个降级的用户体验。当搜索引擎蜘蛛没有安装Silverlight插件的时候也是如此，这可以保证它们能够索引到一些有意义而且准确的信息。</p><p>把下面这段HTML代码添加到default.aspx页面中。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">id</span><span class="kwrd">="AlternativeContent"</span> <span class="attr">style</span><span class="kwrd">="display: none;"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">h2</span><span class="kwrd">&gt;</span>Hi, this is my alternative content<span class="kwrd">&lt;/</span><span class="html">h2</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre><p>注意，这里写的是display:none，意味着我们并不期望浏览器去渲染这段内容...除非Silverlight插件不可用。为了实现这个效果，把下面这小段JS代码添加到页面中：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">="text/javascript"</span><span class="kwrd">&gt;</span>
<span class="kwrd">if</span> (!isSilverlightInstalled()) {
<span class="kwrd">var</span> obj = document.getElementById(<span class="str">'AlternativeContent'</span>);
obj.style.display = <span class="str">""</span>;
}
<span class="kwrd">&lt;/</span><span class="html">script</span><span class="kwrd">&gt;</span></pre><p>注意，这个很方便的isSilverlightInsalled函数是从Petr的<a href="http://blogs.msdn.com/piotrp/archive/2008/05/07/determining-if-silverlight-is-installed-using-javascript.aspx">old-but-good post on the subject</a>文章中找到的。我只是把这个函数添加到我的Silverlight.js文件而已。</p><pre class="csharpcode"><span class="kwrd">function</span> isSilverlightInstalled() {
    <span class="kwrd">var</span> isSilverlightInstalled = <span class="kwrd">false</span>;
    <span class="kwrd">try</span> {
        <span class="rem">//check on IE</span>
        <span class="kwrd">try</span> {
            <span class="kwrd">var</span> slControl = <span class="kwrd">new</span> ActiveXObject(<span class="str">'AgControl.AgControl'</span>);
            isSilverlightInstalled = <span class="kwrd">true</span>;
        }
        <span class="kwrd">catch</span> (e) {
            <span class="rem">//either not installed or not IE. Check Firefox</span>
            <span class="kwrd">if</span> (navigator.plugins[<span class="str">"Silverlight Plug-In"</span>]) {
                isSilverlightInstalled = <span class="kwrd">true</span>;
            }
        }
    }
    <span class="kwrd">catch</span> (e) {
        <span class="rem">//we don't want to leak exceptions. However, you may </span>
        <span class="rem">//to add exception tracking code here</span>
    }
    <span class="kwrd">return</span> isSilverlightInstalled;
}</pre><p>当我们使用一个没有启用Silverlight插件的浏览器中去浏览此页面的时候，我们就会看到备选的内容：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0025.png"><img style="display: inline; border-width: 0px;" title="clip_image002[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0025_thumb.png" border="0" alt="clip_image002[5]" width="244" height="134" /></a></p><p>但是如果安装了Silverlight，我们则会看到漂亮的Silverlight应用程序内容：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0035.png"><img style="display: inline; border-width: 0px;" title="clip_image003[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0035_thumb.png" border="0" alt="clip_image003[5]" width="244" height="184" /></a></p><p>这很不错，但我们怎么让页面显示正确的内容呢？我们想要展示和Silverlight应用程序完全一致的数据，而且又不想写太多代码。我们也实在不想去维护太多页面。所以让我们在页面的AlternativeContent这个DIV里头加入一些基本的代码。这个ListView是用来显示餐馆详细信息的。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">asp:ListView</span> <span class="attr">ID</span><span class="kwrd">="RestaurnatDetails"</span> <span class="attr">runat</span><span class="kwrd">="server"</span>
                <span class="attr">EnableViewState</span><span class="kwrd">="false"</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">LayoutTemplate</span><span class="kwrd">&gt;</span>
       <span class="kwrd">&lt;</span><span class="html">asp:PlaceHolder</span> <span class="attr">ID</span><span class="kwrd">="ItemPlaceHolder"</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">/&gt;</span>
   <span class="kwrd">&lt;/</span><span class="html">LayoutTemplate</span><span class="kwrd">&gt;</span>
   <span class="kwrd">&lt;</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
       <span class="kwrd">&lt;</span><span class="html">asp:DynamicEntity</span> <span class="attr">ID</span><span class="kwrd">="RestaurnatEntity"</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">/&gt;</span>
   <span class="kwrd">&lt;/</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">asp:ListView</span><span class="kwrd">&gt;</span></pre><p>现在我们需要把它和我们的数据源绑定...我发现在VS的设计视图里头很容易就能够做到这一点。注意，要在设计器中编辑这个DIV，你需要将DIV改成可见模式。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0045.png"><img style="display: inline; border-width: 0px;" title="clip_image004[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0045_thumb.png" border="0" alt="clip_image004[5]" width="244" height="130" /></a></p><p>然后我们来配置一下数据源：</p><p><a href="http://blogs.msdn.com/blogfiles/brada/WindowsLiveWriter/Silverlight4RIAServicesReadyforBusinessS_C533/image70.png"><img style="display: inline; border-width: 0px;" title="clip_image005[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0055.png" border="0" alt="clip_image005[5]" width="270" height="212" /></a></p><p>下一步，我们需要基于我们之前定义的导航路径来绑定查询参数。</p><p><a href="http://blogs.msdn.com/blogfiles/brada/WindowsLiveWriter/Silverlight4RIAServicesReadyforBusinessS_C533/image_74.png"><img style="display: inline; border-width: 0px;" title="clip_image006[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0065.png" border="0" alt="clip_image006[5]" width="275" height="192" /></a></p><p>然后，我们对美食的ListView控件也重复同样的操作...</p><p>现在我们得到的代码非常简单:</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">asp:ListView</span> <span class="attr">ID</span><span class="kwrd">="RestaurnatDetails"</span> <span class="attr">runat</span><span class="kwrd">="server"</span>
         <span class="attr">EnableViewState</span><span class="kwrd">="false"</span> <span class="attr">DataSourceID</span><span class="kwrd">="restaurantsDomainDataSource"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">LayoutTemplate</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">asp:PlaceHolder</span> <span class="attr">ID</span><span class="kwrd">="ItemPlaceHolder"</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">LayoutTemplate</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
     <span class="kwrd">&lt;</span><span class="html">asp:DynamicEntity</span> <span class="attr">ID</span><span class="kwrd">="RestaurnatEntity"</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">asp:ListView</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">asp:DomainDataSource</span> <span class="attr">ID</span><span class="kwrd">="restaurantsDomainDataSource"</span> <span class="attr">runat</span><span class="kwrd">="server"</span>
               <span class="attr">DomainServiceTypeName</span><span class="kwrd">="MyApp.Web.DishViewDomainService"</span>
               <span class="attr">QueryName</span><span class="kwrd">="GetRestaurant"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">QueryParameters</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">asp:RouteParameter</span> <span class="attr">name</span><span class="kwrd">="id"</span> <span class="attr">RouteKey</span><span class="kwrd">="restaurantId"</span>
                   <span class="attr">DefaultValue</span> <span class="kwrd">="-1"</span> <span class="attr">Type</span> = <span class="kwrd">"Int32"</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">QueryParameters</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">asp:DomainDataSource</span><span class="kwrd">&gt;</span></pre><p>下一步，我们需要让这些控件基于数据动态生成UI。</p><pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">void</span> Page_Init(<span class="kwrd">object</span> sender, EventArgs e)
{
 RestaurnatDetails.EnableDynamicData(<span class="kwrd">typeof</span>(MyApp.Web.Restaurant));
 PlateDetails.EnableDynamicData(<span class="kwrd">typeof</span>(MyApp.Web.Plate));
 <span class="kwrd">string</span> resId = Page.RouteData.Values[<span class="str">"restaurant"</span>] <span class="kwrd">as</span> <span class="kwrd">string</span>;
 <span class="kwrd">if</span> (resId != <span class="kwrd">null</span>) { Response.Write(<span class="str">"&lt;script type=text/javascript&gt;window.location.hash='#/Plates';&lt;/script"</span>+<span class="str">"&gt;"</span>); }
}</pre><p>注意到，我们在第4-5行处为这两个ListView控件启用了动态数据。</p><p>最后一步，我们需要添加DynamicData需要用到的模板集。你可以从任何DynamicData的工程中获得相应的文件。将其拷贝到Web工程根目录下。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0075.png"><img style="display: inline; border-width: 0px;" title="clip_image007[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0075_thumb.png" border="0" alt="clip_image007[5]" width="165" height="212" /></a></p><p>你可以通过编辑这些模板来控制数据的显示。</p><p>在EntityTemplates目录中，我们需要为每个实体创建一个实体模板（在这个例子中，有美食和餐馆这两个实体）。这会决定他们是如何显示的。</p><pre class="csharpcode"><span class="asp">&lt;%@ Control Language="C#" CodeBehind="Restaurant.ascx.cs" Inherits="MyApp.Web.RestaurantEntityTemplate" %&gt;</span>

<span class="kwrd">&lt;</span><span class="html">asp:DynamicControl</span>  <span class="attr">ID</span><span class="kwrd">="DynamicControl8"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="ImagePath"</span> <span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;</span><span class="html">ul</span> <span class="attr">class</span><span class="kwrd">="restaurant"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">ul</span> <span class="attr">class</span><span class="kwrd">="restaurantDetails"</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">h2</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="NameControl"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="Name"</span> <span class="kwrd">/&gt;</span> <span class="kwrd">&lt;/</span><span class="html">h2</span><span class="kwrd">&gt;</span> <span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl1"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="ContactName"</span> <span class="kwrd">/&gt;</span> (<span class="kwrd">&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl2"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="ContactTitle"</span> <span class="kwrd">/&gt;</span>)<span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl3"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="Address"</span> <span class="kwrd">/&gt;</span>  <span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl4"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="City"</span> <span class="kwrd">/&gt;</span>, <span class="kwrd">&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl5"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="Region"</span> <span class="kwrd">/&gt;</span>  <span class="kwrd">&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl6"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="PostalCode"</span> <span class="kwrd">/&gt;</span>  <span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:DynamicControl</span> <span class="attr">ID</span><span class="kwrd">="DynamicControl7"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">DataField</span><span class="kwrd">="Phone"</span> <span class="kwrd">/&gt;</span>  <span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">asp:HyperLink</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">ID</span><span class="kwrd">="link"</span>  <span class="attr">NavigateUrl</span><span class="kwrd">="&lt;%#GetDetailsUrl() %&gt;"</span> <span class="attr">Text</span><span class="kwrd">="details.."</span><span class="kwrd">&gt;&lt;/</span><span class="html">asp:HyperLink</span><span class="kwrd">&gt;&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;/</span><span class="html">ul</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">ul</span><span class="kwrd">&gt;</span></pre><p>这里我们只是做了些简单的格式化操作，然后把我们需要在备选内容中显示的字段挑选出来。对美食实体也重复同样的操作…</p><p>现在我们已经可以准备运行了。</p><p>访问根目录，在没有添加任何Url参数的情况下，我们会看到一个餐馆列表，当然，全都是HTML代码。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0085.png"><img style="display: inline; border-width: 0px;" title="clip_image008[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0085_thumb.png" border="0" alt="clip_image008[5]" width="275" height="191" /></a></p><p>接着我们可以添加一个导航来定位某个特定餐馆的所有美食。</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0095.png"><img style="display: inline; border-width: 0px;" title="clip_image009[5]" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image0095_thumb.png" border="0" alt="clip_image009[5]" width="249" height="212" /></a></p><p>但是，让我们在真正的浏览器中浏览此页面，确保我们看到的和搜索引擎看到的是一样的。</p><p>Lynx还活着！Lynx是我92年在北卡罗来纳州州立大学Leazar实验室的DEC2100机器上用过的第一个浏览器...现在还可以正常工作！</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image010.png"><img style="display: inline; border-width: 0px;" title="clip_image010" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image010_thumb.png" border="0" alt="clip_image010" width="275" height="184" /></a></p><p>还有细节信息：</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image011.png"><img style="display: inline; border-width: 0px;" title="clip_image011" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image011_thumb.png" border="0" alt="clip_image011" width="275" height="184" /></a></p><p>这款经典的文本浏览器让我们看到了纯文本模式下页面的样子，这恰恰是搜索引擎蜘蛛所看到的。</p><p>现在，来看真正的测试。</p><p>我们使用Bing去搜索“我的美食浏览器——和Joe学烹饪”，显然，这个页面确实在那。</p><p><a href="http://blogs.msdn.com/blogfiles/brada/WindowsLiveWriter/Silverlight4RIAServicesReadyforBusinessS_C533/image_56.png"><img style="display: inline; border-width: 0px;" title="clip_image012" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image012.png" border="0" alt="clip_image012" width="275" height="185" /></a></p><p>点击这个链接？</p><p>浏览器导航到的页面正是我们期望的页面。</p><p><a href="http://blogs.msdn.com/blogfiles/brada/WindowsLiveWriter/Silverlight4RIAServicesReadyforBusinessS_C533/image_58.png"><img style="display: inline; border-width: 0px;" title="clip_image013" src="http://www.imkevinyang.com/wp-content/uploads/2010/05/clip_image013.png" border="0" alt="clip_image013" width="275" height="191" /></a></p><p>当然，这在另外一个<a href="http://www.google.com/#hl=en&amp;source=hp&amp;q=my+foodie+Explorer+Cooking+Class+with+Joe..&amp;btnG=Google+Search&amp;aq=f&amp;aqi=&amp;aql=&amp;oq=my+foodie+Explorer+Cooking+Class+with+Joe..&amp;fp=f55f94328208dcc1" target="_blank">搜索引擎</a>来说也是一样的... 如果你刚好是另外这个搜索引擎的用户:-)</p><h2>总结</h2><p>在上面这个例子中，我们学习了如何创建一个SEO优化过的、以数据驱动的Silverlight应用程序的基本操作。总共分为三个步骤：</p><ul><li>步骤1：做好重要的页面的深层链接</li><li>步骤2：使用网站地图(Sitemap)让搜索引擎知道你网站的所有深层链接</li><li>步骤3：对于重要内容，提供一个备选版本</li></ul><p>希望你们喜欢~</p><p>更多信息，请参考:  <a href="http://www.bing.com/community/blogs/webmaster/archive/2010/03/05/illuminating-the-path-to-seo-for-silverlight.aspx">点亮Silverlight的SEO之路</a>。</p>标签：<a href="http://www.imkevinyang.com/tags/ria" title="RIA" rel="tag">RIA</a>, <a href="http://www.imkevinyang.com/tags/seo" title="SEO" rel="tag">SEO</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight-seo" title="Silverlight SEO" rel="tag">Silverlight SEO</a>, <a href="http://www.imkevinyang.com/tags/sitemap" title="Sitemap" rel="tag">Sitemap</a>, <a href="http://www.imkevinyang.com/tags/%e4%bc%98%e5%8c%96" title="优化" rel="tag">优化</a>, <a href="http://www.imkevinyang.com/tags/%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e" title="搜索引擎" rel="tag">搜索引擎</a>, <a href="http://www.imkevinyang.com/tags/%e6%b7%b1%e5%b1%82%e9%93%be%e6%8e%a5" title="深层链接" rel="tag">深层链接</a>, <a href="http://www.imkevinyang.com/tags/%e7%bd%91%e7%ab%99%e5%9c%b0%e5%9b%be" title="网站地图" rel="tag">网站地图</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/05/2009%e5%b9%b4%e7%ac%ac%e4%b8%80%e5%ad%a3%e5%ba%a6%e4%b8%ad%e5%9b%bd%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e5%b8%82%e5%9c%ba%e8%90%a5%e6%94%b6%e4%bb%bd%e9%a2%9d.html" title="2009年第一季度中国搜索引擎市场营收份额 (2009/05/06)">2009年第一季度中国搜索引擎市场营收份额</a> (2009/05/06)</li><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/03/google%e5%b7%a5%e7%a8%8b%e5%b8%88matt-cutts%e8%b0%88seo.html" title="Google工程师Matt Cutts谈SEO (2009/03/23)">Google工程师Matt Cutts谈SEO</a> (2009/03/23)</li><li><a href="http://www.imkevinyang.com/2009/05/robotstxt%e6%96%87%e4%bb%b6.html" title="Robots.txt文件 (2009/05/06)">Robots.txt文件</a> (2009/05/06)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Silverlight的依赖属性与附加属性</title><link>http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html</link> <comments>http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html#comments</comments> <pubDate>Sun, 28 Mar 2010 13:42:59 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[AttachedProperty]]></category> <category><![CDATA[CLR属性]]></category> <category><![CDATA[DependancyProperty]]></category> <category><![CDATA[依赖属性]]></category> <category><![CDATA[值变更]]></category> <category><![CDATA[寻值]]></category> <category><![CDATA[附加属性]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html</guid> <description><![CDATA[<p>好久没写Silverlight了，依赖属性（Dependency Property）和附加属性（Attached Property）这两个算是很基础的知识都不是很记得了。写一写，当做一下笔记吧。</p><h2>CLR属性 与 依赖属性</h2><p>CLR属性我们非常熟悉了，在DotNet编程中随处可见。最简单最常见的属性访问器就是直接操纵类的私有成员，如下：</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Person
{
    <span class="kwrd">private</span> String _name;
    <span class="kwrd">public</span> <span class="kwrd">string</span> Name
    {
        get { <span class="kwrd">r&#8230;</span></pre>]]></description> <content:encoded><![CDATA[<p>好久没写Silverlight了，依赖属性（Dependency Property）和附加属性（Attached Property）这两个算是很基础的知识都不是很记得了。写一写，当做一下笔记吧。</p><h2>CLR属性 与 依赖属性</h2><p>CLR属性我们非常熟悉了，在DotNet编程中随处可见。最简单最常见的属性访问器就是直接操纵类的私有成员，如下：</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Person
{
    <span class="kwrd">private</span> String _name;
    <span class="kwrd">public</span> <span class="kwrd">string</span> Name
    {
        get { <span class="kwrd">return</span> _name; }
        set { _name = <span class="kwrd">value</span>; }
    }
}</pre><p>C#3.0对这种常见的写法提供了“自动属性”这一特性，方便了偶等这些懒惰的码农。</p><pre class="csharpcode">

<span class="kwrd">public</span> <span class="kwrd">class</span> Person
{
    <span class="kwrd">public</span> <span class="kwrd">string</span> Name { get; set; }
}
</pre><p>这两种写法是等价的，都是<strong><font color="#008000">需要设立一个实例级的私有变量作为属性访问器的持久存储</font></strong>。这对于我们非UI应用来说没什么。因为第一，我们一般不会创建太多类实例；第二，一个类的属性通常不会很多，加几个私有变量不会增加系统负担。但是这两个理由对于UI应用程序来说恰恰不成立。</p><p>在很多UI应用中，我们经常会创建很多类实例，成千上万个实例在UI系统中是很普遍的事情。同时，UI类通常会包含大量的属性供设计人员使用，例如背景颜色，前景颜色，字体，边距等等，这些属性在绝大多数情况下会保持默认值，如果为每个实例都建立这么多的私有变量来存储UI属性的值，势必会造成极大的浪费，对系统负担的开销也是不小。</p><p>鉴于以上提到的问题，设计一个高效的属性存储系统对于UI应用程序的开发是非常重要的。因此Silverlight引入了“依赖属性（DependencyProperty）”。</p><h3>采用键值对替代成员变量作为属性内部存储</h3><p>传统CLR属性，一个属性对应一个私有变量，UI元素的属性那么多，创建过多的私有变量不是一件简单的事情，况且大多数属性只会用到默认值。因此Silverlight在每个类实例中使用一个字典型的成员变量来存放那些用户显式设置的属性（称为Local Value本地值），没有设置的属性就不存。那属性的默认值存放在哪？既然各个实例的默认值都一样（不然也不叫默认值了），那么直接存放到静态成员变量（<span style="background-color: yellow">依赖属性的静态成员变量，而不是注册依赖属性的类的成员变量</span>）上就行了。这也就大大提高了存储的效率。</p><p>在实现上，Silverlight中所有的UI元素都继承自DependencyObject，这个类封装了对依赖属性的存储以及访问等操作。</p><h3>注册依赖属性</h3><p>既然依赖属性采用键值对这样的哈希结构进行存储，那么要获取不同属性的值，我们就必须使用不同的哈希键，否则就会读取到其他属性的值了。因此，当我们在向Silverlight属性系统注册依赖属性的时候，Silverlight会返回一个唯一的属性标识对象，类型为DependencyProperty。我们以后就通过这个唯一标识对象去访问依赖属性的值。</p><p>由于这个唯一标识符是所有类实例都公用并且不会被修改的，因此我们通常将其保存到一个static readonly的成员变量中。</p><p>DependencyProperty类提供了两个方法，一个是Register方法，用于注册依赖属性；另外一个是RegisterAttached，用于注册附加属性，这个后面再讲。</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> DependencyProperty Register(
    <span class="kwrd">string</span> name,
    Type propertyType,
    Type ownerType,
    PropertyMetadata typeMetadata
)</pre></p><p>Register方法的签名由几部分组成，Name参数指明了依赖属性使用的名称，这个名字很重要，<strong><font color="#008000">在定义控件Style和Template的时候，Setter的Property属性填入的值就是注册依赖属性时使用的名称</font></strong>；propertyType指明了依赖属性实际的类型，ownerType指明了是哪个类注册了此依赖属性，最后typeMetadata存放了一些依赖属性的元信息，包括依赖属性使用的默认值，还有属性值发生变更时的通知函数。</p><h3><strong><font color="#2c68a3" size="3">属性的存取</font></strong></h3><p>和CLR属性不同，依赖属性不是直接对私有变量的操纵，而是通过GetValue和SetValue的方法来操作属性值的。</p><p>&#160;</p><p>下面的代码演示了为Ball控件设置一个Center的依赖属性，并且在程序中读取和修改此属性的过程：</p><pre class="csharpcode">

<span class="kwrd">public</span> <span class="kwrd">class</span> Ball : Control
{
    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> DependencyProperty CenterProperty =
        DependencyProperty.Register(<span class="str">&quot;Center&quot;</span>, <span class="kwrd">typeof</span>(Point), <span class="kwrd">typeof</span>(Ball), <span class="kwrd">null</span>);
}

<span class="kwrd">public</span> <span class="kwrd">class</span> BallApp
{
    <span class="kwrd">public</span> <span class="kwrd">void</span> RollBall(Ball ball)
    {
        Point curCenter = (Point)ball.GetValue(Ball.CenterProperty);
        curCenter.X++;

        // 注意对值类型对象操作完毕之后一定要调用SetValue修改才能生效
        ball.SetValue(Ball.CenterProperty, curCenter);
    }
}
</pre><p>由于上述对依赖属性的操作经常需要涉及到类型的转换，比较麻烦，而传统CLR属性用起来和直接操纵普通变量一样方便，因此通常在设计依赖属性的时候，都会使用CLR属性将其包装起来，我们称之为增强型的CLR属性。</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Ball : Control
{
    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> DependencyProperty CenterProperty =
        DependencyProperty.Register(<span class="str">&quot;Center&quot;</span>, <span class="kwrd">typeof</span>(Point), <span class="kwrd">typeof</span>(Ball), <span class="kwrd">null</span>);

    <span class="kwrd">public</span> Point Center
    {
        get { <span class="kwrd">return</span> (Point)GetValue(CenterProperty); }
        set { SetValue(CenterProperty, <span class="kwrd">value</span>); }
    }
}</pre><p>按照约定，依赖属性的名称通常是相应CLR属性名称后面加上个“Property”字符串。</p><p>事实上，使用CLR包装依赖属性并不只是为了方便（<a title="http://msdn.microsoft.com/en-us/library/cc221408%28VS.95%29.aspx#back_dependency_properties" href="http://msdn.microsoft.com/en-us/library/cc221408%28VS.95%29.aspx#back_dependency_properties">http://msdn.microsoft.com/en-us/library/cc221408%28VS.95%29.aspx#back_dependency_properties</a>），很多依赖于CLR属性作为基础的工具或者子系统并不能直接访问依赖属性，而只能通过CLR属性去间接访问依赖属性。例如上面的例子中，假设我们并没有设置一个Center的CLR属性，那么以下的Xaml将会编译失败，因为Xaml解析器无法知道Ball类有一个Center的依赖属性（在Style中设置Center属性值就可以编译成功，因为Style是动态查找属性的）。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Ball</span> <span class="attr">Center</span><span class="kwrd">=&quot;2&quot;</span> <span class="kwrd">/&gt;</span></pre><h2>依赖属性的寻值逻辑和值变更通知</h2><p>上面提到的只是依赖属性相比CLR属性在存储效率的不同，实际上，依赖属性还有其他实用的特性。</p><h3>寻值逻辑</h3><p>CLR属性在获取值的时候是直接读取成员变量值返回的，而依赖属性在使用的时候是通过GetValue函数的调用来获取属性的值。实际上，GetValue内部做的事情可不止是简单的读取字典里头存放的值。他还有寻值逻辑。如下图所示：</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="依赖属性GetValue寻值逻辑" border="0" alt="依赖属性GetValue寻值逻辑" src="http://www.imkevinyang.com/wp-content/uploads/2010/03/image2.png" width="373" height="224" /></p><p>当你调用GetValue去读取一个依赖属性的值的时候，Silverlight的属性系统会首先从动画系统中查找当前是否有作用在此依赖属性上的动画，如果有，则返回此动画值。从这里也可以看出，依赖属性是Silverlight实现动画机制的基础。<span style="background-color: yellow">注意，如果动画已经停止了，并且没有设置FillBehavior=HoldEnd的话，那么Silverlight就不会返回此动画值。</span></p><p><span style="background-color: yellow"></span></p><p>如果读不到动画值，那么Silverlight就会尝试读取本地值。本地值有几种类型，一种是用户通过代码或者Xaml直接设定的值。一种是通过资源绑定得到的值，最后一种是通过数据绑定得到的值。这些都被视为本地值。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">StackPanel</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">StackPanel.Resources</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">System:String</span> <span class="attr">x:Key</span><span class="kwrd">=&quot;TextBlockResource&quot;</span><span class="kwrd">&gt;</span>资源数据绑定文本<span class="kwrd">&lt;/</span><span class="html">System:String</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">StackPanel.Resources</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">=&quot;{Binding Source={StaticResource TextBlockResource}}&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;DataBindingElement&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;{Binding ElementName}&quot;</span> <span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre><p>如果还是读取不到，那么就继续尝试读取控件模板和样式中设置的值。</p><p>如果所有这些值都读取失败，那么Silverlight属性系统就会返回该依赖属性的默认值。当我们注册依赖属性的时候，可以传入一个PropertyMetaData对象，这个对象包含了此依赖属性的默认值和值变更通知回调函数。如果注册的时候没有传入默认值，则对于引用类型的依赖属性，返回null，对于字符串，返回String.Empty，对于值类型，则返回一个以默认值初始化的实例。</p><p><span style="background-color: yellow">这里需要对集合类型特别注意，由于通过PropertyMetaData传入的默认值是所有类实例共享的，因此，一定要在类构造函数中显式传入集合的实例</span>。</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> GameRoom : Control
{
    <span class="kwrd">public</span> List&lt;Ball&gt; Balls
    {
        get { <span class="kwrd">return</span> (List&lt;Ball&gt;)GetValue(BallsProperty); }
        set { SetValue(BallsProperty, <span class="kwrd">value</span>); }
    }

    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> DependencyProperty BallsProperty =
        DependencyProperty.Register(<span class="str">&quot;Balls&quot;</span>, <span class="kwrd">typeof</span>(List&lt;Ball&gt;), <span class="kwrd">typeof</span>(GameRoom), <span class="kwrd">null</span>);

    <span class="kwrd">public</span> GameRoom()
    {
        Balls = <span class="kwrd">new</span> List&lt;Ball&gt;();
    }
}</pre><p>可能正是因为Silverlight的依赖属性在获取值的时候需要从多个地方去读取值，而不是像CLR属性一样，直接从成员变量中读取值，所以才被称之为“依赖”属性吧。</p><h3>值变更通知</h3><p>属性值的变更通知我们并不陌生。我们在DotNet中实现的时候，一般是让类实现INotifyPropertyChanged接口。在UI系统中，值变更通知是经常需要用到的。数据源一旦变更，所有相应的UI元素的值都要相应的做出调整。Silverlight的依赖属性对此有内置的支持。只要你在绑定时使用依赖属性，那么当依赖属性值发生变更的时候，所有绑定的地方的值都会同步更新。而且，依赖属性也提供了一个值变更通知函数（在注册依赖属性时通过PropertyMetaData传入），你可以自定义一个函数来控制值变更时需要执行的操作。</p><pre class="csharpcode">

<span class="kwrd"></span>&#160;

<span class="kwrd">public</span> <span class="kwrd">class</span> Ball : Control
{
    <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> DependencyProperty CenterProperty =
        DependencyProperty.Register(<span class="str">&quot;Center&quot;</span>, <span class="kwrd">typeof</span>(Point), <span class="kwrd">typeof</span>(Ball), <span class="kwrd">new</span> PropertyMetadata(OnCenterChanged));

    <span class="kwrd">public</span> Point Center
    {
        get { <span class="kwrd">return</span> (Point)GetValue(CenterProperty); }
        set { SetValue(CenterProperty, <span class="kwrd">value</span>); }
    }

    <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> OnCenterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Ball ball = d <span class="kwrd">as</span> Ball;
        <span class="rem">// 获取新的球心</span>
        Point newCenter = (Point)e.NewValue;
        <span class="rem">// ...</span>
    }
}
</pre><h2>Silverlight的附加属性（Attached Property）——全局的依赖属性</h2><p>刚才提到的依赖属性和CLR属性一样都是服务于某一个类的。只不过将属性改造得存储上更有效率，使用上更加强大。在Silverlight中还有一种特殊的依赖属性，这种依赖属性并不只是服务于某个特定的类，而是服务于全局，这就是附加属性。从名字上也可以看出来，附加属性是在某个类里面注册，然后可以被其他类所使用。</p><p>什么情况下需要使用附加属性呢？举Canvas类的ZIndex属性作为例子。</p><p>容器类在叠加子控件的时候，需要考虑哪个控件放置在最上面，那个放在下面。</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/03/image3.png" width="202" height="203" /></p><p>那么容器类怎么知道子控件的叠放顺序呢？最不动脑子的设计就是为所有的控件都添加一个ZIndex的属性，属性的值代表叠放的顺序。但这样的后果就是，如果我这个控件不参与布局，那多这个属性就会显得很浪费。所以比较理想的设计是，需要用到这个属性的时候就有这个属性，不需要的时候就没有这个属性的负担。附加属性的出现就是为了解决这样的问题。一旦控件需要某个属性的时候，我们可以把这个属性附加到这个控件类上。</p><p>注册附加属性和依赖属性差不多，只不过函数名为RegisterAttached。这个就不多说了。</p><h2>什么时候应该用到依赖属性</h2><p>既然依赖属性那么高效，而且那么强大，那么我们是不是应该保持使用依赖属性的习惯呢？事实上，任何好处都是有代价的。Silverlight的依赖属性在访问效率上并不如直接访问成员变量那么高效。因此，对于那些比较简单而访问频率又非常高的属性，建议还是使用传统的CLR属性去实现。</p><p>&#160;</p><p>暂时想到这么多了，以后有新的认识再补充补充。</p><p style="text-align: right">——<a title="Silverlight的依赖属性与附加属性" href="http://www.imkevinyang.com/2010/03/Silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/tags/attachedproperty" title="AttachedProperty" rel="tag">AttachedProperty</a>, <a href="http://www.imkevinyang.com/tags/clr%e5%b1%9e%e6%80%a7" title="CLR属性" rel="tag">CLR属性</a>, <a href="http://www.imkevinyang.com/tags/dependancyproperty" title="DependancyProperty" rel="tag">DependancyProperty</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7" title="依赖属性" rel="tag">依赖属性</a>, <a href="http://www.imkevinyang.com/tags/%e5%80%bc%e5%8f%98%e6%9b%b4" title="值变更" rel="tag">值变更</a>, <a href="http://www.imkevinyang.com/tags/%e5%af%bb%e5%80%bc" title="寻值" rel="tag">寻值</a>, <a href="http://www.imkevinyang.com/tags/%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7" title="附加属性" rel="tag">附加属性</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html" title="图片等资源的引用路径问题 (2009/03/19)">图片等资源的引用路径问题</a> (2009/03/19)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%9c%a8xaml%e4%b8%ad%e8%be%93%e5%85%a5%e5%b0%96%e6%8b%ac%e5%8f%b7%e6%96%87%e6%9c%ac.html" title="在Xaml中输入尖括号文本 (2009/02/28)">在Xaml中输入尖括号文本</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%b0%86silverlight%e6%90%ac%e5%88%b0%e6%a1%8c%e9%9d%a2.html" title="将Silverlight搬到桌面 (2009/02/28)">将Silverlight搬到桌面</a> (2009/02/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html/feed</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Silverlight启用Assembly Caching之后铁通用户无法访问</title><link>http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html</link> <comments>http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html#comments</comments> <pubDate>Sat, 13 Feb 2010 05:24:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[Assembly Caching]]></category> <category><![CDATA[HTTP]]></category> <category><![CDATA[HTTP Watch]]></category> <category><![CDATA[跨域]]></category> <category><![CDATA[重定向]]></category> <category><![CDATA[铁通]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html</guid> <description><![CDATA[<p>去年年底的时候，有客户向我们公司反映，他在自己公司内网（铁通ADSL）无法访问我们的Silverlight应用程序，而在他家里（网通ADSL）就可以正常访问。我们其他的客户并没有反映过类似的问题。</p><h2>问题分析排查</h2><p>由于他用的是笔记本，在家里和在公司访问时的系统环境是一样的，这样也就排除了系统环境的原因。那只能怀疑是网络环境的问题了。后来在现场使用HTTP Watch调试发现，当Silverlight在下载其中几个缓存程序集的zip包（我们的Si&#8230;</p>]]></description> <content:encoded><![CDATA[<p>去年年底的时候，有客户向我们公司反映，他在自己公司内网（铁通ADSL）无法访问我们的Silverlight应用程序，而在他家里（网通ADSL）就可以正常访问。我们其他的客户并没有反映过类似的问题。</p><h2>问题分析排查</h2><p>由于他用的是笔记本，在家里和在公司访问时的系统环境是一样的，这样也就排除了系统环境的原因。那只能怀疑是网络环境的问题了。后来在现场使用HTTP Watch调试发现，当Silverlight在下载其中几个缓存程序集的zip包（我们的Silverlight应用程序启用了Assembly Caching）时，HTTP请求被302永久重定向到一个奇怪的IP上。</p><p><img style="display: inline; border-width: 0px;" title="Silverlight启用Assembly Caching之后铁通用户无法访问" src="http://www.imkevinyang.com/wp-content/uploads/2010/02/image.png" border="0" alt="Silverlight启用Assembly Caching之后铁通用户无法访问" width="564" height="148" /></p><p>这样，由于zip包和Xap包地址的主机域不同，构成跨域，Silverlight会要求zip包所在的网站提供clientaccesspolicy.xml或者crossdomain.xml文件。而那个奇怪的IP所在网站下根本就没有这两个文件，所以请求失败。进而导致整个程序挂掉。</p><h2>Assembly Caching程序集缓存</h2><p>Assembly Caching（又称Application Library Caching）是Silverlight 3的新特性。以前Silverlight都是将所有用到的dll放到一个xap包之中，这样整个xap包会很大，下载相对比较慢。启用Assembly Caching之后，Silverlight工程用到的dll就可以在编译的时候自动打包到各自的zip包中，然后Silverlight在加载Xap包之后会自动下载这些zip包并解压出里头的dll，然后加载到应用程序域中。这样一来可以大大提高程序集下载的并行度，同时也可以使到不同Silverlight程序之间可以利用浏览器缓存而无需重复下载。</p><p>Silverlight在加载Xap包之后会去读取xap包中的appmanifest.xaml文件，然后下载该文件中指定的程序集文件。如果程序集文件Url和当前Xap包Url构造跨域（参考Silverlight SDK文档），则Silverlight会向该程序集所在网站的根目录请求跨域策略文件。</p><h2>为什么会被重定向</h2><p>这个问题困扰了我们很久。当时我们的第一反应是怀疑网关设置了什么规则。当用户访问特定Url的时候，触发了这个规则，导致HTTP请求被挟持。但是和客户公司网管沟通之后，对方明确表示并没有设置过类似的规则。</p><p>直到最近，客户和电信通（率属铁通）的人沟通之后，那边的技术人员说这是由于铁通的缓存加速服务器造成。据说是铁通为了让用户下载更快，就将某些HTTP请求进行重定向。后来电信通的技术人员告诉客户他们已经没问题了，但是他们并没有告知详细的问题所在，到底是由于我们的HTTP请求碰巧符合特定规则，还是怎么回事。也不知道他们是怎么解决的，是只将客户公司的IP列入禁止缓存列表，还是将我们Silverlight应用程序使用的域名加入禁止缓存列表，我们都无从知道。对于我们来说，这并没有真正解决问题。如果将来其他客户也通过铁通访问我们的产品，那么可能还是会出现类似的问题。由于我家里也是铁通的网络，所以我决定自己研究一下到底是怎么回事。</p><p>由于铁通那边没有任何可用的技术信息，Google也没有找到有价值的信息，唯一猜测的就是HTTP请求可能符合特定规则然后就被无辜重定向了。因此我只能采用最原始的人肉测试了。尝试不断的调整出问题的Url然后看是否被重定向了来发现规律。修改zip包所在目录，修改zip包文件名，修改zip包后缀，修改IIS的MIME类型，测试不同域名，等等。在历经100多次尝试之后，终于发现了<strong><span style="color: #008000;">当文件大小超过40K左右，并且后缀名是zip或者rar等常见的下载文件后缀，就会被铁通重定向。而且有时候第一、二次不会被重定向，刷新多几次的时候就才会被重定向</span></strong>。后面一点让我走了不少弯路，多少次我以为找到规律了，最后验证结论的时候还是错了。</p><p>o(︶︿︶)o</p><h2>怎么解决</h2><p>知道具体问题所在之后，我们几个技术人员就开始讨论如何解决这个问题。由于Silverlight对于缓存程序集打包之后的文件后缀没有要求，不管什么后缀，都会以zip文件流的格式去解析。因此可以修改打包文件的后缀来“逃过”铁通的魔掌。</p><p>修改文件后缀也有两种方法。</p><p>一种是在部署的时候，通过自动化脚本，修改所有zip文件后缀，然后修改xap包中appmanifest.xaml里头程序集的Url。这种方式的好处是一劳永逸，通用性强，以后部署的时候只需要执行一次脚本即可，其他应用程序可以共用。缺点是脚本编写比较复杂，并且部署的时候需要多加一步。</p><p>另外一种方法是将用到的Silverlight系统程序集放到工程底下，然后修改同名的xml配置文件，使其打包的文件使用其他后缀名。好处是这样编译完之后就可以直接部署了，无需执行什么操作，也不需要写脚本。坏处就是首先需要修改所有现有的工程，而且以后如果要开发新的Silverlight应用，也要记得这么做。</p><p>不管怎么样，这两种方法都不简单。后来我就想，既然客户可以和电信通联系，为什么我不可以直接和铁通联系呢。我就上网搜了一下北京铁通客户中心，找到申诉通道，填写完整的申述理由。然后第二天又打他们的客服电话去骚扰他们。结果过了两天，申述结果就下来了，“问题已解决”。对方客服还本着能自己动手决不麻烦别人的精神，帮我填写了用户满意度一栏：“非常满意”。</p><h2>更深层的东西</h2><p>其实最终解决问题的办法非常简单，就是投诉。我不满意你的服务，我就有权利投诉你。可是为什么一开始没有意识到这种解决办法呢？</p><p>我觉得这是和我们接触的社会环境有很大关系。我们潜意识里头已经习惯了各种中国式的流氓。运营商喜欢往你访问的网站中插播广告，访问我自己的博客偶尔还有弹窗广告；上Google搜索技术资料，一不小心点了blogspot的链接就导致Google被重置了，然后就10分钟不可用。没有明文规定告诉你什么是被禁止的，我们只能人肉测试。我们除了接受、适应并绕过这种事实之外还能做什么？也许我们还可以发出几声“中国式的抗议”吧。</p><p>言多必封，不多说了。</p><p style="text-align: right;">——<a title="Silverlight启用Assembly Caching之后铁通用户无法访问" href="http://www.imkevinyang.com/2010/02/Silverlight%e5%90%af%e7%94%a8Assembly%20Caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/tags/assembly-caching" title="Assembly Caching" rel="tag">Assembly Caching</a>, <a href="http://www.imkevinyang.com/tags/http" title="HTTP" rel="tag">HTTP</a>, <a href="http://www.imkevinyang.com/tags/http-watch" title="HTTP Watch" rel="tag">HTTP Watch</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/%e8%b7%a8%e5%9f%9f" title="跨域" rel="tag">跨域</a>, <a href="http://www.imkevinyang.com/tags/%e9%87%8d%e5%ae%9a%e5%90%91" title="重定向" rel="tag">重定向</a>, <a href="http://www.imkevinyang.com/tags/%e9%93%81%e9%80%9a" title="铁通" rel="tag">铁通</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2010/05/64%e4%bd%8d%e7%b3%bb%e7%bb%9f%e4%b8%8biis7-isapi%e5%a4%84%e7%90%86%e5%99%a8%e5%8a%a0%e8%bd%bd%e5%a4%b1%e8%b4%a5.html" title="64位系统下IIS7 ISAPI处理器加载失败 (2010/05/05)">64位系统下IIS7 ISAPI处理器加载失败</a> (2010/05/05)</li><li><a href="http://www.imkevinyang.com/2009/11/asp-net%e9%a1%b5%e9%9d%a2%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98.html" title="Asp.Net页面的编码问题 (2009/11/27)">Asp.Net页面的编码问题</a> (2009/11/27)</li><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2009/11/%e3%80%90%e6%8e%a8%e8%8d%90%e3%80%91%e4%b8%a4%e6%ac%behttp%e6%b5%81%e9%87%8f%e5%88%86%e6%9e%90%e5%b7%a5%e5%85%b7%e7%9a%84%e6%af%94%e8%be%83.html" title="【推荐】两款HTTP流量分析工具的比较 (2009/11/08)">【推荐】两款HTTP流量分析工具的比较</a> (2009/11/08)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Blend小贴士&#8212;&#8212;改变鼠标滚轮的默认行为</title><link>http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html</link> <comments>http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html#comments</comments> <pubDate>Fri, 18 Sep 2009 04:47:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[Blend]]></category> <category><![CDATA[Tips]]></category> <category><![CDATA[小贴士]]></category> <category><![CDATA[缩放]]></category> <category><![CDATA[鼠标滚轮]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/10/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html</guid> <description><![CDATA[<p>使用Blend的一个最大的别扭之处就在于它默认情况下滚轮的作用是放大缩小，而不是我们熟悉的滚动屏幕。还好这个默认行为是可以修改的。在菜单Tool=&#62;Options=&#62;Artboard中找到Mouse Wheel一节，将其改成Ctrl+滚动即可。以后滚轮就是滚动屏幕的作用，Ctrl+滚轮才是缩放。</p><p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Blend 3 Zoom by Mouse Wheel" border="0" alt="Blend 3 Zoom by Mouse Wheel" src="http://www.imkevinyang.com/wp-content/uploads/2009/10/image_thumb4.png" width="226" height="55" /></p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/tags/blend" title="Blend" rel="tag">Blend</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/tips" title="Tips" rel="tag">Tips</a>, <a href="http://www.imkevinyang.com/tags/%e5%b0%8f%e8%b4%b4%e5%a3%ab" title="小贴士" rel="tag">小贴士</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%a9%e6%94%be" title="缩放" rel="tag">缩放</a>, <a href="http://www.imkevinyang.com/tags/%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae" title="鼠标滚轮" rel="tag">鼠标滚轮</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的&#8230;</h4>]]></description> <content:encoded><![CDATA[<p>使用Blend的一个最大的别扭之处就在于它默认情况下滚轮的作用是放大缩小，而不是我们熟悉的滚动屏幕。还好这个默认行为是可以修改的。在菜单Tool=&gt;Options=&gt;Artboard中找到Mouse Wheel一节，将其改成Ctrl+滚动即可。以后滚轮就是滚动屏幕的作用，Ctrl+滚轮才是缩放。</p><p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Blend 3 Zoom by Mouse Wheel" border="0" alt="Blend 3 Zoom by Mouse Wheel" src="http://www.imkevinyang.com/wp-content/uploads/2009/10/image_thumb4.png" width="226" height="55" /></p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/tags/blend" title="Blend" rel="tag">Blend</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/tips" title="Tips" rel="tag">Tips</a>, <a href="http://www.imkevinyang.com/tags/%e5%b0%8f%e8%b4%b4%e5%a3%ab" title="小贴士" rel="tag">小贴士</a>, <a href="http://www.imkevinyang.com/tags/%e7%bc%a9%e6%94%be" title="缩放" rel="tag">缩放</a>, <a href="http://www.imkevinyang.com/tags/%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae" title="鼠标滚轮" rel="tag">鼠标滚轮</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html" title="Sql Tips——Update语句也使用表别名(Table Alias) (2010/07/02)">Sql Tips——Update语句也使用表别名(Table Alias)</a> (2010/07/02)</li><li><a href="http://www.imkevinyang.com/2009/09/visual-studio%e5%b0%8f%e8%b4%b4%e5%a3%ab%e5%8a%a0%e4%ba%86try-catch%e4%b9%9f%e8%83%bd%e8%87%aa%e5%8a%a8%e5%ae%9a%e4%bd%8d%e5%88%b0%e5%bc%82%e5%b8%b8%e4%bb%a3%e7%a0%81.html" title="Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码 (2009/09/18)">Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html" title="图片等资源的引用路径问题 (2009/03/19)">图片等资源的引用路径问题</a> (2009/03/19)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>解决Silverlight引用中文字体的问题</title><link>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e5%bc%95%e7%94%a8%e4%b8%ad%e6%96%87%e5%ad%97%e4%bd%93%e7%9a%84%e9%97%ae%e9%a2%98.html</link> <comments>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e5%bc%95%e7%94%a8%e4%b8%ad%e6%96%87%e5%ad%97%e4%bd%93%e7%9a%84%e9%97%ae%e9%a2%98.html#comments</comments> <pubDate>Mon, 07 Sep 2009 16:34:19 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[中文字体]]></category> <category><![CDATA[字体]]></category> <category><![CDATA[字体打包]]></category> <category><![CDATA[引用]]></category> <category><![CDATA[本地字体]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e5%bc%95%e7%94%a8%e4%b8%ad%e6%96%87%e5%ad%97%e4%bd%93%e7%9a%84%e9%97%ae%e9%a2%98.html</guid> <description><![CDATA[<h2>问题描述</h2><p>在Silverlight程序中，对文字设置了中文字体之后不起任何作用。</p><h2>问题分析</h2><p>Silverlight内置了十几种常见拉丁字体，如Arial，Comic Sans MS，Courier New，Lucida Sans Unicode等。默认使用的字体是Portable User Interface。这是一种复合字体，Silverlight会根据文字的语言选择最佳的字体。但是，这种字体通常在显示中文的时候非常难看。下图是默认的显示效果：</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb6.png" width="404" height="51" /></p><p>所以，我们&#8230;</p>]]></description> <content:encoded><![CDATA[</p><h2>问题描述</h2><p>在Silverlight程序中，对文字设置了中文字体之后不起任何作用。</p><h2>问题分析</h2><p>Silverlight内置了十几种常见拉丁字体，如Arial，Comic Sans MS，Courier New，Lucida Sans Unicode等。默认使用的字体是Portable User Interface。这是一种复合字体，Silverlight会根据文字的语言选择最佳的字体。但是，这种字体通常在显示中文的时候非常难看。下图是默认的显示效果：</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb6.png" width="404" height="51" /></p><p>所以，我们需要在程序中手动指定文字的字体。</p><h3>三种字体引用方式</h3><p>如果使用的字体是Silverlight内置支持的，那么无需做任何配置，直接指定FontFamily即可。内置的字体有Arial，Arial Black，Comic Sans MS，Courier New，Lucida Sans Unicode，Times New Roman，Georgia，Trebuchet MS，Verdana和Webdings。使用这些字体不依赖于客户端操作系统。</p><p>同时Silverlight也支持引用本地系统一部分字体（注意，不是全部本地字体都支持）。如Segoe UI，Symbol，Tahoma，宋体，等等。使用这些字体需要注意，其他客户端系统中可能不存在这些字体，如英文操作系统一般没有宋体。那么如果你使用了宋体那就会有问题。</p><p>如果你需要让Silverlight应用程序在不同系统下都有一致的字体，或者你想用某些字体，但是这些字体不支持本地引用（如隶书），那么Silverlight允许你将字体文件打包到应用程序中，可以放在Xap包中，也可以放在ClientBin目录下，然后在代码中动态下载并引用这些字体文件。这样牺牲的代价就是Xap包会变得较大。</p><p>为了更好显示中文，我需要为上面的文字显式指定使用“宋体”。代码如下：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span> <span class="attr">Background</span><span class="kwrd">=&quot;White&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">=&quot;Hello，测试中英文混合显示效果&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;26&quot;</span> <span class="attr">FontFamily</span><span class="kwrd">=&quot;宋体&quot;</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">Grid</span><span class="kwrd">&gt;</span></pre><p>Ctrl+F5运行，却发现字体没有发生明显的变化。说明字体的设置不起作用。我又测试了一下将宋体打包到应用程序中。为了简单，我使用Blend3帮我自动完成这个操作。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Blend 3中字体打包" border="0" alt="Blend 3中字体打包" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb7.png" width="246" height="140" /></p><p>选中一种字体之后，勾选字体面板下面的Embed复选框即可将指定字体打包到Silverlight工程中去。这个时候工程中自动生成了Fonts文件夹，里面放置了宋体这个字体文件。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Visual Studio 打包字体" border="0" alt="Visual Studio 打包字体" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb8.png" width="165" height="112" /></p><p>同时，Xaml也发生了变化，由引用系统的宋体改成引用Fonts.zip包中的宋体了。如下：</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span> <span class="attr">Background</span><span class="kwrd">=&quot;White&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">=&quot;Hello，测试中英文混合显示效果&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;26&quot;</span> <span class="attr">FontFamily</span><span class="kwrd">=&quot;Fonts/Fonts.zip#宋体&quot;</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">Grid</span><span class="kwrd">&gt;</span></pre><p>运行结果发现字体依旧。</p><p>后来查阅Silverlight官方文档的时候，看到字体列表一节时，突然想到，<strong><font color="#008000">是不是因为字体名不规范？不能直接使用“宋体”，而应该使用Simsun</font></strong>。赶紧测试了一下，发现果然是这个问题。只需将上面两个示例代码中的宋体改成Simsun即可正确显示出宋体的效果来。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb9.png" width="388" height="33" /></p><p>后来又测试了一下其它中文字体，如微软雅黑，如果直接这样写中文的话是显示不出来的，一定要写“Microsoft YaHei”。可恶的Blend，帮我自动生成的代码居然有这种莫名其妙的错。不知道这算是Silverlight和Blend的Bug还是设计使然。</p><h2>总结</h2><p>在Silverlight中，如果要引用字体，一定不能直接写上中文，否则不起任何作用。如果你是在英文操作系统下的话，你可以打开字体文件（C:\windows\fonts文件夹下，Silverlight支持ttf,odttf和otf这几种后缀的字体文件），其中的字体名称一栏就是FontFamily所使用的名称。只是在中文操作系统下，支持中文的字体在这里会显示为中文名，而不是英文名。</p><p><img style="border-bottom: 0px; border-left: 0px; margin: 0px; display: inline; border-top: 0px; border-right: 0px" title="FontFamily" border="0" alt="FontFamily" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb10.png" width="316" height="132" /></p><p>常见中文字体名和英文字体名的对应关系如下：</p><table border="1" cellspacing="0" cellpadding="0" height="400"><thead><tr><td colspan="2" align="center">常见中文字体与FontFamily映射表</td></tr></thead><tbody><tr><td valign="top" width="171">宋体（英文不等宽）</td><td valign="top" width="429">Simsun</td></tr><tr><td valign="top" width="171">宋体（英文等宽）</td><td valign="top" width="429">NSimsun</td></tr><tr><td valign="top" width="171">楷体</td><td valign="top" width="429">KaiTi</td></tr><tr><td valign="top" width="171">黑体</td><td valign="top" width="429">SimHei</td></tr><tr><td valign="top" width="171">仿宋</td><td valign="top" width="429">FangSong</td></tr><tr><td valign="top" width="171">微软正黑体</td><td valign="top" width="429">Microsoft JhengHei</td></tr><tr><td valign="top" width="171">细明体</td><td valign="top" width="429">MingLiu</td></tr><tr><td valign="top" width="171">微软雅黑</td><td valign="top" width="429">Microsoft YaHei</td></tr><tr><td valign="top" width="171">隶书</td><td valign="top" width="429">LiSu（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">华文彩云</td><td valign="top" width="429">STCaiyun（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">华文琥珀</td><td valign="top" width="429">STHupo（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">华文隶书</td><td valign="top" width="429">STLiti（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">华文新魏</td><td valign="top" width="429">STXinwei（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">华文行楷</td><td valign="top" width="429">STXingkai（只能打包，不支持本地系统引用）</td></tr><tr><td valign="top" width="171">幼圆</td><td valign="top" width="429">YouYuan（只能打包，不支持本地系统引用）</td></tr></tbody></table><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/%e4%b8%ad%e6%96%87%e5%ad%97%e4%bd%93" title="中文字体" rel="tag">中文字体</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e4%bd%93" title="字体" rel="tag">字体</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%97%e4%bd%93%e6%89%93%e5%8c%85" title="字体打包" rel="tag">字体打包</a>, <a href="http://www.imkevinyang.com/tags/%e5%bc%95%e7%94%a8" title="引用" rel="tag">引用</a>, <a href="http://www.imkevinyang.com/tags/%e6%9c%ac%e5%9c%b0%e5%ad%97%e4%bd%93" title="本地字体" rel="tag">本地字体</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html" title="图片等资源的引用路径问题 (2009/03/19)">图片等资源的引用路径问题</a> (2009/03/19)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%9c%a8xaml%e4%b8%ad%e8%be%93%e5%85%a5%e5%b0%96%e6%8b%ac%e5%8f%b7%e6%96%87%e6%9c%ac.html" title="在Xaml中输入尖括号文本 (2009/02/28)">在Xaml中输入尖括号文本</a> (2009/02/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e5%bc%95%e7%94%a8%e4%b8%ad%e6%96%87%e5%ad%97%e4%bd%93%e7%9a%84%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>解决Silverlight无法调试的问题</title><link>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e6%97%a0%e6%b3%95%e8%b0%83%e8%af%95%e7%9a%84%e9%97%ae%e9%a2%98.html</link> <comments>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e6%97%a0%e6%b3%95%e8%b0%83%e8%af%95%e7%9a%84%e9%97%ae%e9%a2%98.html#comments</comments> <pubDate>Tue, 01 Sep 2009 06:26:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[疑难杂症]]></category> <category><![CDATA[Silverlight无法调试]]></category> <category><![CDATA[Visual Studio]]></category> <category><![CDATA[调试]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/08/%e8%a7%a3%e5%86%b3silverlight%e8%b0%83%e8%af%95%e7%8a%b6%e6%80%81%e4%b8%8b%e6%97%a0%e6%b3%95%e8%b7%9f%e8%bf%9b%e6%96%ad%e7%82%b9%e7%9a%84%e9%97%ae%e9%a2%98.html</guid> <description><![CDATA[<h2>问题描述</h2><p>在Silverlight开发过程中，经常时不时的会碰到Silverlight无法调试的问题。我就遇到下面几种情况：</p><p>1. Web Application+Silverlight，F5进入调试状态之后无法跟进Silverlight程序中下的断点</p><p>2. 项目中有两个Silverlight工程，其中一个Silverlight程序中有一个鼠标点击事件会将当前页面导航到另外一个Silverlight程序的承载页面。第一个Silverlight程序断&#8230;</p>]]></description> <content:encoded><![CDATA[<h2>问题描述</h2><p>在Silverlight开发过程中，经常时不时的会碰到Silverlight无法调试的问题。我就遇到下面几种情况：</p><p>1. Web Application+Silverlight，F5进入调试状态之后无法跟进Silverlight程序中下的断点</p><p>2. 项目中有两个Silverlight工程，其中一个Silverlight程序中有一个鼠标点击事件会将当前页面导航到另外一个Silverlight程序的承载页面。第一个Silverlight程序断点正常，但是第二个Silverlight程序中的断点不能自动停下来</p><p>3. 无论是在TestPage模式下调试还是在Web工程上调试，只要打开了Silverlight调试开关，那么启动的时候会提示“<strong><font color="#008000">Unable to start debugging. Cannot locate Microsoft Internet Explorer</font></strong>”。如果你是直接Ctrl+F5运行，有时候也会出现一样的问题。</p><h2>单个Silverlight工程无法调试</h2><p>对于第一个问题，请检查如下设置是否正确：</p><p>1. <strong><font color="#008000">确认启用了Silverlight调试</font></strong>。双击Asp.Net工程中的属性文件夹打开属性设置页，找到Web一栏，在此页卡的最下面有几个调试选项，如下图所示：</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/08/image_thumb5.png" width="166" height="116" /> <img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/08/image_thumb6.png" width="511" height="42" /></p><p>确认最后一项“Silverlight”之前的勾是勾上的。</p><p>2. <strong><font color="#008000">确保浏览器访问的Xap包是最新的</font></strong>。检查IE是否已经清除了缓存，或者ClientBin中的Xap因为某些原因没能更新（如因配置管理导致无法覆盖）</p><p>3. <strong><font color="#008000">检查Asp.Net工程是否绑定了Silverlight应用</font></strong>。可以通过asp.net工程的属性面板中的Silverlight Application页卡查看是否绑定成功。如下：</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Silverlight Applications Settings" border="0" alt="Silverlight Applications Settings" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb.png" width="331" height="204" /></p><p>4. <strong><font color="#008000">检查Silverlight工程的StartupObject是否设置正确</font></strong>。有时候我们对工程的命名空间进行重命名，会导致Silverlight应用程序的入口对象失效，从而导致无法启动等情况。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Silverlight Application Startup Object" border="0" alt="Silverlight Application Startup Object" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb1.png" width="453" height="131" /></p><h2>IE8下无法同时调试多个Silverlight工程？！</h2><p>IE8和以往的IE不大一样，它的多标签是采用多进程的方式来实现的。整个窗口是一个框架进程，每个Tab标签页是一个独立的子进程（实际上，IE8会根据内存动态控制Tab进程的数目，因此多个标签页可能会共存于同一个进程之中）。当你尝试在多个标签页中打开不同的Silverlight应用程序时，例如从SilverlightApplication1中打开新页面到SilverlightApplication2页面，这个时候你会发现，SilverlightApplication2应用程序无法调试。</p><p>这是因为，<strong><font color="#008000">Visual Studio除了启动窗口进程之外，不会自动帮我们Attach其他的包含Silverlight应用程序的进程，如果我们需要在多个标签页（或者多个窗口）中同时调试不同的Silverlight应用程序，那么我们必须自己手动Attach这些进程</font></strong>。</p><p>举个简单的例子，我有两个Silverlight工程，其中SilverlightApplication1中包含链接指向SilverlightApplication2页面，点击链接会在新标签页中打开SilverlightApplication2的承载页面。</p><p>为了Attach相应的进程，首先我们需要找到SilverlightApplication2承载页面对应的进程。打开ProcessExplorer，我们可以看到三个进程。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb2.png" width="232" height="59" /></p><p>其中的ID为4528的是父进程，也就是框架进程，用于管理不同的标签进程之间的通信等事务。5160和5248分别对应着两个标签页进程。至于哪个对应哪个我们在这里无法根据进程号确定。</p><p>我们再打开Visual Studio中的Attach窗口（菜单=&gt;Debug=&gt;Attach to process…）</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb3.png" width="510" height="185" /></p><p>这里列出了所有系统可用的进程清单，我们可以看到三个IE进程，其中一个是灰色的，这表示了这个进程已经被Attach到Visual Studio的调试器上了。排除了框架进程4258外，就剩下5248这个进程了，这个进程就是我们要找的SilverlightApplication2对应的承载页面的进程了。选中之后Attach到调试器上，我们发现，SilverlightApplication2中的断点还是显示为空心红圈，依然无法调试。</p><p>这是因为我们指定的进程代码类型不正确。我们注意到，上图中最上面有一个Attach to，后面显示的是Automatic，这个代表着Visual Studio的调试器会自动帮我们选择进程的调试类型，例如是托管代码调试，还是脚本调试，等等。我们选中5248这个进程，发现Visual Studio给我们选择的方式是脚本调试。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb4.png" width="504" height="144" /></p><p>在Visual Studio中，脚本调试和Silverlight调试是不能共存的，这也就是为什么有时候你按下F5的时候，Visual Studio会提示你，调试Silverlight程序会暂时关闭脚本调试的功能。因此在脚本调试下，我们无法跟进Silverlight应用程序的断点。</p><p>这里额外说一点，IE8高级选项中的禁用脚本调试设置对Visual Studio一点影响都没有，因为Visual Studio 2008在调试器启动的时候会自动启用脚本调试（可以通过注册表禁用此特性），除非在Web Application属性中打开了Silverlight调试。</p><p>回到刚才的问题，由于Visual Studio帮我们自动选择的调试类型有误，导致我们无法调试SilverlightApplication2，因此我们需要手动指定Attach类型。点击Attach to后侧的select按钮。</p><p><img style="border-right-width: 0px; margin: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/09/image_thumb5.png" width="308" height="211" /></p><p>在弹出的选择代码类型窗口中勾选上Silverlight。确定之后再次Attach，我们发现，这一次，断点真的起作用了。</p><p>当然，如果这种方式比较麻烦的话，我们也可以通过改变IE8的Tab进程创建方式来让不同标签页共存于一个进程中。在注册表HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main下面有一个TabProcGrowth键值（DWORD类型），当其设置为0时， IE框架和Tab工作在一个进程里面，Tab采用线程的方式创建，同时IE的保护模式（Protect Mode）会关闭。TabProcGrowth=1时IE框架和Tab工作在不同的进程里面。TabProcGrowth&gt;1时，此值将决定IE8最多创建的Tab进程数目。如果TabProcGrowth 不存在，则会根据可用的物理内存数量决定Tab进程的数量。</p><h2>调试时无法打开IE窗口的问题</h2><p>这个问题是我最近才遇到的，我也不知道为什么突然之间，我的Silverlight工程按下F5的时候无法调试，弹出下面这个对话框：Unable to start debugging. Cannot locate Microsoft Internet Explorer.</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb15.png" width="248" height="141" /></p><p>如果直接运行，那么能够打开，但是打开之后Visual Studio还是会弹出一样的错误。</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb16.png" width="257" height="134" /></p><p>这个问题折腾了我半天，我尝试了重启电脑，重装Silverlight Tools，新建干净的测试工程，修改系统和Visual Studio的默认浏览器（注意，系统和Visual Studio的默认浏览器是独立设置的）均以失败告终。Google了很久，Silverlight官方论坛上倒是有不少帖子和这个相关的，但我细细看了之后发现没有一个回帖能够解决我的问题的。有个发帖的家伙问题是解决了，但是不把怎么解决的说一下就跑了，强烈bs一下这种人！</p><p>话说回来，我最后是怎么解决这个问题的呢，是用了Process Monitor这个小工具（微软Sysinternal荣誉出品！）。之前有一次asp.net网站的GlobalError里头出现了一个“文件不存在”的HTTPException，查了半天没查出来，后来使用这个工具监视了一下WebDevServ.exe进程之后发现该进程尝试去访问某个不存在的文件。</p><blockquote><p>Process Monitor，可以监控当前系统中所有进程的活动，包括对文件系统的操作，读写注册表，网络访问以及线程活动等等，非常实用的调试维护工具。</p></blockquote><p>我打开这个工具，选择监视进程为devenv.exe。在Visual Studio中F5开始调试，立即弹出出错对话框，OK，把PM暂停一下，否则条目太多了。</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb17.png" width="298" height="98" /></p><p>但是事件条目还是太多了，所以我把Result为SUCCESS的条目过滤掉，因为我们只关注那些失败的条目。</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb18.png" width="271" height="171" /></p><p>然后对日志条目进行细致的排查，终于发现了问题根源：</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb19.png" width="546" height="45" /></p><p>原来Visual Studio在调试或者运行的时候会去读取注册表中的HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\iexplore.exe项，然后读取不到，因而才报那个错误。难怪提示Cannot locate Microsoft internet explorer呢。</p><p>我打开regedit注册表编辑器，找到这个路径，然后把缺失的项加上去，重新回到Visual Studio中F5，终于可以了，内牛满面~</p><p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/12/image_thumb20.png" width="330" height="156" /></p><p>希望我的解决方法能够给你一些启发，以后遇到类似莫名其妙的问题，可以想到使用PM这个工具去排查问题。</p><p><font color="#ff0000">update</font>: 更新了新的症状（F5调试的时候弹出cannot locate microsoft internet explorer的对话框）的解决办法。</p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight%e6%97%a0%e6%b3%95%e8%b0%83%e8%af%95" title="Silverlight无法调试" rel="tag">Silverlight无法调试</a>, <a href="http://www.imkevinyang.com/tags/visual-studio" title="Visual Studio" rel="tag">Visual Studio</a>, <a href="http://www.imkevinyang.com/categories/techarticles/knottyproblems" title="疑难杂症" rel="tag">疑难杂症</a>, <a href="http://www.imkevinyang.com/tags/%e8%b0%83%e8%af%95" title="调试" rel="tag">调试</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/08/firebug%e5%9c%a8edithtml%e6%97%b6%e4%b8%a2%e5%a4%b1%e4%ba%8b%e4%bb%b6%e5%a4%84%e7%90%86%e5%87%bd%e6%95%b0-2.html" title="Firebug在EditHtml时丢失事件处理函数 (2009/08/19)">Firebug在EditHtml时丢失事件处理函数</a> (2009/08/19)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2009/09/visual-assist%e4%bb%a3%e7%a0%81%e6%8f%90%e7%a4%ba%e4%bd%bf%e7%94%a8%e7%9a%84%e5%ad%97%e7%ac%a6%e4%b8%b2%e6%a8%a1%e7%b3%8a%e5%8c%b9%e9%85%8d%e7%ae%97%e6%b3%95.html" title="Visual Assist代码提示使用的字符串模糊匹配算法 (2009/09/28)">Visual Assist代码提示使用的字符串模糊匹配算法</a> (2009/09/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3silverlight%e6%97%a0%e6%b3%95%e8%b0%83%e8%af%95%e7%9a%84%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>枚举导致的WCF Web Service接口返回异常</title><link>http://www.imkevinyang.com/2009/08/%e6%9e%9a%e4%b8%be%e5%af%bc%e8%87%b4%e7%9a%84wcf-web-service%e6%8e%a5%e5%8f%a3%e8%bf%94%e5%9b%9e%e5%bc%82%e5%b8%b8.html</link> <comments>http://www.imkevinyang.com/2009/08/%e6%9e%9a%e4%b8%be%e5%af%bc%e8%87%b4%e7%9a%84wcf-web-service%e6%8e%a5%e5%8f%a3%e8%bf%94%e5%9b%9e%e5%bc%82%e5%b8%b8.html#comments</comments> <pubDate>Sun, 23 Aug 2009 13:44:58 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[WCF]]></category> <category><![CDATA[Web Service]]></category> <category><![CDATA[异常]]></category> <category><![CDATA[枚举]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/08/%e6%9e%9a%e4%b8%be%e5%af%bc%e8%87%b4%e7%9a%84wcf-web-service%e6%8e%a5%e5%8f%a3%e8%bf%94%e5%9b%9e%e5%bc%82%e5%b8%b8.html</guid> <description><![CDATA[<p>枚举在DotNet中是一个比较特别的类型，因为你可以将任意整数赋值给一个枚举类，而不会导致编译或者运行时异常。不知道为什么要这样设计，感觉在这样的设计下，枚举类就变成弱类型了，丧失了类型安全检测了。曾经就有一次在Silverlight项目中遇到了和枚举类这个设计相关的奇怪问题，调试了半天才解决。</p><p>当时的症状是这样的，客户端Silverlight程序（当时是Silverlight 2.0 RTM）在调用Web Service返回的时候抛出了一个C&#8230;</p>]]></description> <content:encoded><![CDATA[<p>枚举在DotNet中是一个比较特别的类型，因为你可以将任意整数赋值给一个枚举类，而不会导致编译或者运行时异常。不知道为什么要这样设计，感觉在这样的设计下，枚举类就变成弱类型了，丧失了类型安全检测了。曾经就有一次在Silverlight项目中遇到了和枚举类这个设计相关的奇怪问题，调试了半天才解决。</p><p>当时的症状是这样的，客户端Silverlight程序（当时是Silverlight 2.0 RTM）在调用Web Service返回的时候抛出了一个CommunicationException，这个错误没能提供任何信息，Silverlight把所有的Web Service的异常都替换成这个没有调试意义的异常。我尝试在Web Service端跟了一下，发现程序正常的走到最后一个大括号，没有抛出任何异常。但是返回的时候却还是抛出了这个CommunicationException异常。</p><p>Google了一下，实在找不到相关的文章。只能自己分析了。在对涉及到的类做了详尽的检查之后，还是没有检查出什么设计问题来。该标注的属性都标注了。绞尽脑汁，后来终于想起了一丝线索，就是某个类里面定义了一个枚举成员，这个枚举类我之前修改过。我回想起当时的修改，我是把一个成员给删掉了，但是这会有什么关系呢？？我重新跟了一下，重点跟踪和该枚举成员相关的代码，终于发现了在一个数据库查询的时候，返回的枚举成员就是之前删掉的那个成员。由于枚举的设计是允许未定义成员的存在，因此这里不会报错，代码会继续执行直到返回。但是Silverlight客户端Web Service代理在反射此类型的时候则会出错（因为没有对应的枚举成员存在）。遗憾的是，Silverlight对Web Service返回的结果异常的报错机制不能帮我们很好的发现这个问题。我后来测试发现，如果在调用Web Service的时候传入一个非法的成员值，Silverlight是会抛出一个反射类型出错的异常，而且会帮你定位到出错的那个枚举成员上。</p><p>后来项目开发中还遇到和这个类似的问题，就是在实例化一个类实例的时候，由于类中使用C#3.0的自动属性特性去定义的枚举成员，成员的初始值是0，而枚举类中并没有0的成员，所以会遇到和上面一样的问题。</p><p>实际上，微软给的最佳开发实践中指出了，枚举类的一个设计原则就是，一定要定义一个0值的成员，这样可以避免枚举初始化值无效的问题。</p><p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>标签：<a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/wcf" title="WCF" rel="tag">WCF</a>, <a href="http://www.imkevinyang.com/tags/web-service" title="Web Service" rel="tag">Web Service</a>, <a href="http://www.imkevinyang.com/tags/%e5%bc%82%e5%b8%b8" title="异常" rel="tag">异常</a>, <a href="http://www.imkevinyang.com/tags/%e6%9e%9a%e4%b8%be" title="枚举" rel="tag">枚举</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/05/javascript%e4%b8%ad%e8%8e%b7%e5%8f%96%e5%87%ba%e9%94%99%e4%bb%a3%e7%a0%81%e6%89%80%e5%9c%a8%e6%96%87%e4%bb%b6%e5%8f%8a%e8%a1%8c%e6%95%b0.html" title="Javascript中获取出错代码所在文件及行数 (2009/05/18)">Javascript中获取出错代码所在文件及行数</a> (2009/05/18)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2009/09/visual-studio%e5%b0%8f%e8%b4%b4%e5%a3%ab%e5%8a%a0%e4%ba%86try-catch%e4%b9%9f%e8%83%bd%e8%87%aa%e5%8a%a8%e5%ae%9a%e4%bd%8d%e5%88%b0%e5%bc%82%e5%b8%b8%e4%bb%a3%e7%a0%81.html" title="Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码 (2009/09/18)">Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码</a> (2009/09/18)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/08/%e6%9e%9a%e4%b8%be%e5%af%bc%e8%87%b4%e7%9a%84wcf-web-service%e6%8e%a5%e5%8f%a3%e8%bf%94%e5%9b%9e%e5%bc%82%e5%b8%b8.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Silverlight SEO（搜索引擎优化）白皮书</title><link>http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html</link> <comments>http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html#comments</comments> <pubDate>Mon, 06 Apr 2009 13:47:03 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[好文分享]]></category> <category><![CDATA[SEO]]></category> <category><![CDATA[搜索引擎]]></category> <category><![CDATA[白皮书]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html</guid> <description><![CDATA[<div class="statement"><span style="color: #ff0000;">转载说明: </span><p>英文原文出处：<a title="http://silverlight.net/learn/whitepapers/seo.aspx" href="http://silverlight.net/learn/whitepapers/seo.aspx">http://silverlight.net/learn/whitepapers/seo.aspx</a></p><p>中文翻译出处：http://www.mdong.org/?p=277</p></div><p>概要</p><p>这份文档描述了一些Silverlight程序的搜索引擎优化（SEO）技巧。这些技巧是用来帮助开发人员使得Silverlight内容能够在搜索引擎的结果页被发现，并为没有激活Silverlight的用户提供合意的体验。</p><p><strong>这份文档将包括以下的章节：</strong></p><p>*介&#8230;</p>]]></description> <content:encoded><![CDATA[<div class="statement"><span style="color: #ff0000;">转载说明: </span></p><p>英文原文出处：<a title="http://silverlight.net/learn/whitepapers/seo.aspx" href="http://silverlight.net/learn/whitepapers/seo.aspx">http://silverlight.net/learn/whitepapers/seo.aspx</a></p><p>中文翻译出处：http://www.mdong.org/?p=277</p></div><p>概要</p><p>这份文档描述了一些Silverlight程序的搜索引擎优化（SEO）技巧。这些技巧是用来帮助开发人员使得Silverlight内容能够在搜索引擎的结果页被发现，并为没有激活Silverlight的用户提供合意的体验。</p><p><strong>这份文档将包括以下的章节：</strong></p><p>*介绍<br /> *搜索引擎工作原理<br /> *开发Silverlight程序的方法<br /> *Silverlight程序的SEO技巧<br /> *总结</p><p><strong>介绍</strong></p><p>搜索引擎能够直接识别HTML内容。与此同时，搜索引擎先天的不识别Silverlight内容。这一点与搜索引擎不支持其它的一些通过HTML呈现的对象类似，如脚本、css、媒体文件以及ActiveX控件。为了使Silverlight内容能够被搜索引擎收录，你可以使用搜索引擎已经支持的方法，如将孤立的Silverlight岛与跟内容相关的HTML metadata相结合。</p><p>SEO的目的是增加页面在搜索引擎的主要结果页(图中被红色矩形标出的部分)的显示机会，而不是在广告或者赞助商的页面。</p><p><a href="http://www.mdong.org/wp-content/uploads/2008/11/fig1.jpg"><img title="搜索引擎的搜索结果页" src="http://www.mdong.org/wp-content/uploads/2008/11/fig1-300x206.jpg" alt="搜索引擎的搜索结果页" width="300" height="206" /></a></p><p>搜索引擎的搜索结果页</p><p>虽然搜索引擎技术的前景因为大量的竞争者不断地改进与革新正在迅速地变化，而SEO所依赖的搜索引擎算法中的一些基本原理是类似的。</p><p><strong>搜索引擎的工作原理</strong></p><p>搜索引擎能够抓取、评估与收录Web页面内容。抓取过程由搜索引擎爬虫（robot）执行，它们顺着网站的链接爬行并捕获内容。这时搜索引擎使用算法权重Web页面的价值。这个信息被用于建立搜索索引，也就是建立一个基于查询的结果页。<br /> 一个Web页面在搜索引擎的结果中会获很高的排名的主要原因是：页面中的词句与匹配的关键字在过去经常被搜索到。动态页面与不规范的元素，诸如页面中的脚本、样式表、对象以及embed标签等对搜索引擎来说是一种质疑，是一贯就就没有做好的领域。</p><p>在这种情况下，搜索引擎需要做以下的工作：</p><p>下载链接内容与关联的源页面相匹配。<br /> 在浏览器中解析、转换、执行或呈现元素以获得与用户浏览页面同等的体验。</p><p><a href="http://www.mdong.org/wp-content/uploads/2008/11/fig2.jpg"><img title="搜索引擎简化示意图" src="http://www.mdong.org/wp-content/uploads/2008/11/fig2.jpg" alt="搜索引简化擎示意图" width="500" height="232" /></a></p><p>搜索引擎简化示意图</p><p><strong>开发Silverlight程序的方法</strong></p><p>如果你正在计划开发一个Silverlight程序，那么你有许多工作可以做，以确保程序被搜索引擎发现并收录。</p><p>接下来是你可以采取的一些使得程序可以与HTML内容共存的方式。</p><p><strong>混合HTML与Silverlight内容</strong></p><p>该方式使得同一页面内的HTML文本与Silverlight内容相混合，它在功能上的递送更为丰富，原生的HTML内容也将被搜索引擎收录。为此，留心将Silverlight内容以适应内嵌或者环绕、字块的方式设计。这看起来像是格子中的交互构件适应在HTML文本的周围。 Silverlight程序的交互支持真正的文本比隐藏在搜索引擎可搜索的文本中将更具优势。</p><p><a href="http://www.mdong.org/wp-content/uploads/2008/11/fig3.jpg"><img title="岛式文本与Silverlight交互" src="http://www.mdong.org/wp-content/uploads/2008/11/fig3.jpg" alt="岛式文本与Silverlight交互" width="258" height="259" /></a></p><p>岛式文本与Silverlight交互</p><p><strong>使用HTML桥动态生成Silverlight内容</strong></p><p>这个方法略微难以实现，并限制Siverlight的体验。如果你拥有现有XHTML内容并希望使用Silverlight提升体验，使用这个方法你可以获得很大的成功。在这个方法中，XHTML内容是爬虫与低端（Down-Level）客户端的基础体验，Silverlight体验仅留作在客户端平台用户运行Silverlight。</p><p>在这个方法中，XHTML内容可以对目标客户端实现高保真的体验。它还公开的作为嵌套的预备内容内嵌在Silverlight插件的object标签中。一个属性从优雅降级模式区分出这个模式，这个模式中Silverlight程序的UI被嵌套预备内容所驱动。换句话说，程序逻辑会使用DOM桥用于取得object标签嵌套的预备内容，并使用它来构建Silverlight UI。使用XSLT转化XHTML到XAML将会变得更为简单，或者使用数据绑定，绑定XAML UI属性到提取的标记中的object呈现内容。</p><p><strong>优雅降级</strong></p><p>在这份文档中，主要关注通过优雅降级的方法达到的SEO。在这样的一个环境中，Silverlight内容是用户的主要体验，以嵌套在object标签的预备内容的使用作为低端体验。</p><p><strong>Silverlight程序的SEO技巧</strong></p><p>使得Silverlight内容被搜索引擎引索的关键因素是存在一个方法针对未激活Silverlight的系统与用户。包括以下情况：</p><p>*包含Silverlight内容的Web页面何如在当前不被Silverlight所支持的客户端/浏览器的配置中运作，如Opera或Windows 98。<br /> *对于使用无障碍程序（如屏幕阅读者与播音者）的用户来说Web页面如何运作？<br /> *对于使用文本浏览器的用户来说Web页面如何运作？如不支持脚本的Lynx等。</p><p>呈现相关的metadata与预备内容会使得Silverlight内容对于低端用户更为友好，这种友好对于搜索引擎也同样适用。</p><p>当创建Silverlight程序时，假设所有的用户已经安装了Silverlight或者有条件安装Silverlight。你准备如何为用户描述应用程序：</p><p>*了解你的用户。<br /> *计划如何向他们描述应用程序。<br /> *确定关键字，用于与搜索用户相联系。</p><p>你所使用的页面的标题以及头部片段、body内容、预备内容的关键词扮演了一个搜索引擎寻找与收录内容以及用户如何找到内容的重要角色。</p><p>下面的许多技术你可以用于优化搜索引擎结果并提升用户体验：</p><p>*使用描述的页面标题<br /> *增加描述Metadata<br /> *使用语义化的程序名称<br /> *使用object标签<br /> *确定Silverlight的预备内容<br /> *当使用Silverlight.js时使用creatObject<br /> *测试低端体验</p><p><strong>使用描述的页面标题</strong></p><p>给页面一个完美的标题。Web页面的作者必须修改与个性化页面中的标记，可以通过Visual Studio或者Expression Blend由Silverlight工程模板生成。为了有更好的讨论效果，我们假定你有一个Silverlight程序，提供西雅图地区的交通地图。图中展示了一个默认的页面标题与良好的页面标题。</p><p><a href="http://www.mdong.org/wp-content/uploads/2008/11/fig4.jpg"><img title="糟糕的页面标题与良好的页面标题" src="http://www.mdong.org/wp-content/uploads/2008/11/fig4.jpg" alt="糟糕的页面标题与良好的页面标题" width="474" height="147" /></a></p><p>糟糕的页面标题与良好的页面标题</p><p><strong>增加描述Metadata</strong></p><p>页面的关键词meta标签对于搜索引擎决定页面的rank值来说并不是很有效。但是，一个页面的标题与meta描述标签（属性名为description的meta标签）对于保证搜索用户在结果页查看你的页面与联系他们正在寻找的内容却有很大的帮助。</p><p>如果你有一个顶级(Top-Level)的Silverlight程序，占用了整个的客户端浏览器显示区域，或者一个依靠该程序的登录页面，这个时候你必须在HTML页面增加一个meta描述标签。下面的代码展示了meta描述标签的格式。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">head</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">meta</span> <span class="attr">name</span><span class="kwrd">="description"</span>
<span class="attr">content</span><span class="kwrd">="Silverlight development community..."</span> <span class="kwrd">&gt;</span>
...
<span class="kwrd">&lt;/</span><span class="html">head</span><span class="kwrd">&gt;</span></pre><p>如果有一个页面拥有大量的文本内容，并包括了相关的关键字，这时你可以忽略meta描述。搜索引擎会在结果页显示一部分你的页面的内容，任何残余的描述可能事实上被证明都不会显示。</p><p>下面的图像展示了一个包括描述的搜索页面入口的例子，以及当meta描述标签未定义时它将如何显示。</p><p><a href="http://www.mdong.org/wp-content/uploads/2008/11/fig5.jpg"><img title="搜索引擎结果页，有meta描述标签与没有meta描述标签" src="http://www.mdong.org/wp-content/uploads/2008/11/fig5.jpg" alt="搜索引擎结果页，有meta描述标签与没有meta描述标签" width="499" height="130" /></a></p><p>搜索引擎结果页，有meta描述标签与没有meta描述标签</p><p><strong>使用语义化的程序名称</strong></p><p>给应用程序赋予一个实用的名字是另外一个帮助搜索引擎找到你的Web页面的方式。如：一个应用程序提供了一个关于西雅图地区的交通地图，可以被命名为SeattleTrafficMaps.xap。</p><p>即使你的应用程序已经使用了一个不同的名字，修改它的名字也是相当容易。如：将MyTestSLApp.xap命名为 SeattleTrafficMaps.xap。当你没有在其它代码处使用这个程序名，回头修改它将是一个简单的操作。默认请况下，在 Silverlight模板中对其没有依赖。</p><p><strong>使用object标签</strong></p><p>object标签被设计用作HTML。如果在主object不能被载入显示内容，这时客户端浏览器会继续寻找在object标签中的替换内容。</p><p>Silverlight内容的发布者必须使用object标签（不是embed标签）来初始化Silverlight。下面的代码展示了如何加入object标签。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">object</span> <span class="attr">type</span><span class="kwrd">="application/x-silverlight-2"</span>
<span class="attr">data</span><span class="kwrd">="data:application/x-silverlight,"</span>
<span class="attr">width</span><span class="kwrd">="..."</span> <span class="attr">height</span><span class="kwrd">="..."</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">param</span> <span class="attr">name</span><span class="kwrd">="source"</span> <span class="attr">value</span><span class="kwrd">="SeattleTrafficMaps.xap"</span> <span class="kwrd">/&gt;</span>
<span class="rem">&lt;!-- Other parameters, if any --&gt;</span>
  ...
<span class="rem">&lt;!-- The “Get Silverlight” messages and badge --&gt;</span>
<span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>This content requires Microsoft Silverlight.
<span class="kwrd">&lt;</span><span class="html">a</span> <span class="attr">href</span><span class="kwrd">="http://go.microsoft.com/fwlink/?LinkID=124807"</span>
<span class="attr">style</span><span class="kwrd">="text-decoration: none;"</span><span class="kwrd">&gt;</span> 

<span class="kwrd">&lt;</span><span class="html">img</span> <span class="attr">src</span><span class="kwrd">="http://go.microsoft.com/fwlink/?LinkId=108181"</span>
<span class="attr">alt</span><span class="kwrd">="Get Microsoft Silverlight"</span>
<span class="attr">style</span><span class="kwrd">="border-style: none"</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">a</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">object</span><span class="kwrd">&gt;</span></pre><p><strong>确定Silverlight的预备内容</strong></p><p>Silverlight程序的object标签必须被补充嵌套在预备内容中，也就是被显示在缺少Silverlight的系统中的内部HTML。下面的代码显示了如何做到这点。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">object</span> <span class="attr">type</span><span class="kwrd">="application/x-silverlight-2"</span>
<span class="attr">data</span><span class="kwrd">="data:application/x-silverlight,"</span>
<span class="attr">width</span><span class="kwrd">="..."</span> <span class="attr">height</span><span class="kwrd">="..."</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">param</span> <span class="attr">name</span><span class="kwrd">="source"</span> <span class="attr">value</span><span class="kwrd">="SeattleTrafficMaps.xap"</span> <span class="kwrd">/&gt;</span>
<span class="rem">&lt;!-- Other parameters, if any --&gt;</span>
  ...
<span class="rem">&lt;!-- Nested alternate HTML content for search --&gt;</span>
<span class="kwrd">&lt;</span><span class="html">h3</span><span class="kwrd">&gt;</span>Traffic map of the Seattle-Puget Sound area<span class="kwrd">&lt;/</span><span class="html">h3</span><span class="kwrd">&gt;</span> 

<span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>Up-to-the-minute traffic situation overlaid on the map of
     the Seattle-Puget Sound area, powered by
<span class="kwrd">&lt;</span><span class="html">a</span> <span class="attr">href</span><span class="kwrd">="http://maps.live.com"</span><span class="kwrd">&gt;</span>Live Maps<span class="kwrd">&lt;/</span><span class="html">a</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span> 

<span class="rem">&lt;!-- Canned image representing the application contents --&gt;</span>
<span class="kwrd">&lt;</span><span class="html">img</span> <span class="attr">src</span><span class="kwrd">="SeattleTraffic_RushHour.jpg"</span>
<span class="attr">alt</span><span class="kwrd">="Seattle traffic at 5:30pm (evening rush-hour)"</span> <span class="kwrd">/&gt;</span>
<span class="rem">&lt;!-- The “Get Silverlight” message and badge --&gt;</span>
<span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>This content requires Microsoft Silverlight.
<span class="kwrd">&lt;</span><span class="html">a</span> <span class="attr">href</span><span class="kwrd">="http://go.microsoft.com/fwlink/?LinkID=124807"</span>
<span class="attr">style</span><span class="kwrd">="text-decoration: none;"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">img</span> <span class="attr">src</span><span class="kwrd">="http://go.microsoft.com/fwlink/?LinkId=108181"</span>
<span class="attr">alt</span><span class="kwrd">="Get Microsoft Silverlight"</span>
<span class="attr">style</span><span class="kwrd">="border-style: none"</span><span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">a</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">object</span><span class="kwrd">&gt;</span></pre><p><strong>当使用Silverlight.js时使用createObject</strong></p><p>Silverlight.js的主函数供于跨平台、跨浏览器，借助构建恰当的标记使得Silverlight内容与HTML DOM相挂钩。典型的，包括围绕浏览器工作的object标签。createObject函数统一提供了父级元素的id，如：一个div或者span的内嵌，Silverlight object会作为子元素挂钩。这个方法使用了以下的逻辑。</p><pre class="csharpcode"><span class="kwrd">if</span> (slParentElement != <span class="kwrd">null</span>) {
   slParentElement.innerHTML = slPluginHTML;
}</pre><p>假设你的标记由以下组成。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">id</span><span class="kwrd">="divWithinWhichSLObjectExists"</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">="text/javascript"</span><span class="kwrd">&gt;</span>
&lt;!--
    Silverlight.createObject(<span class="str">"slObjectId"</span>,
                             <span class="str">"divWithinWhichSLObjectExists"</span>,
                             ...); 

<span class="rem">// --&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">script</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre><p>当浏览器运行时，有效的DOM应该如下面的代码。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">id</span><span class="kwrd">="divWithinWhichSLObjectExists"</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">object</span> <span class="attr">classid</span><span class="kwrd">="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"</span>
 <span class="attr">width</span><span class="kwrd">="100"</span> <span class="attr">height</span><span class="kwrd">="100"</span>
<span class="attr">codebase</span><span class="kwrd">="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">param</span> <span class="attr">name</span><span class="kwrd">="source"</span> <span class="attr">value</span><span class="kwrd">="SeattleTrafficMaps.xap"</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">embed</span> <span class="attr">type</span><span class="kwrd">="application/x-shockwave-flash"</span> <span class="attr">width</span><span class="kwrd">="100"</span> <span class="attr">height</span><span class="kwrd">="100"</span> <span class="attr">source</span><span class="kwrd">="SeattleTrafficMaps.xap"</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">embed</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">object</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre><p>存在附带产生有益的效用供于以下原因：更换父级div的内部HTML移动了该div中任何其它现有的子元素。搜索引擎会在所有脚本执行与改变DOM之前经常分析与引索标记。</p><p>换句话说，你可以增加详尽的相关的metadata作为内在HTML内嵌在Silverlight object中的父级div元素。搜索引擎会处理metadata，但是metadata不会显示在浏览器中。</p><p>如果你的父级div已经嵌套了关联的内容，下面的代码将是蜘蛛能够看到的。</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">id</span><span class="kwrd">="divWithinWhichSLObjectExists"</span><span class="kwrd">&gt;&lt;!</span><span class="html">--</span> <span class="attr">Nested</span> <span class="attr">alternate</span> <span class="attr">HTML</span> <span class="attr">content</span> <span class="attr">for</span> <span class="attr">search</span> <span class="attr">--</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">div</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">h3</span><span class="kwrd">&gt;</span>Traffic map of the Seattle-Puget Sound area<span class="kwrd">&lt;/</span><span class="html">h3</span><span class="kwrd">&gt;</span>
Up-to-the-minute traffic situation overlaid on the map of
the Seattle-Puget Sound area, powered by
<span class="kwrd">&lt;</span><span class="html">a</span> <span class="attr">href</span><span class="kwrd">="http://maps.live.com"</span><span class="kwrd">&gt;</span>Live Maps<span class="kwrd">&lt;/</span><span class="html">a</span><span class="kwrd">&gt;</span> 

<span class="rem">&lt;!-- canned image representing app contents --&gt;</span>
<span class="kwrd">&lt;</span><span class="html">img</span> <span class="attr">src</span><span class="kwrd">="SeattleTraffic_RushHour.jpg"</span> <span class="attr">alt</span><span class="kwrd">=""</span> <span class="kwrd">/&gt;</span> alt="Seattle traffic at 5:30pm (evening rush-hour)" /<span class="attr">&amp;gt;</span><span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>
<span class="rem">&lt;!-- Invocation of the createObject function in Silverlight.js --&gt;</span>
<span class="kwrd">&lt;</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">="text/javascript"</span><span class="kwrd">&gt;&lt;!</span><span class="html">--</span>
    <span class="attr">Silverlight</span>.<span class="attr">createObject</span>(<span class="kwrd">"slObjectId"</span>, //<span class="attr">SL</span> <span class="attr">plug-in</span> <span class="attr">id</span>
                             <span class="kwrd">"divWithinWhichSLObjectExists"</span>, //<span class="attr">parent</span> <span class="attr">id</span>
                             ...); 

// <span class="attr">--</span><span class="kwrd">&gt;&lt;/</span><span class="html">script</span><span class="kwrd">&gt;&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre><p><strong>测试低端体验</strong></p><p>不管内容中相关的Silverlight与HTML的如何重要，针对没有安装Silverlight的用户的页面测试是非常必要的。</p><p>使得低端用户可以访问这个页面，执行以下步骤：</p><p>1.关闭所有的Internet请求，启动一个新的请求。</p><p>2.在工具菜单，选择管理加载项，然后点击开启/禁止加载项。会弹出管理加载项对话框。</p><p>3.选择Microsoft Silverlight，选择禁用按钮，然后点击确定。</p><p>4.重启Internet Explorer并操作转向有Silverlight内容的Web页面。</p><p>5.重复返回管理加载项对话框，选择Microsoft Silverlight、并选择启用。</p><p>注：</p><p>用于临时关闭Silverlight插件的程序仅作用于当前使用的浏览器。</p><p>当你测试低端体验完毕，值得在你的页面中加入一个统计工具，如SEO浏览器以了解标记的效果以及SEO的内容。</p><p><strong>总结</strong></p><p>搜索引擎收录非原生的HTML内容的能力非常有限。但是，如果你通过几种方式构造并呈现了你的应用程序，这将有更大的可能性响应到搜索查询并显示在搜索引擎结果页。</p><h5>英文原文</h5><p>Search Engine Optimization for Silverlight applications</p><p>Ashish Shetty</p><p>Microsoft Corporation</p><p>October 2008</p><p>Summary</p><p>This document describes some best practices for search engine optimization of Silverlight applications. These practices are designed to help developers make their Silverlight content discoverable on a search engine results page and to provide an acceptable experience for users who do not have Silverlight enabled.</p><p>This document contains the following sections:</p><ul><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#introduction">Introduction</a></li><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#how_search_engines_work">How Search Engines Work</a></li><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#approaches_for_developing_a_silverlight_application">Approaches for Developing a Silverlight Application</a></li><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#search_engine_optimization_techniques_for_silverlight_applications">Search Engine Optimization Techniques for Silverlight Applications</a></li><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#conclusion">Conclusion</a></li></ul><p>Introduction</p><p>Search engines are geared toward recognizing HTML content. At this time, they do not recognize Silverlight content natively. This is similar to the search engine support for other objects on the HTML page, such as script blocks, CSS blocks, media files, and ActiveX controls. To make Silverlight content indexable by search engines, you can use approaches that search engines are already familiar with, such as combining the islands of Silverlight content with HTML metadata about that content.</p><p>The goal of search engine optimization (SEO) is to increase the chances that your page will appear in the main section of the search engine results page (outlined by the red rectangle in Figure 1), not the paid or sponsored results.</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2009/04/clip-image001.jpg"><img style="margin: 0px 0px 10px; display: inline; border-width: 0px;" title="clip_image001" src="http://www.imkevinyang.com/wp-content/uploads/2009/04/clip-image001-thumb.jpg" border="0" alt="clip_image001" width="612" height="423" /></a></p><p>Figure 1 - Search engine results page</p><p>Even though the search landscape is rapidly changing, with multiple competitors continuously improving and evolving how they implement search, SEO relies on some fundamental similarities among search engine algorithms.</p><p>How Search Engines Work</p><p>Search engines crawl, weight, and index Web page content. Crawling is done by a search robot that traverses the links in a Web site and captures the content. Search engines then use algorithms and heuristics to assign weights to Web pages. This information is used to build the search index, which is used to build a results page based on your query.</p><p>The main reason for a Web page to be highly ranked in search engine results is that the words on the page match the keywords that are used to search. The presence of dynamic and nonstandard elements such as script, style, object, and embed tags in the page is a challenge to search engines, and this is an area where they have traditionally not done well.</p><p>In this situation, search engines have to do the following:</p><ul><li>Download linked content and associate it with the source page.</li><li>Parse, convert, execute, or render elements to obtain the same experience as the user viewing the page in a browser.</li></ul><p>Figure 2 is a simplified view of how a search engine works.</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2009/04/clip-image002.jpg"><img style="margin: 0px 0px 10px; display: inline; border-width: 0px;" title="clip_image002" src="http://www.imkevinyang.com/wp-content/uploads/2009/04/clip-image002-thumb.jpg" border="0" alt="clip_image002" width="563" height="264" /></a></p><p>Figure 2 - A simplified view of a search engine</p><p>Approaches for Developing a Silverlight Application</p><p>If you are planning to build a Silverlight application, there are things you can do to make sure that your application is discovered and returned by search engines.</p><p>The following are some of the patterns that you can adopt for how your application coexists with the HTML content.</p><p>Mix HTML with Silverlight Content</p><p>This pattern involves mixing HTML text with Silverlight content in the same page so that it delivers richness in functionality and the native HTML content is consumable by search engines. To do this, consider designing your Silverlight content in such a way that it fits within, or around, a block of text. This looks like a grid of interacting components that fit around HTML text. An advantage of this approach is that it ensures that your Silverlight interactivity is truly supporting the text, rather than hiding otherwise searchable text from search engines. Figure 3 shows a Web page with this approach.</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2009/04/clip-image003.jpg"><img style="margin: 0px 0px 10px; display: inline; border-width: 0px;" title="clip_image003" src="http://www.imkevinyang.com/wp-content/uploads/2009/04/clip-image003-thumb.jpg" border="0" alt="clip_image003" width="262" height="263" /></a></p><p>Figure 3 - Islands of text and Silverlight interactivity</p><p>Use HTML Bridge to Generate Silverlight Content Dynamically</p><p>This approach is slightly harder to achieve and can be limiting to the Silverlight experience. You will have most success with this approach if you have existing XHTML content and want to enhance the experience with Silverlight. In this approach, the XHTML content is the base experience for search robots and down-level clients, while the Silverlight experience is reserved for consumers on client platforms capable of running Silverlight.</p><p>In this approach, the XHTML content has the full-fidelity experience for its target clients. It is still declared as nested alternate content within the object tag for the Silverlight plug-in. The one attribute that differentiates this pattern from the graceful degradation pattern is that in this pattern, the Silverlight application’s UI is driven by the nested alternate content. In other words, application logic will use the DOM Bridge to get the nested alternate content from the object tag and use it to construct the Silverlight UI. This can be as simple as using XSLT to transform the XHTML to XAML, or perhaps using data binding to bind XAML UI properties to an object representing content from the extracted markup.</p><p>Graceful Degradation</p><p>In this document, we focus primarily on search engine optimization using the graceful degradation approach. In such a scenario, the Silverlight content is the primary experience for consumers, and the use of nested alternate content within the object tag serves as the down-level experience.</p><p>Search Engine Optimization Techniques for Silverlight Applications</p><p>The key consideration for making Silverlight content indexable by search engines is to use the approaches that are used for systems and users for which Silverlight is not enabled. Considerations include the following:</p><ul><li>How the Web page with Silverlight content behaves in client/browser configurations such as Opera or Windows 98, which are not currently supported by Silverlight.</li><li>How the Web page behaves for customers who use accessibility programs such as screen readers and narrators.</li><li>How the Web page behaves for customers who use from a text browser such as Lynx, where no scripts can execute.</li></ul><p>Presenting contextual metadata and alternate content that would make Silverlight content friendly to down-level users will also make it friendly to search engines.</p><p>When creating your Silverlight application, do not assume that all users will have Silverlight installed or have computers with the ability to install Silverlight. Prepare for how you would describe your application to these users.</p><ul><li>Know your audience.</li><li>Plan on how you would describe your application to them.</li><li>Identify the keywords that you would use to connect with searchers.</li></ul><p>The words that you use in your titles, page and section headers, body content, and alternate content play an important role in how the search engines find and index your content, and also how a user finds your content.</p><p>The following are some of the techniques you can use to optimize your search engine results and improve the experience for all users:</p><ul><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#use_a_descriptive_page_title">Use a Descriptive Page Title</a></li><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#add_description_metadata">Add Description Metadata</a></li><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#use_a_meaningful_application_name">Use a Meaningful Application Name</a></li><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#use_the_object_tag">Use the object Tag</a></li><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#specify_alternate_content_for_silverlight">Specify Alternate Content for Silverlight</a></li><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#use_createobject_when_using_silverlight.js">Use createObject When Using Silverlight.js</a></li><li><a href="http://silverlight.net/learn/whitepapers/seo.aspx#test_downlevel_experiences">Test Down-Level Experiences</a></li></ul><p>Use a Descriptive Page Title</p><p>Give your page a good title. Web page authors must update and customize the markup in the pages generated by Silverlight project templates in Visual Studio or Expression Blend. For the purposes of discussion, let’s assume you have a Silverlight application that provides interactive traffic maps for the Seattle area. Figure 4 shows bad (default) and good Web page titles.</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2009/04/clip-image004.jpg"><img style="margin: 0px 0px 10px; display: inline; border-width: 0px;" title="clip_image004" src="http://www.imkevinyang.com/wp-content/uploads/2009/04/clip-image004-thumb.jpg" border="0" alt="clip_image004" width="478" height="151" /></a></p><p>Figure 4 - Bad and good page titles</p><p>Add Description Metadata</p><p>Keywords in your page’s meta tag are not very useful for search engines to determine your page’s rank. However, a page title and meta description tag (that is, a meta tag whose name attribute is set to "description") are extremely useful in ensuring that searchers who view your page on a results page associate it with content that they are looking for.</p><p>If you have a top-level Silverlight application that occupies the full extent of the browser’s client area, or one that exists on your landing page, then you must have a meta description tag on your HTML page. The following code shows the format of the meta description tag.</p><p>&lt;head&gt; &lt;meta name="description" content="Microsoft portal site for the Silverlight development community..." &gt; ... &lt;/head&gt;</p><p>If you have a page with a lot of text content that contains relevant keywords, then you can omit the meta description. The search engine will show a portion of your page content on the results page, and any stub description may actually prove counterproductive.</p><p>The following figure shows a sample search page entry with a description, and how it would appear if the meta description tag were not present.</p><p><a href="http://www.imkevinyang.com/wp-content/uploads/2009/04/clip-image005.jpg"><img style="margin: 0px 0px 10px; display: inline; border-width: 0px;" title="clip_image005" src="http://www.imkevinyang.com/wp-content/uploads/2009/04/clip-image005-thumb.jpg" border="0" alt="clip_image005" width="568" height="151" /></a></p><p>Figure 5 - Search results page with and without a meta description tag</p><p>Use a Meaningful Application Name</p><p>Giving a useful name to your application is another way to help the search engines find your Web page. For example, an application that provides traffic maps for the Seattle area could be named SeattleTrafficMaps.xap.</p><p>Even if your application was built using a different name, it is easy to change the name, for example, from MyTestSLApp.xap to SeattleTrafficMaps.xap. Changing the name back at a later time is a simple operation if that name is not referred to elsewhere in your code. By default, there are no dependencies of this kind in the Silverlight templates.</p><p>Use the object Tag</p><p>The object tag in HTML is designed so that if the main object cannot be loaded to display content, then browser clients will continue to look for alternative content within the object tag.</p><p>Silverlight content publishers must use the object tag (not the embed tag) to instantiate Silverlight. The following code shows how you can add the object tag.</p><p>&lt;object type="application/x-silverlight-2" data="data:application/x-silverlight," width="..." height="..."&gt; &lt;param name="source" value="SeattleTrafficMaps.xap" /&gt; &lt;!-- Other parameters, if any --&gt; ... &lt;!-- The “Get Silverlight” messages and badge --&gt; &lt;p&gt;This content requires Microsoft Silverlight. &lt;a href="<a href="http://go.microsoft.com/fwlink/?LinkID=124807">http://go.microsoft.com/fwlink/?LinkID=124807</a>" style="text-decoration: none;"&gt; &lt;img src="<a href="http://go.microsoft.com/fwlink/?LinkId=108181">http://go.microsoft.com/fwlink/?LinkId=108181</a>" alt="Get Microsoft Silverlight" style="border-style: none"/&gt; &lt;/a&gt; &lt;/p&gt; &lt;/object&gt;</p><p>Specify Alternate Content for Silverlight</p><p>The object tag for the Silverlight application must be supplemented with nested alternate content, namely the inner HTML that is displayed on systems where Silverlight is absent. The following code shows how you can do that.</p><p>&lt;object type="application/x-silverlight-2" data="data:application/x-silverlight," width="..." height="..."&gt; &lt;param name="source" value="SeattleTrafficMaps.xap" /&gt; &lt;!-- Other parameters, if any --&gt; ... &lt;!-- Nested alternate HTML content for search --&gt; &lt;h3&gt;Traffic map of the Seattle-Puget Sound area&lt;/h3&gt; &lt;p&gt;Up-to-the-minute traffic situation overlaid on the map of the Seattle-Puget Sound area, powered by &lt;a href="http://maps.live.com"&gt;Live Maps&lt;/a&gt; &lt;/p&gt; &lt;!-- Canned image representing the application contents --&gt; &lt;img src="SeattleTraffic_RushHour.jpg" alt="Seattle traffic at 5:30pm (evening rush-hour)" /&gt; &lt;!-- The “Get Silverlight” message and badge --&gt; &lt;p&gt;This content requires Microsoft Silverlight. &lt;a href="<a href="http://go.microsoft.com/fwlink/?LinkID=124807">http://go.microsoft.com/fwlink/?LinkID=124807</a>" style="text-decoration: none;"&gt; &lt;img src="<a href="http://go.microsoft.com/fwlink/?LinkId=108181">http://go.microsoft.com/fwlink/?LinkId=108181</a>" alt="Get Microsoft Silverlight" style="border-style: none"/&gt; &lt;/a&gt; &lt;/p&gt; &lt;/object&gt;</p><p>Use createObject When Using Silverlight.js</p><p>The primary function of Silverlight.js is to provide a cross-browser, cross-platform means of constructing the right markup to get Silverlight content hooked up to the HTML DOM. Typically this involves working around browser quirks to generate the object tag with the right set of parameters. The createObject function also takes the id of a parent element, for example a div or span, within which the Silverlight object will be hooked up as child element. This approach uses the following logic.</p><p>if (slParentElement != null) { slParentElement.innerHTML = slPluginHTML; }</p><p>For example, assume that your markup consisted of the following code.</p><p>&lt;div id="divWithinWhichSLObjectExists"&gt; &lt;script type="text/javascript"&gt; Silverlight.createObject("slObjectId", "divWithinWhichSLObjectExists", ...); &lt;/script&gt; &lt;/div&gt;</p><p>The effective DOM would be like the following code when executed on the browser.</p><p>&lt;div id="divWithinWhichSLObjectExists"&gt; &lt;object type="application/x-silverlight-2" data="data:application/x-silverlight," width="..." height="..."&gt; &lt;param name="source" value="SeattleTrafficMaps.xap" /&gt; &lt;!-- Other Parameters, if any --&gt; ... &lt;!-- The “Get Silverlight” message and badge --&gt; &lt;p&gt;This content requires Microsoft Silverlight. &lt;a href="<a href="http://go.microsoft.com/fwlink/?LinkID=124807">http://go.microsoft.com/fwlink/?LinkID=124807</a>" style="text-decoration: none;"&gt; &lt;img src="<a href="http://go.microsoft.com/fwlink/?LinkId=108181">http://go.microsoft.com/fwlink/?LinkId=108181</a>" alt="Get Microsoft Silverlight" style="border-style: none"/&gt; &lt;/a&gt; &lt;/p&gt; &lt;/object&gt; &lt;/div&gt;</p><p>This has a beneficial side effect for the following reasons:</p><ul><li>Replacing the inner HTML of the parent div removes any other existing child elements in that div.</li><li>Search engines often parse and index markup as it is served—before any scripts execute and change the DOM.</li></ul><p>In other words, you can add detailed contextual metadata as native HTML within the parent div element of the Silverlight object. Search engines will process the metadata, but the metadata will not show up in the browser.</p><p>If your parent div has nested contextual content, the following code is what the search robot sees.</p><p>&lt;div id="divWithinWhichSLObjectExists"&gt; &lt;!-- Nested alternate HTML content for search --&gt; &lt;div&gt; &lt;h3&gt;Traffic map of the Seattle-Puget Sound area&lt;/h3&gt; &lt;p&gt;Up-to-the-minute traffic situation overlaid on the map of the Seattle-Puget Sound area, powered by &lt;a href="http://maps.live.com"&gt;Live Maps&lt;/a&gt; &lt;/p&gt; &lt;!-- canned image representing app contents --&gt; &lt;img src="SeattleTraffic_RushHour.jpg" alt="Seattle traffic at 5:30pm (evening rush-hour)" /&gt; &lt;/div&gt; &lt;!-- Invocation of the createObject function in Silverlight.js --&gt; &lt;script type="text/javascript"&gt; Silverlight.createObject("slObjectId", //SL plug-in id "divWithinWhichSLObjectExists", //parent id ...); &lt;/script&gt; &lt;/div&gt;</p><p>Test Down-Level Experiences</p><p>Regardless of the relative importance of Silverlight and HTML in your content, it is important to test the page as a user who does not have Silverlight installed.</p><p>To access the page as a down-level user, perform the following steps:</p><ol><li>Close all instances of Internet Explorer, and then start a new instance.</li><li>On the Tools menu, point to Manage Add-ons, and then click Enable or Disable Add-ons. The Manage Add-ons dialog box is displayed.</li><li>Select Microsoft Silverlight, select the Disable button, and then click OK.</li><li>Restart Internet Explorer and navigate to the Web page that has your Silverlight content.</li></ol><p>To revert, return to the Manage Add-ons dialog box, select Microsoft Silverlight, and select Enable.</p><p>Note</p><p>The procedure for temporarily disabling the Silverlight plug-in differs depending on the browser you are using.</p><p>After you have tested the down-level experience, it is worthwhile validating your page with a static analysis tool such as <a href="http://seo-browser.com/">SEO Browser</a> that understands the impact of markup and content on search engine optimization.</p><p>Conclusion</p><p>The ability of search engines to index content that is not native HTML is very limited. However, if you structure and present your Silverlight application in certain ways, they have a better chance of appearing on a search engine results page in response to a search query.</p>标签：<a href="http://www.imkevinyang.com/tags/seo" title="SEO" rel="tag">SEO</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/categories/greatpoststoshare" title="好文分享" rel="tag">好文分享</a>, <a href="http://www.imkevinyang.com/tags/%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e" title="搜索引擎" rel="tag">搜索引擎</a>, <a href="http://www.imkevinyang.com/tags/%e7%99%bd%e7%9a%ae%e4%b9%a6" title="白皮书" rel="tag">白皮书</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/05/2009%e5%b9%b4%e7%ac%ac%e4%b8%80%e5%ad%a3%e5%ba%a6%e4%b8%ad%e5%9b%bd%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e5%b8%82%e5%9c%ba%e8%90%a5%e6%94%b6%e4%bb%bd%e9%a2%9d.html" title="2009年第一季度中国搜索引擎市场营收份额 (2009/05/06)">2009年第一季度中国搜索引擎市场营收份额</a> (2009/05/06)</li><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/03/google%e5%b7%a5%e7%a8%8b%e5%b8%88matt-cutts%e8%b0%88seo.html" title="Google工程师Matt Cutts谈SEO (2009/03/23)">Google工程师Matt Cutts谈SEO</a> (2009/03/23)</li><li><a href="http://www.imkevinyang.com/2009/05/robotstxt%e6%96%87%e4%bb%b6.html" title="Robots.txt文件 (2009/05/06)">Robots.txt文件</a> (2009/05/06)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>图片等资源的引用路径问题</title><link>http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html</link> <comments>http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html#comments</comments> <pubDate>Thu, 19 Mar 2009 13:49:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[技术随笔]]></category> <category><![CDATA[BuildAction]]></category> <category><![CDATA[Xap]]></category> <category><![CDATA[图片]]></category> <category><![CDATA[引用]]></category> <category><![CDATA[资源文件]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html</guid> <description><![CDATA[<ol><p>在SL中，我们经常会遇到资源引用的问题，尤其是图片资源。这里就有两个地方需要注意的：</p><li>图片放哪里？</li><li>Xaml中怎么引用图片？</li></ol><p>下面我会通过一个简单的Demo来讲解一下这两个问题。</p><p>首先，新建两个工程，如下图：</p><p><img title="clip_image001" style="border-right: 0px; border-top: 0px; display: inline; margin: 0px 0px 10px; border-left: 0px; border-bottom: 0px" height="487" alt="clip_image001" src="http://www.imkevinyang.com/wp-content/uploads/2009/03/clip-image001-thumb.png" width="283" border="0" /></p><p>这里，我们在SL工程中的Images文件夹放了4张图片（其中Image.jpg可以忽略），在Web工程的ClientBin目录下也建了个叫Images的文件夹，下面只有一张我们要用来外部引用的图片。</p><p>右键SL工程中任意一张图片=&#62;属性（&#8230;</p>]]></description> <content:encoded><![CDATA[<ol><p>在SL中，我们经常会遇到资源引用的问题，尤其是图片资源。这里就有两个地方需要注意的：</p><li>图片放哪里？</li><li>Xaml中怎么引用图片？</li></ol><p>下面我会通过一个简单的Demo来讲解一下这两个问题。</p><p>首先，新建两个工程，如下图：</p><p><img title="clip_image001" style="border-right: 0px; border-top: 0px; display: inline; margin: 0px 0px 10px; border-left: 0px; border-bottom: 0px" height="487" alt="clip_image001" src="http://www.imkevinyang.com/wp-content/uploads/2009/03/clip-image001-thumb.png" width="283" border="0" /></p><p>这里，我们在SL工程中的Images文件夹放了4张图片（其中Image.jpg可以忽略），在Web工程的ClientBin目录下也建了个叫Images的文件夹，下面只有一张我们要用来外部引用的图片。</p><p>右键SL工程中任意一张图片=&gt;属性（Property），我们会看到下面这样的配置菜单。</p><p><img title="clip_image002" style="border-right: 0px; border-top: 0px; display: inline; margin: 0px 0px 10px; border-left: 0px; border-bottom: 0px" height="100" alt="clip_image002" src="http://www.imkevinyang.com/wp-content/uploads/2009/03/clip-image002-thumb.png" width="301" border="0" /></p><p>其中两个配置项是我们所关心的，一个是Build Action，另外一个是Copy To Output Directory。</p><p>其中Build Action会决定VS是如果处理你这个文件的，点开下拉菜单会看到可以选择的编译动作有好几个，这里我们只讲下面几个（因为我只研究过这几个^_^，如果其他选项你知道的话，请告诉我）。</p><ul><li>Resource —— 资源会被打包在程序集内部</li><li>Content——资源会被打包在Xap包里面</li><li>None——资源既不会被集成到程序集内，也不会打包到xap包中。不过我们可以通过设置CopyToOutputDirectory选项让其自动拷贝到xap包所在目录。</li></ul><p>再来说引用的问题。</p><ul><li>使用前置 / 引用资源时，SL会从当前Xap包中查找资源，找不到的话会到Xap包所在的目录查找</li><li>不使用前置 / 引用资源时，SL会从当前程序集内查找资源，如果找不着则会到Xap包所在目录查找其他选项你知道的话</li><li>你也可以使用/{程序集名};component/{图片资源路径}的方式来访问，这样就查找的路径就限定在程序集内部了，也就是那些标记为Resource的资源。<p align="right">&#160;</p></li></ul><p align="right">——Kevin Yang</p>标签：<a href="http://www.imkevinyang.com/tags/buildaction" title="BuildAction" rel="tag">BuildAction</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/xap" title="Xap" rel="tag">Xap</a>, <a href="http://www.imkevinyang.com/tags/%e5%9b%be%e7%89%87" title="图片" rel="tag">图片</a>, <a href="http://www.imkevinyang.com/tags/%e5%bc%95%e7%94%a8" title="引用" rel="tag">引用</a>, <a href="http://www.imkevinyang.com/categories/techarticles" title="技术随笔" rel="tag">技术随笔</a>, <a href="http://www.imkevinyang.com/tags/%e8%b5%84%e6%ba%90%e6%96%87%e4%bb%b6" title="资源文件" rel="tag">资源文件</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%9c%a8xaml%e4%b8%ad%e8%be%93%e5%85%a5%e5%b0%96%e6%8b%ac%e5%8f%b7%e6%96%87%e6%9c%ac.html" title="在Xaml中输入尖括号文本 (2009/02/28)">在Xaml中输入尖括号文本</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%b0%86silverlight%e6%90%ac%e5%88%b0%e6%a1%8c%e9%9d%a2.html" title="将Silverlight搬到桌面 (2009/02/28)">将Silverlight搬到桌面</a> (2009/02/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>谈谈Silverlight的一个跨域安全考虑</title><link>http://www.imkevinyang.com/2009/03/%e8%b0%88%e8%b0%88silverlight%e7%9a%84%e4%b8%80%e4%b8%aa%e8%b7%a8%e5%9f%9f%e5%ae%89%e5%85%a8%e8%80%83%e8%99%91.html</link> <comments>http://www.imkevinyang.com/2009/03/%e8%b0%88%e8%b0%88silverlight%e7%9a%84%e4%b8%80%e4%b8%aa%e8%b7%a8%e5%9f%9f%e5%ae%89%e5%85%a8%e8%80%83%e8%99%91.html#comments</comments> <pubDate>Thu, 19 Mar 2009 13:44:00 +0000</pubDate> <dc:creator>Kevin Yang</dc:creator> <category><![CDATA[Silverlight]]></category> <category><![CDATA[技术随笔]]></category> <category><![CDATA[Crossdomain.xml]]></category> <category><![CDATA[安全策略文件]]></category> <category><![CDATA[跨域]]></category><guid isPermaLink="false">http://www.imkevinyang.com/2009/03/%e8%b0%88%e8%b0%88silverlight%e7%9a%84%e4%b8%80%e4%b8%aa%e8%b7%a8%e5%9f%9f%e5%ae%89%e5%85%a8%e8%80%83%e8%99%91.html</guid> <description><![CDATA[<p>在文档中看到Silverlight在设计的时候对网络安全方面做了很多考虑。但由于本人对安全方面并不是特别懂，所以看得挺模糊的。最近和同事黄讨论了其中一些点，得到一些结论，和大家分享一下。</p><p>在文档中有这么一段话：</p><blockquote><p>There are important security considerations before you allow Silverlight clients to access Web services in a cross-domain situation. W&#8230;</p></blockquote>]]></description> <content:encoded><![CDATA[<p>在文档中看到Silverlight在设计的时候对网络安全方面做了很多考虑。但由于本人对安全方面并不是特别懂，所以看得挺模糊的。最近和同事黄讨论了其中一些点，得到一些结论，和大家分享一下。</p><p>在文档中有这么一段话：</p><blockquote><p>There are important security considerations before you allow Silverlight clients to access Web services in a cross-domain situation. Whenever you put a cross-domain policy file in place you should configure your Web server hosting the Web services to disable browser caching. This enables you to easily update the file or restrict access to your Web services if necessary. Once the cross-domain policy file is checked, it remains in effect for the browser session so the impact of non-caching to the end-user is minimal.</p><p><strong>In addition, all Silverlight requests are sent with cookies and authentication. This means that if you have Web services that allow users to access private information, you should host these in a different domain than the Web services exposed to third-party callers. For example, you have a Web store hosted at <a href="http://www.tailspintoys.com">http://www.tailspintoys.com</a>. Your site allows customers to store billing information that includes credit card numbers. You should not expose a Web service that returns product inventory to third-party Silverlight clients at the same domain. Because cookies and authentication are sent with each message, if you host these Web services on the same domain, you have effectively given the third-party callers access to your customer's private billing information. In this example, your publicly exposed Web services could safely be hosted at http://services.tailspintoys.com, because this is a different domain. You must carefully consider who you have exposed Web services to, and what other Web services are located at that domain. Also, you should always keep your cross-domain policy file as restrictive as possible. For more information about exposing secure Web services, see Security Considerations for Service Access and Making a Service Available Across Domain Boundaries. </strong></p></blockquote><p>我对第二段做了个简单的翻译：</p><p>所有的sl请求都会将Cookie和身份验证信息连同发送。这就意味着如果你有一个Web服务，允许用户访问隐私信息，那么你应该将这个web服务放置在其他的域下，和暴露给第三方调用者的web服务的域名区分开。例如，如果你有一个网店放置在<a href="http://www.tailspintoys.com">http://www.tailspintoys.com</a>，你的网店允许客户存储交易的信息，其中包含了信用卡号码。那么你不应该将一个返回产品清单的web服务放在同个主机域下，然后暴露给第三方的SL客户端。因为Cookie和身份验证信息会和请求连同发送，如果你将这些web服务放置在同个域下的话，你就给了第三方的调用者一个很方便的途径来访问你的客户的私人交易信息。在这个例子中，你暴露给第三方的web服务应该放置在http://services.tailspintoys.com。因为这是一个不同的主机域。你必须非常小心的选择哪些服务可以公开，哪些服务应该部署在那个域下。</p><p>我们知道Cookie中有一个主机名的属性，对于只有对于同个主机域的请求，浏览器才会把Cookie连带发送。SL也不例外。</p><p>假设这么一种场景：淘宝开放了一个Web服务，这个服务干什么我们并不关心。但是我们知道，如果你想要你的Web服务被其他第三方的客户端调用，你必须在网站下放置一个特定的xml文件，我们称为&quot;安全策略配置&quot;文件，Flash对应的是crossdomain.xml文件，Silverlight除了支持Flash的这个策略文件之外自己也有一套策略配置，放在clientaccesspolicy.xml文件中。与Flash不同的是，SL只会从网站的根目录下去寻找这个策略文件，也就是说即使你的web服务是放在/serivce/目录下的，那么SL客户端也会查找&quot;主机名/clientaccesspolicy.xml&quot;这个文件是否存在（我不清楚为什么要这样设计）。因此淘宝为了让他的Web服务被Silverlight支持，就必须在网站根目录下放置一个策略文件。</p><p>假设一个顾客在淘宝<a href="http://www.taobao.com"></a>www.taobao.com 上面购买了一些东西，登录的会话验证信息可能会存放在Cookie中，然后这个顾客又访问了一个恶意网站（<a href="http://www.eyi.com"></a>www.eyi.com 当然域名没那么弱了^^），这个恶意网站会向淘宝发送一些登录的HTTP请求。因为这个时候是属于跨域请求，所以Silverlight Runtime会去查找网站根目录下有没有这个策略文件，发现有（并且通过了文件里面定义的访问权限的验证），那么这个请求就会被允许，同时会把你在<a href="http://www.taobao.com"></a>www.taobao.com 上面的Cookie也连带发送到淘宝系统那里，那么这个时候，这个恶意网站是不是就在你不知情的情况下登录到了淘宝后台，然后这个时候他就可以执行一些你不期望的操作了。</p><p>当然这个例子能不能work还有待商榷，只是通过这个例子想告诉大家的是，对于策略安全文件一定要非常小心的配置好访问权限，<font color="#ff0000"><strong>暴露给第三方的</strong><strong>Web服务（涉及到跨域策略安全的），最好放在一个隔离的域下</strong></font>，这样可以降低安全风险。</p><p>不知道我这样理解有没有问题，如果不正确的话请纠正我~</p><p>下面这张是Silverlight的跨域场景示意图</p><p><img title="image" style="border-right: 0px; border-top: 0px; display: inline; margin: 0px 0px 10px; border-left: 0px; border-bottom: 0px" height="357" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/03/image-thumb7.png" width="557" border="0" /></p><p>还要说明的一点是，Silverlight Runtime在检测安全策略文件时，是先检测clientaccesspolicy.xml 再检测crossdomain.xml文件（当然拉，自己的东西肯定先检测了）。一旦请求完成，策略文件在整个应用程序会话周期内一直有效（这个感觉和浏览器为了防止DNS Rebinding攻击的做法是类似的），也就是说不用每次都请求这个文件了。如果第一次请求该文件失败，那么接下来的请求同样的也会失败。</p><p>策略文件只能放置在根目录下，无论你当前请求的资源是位于网站的哪个目录下。</p><p>策略文件本身不允许服务器将其重定向，响应的状态码只能是200或者404，但是请求的资源本身是可以被重定向的，只要源URL和目标URL都在跨域策略文件中声明了。</p><p> <strong></strong><p align="right">——Kevin Yang</p>标签：<a href="http://www.imkevinyang.com/tags/crossdomainxml" title="Crossdomain.xml" rel="tag">Crossdomain.xml</a>, <a href="http://www.imkevinyang.com/categories/techarticles/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/silverlight" title="Silverlight" rel="tag">Silverlight</a>, <a href="http://www.imkevinyang.com/tags/%e5%ae%89%e5%85%a8%e7%ad%96%e7%95%a5%e6%96%87%e4%bb%b6" title="安全策略文件" rel="tag">安全策略文件</a>, <a href="http://www.imkevinyang.com/categories/techarticles" title="技术随笔" rel="tag">技术随笔</a>, <a href="http://www.imkevinyang.com/tags/%e8%b7%a8%e5%9f%9f" title="跨域" rel="tag">跨域</a><br /><h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4><ul class="st-related-posts"><li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> (2009/09/18)</li><li><a href="http://www.imkevinyang.com/2009/02/silverlight-2-rtm-%e5%a4%9a%e5%9b%bd%e8%af%ad%e8%a8%80%e6%94%af%e6%8c%81%ef%bc%88%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e6%9c%ac%e5%9c%b0%e5%8c%96%ef%bc%89.html" title="Silverlight 2 RTM 多国语言支持（应用程序本地化） (2009/02/28)">Silverlight 2 RTM 多国语言支持（应用程序本地化）</a> (2009/02/28)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight-2%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bdxap%e5%8c%85%e4%b8%ad%e7%9a%84%e7%a8%8b%e5%ba%8f%e9%9b%86.html" title="Silverlight 2动态加载Xap包中的程序集 (2009/03/02)">Silverlight 2动态加载Xap包中的程序集</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/05/silverlight-4ria-services-%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96seo.html" title="Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO) (2010/05/04)">Silverlight 4+RIA Services&#8211;搜索引擎优化(SEO)</a> (2010/05/04)</li><li><a href="http://www.imkevinyang.com/2009/04/silverlight-seo%ef%bc%88%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8e%e4%bc%98%e5%8c%96%ef%bc%89%e7%99%bd%e7%9a%ae%e4%b9%a6.html" title="Silverlight SEO（搜索引擎优化）白皮书 (2009/04/06)">Silverlight SEO（搜索引擎优化）白皮书</a> (2009/04/06)</li><li><a href="http://www.imkevinyang.com/2009/03/silverlight2-%e5%8a%a8%e6%80%81%e5%8a%a0%e8%bd%bd%e7%a8%8b%e5%ba%8f%e9%9b%86-ondemand%e6%a8%a1%e5%bc%8fdynamic-load-assembly.html" title="Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly) (2009/03/02)">Silverlight2 动态加载程序集&#8212;OnDemand模式(Dynamic Load Assembly)</a> (2009/03/02)</li><li><a href="http://www.imkevinyang.com/2010/02/silverlight%e5%90%af%e7%94%a8assembly-caching%e4%b9%8b%e5%90%8e%e9%93%81%e9%80%9a%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%ae.html" title="Silverlight启用Assembly Caching之后铁通用户无法访问 (2010/02/13)">Silverlight启用Assembly Caching之后铁通用户无法访问</a> (2010/02/13)</li><li><a href="http://www.imkevinyang.com/2010/03/silverlight%e7%9a%84%e4%be%9d%e8%b5%96%e5%b1%9e%e6%80%a7%e4%b8%8e%e9%99%84%e5%8a%a0%e5%b1%9e%e6%80%a7.html" title="Silverlight的依赖属性与附加属性 (2010/03/28)">Silverlight的依赖属性与附加属性</a> (2010/03/28)</li><li><a href="http://www.imkevinyang.com/2009/03/%e5%9b%be%e7%89%87%e7%ad%89%e8%b5%84%e6%ba%90%e7%9a%84%e5%bc%95%e7%94%a8%e8%b7%af%e5%be%84%e9%97%ae%e9%a2%98.html" title="图片等资源的引用路径问题 (2009/03/19)">图片等资源的引用路径问题</a> (2009/03/19)</li><li><a href="http://www.imkevinyang.com/2009/02/%e5%9c%a8xaml%e4%b8%ad%e8%be%93%e5%85%a5%e5%b0%96%e6%8b%ac%e5%8f%b7%e6%96%87%e6%9c%ac.html" title="在Xaml中输入尖括号文本 (2009/02/28)">在Xaml中输入尖括号文本</a> (2009/02/28)</li></ul>]]></content:encoded> <wfw:commentRss>http://www.imkevinyang.com/2009/03/%e8%b0%88%e8%b0%88silverlight%e7%9a%84%e4%b8%80%e4%b8%aa%e8%b7%a8%e5%9f%9f%e5%ae%89%e5%85%a8%e8%80%83%e8%99%91.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> </channel> </rss>