‘ .NET开发 ’ category archive

扩展方法使用小结

325 views 九月 28, 09 by Timothy

随着.Net Framework一路走来,已经让广大开发人员体验到快速开发的甜头,这得益于.Net Framework为我们提供了更高层次的封装,开发人员不必关心底层的Win32 API及其繁琐的调用参数,而可以把大部分的经历放在对业务的分析和实现。随着.Net的不断革新,也引入了更多的特性,例如C# 2.0,就增加了匿名方法和迭代器,这些特性让我们的编码效率更高。随着C# 3.0的推出,引入了更多的新特性,包括:隐式类型局部变量、对象初始化器、Lambda表达式、扩展方法、匿名类型。

而这些特性,都为LINQ的推出,构建好了基础。其中一个比较不错的特性,就是扩展方法。扩展方法,顾名思义,就是在类型定义完成之后,再继续为其添加新的方法。这是相当方便的,比如对于一个已经封装好的Assembly来说,我们不用改动Assembly的代码,而通过扩展方法就能实现对其功能的扩展,而且在调用的时候,仅仅通过代码,你几乎判断不出这是扩展方法,还是Assembly本身的方法。

扩展方法在.Net 3.5中的应用也是非常普遍的,如果你仔细观察,就会发现我们常用的Linq to Object中的Where,Select,Average,Sum等方法,以及Linq to SQL中的Where,Select,Average,Sum等方法,其实都是扩展方法,他们分别定义于System.Linq.Enumerable类和System.Linq.Queryable类之中。

就扩展方法本身而言,也存在一些限制之处。对于编译器来说,如果扩展方法和被扩展类型的方法发生冲突的时候,在调用此方法的时候,究竟是调用被扩展类型的方法,还是扩展方法呢?通过一个例子,我们就能发现其中的区别。

   1:    class Program
   2:      {
   3:          static void Main(string[] args)
   4:          {
   5:              new TestClassA().Display("Test");
   6:              new TestClassB().Display("Test");
   7:              Console.ReadLine();
   8:          }
   9:      }
  10:  
  11:      class TestClassA
  12:      {
  13:          public void Display(int b)
  14:          {
  15:              Console.WriteLine("This is TestClassA.Display() ...");
  16:          }
  17:      }
  18:  
  19:      class TestClassB
  20:      {
  21:          public void Display(string s)
  22:          {
  23:              Console.WriteLine("This is TestClassB.Display() ...");
  24:          }
  25:      }
  26:  
  27:      static class TestClassExtention
  28:      {
  29:          static public void Display(this object o, string s)
  30:          {
  31:              Console.WriteLine("This is TestClassExtention.Display() ...");
  32:          }
  33:      }

程序输出:

ExtentionMethod

可以看出,TestClassA的方法和扩展方法并没有冲突,因为他们的方法签名是不一样的,而TestClassB的方法和扩展方法有冲突,因为他们的都是接受一个string类型的输入参数。从结果可以看到,程序对Display的方法调用,TestClassB本身的Display方法,要“优先”于扩展方法Display被调用。因此,类本身的方法如果满足调用条件,那么这个方法会被优先执行,只有在类当中无法找到同样参数的方法时,扩展方法才有机会被执行。所以,我们可以得出这样的结论:扩展方法的优先级较低,也即扩展方法不会覆盖同名的类本身的方法。

另外,还有一个比较明显的区别,就是扩展方法要远远弱于类本身的方法,比如,在一个类中,类的方法可以访问自己的非公有成员,而扩展方法做不到这一点。

IIS7中Host WCF遇到的问题

366 views 九月 03, 09 by Timothy

最近重装了系统,用上了Windows 7,在IIS7中Host WCF Service的时候,遇到一个比较奇怪的问题,当在站点下面添加应用,指向WCF的目录后,访问.svc文件,浏览器提示以下错误:

 

The page you are requesting cannot be served because of the extension configuration.
If the page is a script, add a handler. If the file should be downloaded, add a MIME map. 

 

这种错误应该是.svc文件没有映射到相关的handler上,因此IIS不知道怎么处理该请求。带着错误信息,在网上搜索了一把,终于找到了解决方法,看来搜索引擎很强大。

解决方法如下:

1.用管理员身份运行cmd命令行

2.切换到目录C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation

3.运行命令: servicemodelreg –i

