Joycode@Ab110.com

September 2007 - Posts

Programming WCF Services翻译笔记
cover_small.gif翻译Programming WCF Services的鳞词片语,然而通过翻译笔记可以管中窥豹,了解本书的主要内容,并从中获取有关WCF的知识。

Programming WCF Services翻译笔记(一)
介绍了翻译此书的由来,以及我对翻译的一些体会。

Programming WCF Services翻译笔记(二)
首先介绍了服务的本质,然后介绍了WCF的一些基础知识。

Programming WCF Services翻译笔记(三)
介绍了WCF的绑定以及WCF体系架构。

Programming WCF Services翻译笔记(四)
介绍了服务契约的相关知识,包括操作重载、契约的继承、服务契约的分解与设计、契约查询。

Programming WCF Services翻译笔记(五)
介绍了数据契约的相关知识,包括Serializable、DataContract、序列化、KnownType。

Programming WCF Services翻译笔记(六)
介绍了数据契约的版本控制,以及一些特殊类型的数据契约,包括枚举、委托、数据集与数据表、泛型与集合。
VS 2008的性能改进

[原文地址] VS 2008 Performance Improvements

[原文发表时间] Thursday, September 27, 2007 4:52 PM 

 

VS 2008,我们就开发人员所关心的一些常见的使用场景在性能上作了很大的改进.我们对新的产品功能以及现有的产品功能都设置了明确的性能指标。

例如,对于新的 LINQ,我们设置的性能目标是: 对同一个查询,LINQ性能必须显著优于SqlDataAdapter,SqlDataReader相比也必须有竞争力;SQL Server检索数据时,LINQ的接口必须是最轻量级的. 在我们的测试过程中,  我们所尝试过的每个测试案例几乎都表明,LINQ实际上的确SqlDataAdaptor表现更好, 在大多数那些的例外的测试案例中, 完成相同的任务,LINQSqlDataReader落后的速度不超过10% 考虑到 LINQ的强大功能,我们认为这样的取舍是合理的。

Visual Studio 2008中我们能看到的更显著的性能提高包括:

·         重新生成一个 VisualBasic 项目并运行一个后台编译器的速度提高到了原来的3,使用的内存却只有原来的1/3。更多细节在这里

·         在编辑器里滚动较大的 C# 文件的速度比原来快了一倍,键入新文本的速度是原来的1.5.

·         C# 中庞大类型的智能感应响应时间提高了至多10倍。

·         增量生成C++/ CLI 项目解决方案的时间最快可以提高到原来的1.9倍。更多细节在这里

·          Office Word Excel 文件在服务器上处理的速度快了20倍。

·         TFS 版本控制命令处理经过重写后,能够在不需要绑定内存到服务器上的情况下,支持无限量的关键命令操作。 在我们的测试衡量结果中,关键命令的运行速度还提高了 10% 60%,尤其是在比较大的项目上操作时有了很大的性能提高。从-可以看到更多关于改进TFS可测量性的工作。

 

我们还致力于充分利用多核硬件的优势来提高性能。正如我以前的日志中提到的,我们对MSBuild工具增添了多线程支持。此外,使用 / MP 开关您可以大大提高您的 C++ 项目生成时间 在内部的项目里,我们看到C++前台编译器在双核硬件上性能的提高最多可高达30%.NET Framework 3.5 运行时的性能也有了显著提升,我们精简了CLR的线程池,使得各种类型的多线程应用程序得到性能改进。例如,当这些架构方面的改进与套接字端口API的改进结合在一起,并使用双核处理器的情况下,异步套接字端口I/O的操作速度最快提高了70%。更多关于此项工作的细节在这里

 

上面这些只是VS2008性能改进的一些重要方面VS2008中还有许多其他的性能改进,而且我相信仍然有些地方我们能够做得更好。像任何其他东西一样,这是一场旅行,而非终点。

 

Namaste !

在WCF中获取服务元数据信息

所谓获取WCF的服务元数据(Metadata),归根结点,实际上就是获取服务的终结点(Endpoint)的信息,这是服务公开在外的数据信息,包括Address、Binding与Contract,也就是所谓的ABCs。Juval L?wy在《Programming WCF Services》一书中,用生动形象的棒棒糖表示了终结点的构成:
 figure-1.5.gif

