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");
}