0

I am making an ASP.NET Webapplication, which I use to edit the settings (an XML file) of a Windows Service. The Windows Service can run on the same server as the Web application, I have gotten that to work perfect, the issue I am having is when the Windows Service is running on a different server and the Web application needs to send a Xml file to the Windows Service.

My goal is to have the ASP.NET Webapplication sent the XML file that it just updated over Http to the Windows Service, which has a HttpListener.

What I have managed so far:

ASP.NET application:

public string PushSettings(string serverName, string xmlFile)
{
    var prefix = "http://" + serverName+ ":";
    var portnumber = ConfigurationManager.AppSettings["PortNumber"];
    var command = ConfigurationManager.AppSettings["PushSettingsCommand"];
    var request = (HttpWebRequest)WebRequest.Create(prefix + portnumber + command);
    var bytes = System.Text.Encoding.ASCII.GetBytes(xmlFile);
    request.ContentType = "text/xml; encoding='utf-8'";
    request.ContentLength = bytes.Length;
    request.Method = "POST";
    var requestStream = request.GetRequestStream();
    requestStream.Write(bytes, 0, bytes.Length);
    requestStream.Close();

    try
    {
        var response = (HttpWebResponse)request.GetResponse();
        return response.StatusCode.ToString();
    }
    catch (WebException ex)
    {
        Log.Info("WebException thrown while trying to connect to httplistener. Exception message: " + ex.Message + " The following request was attempted: " + prefix + portnumber + command);
        throw new WebException("WebException thrown while trying to connect to httplistener. Exception message: " + ex.Message + " The following request was attempted: " + prefix + portnumber + command);
    }
}

(string xmlFile is the entire XML file as a string)

Windows Service:

public void RunHttpListener()
{
    var listener = new HttpListener();
    try
    {
        listener.Prefixes.Add(_Prefix);

        listener.Start();

        var context = listener.GetContext();
        var request = context.Request;
        var ipAdress = context.Request.RemoteEndPoint?.ToString();

        if(_Prefix.Contains("PushSettings"))
        {
            SaveFile(context.Request.ContentEncoding, getSettings.GetBoundary(context.Request.ContentType), context.Request.InputStream);
        }

        var response = context.Response;
        const HttpStatusCode responseString = HttpStatusCode.OK;
        var buffer = Encoding.UTF8.GetBytes(responseString.ToString());
        response.ContentLength64 = buffer.Length;
        var output = response.OutputStream;
        output.Write(buffer, 0, buffer.Length);
        output.Close();
        listener.Stop();
    }
    catch (Exception ex)
    {
        Log.Info(ex.Message);
        if (listener.IsListening)
        {
            listener.Stop();
        }
    }
}

(_Prefix is for example: {serverName}/PushSettings)

GetBoundary() and SaveFile() is code I found on this Stack Overflow thread: Httplistener and file upload , that throws an exception because len == 0 on the third time it loops through the first while(true) { }. Here is the code from that thread:

public String GetBoundary(String ctype)
{
    return "--" + ctype.Split(';')[1].Split('=')[1];
}

public void SaveFile(Encoding enc, String boundary, Stream input)
{
    var boundaryBytes = enc.GetBytes(boundary);
    var boundaryLen = boundaryBytes.Length;

    using (var output = new FileStream("Settings.xml", FileMode.Create, FileAccess.Write))
    {
        var buffer = new Byte[1024];
        var len = input.Read(buffer, 0, 1024);
        var startPos = -1;

        // Find start boundary
        while (true)
        {
            if (len == 0)
            {
                throw new Exception("Start Boundaray Not Found");
            }

            startPos = IndexOf(buffer, len, boundaryBytes);
            if (startPos >= 0)
            {
                break;
            }
            else
            {
                Array.Copy(buffer, len - boundaryLen, buffer, 0, boundaryLen);
                len = input.Read(buffer, boundaryLen, 1024 - boundaryLen);
            }
        }

        // Skip four lines (Boundary, Content-Disposition, Content-Type, and a blank)
        for (var i = 0; i < 4; i++)
        {
            while (true)
            {
                if (len == 0)
                {
                    throw new Exception("Preamble not Found.");
                }

                startPos = Array.IndexOf(buffer, enc.GetBytes("\n")[0], startPos);
                if (startPos >= 0)
                {
                    startPos++;
                    break;
                }
                else
                {
                    len = input.Read(buffer, 0, 1024);
                }
            }
        }

        Array.Copy(buffer, startPos, buffer, 0, len - startPos);
        len = len - startPos;

        while (true)
        {
            var endPos = IndexOf(buffer, len, boundaryBytes);
            if (endPos >= 0)
            {
                if (endPos > 0) output.Write(buffer, 0, endPos - 2);
                break;
            }
            else if (len <= boundaryLen)
            {
                throw new Exception("End Boundaray Not Found");
            }
            else
            {
                output.Write(buffer, 0, len - boundaryLen);
                Array.Copy(buffer, len - boundaryLen, buffer, 0, boundaryLen);
                len = input.Read(buffer, boundaryLen, 1024 - boundaryLen) + boundaryLen;
            }
        }
    }
}

public Int32 IndexOf(Byte[] buffer, Int32 len, Byte[] boundaryBytes)
{
    for (var i = 0; i <= len - boundaryBytes.Length; i++)
    {
        var match = true;
        for (Int32 j = 0; j < boundaryBytes.Length && match; j++)
        {
            match = buffer[i + j] == boundaryBytes[j];
        }

        if (match)
        {
            return i;
        }
    }

    return -1;
}

Here’s an (shortened) example of what the XML file looks like

<?xml version="1.0" encoding="UTF-8"?>
<MonitorSettings>
  <Interval>30000</Interval>
  <QueuCheck>False</QueuCheck>
  <MailAlert>False</MailAlert>
  <WindowsServices>mongodb</WindowsServices>
</MonitorSettings>

The Windows Service code I have so far is able to receive the request from the Webapplication, but it is not saving an XML file because of the exception thrown when len == 0. Is there anything I’m doing incorrectly? Is there a better way to do things? Any good StackOverflow threads that can help?

Edit To be more exact, the Exception is raised here in the function SaveFile() , on the third time it loops in the while(true){ }:

if (len == 0)
{
    throw new Exception("Start Boundaray Not Found");
}
Gogoku7
  • 27
  • 2
  • 8
  • Could you add when and where the exception is raised please? Could be a log but most importantly the line in code and the variable please? – MadStark Sep 21 '17 at 08:52
  • Edited the question to include where the Exception is thrown. – Gogoku7 Sep 21 '17 at 08:57

1 Answers1

0

It looks like I was using a too complicated method of trying to save the body of the Request to an XML file. I did some more research and found this code to work:

    public void SaveFile(HttpListenerContext context)
    {
        // Get the data from the HTTP stream
        var body = new StreamReader(context.Request.InputStream).ReadToEnd();

        var xmlDocument = new XmlDocument();
        xmlDocument.LoadXml(body);
        xmlDocument.Save("Settings.xml");
    }
Gogoku7
  • 27
  • 2
  • 8