WCF服务可能包含多个终结点,每个终结点相当于是通信的入口,客户端和服务端通过终结点交换信息,如下图所示:
 wcf07.gif

因而,如果能够获取终结点的详细信息,有助于我们更好地剖析服务的定义、内容与执行方式。

服务有两种方案可以发布自己的元数据。一种是基于HTTP-GET协议提供元数据;另一种则为元数据交换方式,它往往使用一个专门的终结点,称之为元数据交换终结点。元数据交换终结点与其它终结点相似,仍然包含了地址、绑定与契约,但是使用的服务契约为WCF提供的接口IMetadataExchange。

实际上,这两种发布元数据的方式代表了它使用了两种不同的标准协议,前者为HTTP/GET请求,后者为WS-MetadataExchange(MEX)。在WCF,以MetadataExchangeClientMode枚举类型表示这两种元数据交换模式:
public enum MetadataExchangeClientMode
{
   MetadataExchange,
   HttpGet
}

WCF为终结点定义了一个专门的ServiceEndpoint类,被定义在System.ServiceModel.Description命名空间中。ServiceEndpoint类包含了EndpointAddress,Binding,ContractDescription三个类型的属性,分别对应Endpoint的Address,Binding,Contract,如下图:
 wcf08.gif

要获取服务的终结点,可以通过抽象类MetadataImporter获取,类的定义如下:
    public abstract class MetadataImporter
    {
        public abstract Collection<ContractDescription> ImportAllContracts();
        public abstract ServiceEndpointCollection ImportAllEndpoints();
        //其它方法略;
}

在类中,最重要的一个方法是ImportAllEndpoints(),它能够获取服务的所有终结点,并返回一个ServiceEndpointCollection类型的对象。该类型为一个终结点集合,可以通过调用ServiceEndpointCollection的Find()方法或FindAll()方法,找到符合条件的一个或多个终结点。它的定义如下:
    public class ServiceEndpointCollection : Collection<ServiceEndpoint>
    {
        public ServiceEndpoint Find(Type contractType);
        public ServiceEndpoint Find(Uri address);

        public Collection<ServiceEndpoint> FindAll(Type contractType);
        //其它成员略
    }

我们可以通过契约类型,或者服务契约的地址,查找符合条件的终结点。

MetadataImporter类只是一个抽象类,如果要获取WSDL元数据,还会需要使用继承它的子类型WsdlImporter:
    public class WsdlImporter : MetadataImporter
    {
        public WsdlImporter(MetadataSet metadata);

        public Collection<Binding> ImportAllBindings();
        public override Collection<ContractDescription> ImportAllContracts();
        public override ServiceEndpointCollection ImportAllEndpoints();
        public ServiceEndpointCollection ImportEndpoints(Binding wsdlBinding);
        //其它成员略;
    }

如果要使用WsdlImporter,需要为其构造函数传递一个MetadataSet类型的对象。而MetadataSet类型的对象则可以通过MetadataExchangeClient类的GetMetadata()方法获得。MetadataExchangeClient类的定义如下所示:
    public class MetadataExchangeClient
    {
        public MetadataExchangeClient();
        public MetadataExchangeClient(Binding mexBinding);
        public MetadataExchangeClient(EndpointAddress address);
        public MetadataExchangeClient(string endpointConfigurationName);
        public MetadataExchangeClient(Uri address, MetadataExchangeClientMode mode);

        public MetadataSet GetMetadata();
        public MetadataSet GetMetadata(EndpointAddress address);
        public MetadataSet GetMetadata(Uri address, MetadataExchangeClientMode mode);

        //其它方法略;
}

假定服务公开的元数据地址为http://localhost:8001/IMyService?wsdl,则获取服务元数据的方法如下:
string mexAddress = “http://localhost:8001/IMyService?wsdl”;
BasicHttpBinding binding = new BasicHttpBinding();
MetadataExchangeClient mexClient = new MetadataExchangeClient(binding);
MetadataSet metadata = mexClient.GetMetadata(new Uri(mexAddress), MetadataExchangeClientMode.HttpGet);
MetadataImporter importer = new WsdlImporter(metadata);
ServiceEndpointCollection endpoints = importer.ImportAllEndpoints();