这样,工具会自动把WCF相关的注册项安装到IIS7中,再打开浏览器访问WCF Service,一切正常。

细想了一下自己的装机过程,先装了VSTS和.net framework,后来发现IIS7没有在windows7里面默认安装,要到部署WCF的时候,才装好IIS7。这样在安装.net framework 3.0的时候,因为没有安装IIS7,所以一些注册项就没有起到作用。此方法可以将WCF的配置项重新配置到IIS7中,供同学们参考。

C# IDE Mobile – Write your C# code anywhere!

415 views 五月 29, 09 by Timothy

最近败了个QWERTY全键盘的HTC Touch pro,全键盘的感觉不错,输入速度比以前靠触摸笔点屏幕快多了。装了个Python的Windows mobile版本,没事学着写Python玩玩。一日突发奇想,要是能在PPC手机上写C#的程序并能运行起来,那就太棒了。果然不出我所料,国外已经有大侠已经做好了这个东东,一个运行在Windows Mobile手机上的简单的C# IDE,让你可以随时在你的PPC手机上写C#的程序。这是作者自己实现的一个简单IDE,现在已经支持的功能如下:

* 可以创建基于图形用户界面的程序

* 可创建方法和类

* 可以调用所有的.NET Compact Framework的类。

* 执行文件操作

* 运行进程

* 使用.NET 2.0中的范型

* 支持C#的控制语句,包括循环、条件判断……

IDE的使用非常简单,写入你的代码,然后可以立即运行,看到结果。

简单的例子,如下:

   1:  using System.Windows.Forms;
   2:  namespace TestNS
   3:  {
   4:      class TestCL
   5:      {
   6:         public static void Main()
   7:         {
   8:              MessageBox.Show("Hello Timothy!");
   9:         }
  10:      }
  11:  }

 

点击菜单下面的Debug->Run,运行结果截图如下:

1

 

IDE自带一些简单的功能, 包括插入代码模板,编辑(复制、粘贴、剪切)功能,还支持插件功能。

2

 

软件下载地址: http://www.geocities.com/hrowson/wm5_software/cs_ide_mobile.zip

Code Sample: http://www.geocities.com/hrowson/wm5_software/cs_ide_mobile_samples.zip

用户手册、帮助文档地址: http://www.geocities.com/hrowson/wm5_software/cs_ide_mobile_manual/index.htm

作者主页:http://www.geocities.com/hrowson/wm5_software/index.htm

赶紧下载吧,write your C# code anywhere! 活活~~

Unity 学习笔记(3) — 生命周期管理

426 views 四月 28, 09 by Timothy

Unity根据我们在注册类型的时候所指定的生命周期来管理注册类型的创建和解析。当我们在向容器中注册类型的时候,如果我们没有显式的指明该类型的生命周期管理器(下称:Lifetime Manager),默认的情况下,容器会为我们注册的类型创建一个生命周期短暂的管理器。这样一来,当我们每次调用容器的Resolve方法或者ResolveAll方法,或者采用依赖机制注入实例到其他的类中的时候,容器都会为我们创建新的实例,并且容器不会保存对实例的引用。

容器的RegisterType函数包含多个支持泛型的重载,同时还包含了一一对应的非泛型重载。其中的重载函数,我们可以看到类似下面的声明:

   1:  RegisterType(LifetimeManager lifetime)

参数中的LifetimeManager类型,就是用来控制注册类型生命周期的。Unity中提供了几个继承自LifetimeManager的类作为注册类型的生命周期管理器。在目前的Unity 1.2版本中,共提供了3个LifetimeManager供我们直接在代码中调用。此外,我们也可以实现自己的LifetimeManager,不过必须实现LifetimeManager所必须的一些方法。

1.ContainerControlledLifetimeManager:

容器负责管理注册类型的生命周期,并且注册类型的生命周期和容器一致。当离开容器的作用域范围时,容器会被销毁,同时其中的注册类型也会被销毁。或者,当容器被显式销毁时,其中的注册类型也同样被销毁。但是在容器有效的作用域范围中,当我们使用Resolve方法,或者使用ResolveAll方法获取我们的注册类型的时候,容器会在第一次调用时,创建实例,但是在后面的调用中,我们始终只会得到相同的实例。我们可以利用这种Manager来实现Singleton模式。

2.ExternallyControlledLifetimeManager:

和上一种方式类似,不过容器在不会保留对注册类型的强引用,而只是保留弱引用。也就是说,如果这个注册类型没有在其他地方被强引用的时候,那么这个注册类型可能会被GC给干掉。

3.PerThreadLifetimeManager:

容器保证在每个线程中返回同一个对象实例,那么在不同的线程中,得到的实例是不同的。

下面我们可以试验一下不同的LifetimeManager的效果

a. 默认的情况,不显示的指明LifetimeManager

代码:

   1:  namespace UnityDemo
   2:  {
   3:      class Program
   4:      {
   5:          static void Main(string[] args)
   6:          {
   7:              IUnityContainer container = new UnityContainer();
   8:              container.RegisterType();
   9:  
  10:              INotify notify1 = container.Resolve();
  11:  
  12:              INotify notify2 = container.Resolve();
  13:  
  14:              Console.WriteLine("notify1:" + notify1.GetHashCode());
  15:              Console.WriteLine("notify2:" + notify2.GetHashCode());
  16:  
  17:              Console.ReadLine();
  18:          }
  19:      }
  20:  }

运行结果:

4

从结果我们可以看到,默认情况下不指定LifetimeManager的时候,每次我们获得的Instance其实不是同一个Instance.

b.使用ContainerControlledLifetimeManager

代码:

   1:  namespace UnityDemo
   2:  {
   3:      class Program
   4:      {
   5:          static void Main(string[] args)
   6:          {
   7:              IUnityContainer container = new UnityContainer();
   8:              container.RegisterType(new ContainerControlledLifetimeManager());
   9:  
  10:              INotify notify1 = container.Resolve();
  11:  
  12:              INotify notify2 = container.Resolve();
  13:  
  14:              Console.WriteLine("notify1:" + notify1.GetHashCode());
  15:              Console.WriteLine("notify2:" + notify2.GetHashCode());
  16:  
  17:              Console.ReadLine();
  18:          }
  19:      }
  20:  }

运行结果:

5
使用ContainerControlledLifetimeManager,在Container生命中期内,我们得到的Instance是同一个。

c.使用PerThreadLifetimeManager

代码:

   1:  namespace UnityDemo
   2:  {
   3:      class Program
   4:      {
   5:          static void Main(string[] args)
   6:          {
   7:              IUnityContainer container = new UnityContainer();
   8:              container.RegisterType(new PerThreadLifetimeManager());
   9:  
  10:              Thread thread1 = new Thread(new ParameterizedThreadStart(ThreadProc1));
  11:              Thread thread2 = new Thread(new ParameterizedThreadStart(ThreadProc2));
  12:  
  13:              thread1.Start(container);
  14:              thread2.Start(container);
  15:  
  16:              Console.ReadLine();
  17:          }
  18:  
  19:          static void ThreadProc1(object obj)
  20:          {
  21:              INotify notify1 = (obj as IUnityContainer).Resolve();
  22:              INotify notify2 = (obj as IUnityContainer).Resolve();
  23:  
  24:              Console.WriteLine("ThreadProc1 --- notify1:" + notify1.GetHashCode());
  25:              Console.WriteLine("ThreadProc1 --- notify2:" + notify2.GetHashCode());
  26:  
  27:          }
  28:  
  29:          static void ThreadProc2(object obj)
  30:          {
  31:              INotify notify1 = (obj as IUnityContainer).Resolve();
  32:              INotify notify2 = (obj as IUnityContainer).Resolve();
  33:  
  34:              Console.WriteLine("ThreadProc2 --- notify1:" + notify1.GetHashCode());
  35:              Console.WriteLine("ThreadProc2 --- notify2:" + notify2.GetHashCode());
  36:          }
  37:      }
  38:  }
运行结果:
6
 在结果中可以看到,同一个线程中连续两次获取到的是同一个Instance,而不同的线程中获取到的Instance不一样。

Unity 学习笔记(2) — 配置文件的使用

775 views 四月 25, 09 by Timothy

在Unity的配置中,使用配置文件也是一种非常灵活的方式,毕竟能够通过修改配置文件的文本就能达到改动的目的,而不需要对源码进行改动、重新编译。使用配置文件对Unity进行配置,需要增加两个程序集的引用:System.Configuration和Microsoft.Practices.Unity.Configration,并且在代码中用相应的两个命名空间:

   1:  using System.Configuration;
   2:  using Microsoft.Practices.Unity.Configuration;

