在Pocket PC中使用Web Service连接数据库

Pocket PC中使用Web Service连接数据库

前言<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

微软的移动开发者大会在六月的北京举行了,国内的移动应用软件虽然是刚刚起步,但是这个前景宽广的领域已经受到越来越多软件厂商的关注了。移动设备上的商业应用尽管刚刚起步,但已经显示出巨大的发展潜力。

在微软移动开发挑战赛中,我的作品《饕餮元年无线餐饮管理系统》获得了商业应用的三等奖。为了实现Pocket PC与后台数据库服务器的连接,我的作品中使用了.Net CompactFrameworkWeb Service技术,我将核心部分的实现原理拿出来与大家分享。在本文中没有涉及《饕餮元年》的代码,我用另外一个程序“SQL查询分析器”作为演示的范例。

在嵌入式数据库领域,世界各大数据库厂商都提供了自己的移动解决方案,比如微软的SQL Server CESybaseiAnywhereIBMDB2 Everyplace等。虽然各家厂商都提供了数据同步的解决方案,而且实现原理大同小异,但是,每种数据同步方案都针对自己的数据库,不能兼容其他的数据库产品。

那么有没有什么办法,可以通过一种机制来访问多种数据库呢?微软的Mobile 2003已经完全支持.net Compact Framework开发,而.netWeb Service提供了很好的支持,开发者可以很容易的开发Web Service的服务程序和客户端应用。

本文讨论的是在Windows Mobile2003平台上通过Web Service来访问多种数据库的解决方案。这肯定不会是移动设备访问多种远程数据库的最优解,但我希望这是利用现有技术实现的比较优秀的解决方案。

系统需求:Visual Studio .NET 2003

Pocket PC 2003 模拟器

IIS 5.0

第一个Web Service

目前Web Service受到了广泛的关注,主流的开发工具都为Web Service开发提供了很好的支持。我们在这里使用Visual Studio . NET 2003来做一个简单的Web Service实例,让不了解Web Service开发的程序员更好的进入后续话题的讨论。

我们首先来创建一个ASP.NET Web Service工程:打开File菜单,选择New,然后是Project。在New Project对话框中,Project Types选择“Visual C# Projects”,Templates中选择“ASP.NET Web Service”。Location中选择你的Web Service的位置和名称,由于我的机器上配置了IIS服务,所以我将Web Service直接部署在本机上。请见图一。

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 339pt; HEIGHT: 246.75pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/maning/LOCALS~1/Temp/msoclip1/01/clip_image001.jpg" o:title="NewProject1"><font size="4"></font></imagedata></shape>

ASP.NET Web Service工程和ASP.NET十分相似,只是页面文件的扩展名为asmx,而不是aspx。接下来,我们要为Web Service 创建一个WebMethod。打开Service1.asmx.cs文件,在class Service1中添加两个WebMethodYourNamewelcom,代码如下(粗体字为添加的代码):

<shapetype id="_x0000_t202" coordsize="21600,21600" o:spt="202" path="m0,0l0,21600,21600,21600,21600,0xe"><stroke joinstyle="miter"></stroke><path gradientshapeok="t" o:connecttype="rect"></path></shapetype><shape id="_x0000_s1026" style="MARGIN-TOP: 7.95pt; Z-INDEX: 1; LEFT: 0px; MARGIN-LEFT: 0px; WIDTH: 414pt; POSITION: absolute; HEIGHT: 288.45pt; TEXT-ALIGN: left" stroked="f" type="#_x0000_t202" fillcolor="#eaeaea"><font size="4"></font></shape>

namespace WebService1

{

public class Service1 : System.Web.Services.WebService

{

……

[WebMethod]

public string YourName()

{

return "My Name is wolf!我就是老狼!";

}

[WebMethod]

public string welcom(string yourname)

{

string str = yourname+",欢迎使用wolf的Web Service";

return str;

}

}

}


这里需要提醒大家注意的是,每个WebMethod都必须是public的,而且需要在函数前

加上[WebMethod]的声明。YourName函数返回一个包含英文和中文的string对象,主要是想测试一下Web Service的字符串能否在支持UnicodeWindowsCE平台上正常现实。Welcom函数增加了一个参数,目的也是为了测试Web ServiceWindowsCE平台间是否存在字符串不能正常显示的问题。

然后我们选择Debug菜单中的Start命令(或者按F5)运行这个Web Service,出现如下界面:(见图二)

<shape id="_x0000_i1026" style="WIDTH: 375pt; HEIGHT: 169.5pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/maning/LOCALS~1/Temp/msoclip1/01/clip_image003.png" o:title="WebService"><font size="4"></font></imagedata></shape>

可以看到,我们刚才编写的两个函数的名称被显示了出来。大家可以点击函数名称,来查看WebMethodSOAPHTTP POST等信息,还可以直接点击Invoke按钮,查看WebMethod返回的结果是否正确。

如果您的Web Service工作一切正常,接下来,我们创建一个Smart Device应用程序,在Pocket PC 2003环境下调用我们的Web Service。如果您对如何在Visual Studio .NET 2003下如何创建Smart Device应用程序还不是很了解,希望您参考下面的说明。

打开一个新的VS.NETIDE环境,打开File菜单,选择New,然后是Project。在New Project对话框中,Project Types选择“Visual C# Projects”,Templates中选择“Smart Device Application”,然后点击OK

<shape id="_x0000_i1027" style="WIDTH: 375pt; HEIGHT: 261pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/maning/LOCALS~1/Temp/msoclip1/01/clip_image005.png" o:title="NewProject2"><font size="4"></font></imagedata></shape>

Smart Device Application Wizard对话框中,有两个列表框。上边一个列表框选择程序的目标平台,根据你开发使用机器上所安装的SDK的不同可以显示出不同的选项。其中Pocket PC中包括Pocket PC 2002Pocket PC 2003Windows CE中包括其他支持.NET Compact FrameworkWindowsCE平台。如果您安装了SmartPhoneSDK,这里也会显示出SmartPhone的选项。

下面的对话框选择的是所创建的应用程序类型,包括Windows应用程序、类库、Non-graphical应用程序和空工程。这里的选项根据您选择平台的不同也会略有差异。还有一点需要说明的是,如果您安装了Mobile Internet Toolkit,您也可以通过这个向导来创建目标平台为Mobile设备的ASP.NET Web程序。

我们在这里选择“Pocket PC”和“Windows Application”,点击OK。我们就可以开始移动开发之旅了。

<shape id="_x0000_i1028" style="WIDTH: 513pt; HEIGHT: 201pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/maning/LOCALS~1/Temp/msoclip1/01/clip_image007.png" o:title="IDE"><font size="4"></font></imagedata></shape>

我们先来看一下IDE环境的全景:其实和WinForm程序的开发环境差不多吧。但请大家注意上图中的下拉菜单,做过WindowsCE开发的朋友们一定很熟悉吧。对了,这就是选择应用程序输出设备的菜单。我们在这里选择“CHS Pocket PC 2003 – SDK Emulator”,我们可以选择下拉菜单旁边的Connect To Device按钮来启动模拟器,也可以等到程序运行时再启动模拟器。

请注意:Visual Studio .NET 2003会默认安装Pocket PC 2002SDK,您需要另外安装Pocket PC 2003 SDK和中文映像才能够看到这一项。不过您在Pocket PC 2002的模拟器下调试下面的应用程序也是没有问题的。

下面,我们来添加Web References,选择Project菜单下的“Add Web References”,或者在Solution Explorer中右击Web References,在弹出菜单中选择“Add Web References”。我们就会看到下面的对话框:

<shape id="_x0000_i1029" style="WIDTH: 415.5pt; HEIGHT: 291.75pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/maning/LOCALS~1/Temp/msoclip1/01/clip_image009.png" o:title="AddWebReference"><font size="4"></font></imagedata></shape>

URL里要填写Web ServiceURL,还记得我们运行Web ServiceIE地址栏中的URL吗?http://localhost/WebService1/Service1.asmx。对吗?如果是WinForm程序,这样写是正确的,但在Smart Device应用程序中,这样写就是错的。请大家注意,下面讨论的话题十分重要Windows CE设备的模拟器尽管运行在你的PC上,但它实际上是作为一台远程设备连接到你的PC上的。所以,如果写“localhost”或者“127.0.0.1”,那么程序访问的将是模拟器,而不是你用来开发的PC机。所以,在这里你必须填写你的PC在网络中的实际机器名或者IP地址。所以这里应该填写http://yourname/WebService1/Service1.asmxyourname表示你实际的机器名)。这里如果您填写的是localhost,开发环境也将为你找到Web References,但在调用Web Service时将出现异常。好了,填写好URL,按GO按钮,如果URL正确,则会显示上图的信息,然后点击Add References按钮。这样我们就可以在项目中使用这个Web Service了。

我们打开界面编辑器,添加两个Button和一个TextBox,用来调用两个WebMethod。代码如下:

private void button1_Click(object sender, System.EventArgs e)

{

yourname.Service1 myService = new yourname.Service1();

label1.Text = myService.YourName();

MessageBox.Show(myService.YourName());

}

private void button2_Click(object sender, System.EventArgs e)

{

yourname.Service1 myService = new yourname.Service1();

MessageBox.Show(myService.welcom(textBox1.Text));

}

yournameWeb Service的名称,相当于命名空间,所以我们必须创建一个yourname中的Service1类的对象,然后调用Service1中的方法。大家可以看到,在C#程序中调用Web Server的方法和创建本地类并调用其方法的过程是十分类似的。另外需要说明的是,由于网络因素的影响,调用Web Service不一定成功,所以在商业软件的开发中需要加入异常处理的代码,这里为了程序的简洁就省略了。程序运行结果如下:

<shape id="_x0000_i1030" style="WIDTH: 240pt; HEIGHT: 368.25pt" type="#_x0000_t75"><imagedata src="file:///C:/DOCUME~1/maning/LOCALS~1/Temp/msoclip1/01/clip_image011.png" o:title="PocketPC"><font size="4"></font></imagedata></shape>

SQL查询分析器

在了解了基本的Web Service的开发与调用之后,我们可以进入核心内容的讨论了。Web Service是基于XML语言的,正是这种特性才使Web Service成为连接各种异构系统之间的桥梁。那么有没有一种可以在跨越不同数据库来传递数据的简单方式呢?ASP.NET Web Service是支持返回DataSet对象的,而DataSet又能够被各种数据表示控件所支持,比如DataGrid等,DataSet就是我们要找的桥梁。

在这一部分里,我将创建一个SQL的查询分析器,与其他查询分析器不同的是,我可以在调用时再指定连接的数据库类型,这样就可以实现连接不同数据库了。我们首先来创建SQL查询分析器的Web Service部分:

<shape id="_x0000_i1031" style="WIDTH: 414.75pt; HEIGHT: 159.75pt" type="#_x0000_t75" o:ole=""><imagedata src="file:///C:/DOCUME~1/maning/LOCALS~1/Temp/msoclip1/01/clip_image013.wmz" o:title=""><font size="4"></font></imagedata></shape>

先来看一下SQL ServiceUML图。我们沿用了上面SQL Service中的Service1类,并为它添加了五个WebMethod,其名称和功能介绍见下表:

名称

功能

SetDatabaseType

设置连接数据库的类型

SetDbConnectionString

设置数据库的连接字符串

Create

创建数据库操作对象

ExecuteNonQuery

执行不返回结果的SQL语句

ExecuteDataSet

执行SQL语句,并返回一个DataSet

Web ServiceService1类中,我们首先来声明三个变量用来分别存储数据库操作对象、数据库连接字符串和数据库类型。注意,我们将变量声明为static,是为了让客户端执行不同的WebMethod时,可以访问到相同的数据库操作对象和字符串对象。DBOperater是数据库操作类的基类,而等一下我们创建的是DBOperater派生类的实例。

private static DBOperater m_dbOperater;

private static string m_DatabaseType;

private static string m_DbConnectionString;

SetDatabaseType和SetDbConnectionString两个WebMethod是为了设置数据库类型和数据库连接字符串而提供的方法。在这里需要特别提醒的是,将数据库的连接字符串作为Web Service参数,以明文的方式在网络上传递是一种十分危险的做法,这里只是为了示例程序的简单才这样实现的。强烈建议读者在实现自己的Web Service时,用更好的方法来保护自己的数据库连接字符串。

[WebMethod]

public bool SetDatabaseType(string DatabaseType)

{

if(DatabaseType == "")

return false;

m_DatabaseType = DatabaseType;

return true;

}

[WebMethod]

public bool SetDbConnectionString(string DbString)

{

if(DbString == "")

return false;

m_DbConnectionString = DbString;

return true;

}

下面的Create方法,用来根据m_DatabaseType来创建相应的DBOperater派生类的对象。这里需要说明的是,设置数据库类型(SetDatabaseType)用的是string作为参数,而没有使用enum类型或者其他类型,是为了再以后添加对新的数据库支持时不必修改已有的客户端源代码。

[WebMethod]

public bool Create()

{

if(m_DatabaseType == "SQL Server")

{

m_dbOperater = new DBSqlServerOperater(m_DbConnectionString);

return true;

}

if(m_DatabaseType == "Access")

{

m_dbOperater = new DBAccessOperater(m_DbConnectionString);

return true;

}

return false;

}

而剩下的两个WebMethod只是简单的调用了DBOperater派生类对象的相应方法,而实际的数据库操作则是在DBOperater派生类中具体实现的。这样可以更好地实现数据库操作与客户端操作的分离。

[WebMethod]

public bool ExecuteNonQuery(string sql)

{

return m_dbOperater.ExecuteNonQuery(sql);

}

[WebMethod]

public DataSet ExecuteDataSet(string sql)

{

return m_dbOperater.ExecuteDataSet(sql);

}

我们将对数据库操作的具体方法封装到了DBOperater类中,并由DBOperater类派生出了DBSqlServerOperater和DBAccessOperater类,分别用来进行对Sql Server数据库和Access数据库的操作。DBOperater类暴露了两个虚方法:ExecuteNonQuery()和ExecuteDataSet(),由派生类负责重载实现。而派生类也各自暴露了自己的构造函数,用来获取连接数据库字符串。

下面是DBOperater类的实现代码,可以看到DBOperater类中的两个方法使用了virtual的关键字,声明为虚函数。

// 数据库操作基类

public class DBOperater

{

public virtual bool ExecuteNonQuery(string sql)

{

return true;

}

public virtual DataSet ExecuteDataSet(string sql)

{

return null;

}

}

Web Service的体系结构中,真正进行数据库操作的只有DBOperater的派生类,我们下面看到的DBSqlServerOperater类,使用了System.Data.SqlClient命名空间中的数据库操作类,对SQL Server数据库进行存储操作。DBAccessOperater类对OleDB数据进行操作,使用了System.Data.Oledb命名空间中的类。

// SQL Server 操作类

public class DBSqlServerOperater : DBOperater

{

public DBSqlServerOperater(string DBConnectionString)

{

m_SqlConnection = new SqlConnection(DBConnectionString);

}

public override bool ExecuteNonQuery(string sql)

{

if(sql == "")

return false;

m_SqlConnection.Open();

SqlCommand command = m_SqlConnection.CreateCommand();

command.CommandText = sql;

command.ExecuteNonQuery();

m_SqlConnection.Close();

return true;

}

public override DataSet ExecuteDataSet(string sql)

{

if(sql == "")

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值