注意,如果是HttpGet模式,则元数据地址的后缀必须为?wsdl。由于我们在调用MetadataExchangeClient的GetMetadata()方法时,传递的MetadataExchangeClientMode枚举参数值为HttpGet,因此获取的为基于HTTP-GET的元数据。

如果服务使用的协议为HTTP或者HTTPS,则可能使用元数据交换终结点,也可能为Http-Get模式。此时,我们可以先获取元数据交换终结点,如果没有找到,再获取基于HTTP-GET的终结点:
string mexAddress = “http://localhost:8001/IMyService?wsdl”;
BasicHttpBinding binding = new BasicHttpBinding();
MetadataExchangeClient mexClient = new MetadataExchangeClient(binding);
MetadataSet metadata = mexClient.GetMetadata(new EndpointAddress(mexAddress));
MetadataImporter importer = new WsdlImporter(metadata);
ServiceEndpointCollection endpoints = importer.ImportAllEndpoints();

if (endpoints == null)
{
string httpGetAddress = mexAddress;
if (!mexAddress.EndsWith(“?wsdl”) )
{
    httpGetAddress += “?wsdl”;
}
BasicHttpBinding binding = new BasicHttpBinding();
MetadataExchangeClient mexClient = new MetadataExchangeClient(binding);
MetadataSet metadata = mexClient.GetMetadata(new Uri(mexAddress), MetadataExchangeClientMode.HttpGet);
MetadataImporter importer = new WsdlImporter(metadata);
endpoints = importer.ImportAllEndpoints();
}

在获得ServiceEndpointCollection集合对象后,就可以针对每个ServiceEndpoint获取终结点的Address、Binding、Contract的信息,如下所示:
foreach (ServiceEndpoint endpoint in endpoints)
{
Console.WriteLine(“Endpoint Name is {0}”, endpoint.Name);
Console.WriteLine(“Address is {0}”, endpoint.Address.Uri.AbsoluteUri);
Console.WriteLine(“Binding is {0}”, endpoint.Binding.GetType().ToString());
Console.WriteLine(“Address is {0}”, endpoint.Contract.Name);
Console.WriteLine();
}

通过以上介绍的类,采用相似的途径,还可以获取更多元数据信息,例如服务契约、回调契约、基地址、地址、绑定等信息。

《软件设计精要与模式》出版

访问CSDN读书频道免费阅读样章与下载源代码。
当当网介绍本书的专题:
http://www.dangdang.com/zhuanti2006/4742.shtml

第二书店:http://www.dearbook.com.cn/book/176606
China-Pub:
http://www.china-pub.com/computers/common/info.asp?id=34718
华储网:http://www.huachu.com.cn/itbook/itbookinfo.asp?lbbh=10050146
卓越网:http://www.douban.com/subject/2058073/(通过豆瓣访问)

cover_small.gif

     “给我一个支点,我就能撬起地球”。关键不在于力量有多大,而在于如何合理地利用力量。软件设计同样如此。思想的确立,技巧的把握,将在很大程度上决定软件架构的合理性。基于这样的目的,本书围绕着软件设计的核心内容,结合大量的实例与代码,充分地展示了软件设计之美,以及设计“力量”的巧妙运用。内容涵盖了设计模式、重构、测试驱动开发、极限编程、软件体系架构设计等重要的设计方法与技巧。这些内容是软件设计中最重要的“流行元素”,是程序员向设计师“涅磐”的基石,是从小工到专家的修炼法门。
    本书没有高文大册般的晦涩难懂,却又多了几分一般技术书所没有的温情与雅韵。作者力求从枯燥的技术描述中,带出几分文学作品的情趣出来。谁又规定技术书一定要板着脸孔教训人呢?

