Pregunta

que creó am empuje servicio web de Exchange Notificaciones de escucha basado en la HttpListener en el libro EWS (código de abajo). Se corrió muy bien en un Win 2008 Server con un único núcleo Xeon. Ahora nos trasladamos a un R2 Server Windows 2008 con una CPU Opteron de cuatro núcleos y se bloquea inmediatamente después del proceso de escucha se inicia con HTTPListenerExceptions. Ahora ya que nada ha cambiado, pero el servidor pensé que podría tener algo que ver con múltiples subprocesos. Tal vez someon puede aconsejar, gracias.

public class PushNotificationClient
{
    private uint portNumber;
    private NotificationEventsReceived eventHandler;
    private bool isListening = false;
    private ManualResetEvent stopEvent = new ManualResetEvent(false);
    private bool shouldStop = false;
    private XmlNamespaceManager mgr;
    private XmlSerializer ser;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="portNumber">Port number to listen on</param>
    /// <param name="eventHandler">delegate to call when notifications are
    /// received</param>
    ///
    public PushNotificationClient(
    uint portNumber,
    NotificationEventsReceived eventHandler)
    {
        this.portNumber = portNumber;
        if (eventHandler == null)
        {
            throw new ArgumentNullException("eventHandler");
        }
        this.eventHandler = eventHandler;
        // namespace manager is used for XPath queries when parsing the request
        //
        this.mgr = new XmlNamespaceManager(new NameTable());
        this.mgr.AddNamespace("t",
        "http://schemas.microsoft.com/exchange/services/2006/types");
        this.mgr.AddNamespace("m",
        "http://schemas.microsoft.com/exchange/services/2006/messages");
        // XmlSerializer is used to convert SendNotification elements into proxy
        // class instances
        //
        this.ser = new XmlSerializer(typeof(SendNotificationResponseType));
    }

    /// <summary>
    /// Start Listening
    /// </summary>
    public void StartListening()
    {
        VerifyNotListening();
        this.stopEvent.Reset();
        this.shouldStop = false;
        // Run the listener on a background thread so we are not blocked
        //
        ThreadPool.QueueUserWorkItem(new WaitCallback(ListenOnThread));
    }

    /// <summary>
    /// Stop Listening
    /// </summary>
    public void StopListening()
    {
        VerifyListening();
        // Set the stopEvent. This will cause the worker thread to close our and
        // dispose of the HttpListener and exit the thread
        //
        this.stopEvent.Set();
    }

    /// <summary>
    /// Thread pool method to start listening on the background thread
    /// </summary>
    /// <param name="state">State - ignore</param>
    ///
    private void ListenOnThread(object state)
    {
        using (HttpListener listener = new HttpListener())
        {
            listener.Prefixes.Add(
                String.Format(
                "http://+:{0}/PushNotificationsClient/",
                this.portNumber.ToString()));
            listener.Start();
            this.isListening = true;
            while (!shouldStop)
            {
                IAsyncResult asyncResult = listener.BeginGetContext(
                AsyncCallbackMethod, listener);
                // Wait on either the listener or the stop event
                //
                int index = WaitHandle.WaitAny(
                new WaitHandle[] { stopEvent, asyncResult.AsyncWaitHandle });
                switch (index)
                {
                    case 0:
                        // Stop event was triggered.
                        //
                        shouldStop = true;
                        break;
                    case 1:
                        // Notification was received. Just loop around so we can call
                        // BeginGetContext again
                        //
                        break;
                }
            }
            listener.Stop();
        }
        this.isListening = false;
    }

    /// <summary>
    /// Async method called once we receive a request
    /// </summary>
    /// <param name="result">Async result containing our HttpListener</param>
    ///
    private void AsyncCallbackMethod(IAsyncResult result)
    {
        HttpListener listener = result.AsyncState as HttpListener;
        if (!this.isListening)
        {
            // Our callback gets fired when we stop the listener too. If it is not
            // listening, just return.
            //
            return;
        }
        HttpListenerContext context = listener.EndGetContext(result);
        SendNotificationResponseType request;
        // Now use the XML serializer to turn the XML into a notification
        // serialization type...
        //
        XmlDocument doc = new XmlDocument();
        try
        {
            doc.LoadXml(
            new StreamReader(
            context.Request.InputStream).ReadToEnd());
            // retrieve the first SendNotification element (there should be only one).
            //
            XmlNodeList nodes = doc.SelectNodes("//m:SendNotification[1]", this.mgr);
            if (nodes.Count == 0)
            {
                // this wasn't a SendNotification request or it was malformed or
                // something like that.
                FailRequest(context);
                return;
            }
            string sendNotification = nodes[0].OuterXml;
            using (MemoryStream ms = new MemoryStream())
            {
                byte[] bytes = Encoding.UTF8.GetBytes(sendNotification);
                ms.Write(bytes, 0, bytes.Length);
                ms.Flush();
                ms.Position = 0L;
                request = (SendNotificationResponseType)this.ser.Deserialize(ms);
            }
        }
        catch (XmlException)
        {
            // Failed to deserialize request.
            //
            FailRequest(context);
            return;
        }
        // Fire the delegate
        //
        NotificationResponse response = eventHandler(
        this, /* sender */
        request.ResponseMessages.Items[0]
        as SendNotificationResponseMessageType);
        GenerateResponseXML(context, response);
    }

