zoukankan      html  css  js  c++  java
  • web service中的事件

    介绍
    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]属性,我也希望事件也可以作类似的处理,如果以下成为可能的话那将非常使人激动人心。
    CodeProject原文

    [WebEvent]

    public event ActiveClientsChangedDelegate OnActiveClientsChanged = null;

     

    在web service定义如下的委托:

    public delegate void ActiveClientsChangedDelegate(int[] clients);

     

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

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

     

    Clients是当前服务的活动客户的ID数组。遗憾的是,你使用当前的.NET web服务框架模板是不可行的。而其实现的方法之一是从客户端来调用服务。由于它不具有实时性并且依赖于客户端电脑,因而这并不是一个好办法。这里阐述了另外一种方法,那就是通过异步调用。
    通过异步调用实现web服务回调函数
    先让我们看一个例子。我们有一个web服务,并且希望它能够及时通知他的活动连接客户的数目。有任何客户连接登录后,其他所有的客户能够收到这个通知。一下是该web服务的部分代码:
    Copy Code

    View 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事件:

    // Create proxy for WebService
    m_service = new WebServiceWindowsClient.localhost.WebService();



    // Subscribe for event
    m_service.GetActiveClientsCompleted += new

    WebServiceWindowsClient.localhost.GetActiveClientsCompletedEventHandler(

    m_service_GetActiveClientsCompleted);

     

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

    // This call activates GetActiveClients event listener
    m_service.GetActiveClientsAsync(m_sessionID);

     

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

    // Signal GetActiveClientsCompleted event for each client
    foreach (Guid sID in s_services.Keys)

    {

    s_services[sID].GetActiveClientsCompleted.Set();

    }

     

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

    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事件,在客户端将交给相应的方法处理:

    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事件被激活。

    出处:http://blog.csdn.net/frank_lhj/archive/2009/11/17/4822997.aspx

  • 相关阅读:
    将Oracle数据库设置为归档模式 & Oracle 9i启动归档
    修改用户家目录
    使用Pam_Tally2锁定和解锁SSH失败的登录尝试
    linux系统用户锁定与解锁
    Linux用户密码过期 FAILED to authorize user with PAM (Authentication token is no longer valid; new one req)
    普通用户通过sudo su
    两台服务器配置互信
    red hat官方的rhel操作系统版本号与内核版本号的对应关系
    linux修改IP地址
    Docker学习(12) Dockerfile构建过程
  • 原文地址:https://www.cnblogs.com/jiewei915/p/1961296.html
Copyright © 2011-2022 走看看