内容简介

    本书关注的焦点是软件设计,涵盖了大部分与设计有关的基本要素,包括面向对象编程思想、设计模式、重构、测试驱动开发、极限编程以及软件体系架构设计。其中,尤以设计模式为主,深入探讨了软件设计过程中的原则与模式,并结合大量的实例与代码演示了如何合理运用设计模式,改善程序模块的可复用性、可扩展性,实现模块间的松散耦合。全书将软件设计理论与项目实践完美地结合起来,使其告别了纯理论研究的空泛,具有现实的指导意义。本书共分为5篇,包括:设计之要、.NET Framework与设计模式、媒体播放器的设计之旅、设计模式应用实践以及.NET体系架构设计。
    本书力求讲解浅显明白。在技术探讨上,尽可能地深入透彻;在每一字的描述上,尽可能地简单易懂。本书适用于所有希望提高软件设计水平的程序员、软件工程师,同时,对于软件设计师与系统架构师也具有一定的参考价值。

未经许可,不得以任何方式复制或抄袭本书之部分或全部内容。
版权所有,侵权必究。

出版社:电子工业出版社
作者:张逸
编号:ISBN 978-7-121-03996-6
定价:55.00元(含光盘1张)

样章:   前言   目录    第1章    第2章    第20章

Html Tidy
很多朋友都知道,豆腐最近在项目中遇到了技术上的难题,或者说这个难题在现实生活中本身就是存在的。

比如当对两个html进行比较时, 如何能够正确地向用户提供 友好的比较结果。举一个很简单的例子。
<span>123</span> 和<div>123</div> 在html source 层面是完全不同的字符串,但是对于用户体验来说,这两个字符串是一致的。 再比如
<ul><li>First</li><li>Second</li></ul> 和 <li>First</li><li>Second</li> 在显示的时候是完全一致,但是html 确差了很多。 我们可以从技术上向用户解释说, 他们本来就是不一样的,但是这样会吓跑我们的用户。

我想了很多办法来解决这个问题,解决方案就是建立一个可配置的配置表, 通过反射建立起一套规则,当出现比较结果和human 体验不一致的时候,就利用这套逻辑进行修正,但是这样的问题就是 头疼医疼 脚疼医脚 ,总是滞后于用户发现问题,就和IE 的补丁一样,虽然可以解决问题,但是永远都是再发现问题以后才去解决。

终于有一点,痛下决心,在根子上解决这个问题。 解决这个问题的关键,就是在相同的用户体验的前提下,尽量的将数据源修正为同等比较, 这样的唯一解决方案就是XHTML 了,下一步的问题是,如何进行修正,这个可不是一个小问题。 直道有一天一个很偶然的机会,发现了W3C组织提供的Open Source  的项目Html Tidy,

这个Html Tidy 可以帮助我们 对html 字符串进行修正,并做标准化的处理。详细的关于Html Tidy 的信息,大家可以去这个站点, 我也会在后续的Post 中做详细的介绍。

如果大家也有兴趣的话,我们可以一起来研究和探讨。 谢谢。
如何进行UnitTest
最近在我们的项目中,进行了一次如何进行Test 的大讨论。
 大家都知道,Test 分为UnitTest 和 Function Test, 关于Function Test, 我们大家都没有歧义, 认为现阶段使用WatiN 的自动化测试已经能够满足项目的基本需要, 大家的分歧主要就在于如何进行Unit Test.
很显然,Unit Test是在测试我们的项目的最小单元, 但是问题是在一个 Data Driven 的项目中, 很多的最小单元都会使用到数据库访问,于是 Unit Test 是否需要Touch DB 就成为了这次讨论的核心问题。 我们主要有两种观点
1. 数据库测试也是我们必要的测试一部分 ,因此我们有必要在Unit Test中对物理的数据库访问的函数进行测试。
2.我们的测试并不希望去访问数据库,因为我们的Unit Test的测试用例将近 上千, 这样在每次check in 之后, 运行所有的Unit Test 就会不现实

持第一种观点的同学认为,既然我们有Daily Build的策略,我们不需要每次的 check in 都触发Unit Test的case, 在daily build 中一起运行Unit Test, Coverage Test 和Function Test,将测试报表发到大家的信箱就可以了。
持第二种观点的同学认为,Unit Test是保证代码质量的最低要求,因此需要明每次Check In 都触发Unit Test 并且Unit Test 应该是没有执行次序的, 如果涉及到数据库访问,则必须需要复杂的 Build Script 以保证Unit Test的执行次序。

