web service中的事件

1 篇文章 0 订阅
1 篇文章 0 订阅

介绍

Web service是一个非常流行的工具,它使得在internet社区共享互联网资源成为可能。使用.NET框架和Visual studio 2005或者是后续版本为开发工具,谁都可以在几分钟之内开发出web service。这里有一些技巧,初学者经常遇到,例如部署、web引用等。它是构建web service的简易方法。使用模板创建服务时,唯一不方便使用的地方是还没有合适的办法从web service向客户端发送事件,asp.net web service应用程序模板只是在visual studio 2005中提供。这篇文章讨论了如何在web service中支持事件。

背景

当你对一个web service接口进行描述时,你可以使用属性让web方法对客户端可见。例如,你可以在web客户端想要调用的方法的前面加上[webmethod]属性,我也希望事件也可以作类似的处理,如果以下成为可能的话那将非常使人激动人心。

Collapse Copy Code

[WebEvent]

public event ActiveClientsChangedDelegate OnActiveClientsChanged = null;

web service定义如下的委托:

Collapse Copy Code

public delegate void ActiveClientsChangedDelegate(int[] clients);

当你编写的服务识别到激活客户列表有变化时(注册客户、注销客户),可以进行如下的调用:

Collapse Copy Code

if (OnActiveClientsChanged != null) OnActiveClientsChanged(clients);

Clients是当前服务的活动客户的ID数组。遗憾的是,你使用当前的.NET web服务框架模板是不可行的。而其实现的方法之一是从客户端来调用服务。由于它不具有实时性并且依赖于客户端电脑,因而这并不是一个好办法。这里阐述了另外一种方法,那就是通过异步调用。

通过异步调用实现web服务回调函数

先让我们看一个例子。我们有一个web服务,并且希望它能够及时通知他的活动连接客户的数目。有任何客户连接登录后,其他所有的客户能够收到这个通知。一下是该web服务的部分代码:

Collapse Copy Code

namespace WebService

{

  /// <summary />

  /// Summary description for WebService

  /// </summary />

 

  [WebService(Namespace = "http://localhost/webservices/")]

  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

  public class WebService : System.Web.Services.WebService

  {

    #region private members

    // This static Dictionary keeps track of all currently open sessions

    private static Dictionary<Guid, ClientState> s_services =

                         new Dictionary<Guid, ClientState>();

 

    private int m_clientID;

    #endregion private members

 

    #region WebService interface

    [WebMethod]

    public void StartSession(Guid sessionID, int clientID)

    {

      lock (s_services)

      {

        if (s_services.ContainsKey(sessionID))

        {

          // Session found in the list

          m_clientID = s_services[sessionID].ClientID;

        }

        else

        {

          // Add session to the list

          m_clientID = clientID;

          s_services.Add(sessionID, new ClientState(m_clientID));

        }

      }

 

      lock (s_services)

      {

        // Signal GetActiveClientsCompleted event for each client

        foreach (Guid sID in s_services.Keys)

        {

          s_services[sID].GetActiveClientsCompleted.Set();

        }

      }

    }

 

    [WebMethod]

    public void StopSession(Guid sessionID)

    {

      lock (s_services)

      {

        if (s_services.ContainsKey(sessionID))

        {

          // Remove session from the list

          s_services.Remove(sessionID);

        }

      }

 

      lock (s_services)

      {

        // Signal GetActiveClientsCompleted event for each client

        foreach (Guid sID in s_services.Keys)

        {

          s_services[sID].GetActiveClientsCompleted.Set();

        }

      }

    }

 

    [WebMethod]

    public int[] GetActiveClients(Guid sessionID)

    {

      if (!s_services.ContainsKey(sessionID))

      {

        // Return empty client list

        return new int[] { };

      }

 

      bool signalled = s_services[sessionID].GetActiveClientsCompleted.WaitOne();

      // wait for GetActiveClientsCompleted event

 

      if (signalled)

      {

        lock (s_services)

        {

          // Create client list and return it

          List<int> clients = new List<int>();

          foreach (Guid sID in s_services.Keys)

          {

            if (sID == sessionID) continue;

            clients.Add(s_services[sID].ClientID);

          }

          return clients.ToArray();

        }

      }

      else

      {

        // Return empty client list

        return new int[] { };

      }

    }