    /// <summary>
    /// Fail the request. Right now we don't differentiate between reasons why it
    /// failed.
    /// </summary>
    /// <param name="context">Request context</param>
    ///
    private void FailRequest(HttpListenerContext context)
    {
        context.Response.ContentEncoding = Encoding.UTF8;
        context.Response.ContentType = "text/xml; charset=utf-8";
        context.Response.ProtocolVersion = new Version(1, 1, 0, 0);
        context.Response.StatusCode = 400;
        string response = "<?xml version=\"1.0\"?>" +
        "<Error>Bad Request</Error>";
        byte[] responseBytes = Encoding.UTF8.GetBytes(response);
        context.Response.ContentLength64 = responseBytes.Length;
        context.Response.OutputStream.Write(
        responseBytes, 0, responseBytes.Length);
        context.Response.OutputStream.Flush();
    }

    /// <summary>
    /// Generate the response xml
    /// </summary>
    /// <param name="context">call context</param>
    /// <param name="response">The response enum value</param>
    ///
    private void GenerateResponseXML(
    HttpListenerContext context,
    NotificationResponse response)
    {
        StringBuilder builder = new StringBuilder();
        builder.AppendLine("<?xml version=\"1.0\"?>");
        builder.AppendLine("<s:Envelope xmlns:s= " +
        "\"http://schemas.xmlsoap.org/soap/envelope/\">");
        builder.AppendLine("<s:Body>");
        builder.AppendLine(" <SendNotificationResult " +
        "xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">");
        builder.AppendFormat(" <SubscriptionStatus>{0}</SubscriptionStatus>\r\n",
        response.ToString());
        builder.AppendLine(" </SendNotificationResult>");
        builder.AppendLine("</s:Body>");
        builder.AppendLine("</s:Envelope>");
        context.Response.ContentEncoding = Encoding.UTF8;
        context.Response.ContentType = "text/xml; charset=utf-8";
        context.Response.ProtocolVersion = new Version(1, 1, 0, 0);
        context.Response.StatusCode = 200;
        byte[] responseBytes = Encoding.UTF8.GetBytes(builder.ToString());
        context.Response.ContentLength64 = responseBytes.Length;
        context.Response.OutputStream.Write(
        responseBytes, 0, responseBytes.Length);
        context.Response.OutputStream.Flush();
    }

    /// <summary>
    /// Returns true if the listener is listening
    /// </summary>
    public bool IsListening
    {
        get
        {
            return isListening;
        }
    }
    /// <summary>
    /// Verifies that the listener isn't listening
    /// </summary>
    private void VerifyNotListening()
    {
        if (isListening)
        {
            throw new PushNotificationStateException("Cannot perform this operation " +
            "when listening");
        }
    }

    /// <summary>
    /// Verifies that the listener is listening
    /// </summary>
    private void VerifyListening()
    {
        if (!isListening)
        {
            throw new PushNotificationStateException("Cannot perform this operation " +
            "when not listening");
        }
    }


}
¿Fue útil?

Solución

Sería de gran ayuda si nos donde en la inicialización que estaba fallando dicho, pero sospecho que está bien intentar registrar un URI que no ha habilitado con el comando netsh, o que está tratando de registrar una URI que algún otro proceso ya ha registrado.

Documentación para esa excepción, dice, en parte :

  

será lanzada HttpListenerException   Si los intentos HttpListener a   registrar un identificador uniforme de recursos   (URI) prefijo que ya está   registrado.

Ha algún otro proceso ya registrado http://+:{0}/PushNotificationsClient/? ¿Se acordó de ejecutar el comando netsh para registrar el URI en el puerto correcto y permitir la escucha?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top