经过差不多一周的lunch discussion 我们基本上同意使用第二种方案。

但是第二种方案会带来一些新的挑战,如果进行Unit Test ,那些碰到数据库访问的方法, 或者要调用数据库访问的方法和类该如何测试?
在这里,我提出的解决方案是使用NMock 这个Open Source  的项目。
下面简单介绍一下这个 项目, 你可以在http://nmock.org/ 这个地址看到关于这个项目的详细介绍, 我举一个非常简单的例子。
我们的项目一般都会分为 数据层, 业务层和 展现层。
一个典型的数据层是这样的

namespace Q4.Core.Datalayer.Interface
{
    public interface IUser
    {
        int UserId { get;set;}
        string UserName { get;set;}
        string FirstName { get;set;}
        string LastName { get;set;}
    }
}
namespace Q4.Core.Datalayer
{
    public class User : IUser
    {
   }
}

典型的业务逻辑层,我们一般会添加用户访问的处理逻辑。
namespace Q4.DataAdapter.Interface
{
    public interface IUserEntity
    {
        bool AddUser(string userName, string firstName, string lastName);
    }
}
namespace Q4.DataAdapter
{
    public class UserEntity :IDisposable,Interface.IUserEntity
    {
        private SqlConnection _conn;
        private string _connectionString;

        private static UserEntity _instance;

        public static UserEntity Instance()
        {
            string connectionString = "";
            _instance = new UserEntity(connectionString);
            return _instance;
        }


        private UserEntity(string connectionString)
        {
            _connectionString = connectionString;
            _conn = new SqlConnection(connectionString);
        }

       
        #region IDisposable Members

        public void Dispose()
        {
            if (_conn != null)
            {
                _conn.Dispose();
            }
        }


        #endregion

       

        #region IUserEntity Members

        public bool AddUser(string userName, string firstName, string lastName)
        {
            string sqlFormat = "INSERT INTO [MockUser]([UserName],[FirstName],[LastName])VALUES('{0}','{1}','{2}')";
            string sql = string.Format(sqlFormat, userName, firstName, lastName);

            using (SqlCommand cmd = new SqlCommand(sql))
            {
                cmd.Connection = _conn;
                cmd.ExecuteNonQuery();
            }

            return true;
        }

        #endregion
    }
}

在这一层的下面,我们会根据MVC  的架构再相应的搭建起来Controller 和 View. 这个我就不再浪费 大家的时间了。

如果我们希望在Controller中测试 AddUser 成功后, 我们希望将这个用户再添加到对应的用户组中,如果我们使用Mockup Object  的话,代码就类似于这样

namespace Q4.UnitTest
{
    [TestFixture]
    public class MockupTest
    {
        [Test]
        public void TestAddUser()
        {
            Mockery mocks = new Mockery();
            Q4.DataAdapter.Interface.IUserEntity userService = mocks.NewMock<Q4.DataAdapter.Interface.IUserEntity>();
            Expect.Once
                .On(userService)
                .Method("AddUser")
                .With("doufu@hotmail.com", "boke","Tang")
                .Will(Return.Value(true));

          Q4.DataAdapter.Interface.IUserEntity groupService = mocks.NewMock<Q4.DataAdapter.Interface.IGroupEntity>();
            Expect.Once
                .On(userService)
                .Method("AddUserToGroup")
                .With("doufu@hotmail.com", "Admin")
                .Will(Return.Value(true));

            bool bRet=userService.AddUser("robertx@q4websystems.com", "Robert", "Xue");
           if(bRet)
          {
                  bRet=groupService.AddUserToGroup("doufu@hotmail.com","Admin");
           }
        }
    }
}

当然实际的项目中, 测试的代码不会这么简单,我们需要利用Hashtable 建立起一套内存中的数据结构 供 Unit Test 来调用。不过 我相信再引入NMock 以后, 对于Data Driven 的项目进行Unit Test可以提供一种有益的思路。


欢迎大家跟贴和我一起继续探讨。谢谢。
SQL2005的SQL Server Management Studio对大数据库操作超时解决方法