    #endregion

 

    private class ClientState

    {

      public int ClientID;

      public AutoResetEvent GetActiveClientsCompleted = new AutoResetEvent(false);

      public ClientState(int clientID)

      {

        ClientID = clientID;

      }

    }

  }

}

你可以从webservice的客户端代理部分发现(你可以从自动生成模块reference.cs中找到),针对每个有[WebMethod]申明的,都有一个相应的异步调用方法和相应的完成事件。在本案例中,我们申明了GetActiveUsers方法,因此自动生成了GetActiveUsersAsynch方法和GetAcitveUserscomplated事件。在客户端,当你想为GetActiveUserscomplated事件创建一个监听器时,我们需要做两件事情。第一,在构造器中创建一个句柄处理GetActiveUserscomplated事件:

Collapse Copy Code

// Create proxy for WebService

m_service = new WebServiceWindowsClient.localhost.WebService();

 

// Subscribe for event

m_service.GetActiveClientsCompleted += new

  WebServiceWindowsClient.localhost.GetActiveClientsCompletedEventHandler(

  m_service_GetActiveClientsCompleted);

第二,我们通过对GetActiveUsers的异步调用启动监听:

Collapse Copy Code

// This call activates GetActiveClients event listener

m_service.GetActiveClientsAsync(m_sessionID);

这个异步调用操作并不是无限制的等待,当web服务段的“活动客户列表改变”,并且GetActiveClientsComplated事件有信号标识时,异步调用将会结束:

Collapse Copy Code

// Signal GetActiveClientsCompleted event for each client

foreach (Guid sID in s_services.Keys)

{

  s_services[sID].GetActiveClientsCompleted.Set();

}

上面的情况发生时,web服务的GetActiveClients方法将会执行:

Collapse Copy Code

bool signalled = GetActiveClientsCompleted.WaitOne();

// wait for GetActiveClientsCompleted event

 

if (signalled)

{

    lock (s_services)

    {

      // Create client list and return it

      List<int> clients = new List<int>();

      foreach (Guid sID in s_services.Keys)

      {

        if (sID == sessionID) continue;

        clients.Add(s_services[sID].m_clientID);

      }

      return clients.ToArray();

    }

}

else return new int[] { };

// Return empty client list

一旦事件发生,每一个客户端获得一个GetActiveClientsComplated事件,在客户端将交给相应的方法处理:

Collapse Copy Code

void m_service_GetActiveClientsCompleted(object sender,

   WebServiceWindowsClient.localhost.GetActiveClientsCompletedEventArgs e)

{

  // Add current list of active clients to list box

  int[] clients = e.Result;

  string client_list = "";

  foreach (int client in clients) client_list += client + " ";

  listBoxEvents.Items.Add(string.Format("GetActiveClients " +

                          "completed with result: {0}", client_list));

 

  // This call reactivates GetActiveClients event listener

  m_service.GetActiveClientsAsync(m_sessionID);

}

你可能注意到了在处理函数的最后,我们调用了GetActiveUserAsync方法来激活监听器。这是一个很好的技巧。

如何调试示例项目

你可以下载示例解决方案的源代码来验证这种做法的可行性,验证根本不需要在客户端进行轮询试调用。在示例源代码中,web服务发布在localhost上。你可以尝试着将其部署到你可以访问的其他任何主机上,来验证它的工作过程。在此案例中,你必须得修改客户端源码上包含localhost的所有语句。安装完成后,运行若干个webservicewindowsclient.exe,并且点击start session按钮。

结论

这篇文章阐释了如何通过异步web服务方法调用来实现web服务到客户端的事件回调功能。来自客户端到web服务的每个异步调用都会调用相应的异步方法,这些方法仅是在等待AutoResetEvent被触发。一旦这个事件触发,客户端的相应<方法名>Complated事件被激活。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值