此外,需要修改应用程序的配置文件:

在configSections节点中,加入Unity的section配置信息


...
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<configSections>
...

type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

其中name是section的名称,type就是处理该section的程序类型,Unity提供了UnityConfigurationSection,负责处理配置文件信息,它包含在程序集Microsoft.Practices.Unity.Configuration中

接下来,需要在configuration节点中增加Unity配置节点,格式如下:

   1:  
   2:      
   3:        "" type="" />
   4:      
   5:      
   6:        
   7:           
   8:             "" mapTo="" />
   9:           
  10:           
  11:             "" type="" value="" />
  12:           
  13:        
  14:      
  16:  

unity的子元素,包含节点大致如上,其宗typeAliases是type别名,能够简化下面types中type的配置。containers节点中可以包含多个container的配置。container主要包含的子元素有types元素,instance元素,types元素可以包含多个type元素,用以添加注册类型,instance主要用来添加实例到容器中。type元素,主要包含四个属性:

name:表示注册类型的名称,此属性在配置中可选。

type:注册的源类型

mapto:注册的目标类型

lifetime:设置注册类型的生命周期

此外,还有instances元素,包括name,type,value,typeConverter四个属性。value表示注册实例的初始值,typeConverter是用以转换提供的值到实例的匹配类型的类型转换器。

具体的元素含义,可以参考Unity的帮助文档。

下面我们还是采用Monitor的例子,来实现用配置文件注册类型,配置文件示例:

   1:  "1.0" encoding="utf-8" ?>
   2:  
   3:    
   4:  
"unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
   5:    
   6:  
   7:    
   8:      
   9:        
  10:          
  11:            "UnityDemo.IMonitor,UnityDemo" mapTo="UnityDemo.Monitor,UnityDemo" />
  12:            "UnityDemo.INotify,UnityDemo" mapTo="UnityDemo.EmailNotify,UnityDemo" />
  13:          
  14:        
  15:      
  16:    
  17:  
  18:  

程序代码修改如下:

   1:  using System;
   2:  
   3:  using Microsoft.Practices.Unity;
   4:  using Microsoft.Practices.Unity.Configuration;
   5:  using System.Configuration;
   6:  
   7:  namespace UnityDemo
   8:  {
   9:      class Program
  10:      {
  11:          static void Main(string[] args)
  12:          {
  13:              IUnityContainer container = new UnityContainer();
  14:              UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
  15:              section.Containers.Default.Configure(container);
  16:  
  17:              IMonitor monitor = container.Resolve();
  18:              monitor.Alarm();
  19:  
  20:              Console.ReadLine();
  21:          }
  22:      }
  23:  }

编译运行结果:

使用配置文件,还有许多方便的地方,比如对于程序的扩展而言,新增的模块不再需要修改已编译好的程序,而只需要修改配置文件就可以方便的实现新模块的注册,对于系统的稳定性和可维护性都非常有好处。

Unity 学习笔记(1) — Unity简介及简单使用

556 views 四月 23, 09 by Timothy

Unity是微软Patterns & Practices团队所开发的一个轻量级的,并且可扩展的依赖注入(Dependency Injection)容器,它支持常用的三种依赖注入方式:构造器注入(Constructor Injection)、属性注入(Property Injection),以及方法调用注入(Method Call Injection).现在Unity最新的版本的1.2版,可以在微软的开源站点http://unity.codeplex.com下载最新的发布版本和文档。通过使用Unity,我们能轻松构建松耦合结构的程序,从而让整个程序框架变得清晰和易于维护。

在平常的软件编码过程中,程序的逻辑往往很复杂,尤其是大型项目的开发中,一个模块常常会去引用其他的模块,假设我们有一个监控器类,用来监控CPU的温度,当温度达到预警的范围时,监控器有一个报警的方法,方法里面通过短信提醒器,以发送短信的方式通知维护人员。于是就出现了下面这样一段最为常见的代码:

   1:  public class Monitor
   2:  {
   3:         public void Alarm()
   4:         {
   5:                 SMSNotify notify = new SMSNotify();
   6:                 notify.Send();
   7:          }
   8:  }

在Monitor类中,直接引用到了一个短信提醒器的类,这是最为不灵活和最不易于扩展的一种方式。或许我们想到了面向接口编程,利用多态的好处,可以提供灵活的不同子类的实现,增加代码扩展性等等。但是说到底,接口一定是需要实现的,也就是如下语句迟早要执行:

   1:  public void Alarm()
   2:  {
   3:         INotify notify = new SMSNotify();
   4:         notify.Send();
   5:  }