SQL2005 中,我们使用 SQL Server Management Studio对大数据库操作,不象 SQL2000 的企业管理器那样,作一些大数据库的修改操作时候,不会超时。

如何解决呢? 很简单,在SQL Server Management Studio的 Tool --〉 Options 菜单设置即可。

需要设置的项如下:

配置数据库的超时

“为表设计器更新重写连接字符串的超时值”这个选项必须选中。

同时设置事务超时时间为最大值 即 65535 秒

这个事务设置的范围只能是1到65535 ,不能是0,也不能更大。

Excel 2007 的重大bug

在水木上看到的,Excel 2007在公式计算中有一个超级弱智的大bug:

计算乘法时,当计算结果等于65535,且两个乘数中有一个是小数时,有些时候结果会变成100000……

image

真是不知道产品组是怎么搞的。。。这种毫无理由的bug。。。

想当年似乎有一种计算器还是计算芯片,当计算两个特定的数相乘的时候,结果是错的

Windows Server 2008 RC0今日发布

[原文地址] Windows Server 2008 RC0 released today

[原文发表时间] Tuesday, September 25, 2007 7:10 PM

 

我们今天发布了包括Internet Information Services 7.0在内的Windows Server 2008 Release Candidate 0


这对于IIS来说是一个很大的进步。已经有超过1200个客户签署了IIS7 Beta 2实时协议,并且还有14台主机正部署在IIS7上。在这里可以看到一些客户的故事。

 

另外,Windows Media Services 2008 RC0也在今天提供下载了。它提供了两倍于Windows Media Services 8.0的可扩展性,而且它还支持服务器核心的安装,这大大减少了实现一个固定功能的流服务器的步骤,并可以用作Silverlight视频流的后端。

像你们一样,我也正在热切盼望着我们发布Windows Server 2008——正如我之前日志里提到的,我们计划在明年二月份推出Windows Server 2008, SQL Server 2008Visual Studio 2008.

Namaste!

LINQ 菜谱, 菜单1: 改变Windows 窗体上所有标签的字体

[原文作者]: Kit George

[原文链接]: LINQ Cookbook, Recipe 1: Change the font for all labels on a windows form

 

  我们打算启动一个LINQ 菜谱项目,并逐步将它完成。这个项目的目的是为你在编程和用查询时遇到的一些特殊情况提供解决的方案。我再也想不出一个更好的方式,来关联你能利用LINQ所做的每件事情了。

 

  这个系列项目主要是为您展示LINQ可以做到的各式各样的事情。像任何一本好菜谱一样,我们将为这本菜谱做分类, 那样你之后就可以很容易地查询。 但是不要希望一个特定的 菜谱 会有大量的描述,尽管它会包含重现步骤。请尽管向我们要求任何你想要看到的菜谱,而我们将尽可能多地创造新的。

 

材料:

   -      Visual Studio 2008 (Beta2 或更高版本)

 

类别:

       -       LINQ-To-ObjectsLINQ with Windows FormsLINQ with controls Label

 

制作方法:

-      打开 Visual Studio 2008,点击文件/新建项目 找到并双击Windows窗体应用程序 图标。

-      增加窗体的大小,使其足够容纳一定数量的控件。

-      从工具箱中拖放几个控件到窗体上,确保至少添加3-4个标签控件。

o    我个人比较喜欢的是两个分组控件(GroupBox) 在文本框(TextBox)前放两个标签(Label)(标签在分组控件之上) 并在每个分组控件中放一对单选框(RadioButton)控件。 这样可以确保测试递归代码。

-       添加一个按钮到窗体上并把它的Text属性改为Go 双击这个按钮, 然后修改 事件处理 代码并添加下面的方法:

 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        For Each label In GetLabels(Me)

            label.Font = New Font("Comic Sans MS", 12, _

                                  FontStyle.Bold Or FontStyle.Underline)

        Next

    End Sub

 

    Private Function GetLabels(ByVal sourceControl As Control) _

                               As IEnumerable(Of Control)

        If sourceControl.Controls.Count > 0 Then

            Dim labels = From cont As Control In sourceControl.Controls _

                         Where TypeOf cont Is Label _

                         Select cont

 

            For Each c As Control In sourceControl.Controls

                labels = labels.Union(GetLabels(c))

            Next

 

            Return labels

        End If

 

        Return New List(Of Control)

    End Function

 

