WCF for .NET CF快速入门

摘要
本文可以看作是Chris Tacke的文章An Introduction to WCF for Device Developers的翻译,文中代码由于笔者调试需要稍作了修改,局部做了进一步的说明,并将部分链接更新。
Keyword
Windows Mobile, WCF, .NET CF, Services, Xml Serialization

这是一篇我推荐给很多朋友看过的文章。文章很短,也没有涉及太多WCF原理性的东西,但是作为WCF Mobile开发入门,这却是个很好的向导,为了方便阅读,有些地方我做了额外的说明。
Enjoy it~

1 开发环境与工具

1. Visual Studio 2008 (Orcas) RTM.
2. Power Toys for .NET Compact Framework 3.5
3. 一台 支持.NET Compact Framework3.5Windows Mobile 5.0/6.0 的模拟器或者设备.
(Chris Tacke在他的设备上调试成功,在模拟器上由于某些不可知的因素失败了。笔者在模拟器上调试成功)
4. Windows XP 或者 Vista的操作系统
(Chris TackeXP下调试的,笔者则是在Vista)

2 PC
端的WCF服务程序

当然,这只是一个很简单的模型,就是通过WCF使移动设备与PC进行信息交互。
首先,我们需要在PC机上构建一个服务,这个服务实现的功能很简单,就是进行两个整数的加法,并返回结果。
第一步,打开你的VS创建一个控制台程序,并添加引用:System.ServiceModel
然后,添加一个新的类(事实上是一个接口,它用于定义我们的服务所暴露出来的契约),我们把这个类命名为IMyProcess,其内容如下:

using System.ServiceModel;
namespace Freesc.WCF.Demo
{
        [ServiceContract(Namespace 
= http://Freesc.WCF.Demo)]
       public interface IMyProcess
        
{
            [OperationContract]
            
int Add(int a, int b);
        }

}

接下来,我们需要一个该借口的具体实现来作为我们的服务。为我们的工程另添加一个类,叫做MyProcessService,也就只包含一个Add方法。其代码如下:

using System;

namespace Freesc.WCF.Demo
{
 
public class MyProcessService:IMyProcess
    
{
      
public int Add(int a, int b)
      
{
          Console.WriteLine(
string.Format(
          
"Received 'Add({0}, {1})' returning {2}", a, b, a + b));
          
return a + b;
      }

    }

}

好,服务的内容已经写好了,我们需要来看看这个PC端的Server是怎么工作的了。首先,请将你的Program.cs替换为如下代码:

using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Net;

namespace Freesc.WCF.Demo
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
          
//获得服务器IP
            string hostIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[2].ToString();
#if CLIENT_DISCOVERY_BUILD
          Uri address 
= new Uri(string.Format("http://localhost:8000/calculator", hostIP));
#else
          Uri address 
= new Uri(string.Format("http://{0}:8000/calculator", hostIP));
#endif
            ServiceHost serviceHost 
= new ServiceHost(typeof(MyProcessService), address);
            
try
            
{
                
// 添加一个服务节点
                serviceHost.AddServiceEndpoint(
                    
typeof(IMyProcess),
                    
new BasicHttpBinding(),
                    
"Calculator");
#if !CLIENT_DISCOVERY_BUILD
                
// 允许运行时的元数据交互(使用NetCfSvcUtil工具)
                ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                smb.HttpGetEnabled 
= true;
                serviceHost.Description.Behaviors.Add(smb);
#endif
                serviceHost.Open();
                Console.WriteLine(
"MyProcessService is running at " + address.ToString());
                Console.WriteLine(
"Press <ENTER> to terminate");
                Console.ReadLine();
                
// 把服务状态置为关闭
                serviceHost.Close();
            }

            
catch (CommunicationException ce)
            
{
                Console.WriteLine(
"An exception occured: {0}", ce.Message);
                serviceHost.Abort();
            }

        }

    }

}


这段程序要稍稍复杂一点,首先,你也许会注意到这里用了一些预编译指令。使用这些预编译指令是因为我们要在稍后的一个工具中访问这个运行的服务并为我们生成一些代码。如果你暂时还比较晕的话,别急,稍后会说到这个工具的。

这里的CLIENT_DISCOVERY_BUILD只是一个条件编译的符号,您暂且可以无视之。其实这里只是为了我们编译代码的时候版本切换比较方便。

某些情况下我们希望把前面编译的A版本的代码暂存起来,以免在CS文件中该来改来改去,这时只需要在Debug 的配置项目下做一些修改,比如这里我们加上了Discover这一项,用记事本打开工程文件,可以看到这一段:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Discovery|AnyCPU' ">
    
<DebugSymbols>true</DebugSymbols>
    
<OutputPath>bin"Discovery"</OutputPath>
    
<DefineConstants>TRACE;DEBUG;CLIENT_DISCOVERY_BUILD</DefineConstants>
    
<DebugType>full</DebugType>
    
<PlatformTarget>AnyCPU</PlatformTarget>
    
<ErrorReport>prompt</ErrorReport>
 
</PropertyGroup>

好,那这一段主程序代码到底有什么作用呢?首先,我们需要为我们的服务创建一个Uri

要创建这个Uri首先要知道本机的IP。这里如果你直接Copy Chris Tacke的代码也许不能运行(特别是Vista用户),可能会抛出一个这样的异常:

这个时候你需要检查你的IPAddressAddressFamily,或者直接CMD下察看ipconfig,如果是IPV6的话(如我机器上的AddressList[0]就是iPV6的格式),则会抛除上述异常,iPv4则一切OK

接下来,我们创建了一个服务主机(ServiceHost)和一个服务节点(endpoint),请注意,这里我们用的协议绑定方式是BasicHttpBinding,在精简版的WCF framework中默认只有两种绑定绑定方式(另一种是WindowsMobileMailBinding,我在今后的文章中会介绍)。然后我们给服务起了个名字叫做“Calculator”。

接下来,可以看到我们先前提到过的条件编译符号,在我们开启Discovery的配置环境下,我们的工具(下文会提到)可以与该程序集的元数据进行交互用来生成一些代码,不过上面的代码里是处于关掉的模式。

好了,现在可以来试着编译这段代码了,编译的时候请确保在Discover的模式下。

如果一切OK,你将会看到如下的画面:

注意:如果是Vista用户,如果开启了UAC,你可能需要以管理员的身份运行编译好的可执行程序,否则可能会有某些权限问题。

然后,我们在浏览器中键入这里显示的地址,可以看到如下画面

如果你的确看到上述页面,很好,我们的工作已经完成一半了。

3. NetCFSvcUtil.exe

下面我们需要借助一个小工具---netcfSvcUtil来帮助我们生成一些代码,这个方法适用于那些初次进行WCF for Mobile编程的人,或者是象我这样比较懒,比较喜欢使用小工具的程序员。

打开你的命令行工具,你的Power Toy默认安装在类似这样的目录下:
C:"Program Files"Microsoft.NET"SDK"CompactFramework"v3.5"bin.

在之前的服务运行的时候,在该目录下运行如下的命令:

netcfSvcUtil.exe /language:cs http://localhost:8000/calculator

你可以看到如图的输出:

此时你会发现在该目录下生成了两个
CS文件,这里分别是MyProcessService.csCFClientBase.cs
在接下来的步骤中,我们会用到这两个文件。

4. CF端的应用程序

接下来,我们新建一个Smart Device 的窗体应用程序,工程命名为DeviceClient。将前面生成的那两个文件Copy到该工程中来,然后,我们得添加如下一些引用(主要是那两个由工具生成的cs文件需要)

- System.ServiceModel

- System.Runtime.Serialization

这里的代码如下:

      public Form1()
        
{
            InitializeComponent();
            
try
            
{
//在TextBox中显示本机IP
                tbMyIP.Text = Dns.GetHostEntry(
                Dns.GetHostName()).AddressList[
0].ToString();
            }

            
catch (Exception ex)
            
{
                MessageBox.Show(
"No NIC found?");
            }

        }

       
private void menuCalculate_Click(object sender, EventArgs e)
        
{
            
int a = 0;
            
int b = 0;
            
try
            
{
//接受文本框的输入,并存入整形变量a,b中
                a = int.Parse(tbFirst.Text);
                b 
= int.Parse(tbSecond.Text);
            }

            
catch
            
{
                
//如果转换失败(比如填入了无效的数字)则直接返回
                return;
            }

            SMC.Binding binding 
= MyProcessClient.CreateDefaultBinding();
            
string remoteAddress = MyProcessClient.EndpointAddress.Uri.ToString();
            remoteAddress 
= remoteAddress.Replace("localhost", “192.168.1.101”);
            EndpointAddress endpoint 
= new EndpointAddress(remoteAddress);
            MyProcessClient client 
= new MyProcessClient(binding, endpoint);
            
try
            
{
                lbResult.Text 
= client.Add(a, b).ToString();
            }

            
catch (Exception ex)
            
{
                MessageBox.Show(ex.Message);
            }

        }

代码很短,不过很重要的一点是我们没有使用DeviceClient的默认构造器,我们把RemoteAddress中的”localhost”替换成了服务所在主机的IP(你可以在MyProcessClient类的找到相应的静态字段)

点击menuCalculate我们看到以下的结果:
PC机上

设备上


下载完整代码

总结

从上面的例子我们看到,在Windows Mobile上构建一个WCF的应用程序并不是太难,代码量也不大,只是我们缺少相应的文档资源, 也许本文能帮你节约一点上手的时间。

希望这篇短文能对大家有所帮助,尽管它并没有对某些细节做清楚的阐述,但是相信您已经能够按照文中的做法,在Windows Mobile上轻松构建出你自己的WCF程序,那么本文的目的也就达到了。

Regards
©Freesc Huang
  黄季冬<fox23>@HUST

posted on 2008-03-18 04:03  J.D Huang  阅读(8771)  评论(16编辑  收藏  举报