用.Net的Web服务实现天气预报

王朝c#·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

该例子演示了利用微软.Net框架的Web服务与天气预报站点的硬件进行数据交换来实现Web天气预报的服务。

微软力推.Net的目的,用他自己的话来说就是“使人们能够在任何时候、任何地点以及任何设备上通过我们开发的软件发挥最大的潜能”。在这里大多数人可能认为微软所讲的“任何设备”是指袖珍PC、手持设备、台式电脑及笔记本电脑等。下面的例子我们将向大家展示.Net如何使那些电脑硬件设备驱动程序开发人员发挥自己的潜能,这些设备驱动程序可能和一些专用的PC控制器或PC的标准端口直接通讯。这些驱动程序开发人员大多依靠Windows的驱动开发工具包(DDK)及其其他各种工具,如可安装文件系统开发工具包(IFS)等。虽然这些微软的工具包并没有随着.Net的推出而改变,但是.Net构架仍然给这些硬件设备开发带来了新的机遇。

我们将要构造的示例方案的目的就是通过专用的PC卡自动采集来自于不同天气情报采集点的天气信息。PC卡可以通过每个采集点的标识ID来同时控制每个采集点的数据,按要求每个采集点可以提供该点的温度、湿度和气压等数据。

我们的目标是让用户通过互联网(Web)获得指定采集点的天气预报信息。接下来我们开始结构设计。首先需要为PC卡写一个Windows的驱动程序以便PC卡可以读取指定采集点的天气信息,另外我们还需要利用.Net构造一个网络服务(Web Service)以便互联网用户可以通过Internet访问采集到的天气信息数据。

.Net的托管代码是不能直接访问Windows的内核的。所有我们必须先利用非托管代码写一个用户级(User level)的模块以便网络服务和PC卡的驱动程序之间可以相互交流数据。

PC卡的驱动程序接口

假设我们PC采集卡已安装到专用PC上,而且采集点到PC采集开的信号电缆也连接好。接下来的任务就是驱动程序开发人员开始开发硬件驱动程序。

我们并不打算深入研究如何开发PC卡的硬件驱动程序。其实网上有很多介绍开发驱动程序的工具和资源,也有一些介绍在NT和XP下开发驱动程序差异的文章。我们的主要目的是关心采集数据的封装形式以及用户模块和驱动程序通讯的方法。

我们准备有下面定义的结构来封装采集到的数据:

typedef struct {

unsigned long stationID;

unsigned long state; // for management purposes

unsigned long timeStamp;

double temperature; // celcius

double humidity; // percent

double airPressure; // millibar

} WEATHER_DATA, *PWEATHER_DATA;

从PC卡读取数据我们可以利用Win32 API - DeviceIOControl(...)。为了调用该函数设备驱动程序和用户程序必须共享用户定义的IOCTL码。为了简单起见,我们用WEATHER_DATA结构表示用户程序和驱动程序共享的数据缓冲区。但是在实际应用中,应该小心谨慎,您可以参考微软的技术文章Q126416和Q186775。

用户要求得到指定的采集点的天气信息的过程如下:

1.用户程序分配WEATHER_DATA结构,设置 stationID 和 dataTag。

2.用户程序利用Win32 API - CreateFile(...)打开与PC卡相关联的设备句柄。

3.用户程序调用DeviceIOControl(),并将结构 WEATHER_DATA 作为参数。

4.驱动程序处理调用,利用用户选择的数据采集点的数据填充WEATHER_DATA数据缓冲区。(在我们的例子中,用虚拟数据以模仿显示中的数据采集。)

5.驱动程序返回数据个用户程序,结束DeviceIOControl()调用。

6.用户程序处理得到的数据。

以下的头定义文件为驱动程序和用户程序共用:

// weather_common.h

// Common definitions used by both user level module and

// kernel driver

//

#define WEATHER_TYPE 40000

// The IOCTL function codes from 0x800 to 0xFFF

// are for customer use.

#define IOCTL_GET_WEATHER_DATA

CTL_CODE( WEATHER_TYPE, 0x900, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)

// Define common used weather data structure

typedef struct {

unsigned long stationID;

unsigned long state;

unsigned long timeStamp;

double temperature;

double humidity;

double airPressure;

} WEATHER_DATA, *PWEATHER_DATA;

接下来的代码是用户端的实现:

// UserLevelModule.cpp

//

// Implementation of user level module

...

DWORD dwBytesReturned;

// Create structure and fill initial data

WEATHER_DATA dataStruct;

// specify station to request

dataStruct.stationID = stationID;

...

// Open driver

HANDLE hDriver;