-     修改 New Font 所在的那行代码为你想要的字体样式。

新工具:表单/Cookie 验证网站爬网设置工具

在今年3月份的blog里面,我曾经说过SharePoint Team将会发布一个补丁来让SharePoint Server 2007的搜索引擎支持对基于表单/Cookie验证的网站进行爬网。今天,SharePoint Team正式发布了SharePoint Server 2007 Tool: Add/Edit Crawl Rules with Form/Cookie Credentials。在下载页的说明中有使用方法的介绍。

舵鸟心态

最近股市很火,但我与太太比较担心风险,所以没有敢投入股市,但还是炒了一些基金(股票型)。前段时间大涨,我太太每天回家第一件事情,就是上网查看每天的收益,然后美美的幻想一下,我们的投入大约多久以后很翻一番。前段时间股市有些波折,结果有几天我发现她根本不再查基金的事情了。于是便好奇的询问她,原来她已经知道当天股市跌了,所以基金肯定也跟跌,为了避免影响心情,所以就压根不去看到底跌了多少。

我听到她的表述之后,第一时间便想到了那只大家所熟悉的舵鸟。在风沙等其它威胁来临的时候,别的动物都在狂奔逃命,而舵鸟却把它一向高昂的头颅直接埋入沙中,对即将到来的风险视而不见,一向“我思故我在”的派头。

其实很显然,虽然我太太与舵鸟的表现一样,但动机完全不同(或者说与寓言中的舵鸟动机不同)。因为股市有跌就有涨,没有必要为了一时的跌而影响自己的心情,从而连带一天的快乐心情,所以不看也罢,毕竟我们是做长线投资的。而舵鸟的动机则就完全不同,或者它那头颅再也无法从沙中伸出来,在风沙过后,成为一个永远的雕朔,为人类提供各种警示。

突然想到,其实在IT界也有这种舵鸟心态。技术发展日益月益,但很多公司为了生存,根本没有时间来去考虑新技术,而是想当然得使用自己原有的、已经习惯的技术去进行开发。而做决策的技术人员也往往对于新技术进行潜意识的抗拒。毕竟再简单的技术,也有一定的学习成本,而且有很大的决策风险。微软的合作伙伴当中,也有很多从2002年或者晚的时候,开始接触.NET,但一直使用的是1.0,对于后续版本的改进一直没有任何概念。其实原因很简单:公司在为了“生存”而努力,根本不可能让员工们抽出时间来学习新技术。即使员工们有兴趣,在7*24的连轴工作后也不可能再有精力了。

微软除了产品组外,还在全球设置了几个研究院,用以对未来技术的研究。虽然国内大部分ISV的人员有限,不可能单独设置研究院类似的机构(当然,微软研究院的作用也不是我们将要说的那样),但是仍然可以从产品组当中,专门抽出一个人,来负责跟踪业界各厂商的新技术,在他们学习成熟后,再在企业内部进行成果转化,将这些技术转移给内部其它产品组,从而让新技术转化为生产力。

此职位除了负责以上工作,还会负责新技术的对比,业界各厂商往往推出各种同质的产品,每家都有自己的优势宣传。所以这个职位的人员最好不是某个技术的狂热者。不然很有可能有失偏颇。

另外,该职位由于还具有在内部传授知识的功能,所以最好是由性格比较外向型的人士担任,并且需要一定的口才,如果只是技术好,但实际上学会了无法讲出来,那么学习技能再强对于公司的整体策略也没有什么用处。

以上是我关于“舵鸟心态”的个人想法,欢迎大家讨论。顺祝博客堂网友中秋快乐,送各位一个使用Silverlight创作的中秋节贺卡(李超创作):

http://www.nxmix.com/LetThereBeLight/Default.aspx

PowerShell的Cmdlet的生存周期和执行顺序

认清了Cmdlet的生存周期和执行的顺序对于我们后续的开发和使用有相当重要的意义,因为它直接决定了到时候该怎么开发,能实现哪些功能(比如说一直需要运行的程序,就不适合用Cmdlet来完成)。