这样看来,在实现INotify这个接口的时候,仍然需要具体的类来实现,而这样的代码在程序编译的时候就已经固定下来,如果以后需要使用新的提醒器,仍旧需要修改源代码并重新编译。并且在我们的Monitor类中,明显依赖SMSNotify类,二者之间的耦合度非常紧密。因此Ioc(控制反转)模式被提出用来解决这种问题,也即把接口的具体实现延缓到运行时,接口的实现类是在运行时被装载的。这样,就算有了新的实现类,也不需要更改调用者的代码(可以在Unity中使用配置文件的方式实现)。这种Ioc模式可以被形象的比喻为:接口就像一个空壳,而在具体实现时,向这个空壳注入内容,而让它成为一个真正的实体。这种模式也被形象的称为:依赖注入。通过使用Unity,我们能构建松耦合的软件,并且对象之间相互关联的细节,我们也不必关心,可以交由依赖注入容器全权负责。

前面也提到了依赖注入常用的三种形式:构造器注入、属性注入和方法调用注入,我们可以通过例子来实现这三种形式的注入。还是以上面的场景为例,我们的几个类和接口如下图:

1

1.Constructor Injection

IMonitor接口定义:

   1:  public interface IMonitor
   2:  {
   3:      void Alarm();
   4:  }

Monitor类:

   1:  public class Monitor : IMonitor
   2:  {
   3:      private INotify notify;
   4:  
   5:      public Monitor(INotify n)
   6:      {
   7:          notify = n;
   8:      }
   9:  
  10:      public void Alarm()
  11:      {
  12:          notify.Send();
  13:      }
  14:  }

INotify接口定义:

   1:  public interface INotify
   2:  {
   3:      void Send();
   4:  }

EmailNotify类:

   1:  public class EmailNotify : INotify
   2:  {
   3:      public void Send()
   4:      {
   5:          Console.WriteLine("Send Email Notify...");
   6:      }
   7:  }

SMSNotify类:

   1:  public class SMSNotify : INotify
   2:  {
   3:      public void Send()
   4:      {
   5:          Console.WriteLine("Send SMS Notify...");
   6:      }
   7:  }

可以看到,在Monitor类的构造函数里面,传入的参数是一个INotify接口类型,Alarm方法,调用了实现类的Send方法,但具体调用哪一个实现类的Send方法,只有在注入实体后才知道。Unity容器中,通常使用RegisterType和Resolve方法来分别注册和获取实例,并且这两个方法有很多泛型和非泛型的重载,具体的类型和参数,可以参考Unity的官方帮助文档。

现在我们向Monitor的构造函数注入实现INotify接口的实例:

   1:  static void Main(string[] args)
   2:  {
   3:      IUnityContainer container = new UnityContainer();
   4:      container.RegisterType<IMonitor, Monitor>().RegisterType<INotify, SMSNotify>();
   5:  
   6:      IMonitor monitor = container.Resolve<IMonitor>();
   7:      monitor.Alarm();
   8:  
   9:      Console.ReadLine();
  10:  }

代码中我们注入的INotify实例是SMSNotify类的实例,然后调用monitor.Alrarm(),里面会调用notify.Send().
运行查看结果:
2
上面是针对单个构造函数的情况,如果有多个构造函数,需要指明哪个构造函数是需要被注入的,也即需要在指定被注入的构造函数加上attribute:InjectionConstructor

   1:  public Monitor(INotify n, string name)
   2:  {
   3:      notify = n;
   4:  }
   5:  
   6:  [InjectionConstructor]
   7:  public Monitor(INotify n)
   8:  {
   9:      notify = n;
  10:  }

运行后可得到一样的结果.

2.Property Injection

通过属性注入,我们需要加上attribute: Dependency,使得Unity容器在获取类对象实例时,自动实例化该属性所依赖的对象,并注入到属性中。

修改Monitor类,实现下面的代码:

   1:  public class Monitor : IMonitor
   2:  {
   3:      [Dependency]
   4:      public INotify Notify { get; set; }
   5:  
   6:      public void Alarm()
   7:      {
   8:          Notify.Send();
   9:      }
  10:  }

再在Main函数里面,修改原有的代码,这次我们让容器注入EmailNotify实例:

   1:  container.RegisterType<INotify, EmailNotify>();

运行查看结果:
3 还有一个比较方便的地方,可以为Dependency特性指定名称,这样,在注入时,会将RegisterType所指定的对应名称的实体进行注入,例如:

   1:      public class Monitor : IMonitor
   2:      {
   3:          [Dependency("SMS")]
   4:          public INotify Notify { get; set; }
   5:  
   6:          public void Alarm()
   7:          {
   8:              Notify.Send();
   9:          }
  10:      }

修改Main函数,在RegisterType函数中指定注入名称:

   1:              container.RegisterType<INotify, EmailNotify>("Email");
   2:              container.RegisterType<INotify, SMSNotify>("SMS");

运行查看结果:
2

3.Method Call Injection

Method Call Injection注入的时机和Constructor Injection有一定的区别,构造函数注入,是在容器创建实例的时候,而方法调用注入,是在方法被调用的时候。实现方法调用注入,需要在指定注入的方法前加上attribute: InjectionMethod

修改Monitor类的代码如下:

   1:      public class Monitor : IMonitor
   2:      {
   3:          private INotify notify;
   4:  
   5:          [InjectionMethod]
   6:          public void GetNotify(INotify n)
   7:          {
   8:              notify = n;
   9:          }
  10:  
  11:          public void Alarm()
  12:          {
  13:              notify.Send();
  14:          }
  15:      }

在程序运行时,容器会自动实例化GetNotify方法所依赖的对象,并自动调用该方法,将其注入到方法中。

Main函数如下:

   1:          static void Main(string[] args)
   2:          {
   3:              IUnityContainer container = new UnityContainer();
   4:              container.RegisterType<IMonitor, Monitor>();
   5:              container.RegisterType<INotify, EmailNotify>();
   6:  
   7:              IMonitor monitor = container.Resolve<IMonitor>();
   8:              monitor.Alarm();
   9:  
  10:              Console.ReadLine();
  11:          }

运行查看结果:

3

SQL中的日期计算

136 views 二月 22, 09 by Timothy

这两天写一个和统计数据有关的存储过程,里面要利用日期进行一些计算和判断,也自然要利用SQL的一些日期相关的函数。这里略记一下,当是复习一下SQL。

利用SQL脚本内置的几个函数,我们能灵活的对日期进行计算和比较。常用的几个函数:GETDATE(),DATEDIFF(),DATEADD()

GETDATE() 当然顾名思义,得到当前的日期,返回类型是DateTime类型。

DATEDIFF ( datepart , startdate , enddate ) 用于判断在两个日期之间存在的指定时间间隔的数目。

第一个参数是指定时间间隔的类型,例如mm(月),dd(天),yy(年),ms(毫秒),ss(秒),不同的间隔类型,返回的结果也不一样。

DATEADD (datepart , number, date ) 用于日期运算的函数,将传入的日期,加上指定时间间隔数目的日期。

 

例如,计算得到本年的第一天:

Select DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)

我们来分析下这个SQL语句就可以知道,首先从最里面的getdate()开始,getdate()得到当前日期和时间,外层的datediff,计算当前日期和1900-01-01 00:00:00之间的时间间隔,返回单位是以年来统计的,如果我们分开看DATEDIFF(yy,0,getdate()),0)的结果,返回就是:109。返回的109,传递给最外层的DATEADD函数,将1900-01-01 00:00:00加上109年,得到的结果,自然就是2009-01-01 00:00:00了,也即本年的第一天。

 

同样,灵活的利用这几个函数的组合,我们可以得到不同的结果:

得到当月的第一天:Select DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)

得到当前季度的第一天:Select DATEADD(qq, DATEDIFF(qq,0,getdate()), 0)

得到当天的起始时间: Select DATEADD(dd, DATEDIFF(dd,0,getdate()), 0)

得到上个月最后一天: Select DATEADD(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate()), 0))

得到上个月的第一天: Select DATEADD(m,-1,DATEADD(mm, DATEDIFF(mm,0,getdate()), 0))

其原理就是得到当月第一天,再减去三毫秒(SQL的时间以3毫秒为一个单位),这样以当前为2月,得到的结果就是:2009-01-31 23:59:59.997

得到去年的最后一天: Select DATEADD(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))

得到本月的最后一天: Select DATEADD(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0))

得到本年的最后一天: Select DATEADD(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate())+1, 0))

得到本月的第一个星期一: Select DATEADD(wk, DATEDIFF(wk,0,DATEADD(dd,6-datepart(day,getdate()),getdate())), 0)

Host WCF Service in WAS

240 views 十一月 24, 08 by Timothy

WAS 是 Windows (Process) Activation Service 的缩写,是Windows Vista中所新增的一种进程宿主模型。WAS作为 IIS7.0 特有的新增功能,和以前IIS 6.0的功能相比更加强大,因为它提供并支持除HTTP之外的更多协议,比如TCP方式和Pipe(管道)方式。以下的文中,都把Windows (Process) Activation Service简称为WAS。利用WAS作为WCF(Windows Communication Foundation)的宿主,我们能充分利用WAS的很多优点,因为我们再也不用为非HTTP方式的WCF Service单独编写宿主程序了。而WAS本身的特点,也让我们的服务端程序能享受到只有以往的HTTP方式的WCF Service才能拥有的很多特性。本文也简单向大家分享一下怎样使用WAS来作为WCF Service的宿主。

以往的部署WCF Service的方式,大家一般会想到以下几种:
1. 使用WinForm或者控制台程序作为宿主
2. 使用Windows Service作为宿主
不管我们用怎样的方式来作为WCF Service的宿主,少不了的麻烦,都是需要单独编写Host程序,除此之外,就该轮到WAS了。WAS在Vista中,其实是由一个单独的Windows Service来实现的,如果我们仔细找找,就能找到,Windows Service的名称,就叫做”Windows Process Activation Service”。由此看来,WAS的进程和IIS进程在物理上是隔离开的,能为我们提供一个灵活、稳定的WCF Service宿主环境。WAS内部的工作机制,大致和ASMX WebService类似。

简单了解了WAS的特性,下面我们用一个netTcpBinding的WCF示例来演示怎样利用WAS来Host WCF Service:

首先,我们需要查看Vista的组件中,是否打开了WAS的功能,打开控制面板,打开“程序和功能”对话框,在”打开/关闭 Windows功能”对话框中,确保下面图中的功能项被打开:

其实在这一部操作之后,windows会自动帮我们在IIS中做好配置,不过为了放心,我们还是打开IIS确认一下设置是否正确。

首先是检查IIS站点中的绑定:

确保net.tcp方式,绑定到808端口

打开站点的高级设置,确认”已启用的协议”中,填有”net.tcp”,没有的话,可以补上。

然后是建立应用程序目录,这个目录等下会用来部署WCF的Service端程序。建立好目录后,也在”高级设置–已启用的协议”中,填上net.tcp

到这里,基本的host环境我们已经设置好了。下面来实现我们的服务端和客户端。

建立Contract
[code]
[ServiceContract]
public interface IService1
{
[OperationContract]
string SayHello(string value);
}
[/code]

实现简单的Service类
[code]
public class Service1 : IService1
{
public string SayHello(string value)
{
return string.Format("Hello,{0}", value);
}
}
[/code]

建立svc文件
[code]
<%@ ServiceHost Language="C#" Debug="true" Service="WCFLibrary.Service1" CodeBehind="./App_Data/Service1.cs" %>
[/code]

服务端的WCF配置
[code]










bindingConfiguration="NetTcpBinding" contract="WCFLibrary.IService1">






















[/code]

其实endpoint只需要一个即可,为了方便通过svcutil.exe生成客户端代理,需要通过另外一个endpoint的mexTcpBinding来暴露元数据。这样当服务在发布好的时候,我们可以通过
Svcutil.exe net.tcp://Timothy-T61/WCFService/HelloService.svc/mex 来生成客户端代理了。

完成服务端的编写,直接将服务端程序,部署到刚才在IIS中添加的应用程序目录中。

客户端的wcf配置如下:
[code]









bindingConfiguration="ClientBinding" contract="WCFLibrary.IService1" />

[/code]

客户端拖放一个按钮,添加如下代码:
[code]
private void button1_Click(object sender, EventArgs e)
{
ClientProxy client = new ClientProxy();
MessageBox.Show(client.SayHello("Timothy!"));
}
[/code]

一切就绪,运行程序,点击按钮:

没有单独编写host程序,通过WAS,我们的服务端正常运行了。

Page: 2 of 4 1 2 3 4