hDriver = CreateFile(“\\.\Device\WeatherDevice”,...);

...

// Issue control call to driver passing prepared structure

DeviceIOControl(hDriver,IOCTL_WEATHER_DATA,

(void*)&dataStruct,sizeof(dataStruct),

(void*)&dataStruct,sizeof(dataStruct),

&dwBytesReturned,NULL);

// If succeeded the structure now contains

// the requested data in data

...

// Close driver

CloseHandle(hDriver);

接下来是驱动程序的部分代码:

// WeatherDrv.c

//

// Implementation of kernel driver

NTSTATUS

WeatherDispatch(

IN PDEVICE_OBJECT DeviceObject,

IN PIRP Irp

)

{

...

pIrpStack = IoGetCurrentIrpStackLocation(pIrp);

// Dispatch based on major fcn code.

switch (pIrpStack->MajorFunction)

{

...

case IRP_MJ_DEVICE_CONTROL:

// Dispatch on IOCTL

switch (pIrpStack->Parameters.DeviceIoControl

.IoControlCode)

{

case IOCTL_GET_WEATHER_DATA:

pWeatherData = (PWEATHER_DATA)

pIrp->AssociatedIrp.SystemBuffer;

if(pWeatherData != NULL)

{

// Fill time stamp in data structure

KeQuerySystemTime(&sysTime);

RtlTimeToTimeFields(&sysTime,&tFields);

pWeatherData->timeStamp = tFields.Second

+ 100 * tFields.Minute

+ 10000 * tFields.Hour;

// Emulate controller card work with

// sample data

pWeatherData->temperature = 25;

pWeatherData->humidity = 60;

pWeatherData->airPressure = 1015;

}

pIrp->IoStatus.Information =

sizeof(WEATHER_DATA);

break;

default:

break;

}

Status = STATUS_SUCCESS;

break;

...

// Complete request

}

用户端代码

驱动程序以及驱动程序和用户程序的通讯协议定义好了以后,接下来就是开发用户端模块了。

我们可以开发一个应用程序或者动态连接库。在这里我们实现一个动态连接库。以下代码演示了如何输出一个函数供外部调用:

// weatherDrvCtrl.h

//

// Declaration of GetWeatherData()

DWORD WINAPI GetWeatherData(WEATHER_DATA* pData);

// weatherDrvCtrl.cpp

//

// Definition of GetWeatherData()

DWORD WINAPI GetWeatherData(

WEATHER_DATA* pData)

{

HANDLE hDriver;

DWORD dwErr = ERROR_SUCCESS;

DWORD dwBytesReturned;

// Open driver

HANDLE hDriver;

hDriver = CreateFile(DRIVER_DEVICE_NAME,...);

if(hDriver != INVALID_HANDLE_VALUE)

{

// Issue control call to driver

// passing prepared structure

dwErr = DeviceIOControl(hDriver,IOCTL_WEATHER_DATA,

(void*)&dataStruct,sizeof(dataStruct),

(void*)&dataStruct,sizeof(dataStruct),

&dwBytesReturned,NULL);

if(!dwErr)

{

// If succeeded the structure now contains

// requested data in data field

}

// Close driver

CloseHandle(hDriver);

}

else

{

// Handle device open error;

}

return dwErr;

}

附件的weatherDrvCtrl项目是用Visual Studio .Net构造的,我们还提供了一个Win32的应用程序以供你测试应用程序(weatherDrvCtrl)和驱动程序(weatherDrv)。

到现在为止我们已经完成了驱动程序和用户端调用的所有工作。任何用户程序都可以通过调用动态库输出函数得到指定采集点的天气信息数据。

网络服务Web Service

下面我们来实现.Net的网络服务,以便互联网用户可以享受我们的服务。利用Visual Studio .Net创建Web Service很简单:

1.启动Visuao Studio .Net;

2.新健一个新项目,选择 C# ASP .Net Web服务。

3.编写数据结构:

[ StructLayout( LayoutKind.Sequential )]

public struct WeatherData

{

public UInt32 stationID;

public UInt32 state;

public UInt32 timeStamp;

public Double temperature;

public Double humidity;

public Double airPressure;

}

4.利用属性DllImport绑定动态库:weatherDrvCtrl.DLL。

[DllImport("weatherDrvCtrl.dll")]

static extern unsafe uint GetWeatherData

(ref WeatherData data);

5.创建一个Web方法:

[WebMethod(Description=”Get weather data and station state from specified weather station”)]

public unsafe WeatherData

QueryWeatherData(uint stationID)

{

// Create and initialize data structur

[1] [2] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航