先让我们看一下Cmdlet的生存周期:

   1:   [Cmdlet(VerbsCommon.Add, "Test")] 
   2:      public class AddTest: Cmdlet
   3:      {
   4:   
   5:          protected override void BeginProcessing()
   6:          {
   7:              WriteObject("BeginProcessing");
   8:          }
   9:   
  10:          protected override void ProcessRecord()
  11:          {
  12:              WriteObject("ProcessRecord");
  13:              base.ProcessRecord();
  14:          }
  15:   
  16:          protected override void EndProcessing()
  17:          {
  18:              WriteObject("EndProcessing");
  19:              base.EndProcessing();
  20:          }
  21:   
  22:          protected override void StopProcessing()
  23:          {
  24:              WriteObject("StopProcessing");
  25:              base.StopProcessing();
  26:          }
  27:   
  28:      }
我们可以发现,结果是:

BeginProcessing
ProcessRecord
EndProcessing

基本上和我们猜测的一样的,初始化,执行,完成

可以判断StopProcessing这是在Cmdlet被中止的时候才会触发的。

再让我们看一下Cmdlet的生存周期:

   1:      public class TaskManager
   2:      {
   3:          private static int runCount = 0;
   4:          public static int Run()
   5:          { 
   6:              return runCount ++;
   7:          }
   8:      }
 
   1:      [Cmdlet(VerbsCommon.Add, "Test")] 
   2:      public class AddTest: Cmdlet
   3:      {
   4:          protected override void ProcessRecord()
   5:          {
   6:              WriteObject(TaskManager.Run());
   7:              base.ProcessRecord();
   8:          }
   9:      }
运行这个Cmdlet,多次运行,以及关掉PS后,重新加载后执行的情况来看,我们可以看出:Cmdlet所在程序集从Add-PSSnapIn加载到PowerShell里后,也就是这个DLL被启动起来了,直到这个PowerShell被关掉,完成它的一个生命周期.也就是说,在这运行过程中,我们可以把很多数据记录在静态成员里面,比如说运行的记录等.
Halo主题版本的Tafiti

[原文地址] Halo-themed version of Tafiti

[原文发表时间]  Friday, September 21, 2007 4:59 PM

 

今天我们发布了Tafiti 特别主题版本来庆祝Halo3 的发布。

 

Tafiti是一个带有实验性质的搜索网站的前端,它可以帮助我们进行Web搜索相关的研究项目查询可以跨越多个搜索条件和会话,并且它能够将搜索结果可视化,还支持对搜索结果的存储和分享。Tafiti同时使用了微软的SilverlightLive Search技术,对更丰富的Web用户交互体验以及搜索功能的专业化进行了很好的探索。别忘了点击“Tree View”链接看看效果。

 

这个简洁的例子展示了Silverlight能以怎样全新和有趣的方式呈现数据。这个Tafiti新版本增加一部分功能,就是提供了一个特殊的Halo的搜索宏,它能够搜索到游戏相关的一系列网站。

 

Namaste!

 

从HTTP状态 301,302,200 来看页面跳转

301和302 Http状态有啥区别?

301,302 都是HTTP状态的编码,都代表着某个URL发生了转移,不同之处在于:

301 redirect: 301 代表永久性转移(Permanently Moved),

302 redirect: 302 代表暂时性转移(Temporarily Moved ),

当然 Http 状态 200 标示没有任何问题发生。

 

这两种转移在使用的时候有啥好处或者问题?

301 重定向是网页更改地址后对搜索引擎友好的最好方法,只要不是暂时搬移的情况,都建议使用301来做转址。

302 重定向是临时性转移。

在前些年,不少Black Hat SEO曾广泛应用这项技术作弊,目前,各大主要搜索引擎均加强了打击力度,象Google前些年对Business.com以及近来对BMW德国网站的惩罚。即使网站客观上不是spam,也很容易被搜寻引擎容易误判为spam而遭到惩罚。

研究搜索引擎优化(SEO)的人,应该都知道,301,302 使用不当,或者灵活使用会有不错的效果的,比如参看下面文章: