I have created a Windows forms application which able to publish OPC tags into an MQTT broker, Now I'm trying to do the reverse, write MQTT tags into an OPC server. when I have started both the agent (the publisher) and the transfer (the subscriber) the two threads do the same work which is publishing I don't know what is the problem.
The start method is below :
public byte Start()
{
try
{
byte connectResult;
if (IsLWT == false)
{
connectResult = this._MqttClient.Connect(ClientID, Username, Password, IsCleanSession, KeepAlivePeriode);
}
else
{
connectResult = this._MqttClient.Connect(ClientID, Username, Password, willRetain, willQos, true, willTopic, willMessage, IsCleanSession, KeepAlivePeriode);
}
// 0 means that the connection suceeded
if (connectResult == 0)
{
this.Rate = GetRateFromOPCGroups();
this._publisherThread = new Thread(() => Publish());
this._publisherThread.IsBackground = true;
this._publisherThread.Start();
IsStarted = true;
}
if (connectResult == 0)
{
//this.Rate = GetRateFromOPCGroups();
this._SubscriberThread = new Thread(() => Subscribe(topics));
this._SubscriberThread.IsBackground = true;
this._SubscriberThread.Start();
IsStarted = true;
}
return connectResult;
}
catch (IntegrationObjects.Networking.M2Mqtt.Exceptions.MqttClientException ex)
{
MQTTServiceLogger.TraceLog(MessageType.Error, MQTTServiceMessages.startAgentFailed(this.Name,ex.Message));
return 11;
}
catch (IntegrationObjects.Networking.M2Mqtt.Exceptions.MqttCommunicationException ex)
{
MQTTServiceLogger.TraceLog(MessageType.Error, MQTTServiceMessages.startAgentFailed(this.Name, ex.Message));
return 11;
}
catch (Exception ex)
{
MQTTServiceLogger.TraceLog(MessageType.Error, MQTTServiceMessages.startAgentFailed(this.Name, ex.Message));
return 11;
}
}
1.This is the publish code:
private void Publish()
{
while (true)
{
if (IsStarted)
{
try
{
if (_MqttClient.IsConnected)
{
isConnected = true;
if (this.OPCItems.Count != 0)
{
JsonMQTTMessage JsonMessage = new JsonMQTTMessage();
JsonMessage.Timestamp = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff");
JsonMessage.ListofValues = new List<UpdatedOPCItem>();
lock (lockOPCItems)
{
foreach (OPCItem Item in OPCItems.ToList())
{
if (Item != null)
{
UpdatedOPCItem upItem = new UpdatedOPCItem();
upItem.ID = Item.ItemID;
upItem.value = Item.ItemCurrentValue;
upItem.quality = Item.ItemQuality;
upItem.timestamp = Item.ItemTimeStamp.ToString("yyyy/MM/dd HH:mm:ss.fff");
upItem.DataType = Item.ItemDataType;
JsonMessage.ListofValues.Add(upItem);
}
}
}
var messageTopublish = Newtonsoft.Json.JsonConvert.SerializeObject(JsonMessage);
ushort res = _MqttClient.Publish(Topic, Encoding.UTF8.GetBytes(messageTopublish), Qos, Retain);
ResetValues();
Thread.Sleep(Rate);
This is the Subscribe code:
public void Subscribe(List topics)
{
while (true)
{
if (IsStarted)
{
try
{
if (_MqttClient.IsConnected)
{
isConnected = true;
foreach (string topic in topics)
{
ushort msggId = _MqttClient.Subscribe(new string[] { $"{ topic }" },
new byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE });
}
Thread.Sleep(Rate);
}
else
I wrote a little web server on Linux using the Mono HTTPListener class. It works fine for http requests. However, if I use a self-signed SSL certificate (created with openssl and installed with httpcfg) it will throw an un-catchable exception as soon as the request forom a browser comes in.
The exception is:
Unhandled Exception:
System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: The client stopped the handshake.
at Mono.Security.Protocol.Tls.SslServerStream.EndNegotiateHandshake (IAsyncResult asyncResult) <0xb4b079c8 + 0x001cf> in <filename unknown>:0
at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) <0xb4b07428 + 0x0005f> in <filename unknown>:0
Here is the complete code:
using System;
using System.Net;
using System.IO;
using System.Text;
using System.Threading;
namespace SSLTest
{
class MainClass
{
static void Main ()
{
try
{
HttpListener l = new HttpListener ();
l.Prefixes.Add ("https://*:8443/");
l.Start ();
Console.WriteLine("Server is running.");
while (l.IsListening)
{
//create the worker thread
HttpListenerContext ctx = l.GetContext(); //.GetContext() blocks until something comes in
if(ctx != null)
{
if(ctx.Request.RemoteEndPoint != null)
{
Thread workerThread = new Thread(() => RunWorker(ctx));
workerThread.Start();
}
}
}
Console.WriteLine("Server is stopped.");
}
catch(Exception ex)
{
Console.WriteLine ("Exception in Main: " + ex);
}
}
static void RunWorker(HttpListenerContext ctx)
{
try
{
if(ctx.Request != null)
{
if(ctx.Request.RemoteEndPoint != null)
{
Console.WriteLine ("Got request from " + ctx.Request.RemoteEndPoint.ToString());
string rstr = "Test Website!\n" + DateTime.Now.ToString();
byte[] buf = Encoding.UTF8.GetBytes(rstr);
if(buf!=null)
{
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
}
}
}
catch(Exception ex)
{
Console.WriteLine ("#Exception in RunWorker: " + ex.Message);
}
}
}
}
This is the case when I am using a browser for the first time. The browser will show something like "Unsafe certificate! Do you want to continue (not recommended)?". If I click on Yes and restart the crashed server app it will work from that moment on.
How can I fix this?
Also, I am not able to catch this exception with a try block. It will always terminate my application. How can I prevent that?
Should be fixed by an unreleased bug fix https://bugzilla.xamarin.com/show_bug.cgi?id=52675... although I have not had a chance to test.
I have seen this as well and am currently trying to find a way to handle the exception. This looks to be a bug in Mono.
It occurs when certificate verification fails in any way.
I obtained a CA signed cert which fixed the problem as long as the certificate common name (dns) is the same as the dns used in the URL I'm trying to send a get request to. If I instead specify the public IP address in the url (which the cert is not registered with) the mono app will crash with an unhandled exception.
One option we're considering is implementing a TCP based webserver which would use a TcpListener instead of the heavy HttpListener which would in turn fix other problems we're seeing with mono httplistener prefixes not working correctly when bound to the internal IP behind a NAT. This would mean the cert could be bound pro-grammatically as well, it just takes more work.
Below is a very rough version of what this might look like. By no means is this a finished product but it may serve to help others on this same path... I'll have to do this in two answers, this is the tcp web server.
using System;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
namespace Example.Lib.Net
{
internal class TcpWebServer : IDisposable
{
private TcpListener m_Listener = null;
private bool m_IsSSL = false;
private X509Certificate2 m_ServerCertificate = null;
internal X509Certificate2 ServerCertificate
{
get { return m_ServerCertificate; }
set { m_ServerCertificate = value; }
}
internal void Start(string ip, int port, bool useSsl = false)
{
if (useSsl) // for player streams always use ssl to
{
m_IsSSL = true;
m_ServerCertificate = new X509Certificate2("./cert/cert.pfx", "pass");
X509Store store = new X509Store(StoreName.TrustedPublisher, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(m_ServerCertificate);
store.Close();
}
IPAddress ipAddr = IPAddress.Any;
if (ip != "*") IPAddress.TryParse(ip, out ipAddr);
try
{
m_Listener = new TcpListener(ipAddr, port);
m_Listener.Start();
m_Listener.BeginAcceptTcpClient(OnClientAccepted, m_Listener);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private void OnClientAccepted(IAsyncResult ar)
{
TcpListener listener = ar.AsyncState as TcpListener;
if (listener == null)
return;
TcpClient client = listener.EndAcceptTcpClient(ar);
client.ReceiveBufferSize = 65535;
client.Client.ReceiveBufferSize = 65535;
TcpWebConnection con = new TcpWebConnection(client, this, m_IsSSL);
listener.BeginAcceptTcpClient(OnClientAccepted, listener);
}
}
}
This is the tcp web connection code.
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;
using System.Threading;
using System.Web;
using Example.Lib.Common;
using Example.Lib.Models;
namespace Example.Lib.Net
{
internal enum RequestType
{
None = 0,
GET = 1,
POST = 2,
OPTIONS = 3
}
internal class TcpWebConnection : IDisposable
{
#region private members
private bool m_IsDisposed = false;
private bool m_IsSSL = false;
private bool m_HasHeaders = false;
private bool m_FileCreated = false;
private bool m_IsFileUpload = false;
private RequestType m_RequestType = RequestType.None;
private string m_ReadData = string.Empty;
private string m_Request = string.Empty;
private string m_RemoteIP = string.Empty;
private string m_AbsoluteURI = string.Empty;
private string m_ContentType = string.Empty;
private string m_TempFilename = string.Empty;
private byte[] m_EndBoundaryBytes = null;
private byte[] m_StartBoundaryBytes = null;
private int m_ContentLength = 0;
private long m_StartBoundaryIndex = -1;
private long m_EndBoundaryIndex = -1;
private long m_BytesRead = 0;
private NameValueCollection m_QueryString = null;
private string[] m_Segments = new string[1];
private string m_HttpVersion = "HTTP/1.1";
private byte[] m_PostData = null;
private byte[] m_Buffer = new byte[65535];
private ReadWriteBuffer m_TempBuffer;
private FileStream m_FileStream = null;
private MemoryStream m_FullBuffer = new MemoryStream();
private TcpClient m_Client = null;
private System.IO.Stream m_NetworkStream = null;
private TcpWebServer m_Parent = null;
private Thread m_Thread_Read = null;
private Timer m_Timer_Check = null;
private DateTime m_LastRead = DateTime.Now;
private AutoResetEvent m_WaitHandle_Write;
#endregion private members
#region constructors
internal TcpWebConnection(TcpClient client, TcpWebServer parent, bool ssl)
{
m_WaitHandle_Write = new AutoResetEvent(false);
m_TempBuffer = new ReadWriteBuffer(65535);
m_IsSSL = ssl;
m_Segments[0] = string.Empty;
m_Client = client;
m_Parent = parent;
m_RemoteIP = ((IPEndPoint)m_Client.Client.RemoteEndPoint).Address.ToString();
if (ssl)
{
m_NetworkStream = new SslStream(m_Client.GetStream(), false);
}
else
{
m_NetworkStream = m_Client.GetStream();
}
m_NetworkStream.ReadTimeout = 2000;
m_Timer_Check = new Timer(Timer_Check_Callback, this, 2000, 2000);
// start threads
m_Thread_Read = new Thread(DoRead);
m_Thread_Read.IsBackground = true;
m_Thread_Read.Start();
}
#endregion constructors
#region destructors
~TcpWebConnection()
{
try
{
if (m_Timer_Check != null) m_Timer_Check.Dispose();
m_Timer_Check = null;
}
catch { } // if the timer was
}
#endregion destructors
#region internal properties
internal bool IsLargeFileUpload { get; set; } = false;
internal string TempFilename
{
get { return m_TempFilename; }
set { m_TempFilename = value; }
}
/// <summary>
/// Remote IP
/// </summary>
internal string RemoteIP
{
get { return m_RemoteIP; }
}
internal string AbsoluteURI
{
get { return m_AbsoluteURI; }
}
internal string ContentType
{
get { return m_ContentType; }
}
internal string[] Segments
{
get { return m_Segments; }
}
internal NameValueCollection QueryString
{
get { return m_QueryString; }
}
internal Stream NetworkStream
{
get { return m_NetworkStream; }
}
internal int ContentLength
{
get { return m_ContentLength; }
}
#endregion internal properties
#region private methods
private void Timer_Check_Callback(object state)
{
if ((DateTime.Now - m_LastRead).TotalSeconds > 15)
{
try
{
Program.BlacklistIP(m_RemoteIP, "TcpWebConnection - Timer", "Connection Timed Out");
ProcessRequest(m_ReadData);
Dispose();
}
catch (Exception e) { }
}
}
private void DoRead()
{
if (m_IsSSL)
{
try
{
((SslStream)m_NetworkStream).AuthenticateAsServer(m_Parent.ServerCertificate, false, SslProtocols.Tls, false);
((SslStream)m_NetworkStream).BeginRead(m_Buffer, 0, m_Buffer.Length, new AsyncCallback(SslRead), m_NetworkStream);
m_NetworkStream.ReadTimeout = 5000;
m_NetworkStream.WriteTimeout = 5000;
}
catch (Exception e)
{
//Console.WriteLine("SSL Auth Error: " + e.Message);
}
}
else
{
NormalRead();
}
}
private void UpdatePostData()
{
m_FullBuffer.Position = 0;
byte[] fullBuffer = Common.Conversion.MemoryStreamToByteArray(m_FullBuffer);
m_FullBuffer.Dispose();
if (m_StartBoundaryIndex > -1 && m_EndBoundaryIndex > -1)
{
m_PostData = new byte[m_EndBoundaryIndex - m_StartBoundaryIndex];
Array.Copy(fullBuffer, m_StartBoundaryIndex, m_PostData, 0, m_EndBoundaryIndex - m_StartBoundaryIndex);
}
}
internal void SaveFile(string filepath)
{
try
{
UpdatePostData();
if (m_PostData == null) return;
if (!Directory.Exists(Path.GetDirectoryName(filepath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(filepath));
}
if (File.Exists(filepath))
{
File.Delete(filepath);
}
using (FileStream output = new FileStream(filepath, FileMode.Create, FileAccess.Write))
{
output.Write(m_PostData, 0, m_PostData.Length);
}
}
catch (Exception e)
{
// report error
}
}
private void AppendBuffer(byte[] newBuffer, int length)
{
// we need to keep a running buffer here, the last 1024 bytes? how best to find the end boundary? need to determine when the stream is finished!
m_TempBuffer.Write(newBuffer, length);
if (m_IsFileUpload)
{
if (m_EndBoundaryIndex < 0)
{
m_EndBoundaryIndex = StreamHelper.LastIndexOf(m_TempBuffer.RawBytes, m_TempBuffer.Count, m_EndBoundaryBytes);
if (!IsLargeFileUpload && m_EndBoundaryIndex > -1)
{
m_EndBoundaryIndex = (m_FullBuffer.Length + length) - (m_TempBuffer.Count - m_EndBoundaryIndex);
}
}
if (m_StartBoundaryIndex < 0)
{
m_StartBoundaryIndex = StreamHelper.IndexOf(m_FullBuffer, m_StartBoundaryBytes);
if (m_StartBoundaryIndex > -1)
{
m_StartBoundaryIndex = StreamHelper.IndexOf(m_FullBuffer, Encoding.UTF8.GetBytes("\r\n\r\n"), m_StartBoundaryIndex + m_StartBoundaryBytes.Length) + 4;
}
}
}
if (m_StartBoundaryIndex == -1 || !IsLargeFileUpload) // if this is not a file upload because no start boundary has been found then write buffer to memory
{
m_FullBuffer.Write(newBuffer, 0, length);
}
else
{
if (!m_FileCreated) // we have never written to the file, dump the contents of the full buffer now
{
bool exists = true;
while (exists)
{
m_TempFilename = Config.StaticConfig.TempFolder + "/" + Path.GetRandomFileName();
exists = File.Exists(m_TempFilename);
}
m_FileStream = new FileStream(m_TempFilename, FileMode.Create, FileAccess.Write);
m_FullBuffer.Position = m_StartBoundaryIndex;
m_FullBuffer.CopyTo(m_FileStream);
m_FileStream.Write(newBuffer, 0, length);
m_FileCreated = true;
}
else // we have previously written to the file, append new bytes
{
if (m_EndBoundaryIndex == -1)
{
m_FileStream.Write(newBuffer, 0, length);
}
else
{
m_FileStream.Write(newBuffer, 0, length - m_EndBoundaryBytes.Length);
}
}
}
}
private void NormalRead()
{
try
{
int bufferSize = m_Buffer.Length;
int bytesRead = m_Client.Client.Receive(m_Buffer, bufferSize, 0);
while (bytesRead > 0 && !m_IsDisposed)
{
m_LastRead = DateTime.Now;
m_BytesRead += bytesRead;
if (!m_HasHeaders || m_RequestType == RequestType.GET)
{
string sBuffer = Encoding.ASCII.GetString(m_Buffer, 0, bytesRead);
m_ReadData += sBuffer;
}
AppendBuffer(m_Buffer, bytesRead);
m_HasHeaders = UpdateUniqueHeaders();
if (!m_HasHeaders && m_BytesRead > 1024)
{
Program.BlacklistIP(m_RemoteIP, m_ReadData, "No HTTP headers found in the first 1024 bytes");
return;
}
if (m_RequestType != RequestType.POST)
{
break; // process the request
}
else if (m_EndBoundaryIndex != -1)
{
break; // process the request, we found our end boundary for posted data
}
bytesRead = m_Client.Client.Receive(m_Buffer, bufferSize, 0);
}
ProcessRequest(m_ReadData);
}
catch (Exception e)
{
// report error
}
}
private void SslRead(IAsyncResult ar)
{
if (m_IsDisposed) return;
try
{
int byteCount = -1;
int bufferSize = m_Buffer.Length;
m_LastRead = DateTime.Now;
byteCount = m_NetworkStream.EndRead(ar);
m_BytesRead += byteCount;
if (!m_HasHeaders || m_RequestType == RequestType.GET)
{
string sBuffer = Encoding.ASCII.GetString(m_Buffer, 0, byteCount);
m_ReadData += sBuffer;
}
AppendBuffer(m_Buffer, byteCount);
m_HasHeaders = UpdateUniqueHeaders();
if (!m_HasHeaders && m_BytesRead > 1024)
{
Program.BlacklistIP(m_RemoteIP, m_ReadData, "No HTTP headers found in the first 1024 bytes");
return;
}
if (byteCount > 0)
{
if (m_RequestType != RequestType.POST && m_RequestType != RequestType.None)
{
m_NetworkStream.BeginRead(m_Buffer, 0, bufferSize, new AsyncCallback(SslRead), m_NetworkStream);
}
else if (m_EndBoundaryIndex == -1) // as long as we haven't found the end of the stream continue reading
{
m_NetworkStream.BeginRead(m_Buffer, 0, bufferSize, new AsyncCallback(SslRead), m_NetworkStream);
return;
}
}
}
catch (Exception e)
{
return;
}
ProcessRequest(m_ReadData);
}
private bool UpdateUniqueHeaders()
{
if (m_RequestType == RequestType.None && m_ReadData.Length > 8)
{
m_RequestType = (m_ReadData.StartsWith("GET ") ? RequestType.GET : m_RequestType);
m_RequestType = (m_ReadData.StartsWith("POST ") ? RequestType.POST : m_RequestType);
m_RequestType = (m_ReadData.StartsWith("OPTIONS ") ? RequestType.OPTIONS : m_RequestType);
}
if (m_RequestType == RequestType.GET || m_RequestType == RequestType.POST)
{
string request = m_ReadData;
if (string.IsNullOrEmpty(m_HttpVersion)) m_HttpVersion = m_ReadData.Substring(request.IndexOf("HTTP", 1), 8);
if (string.IsNullOrEmpty(m_ContentType)) m_ContentType = GetHeader(request, "Content-Type");
if (m_ContentLength == 0)
{
int cLength = 0;
int.TryParse(GetHeader(request, "Content-Length"), out cLength);
m_ContentLength = cLength;
if (m_ContentLength / 1024 / 1024 > 20)
{
IsLargeFileUpload = true; // data is sent directly to a file instead of saving in memory
}
}
}
if (m_RequestType != RequestType.None && !string.IsNullOrEmpty(m_HttpVersion) && (!string.IsNullOrEmpty(m_ContentType) || m_RequestType != RequestType.POST))
{
if (m_RequestType == RequestType.POST)
{
try
{
if (m_IsFileUpload == false)
{
m_IsFileUpload = Segments[1].Replace("/", "") == "upload";
}
}
catch { }
if (m_RequestType == RequestType.POST && m_StartBoundaryBytes == null)
{
m_StartBoundaryBytes = Encoding.ASCII.GetBytes(GetStartBoundary());
m_EndBoundaryBytes = Encoding.ASCII.GetBytes(GetEndBoundary());
}
}
if (string.IsNullOrEmpty(m_Request) && m_Segments.Length <= 1 && m_QueryString == null)
{
// Extract the Requested Type and Requested file/directory
string m_Request = m_ReadData.Substring(0, m_ReadData.IndexOf("HTTP", 1) - 1);
//Replace backslash with Forward Slash, if Any
m_Request = m_Request.Replace("\\", "/");
m_Request = m_Request.Replace("GET ", "");
m_Request = m_Request.Replace("POST ", "");
Uri uri = new Uri("http://localhost" + m_Request);
NameValueCollection query = HttpUtility.ParseQueryString(uri.Query);
//SendHeader(sHttpVersion, "image/jpeg", Program.BlankImageBuffer.Length, " 200 OK");
m_AbsoluteURI = m_Request;
m_Segments = uri.Segments;
m_QueryString = query;
}
if (m_RequestType != RequestType.POST)
{
return true;
}
else if (m_ContentLength > 0 && m_EndBoundaryBytes != null)
{
return true;
}
}
return false;
}
private string GetStartBoundary()
{
return "--" + m_ContentType.Split(';')[1].Split('=')[1];
}
private string GetEndBoundary()
{
return "--" + m_ContentType.Split(';')[1].Split('=')[1] + "--\r\n";
}
private string GetHeader(string request, string key)
{
string result = string.Empty;
int iStartPos = request.IndexOf(key + ":", 0) + key.Length + 1;
if (request.IndexOf(key + ":", 0) > -1)
{
// Get the HTTP text and version e.g. it will return "HTTP/1.1"
int iEndPos = request.IndexOf("\r\n", iStartPos);
result = request.Substring(iStartPos, iEndPos - iStartPos).Trim();
}
return result;
}
private void CleanFile()
{
try
{
if (!string.IsNullOrEmpty(m_TempFilename) && File.Exists(m_TempFilename))
{
using (Stream stream = File.Open(m_TempFilename, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, buffer.Length);
//stream.Position = 0;
//stream.Write(data, 0, data.Length);
}
}
}
catch { }
}
private void ProcessRequest(string request)
{
try
{
if (request.Length < 5) return;
List<string> headers = null;
if (request.StartsWith("OPTIONS"))
{
headers = GetCommonHeader("", 0);
headers.Add("Access-Control-Allow-Credentials: true");
headers.Add("Access-Control-Allow-Headers: Authorization, X-Mashape-Authorization, Accept, Content-Type, X-Requested-With, X-PINGOTHER, X-File-Name, Cache-Control");
headers.Add("Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS");
headers.Add("Keep-Alive: timeout=15,max=100");
headers.Add("Access-Control-Allow-Origin: *");
headers.Add("Connection: close");
SendHeader(headers);
return;
}
UpdateUniqueHeaders();
CleanFile();
CloseFile();
if (m_Timer_Check != null) m_Timer_Check.Dispose();
string responseText = Program.ProcessRequest(this);
if (string.IsNullOrEmpty(responseText)) responseText = "\r\n";
byte[] buf = Encoding.ASCII.GetBytes(responseText);
headers = GetCommonHeader("text/html", buf.Length, " 200 OK");
headers.Add("Access-Control-Allow-Origin: *");
SendHeaderAndData(headers, buf);
}
catch (Exception e) { }
finally
{
Dispose();
}
}
private void CloseFile()
{
try
{
if (m_FileStream != null)
{
m_FileStream.Dispose();
m_FileStream = null;
}
}
catch { }
}
/// <summary>
/// This function send the Header Information to the client (Browser)
/// </summary>
/// <param name="sHttpVersion">HTTP Version</param>
/// <param name="sMIMEHeader">Mime Type</param>
/// <param name="iTotBytes">Total Bytes to be sent in the body</param>
/// <param name="mySocket">Socket reference</param>
/// <returns></returns>
public List<string> GetCommonHeader(string mimeHeader = "text/html", int length = -1, string sStatusCode = " 200 OK", string filename = "", bool chunked = false)
{
// if Mime type is not provided set default to text/html
List<string> headers = new List<string>();
headers.Add(m_HttpVersion + sStatusCode);
headers.Add("Server: ExampleTcpWebServer");
if (!string.IsNullOrEmpty(mimeHeader))
{
headers.Add("Content-Type: " + mimeHeader);
}
if (length > -1)
{
headers.Add("Content-Length: " + length);
}
headers.Add("Date: " + DateTime.Now.ToUniversalTime().ToString("ddd, d MMM yyyy HH:mm:ss") + " GMT");
if (!string.IsNullOrEmpty(filename))
{
headers.Add("Content-Disposition: attachment; filename=\"" + filename + "\"");
}
if (chunked)
{
headers.Add("Transfer-Encoding: chunked");
}
return headers;
}
public void SendHeader(List<string> headers)
{
string sHeader = string.Empty;
foreach (string header in headers)
{
sHeader += header + "\r\n";
}
sHeader += "\r\n";
byte[] bSendData = Encoding.ASCII.GetBytes(sHeader);
SendToBrowser(bSendData, bSendData.Length);
}
public void SendHeaderAndData(List<string> headers, byte[] data)
{
string sHeader = string.Empty;
foreach (string header in headers)
{
sHeader += header + "\r\n";
}
sHeader += "\r\n";
byte[] bHeader = Encoding.ASCII.GetBytes(sHeader);
byte[] combined = new byte[bHeader.Length + data.Length];
Array.Copy(bHeader, combined, bHeader.Length);
Array.Copy(data, 0, combined, bHeader.Length, data.Length);
SendToBrowser(combined, combined.Length);
}
/// <summary>
/// Sends data to the browser (client)
/// </summary>
/// <param name="bSendData">Byte Array</param>
/// <param name="mySocket">Socket reference</param>
public void SendToBrowser(byte[] bSendData, int length)
{
try
{
if (Common.TcpHelper.SocketConnected(m_Client.Client))
{
if (m_IsSSL)
{
m_NetworkStream.Write(bSendData, 0, length);
}
else
{
m_Client.Client.Send(bSendData, length, 0);
}
}
else
{
Dispose();
}
}
catch (Exception e)
{
//Console.WriteLine("Error Occurred : {0} ", e);
}
}
#endregion private methods
#region IDisposable
public void Dispose()
{
if (!m_IsDisposed)
{
m_IsDisposed = true;
try
{
if (!string.IsNullOrEmpty(m_TempFilename) && File.Exists(m_TempFilename))
{
File.Delete(m_TempFilename);
}
}
catch { }
CloseFile();
try
{
m_Client.Client.Close(5);
m_Client.Close();
m_Client.Client.Dispose();
}
catch { }
try
{
m_NetworkStream.Dispose();
}
catch { }
try
{
if (Thread.CurrentThread != m_Thread_Read && m_Thread_Read.IsAlive)
{
m_Thread_Read.Join(1000);
if (m_Thread_Read.IsAlive) m_Thread_Read.Abort();
}
}
catch { }
try
{
m_ReadData = null;
m_PostData = null;
m_Buffer = null;
m_TempBuffer = null;
if (m_FullBuffer != null) m_FullBuffer.Dispose();
if (m_Timer_Check != null) m_Timer_Check.Dispose();
m_Timer_Check = null;
}
catch { }
}
}
#endregion IDisposable
}
}
I have coded a service in C# which runs and updates a CRM solution. I am trying to get the service to re-establish a connection to the database if it has to drop for some reason. So far when I detach the database and then reattach it, the service stops by itself.. Another thing is that then I detach the database, there is no exception logged by my synch app - it just stops dead.
My partial class where I call my synch from:
namespace Vessel_Schedule_Synch
{
[DisplayName("CRM Vessel Synch")]
partial class startVessel : ServiceBase
{
System.Threading.Timer t;
VesselUpdater v;
protected override void OnStart(string[] args)
{
//System.Threading.Thread.Sleep(20000);
v = new VesselUpdater();
t = new System.Threading.Timer(new System.Threading.TimerCallback(t_TimerCallback), null, 0, 300000);
//InfoLogger.Info("Starting service " + this.ServiceName, true);
}
private void t_TimerCallback(object state)
{
t.Change(Timeout.Infinite, Timeout.Infinite);
lock (v)
{
InfoLogger.Info("Timer fired... updating vessels");
try
{
v.Process();
v.updateCRM();
}
catch (Exception e)
{
if (v == null)
{ throw e; }
else
{
InfoLogger.Exception(e);
}
}
finally
{
InfoLogger.Info("End of Timer Trigger... Restarting Timer.");
t.Change(30000, 30000);
}
}
}
protected override void OnStop()
{
InfoLogger.Info("Service Stopped " + this.ServiceName, true);
}
}
}
My synch class where I have tried to use a bool to test the connection:
namespace Vessel_Schedule_Synch
{
class VesselUpdater
{
private OrganizationServiceProxy _serviceProxy;
private IOrganizationService _service;
private Logger logger = LogManager.GetLogger("VesselUpdater");
public string ConnectionString { get; set; }
public string ServiceUrl { get; set; }
int i = 0;
private bool InitialiseCRMConnection;
public VesselUpdater()
{
InitialiseCRMConnection = true;
Console.WriteLine("Starting the service");
LogMessage("Starting service");
ServiceUrl = ConfigurationManager.AppSettings["CRMUrl"];
LogMessage(ConnectionString);
ConnectionString = ConfigurationManager.ConnectionStrings["iRoot"].ConnectionString;
LogMessage(ServiceUrl);
Console.WriteLine(ServiceUrl);
}
public void Process()
{
if (!InitialiseCRMConnection)
return;
LogMessage("Process Starting");
ClientCredentials UserCredentials = new ClientCredentials();
string UserName = ConfigurationManager.AppSettings["User"];
string Password = ConfigurationManager.AppSettings["Password"];
UserCredentials.UserName.UserName = UserName;
UserCredentials.UserName.Password = Password;
ClientCredentials DivCredentials = null;
Uri HomeRealmURI = null;
Uri serviceurl = new Uri(ServiceUrl);
_serviceProxy = new OrganizationServiceProxy(serviceurl, HomeRealmURI, UserCredentials, DivCredentials);
_serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
_service = (IOrganizationService)_serviceProxy;
_serviceProxy.EnableProxyTypes();
LogMessage("CRM Connection Initiated");
InitialiseCRMConnection = false;
}
public void updateCRM()
{
try
{
ProcessVesselSchedule("Insert");
ProcessVesselSchedule("Modification");
}
catch (Exception e)
{
InitialiseCRMConnection = true;
InfoLogger.Exception(e);
LogMessage("Exception " + e);
}
}
private void ProcessVesselSchedule(string Type)
{
if (InitialiseCRMConnection)
return;
try
{
LogMessage(string.Format("Processing Vessesl Schedules {0}", Type));
using (SqlConnection con = new SqlConnection(ConnectionString))
{
SqlCommand cmd = new SqlCommand("VesselScheduleInformation", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Type", Type);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
try
{
LogMessage("Processing Record");
LogMessage(dr["new_Name"].ToString());
string Name = dr["new_Name"].ToString() + " " + dr["new_VoyageNo"].ToString();
string Vesselname = dr["new_Name"].ToString();
int LineNo = (int)dr["Line Number"];
string NAVVesselScheduleCode = dr["new_NAVVesselScheduleCode"].ToString();
string CarrierService = dr["new_CarrierService"].ToString();
string ETA = dr["new_ETA"].ToString();
string ETD = dr["new_ETD"].ToString();
string VesselCode = dr["new_Vessel"].ToString();//Vessel Code
string VoyageNo = dr["new_VoyageNo"].ToString();
string TranshipmentVessel = dr["new_TranshipmentVessel"].ToString();
string TranshipmentVoyageNo = dr["new_TranshipmentVoyageNo"].ToString();
string Port = dr["new_Port"].ToString();
string PortOfDis = dr["new_DischargePort"].ToString();
string PortOfLoad = dr["new_LoadPort"].ToString();
//string StackStart = dr["new_StackStart"].ToString();
//string StackEnd = dr["new_StackEnd"].ToString();
bool Create = false;
LogMessage("Assigned all variables");
Console.WriteLine("Assigned all variables");
new_vesselschedule VesselS = FindVessleSchedule(NAVVesselScheduleCode, LineNo, out Create);
//if (DateTime.Parse(StackStart).ToUniversalTime() >= DateTime.Parse("1900-01-01"))
//{
// VesselS["new_stackstart"] = DateTime.Parse(StackStart).ToUniversalTime();
//}
//if (DateTime.Parse(StackEnd).ToUniversalTime() >= DateTime.Parse("1900-01-01"))
//{
// VesselS["new_stackend"] = DateTime.Parse(StackEnd).ToUniversalTime();
//}
VesselS.new_name = Name;
VesselS.new_navvesselschedulecode = NAVVesselScheduleCode;
VesselS.new_CarrierService = CarrierService;
if (DateTime.Parse(ETA).ToUniversalTime() >= DateTime.Parse("1900-01-01"))
{
VesselS.new_ETA = DateTime.Parse(ETA).ToUniversalTime();
}
if (DateTime.Parse(ETD).ToUniversalTime() >= DateTime.Parse("1900-01-01"))
{
VesselS.new_ETD = DateTime.Parse(ETD).ToUniversalTime();
}
VesselS.new_vesselcodeimport = VesselCode;
VesselS.new_vesselnameimport = Vesselname;
VesselS.new_VoyageNo = VoyageNo;
VesselS.new_TransshipmentVessel = TranshipmentVessel;
VesselS.new_TransshipmentVoyageNo = TranshipmentVoyageNo;
VesselS.new_dischargeportimport = PortOfDis;
VesselS.new_loadportimport = PortOfLoad;
if (Create)
{
LogMessage(string.Format("Created {0} {1}", NAVVesselScheduleCode, LineNo));
_serviceProxy.Create(VesselS);
}
else
{
LogMessage(string.Format("Updated {0} {1}", NAVVesselScheduleCode, LineNo));
_serviceProxy.Update(VesselS);
}
using (SqlCommand cmdUpdateMates = new SqlCommand())
{
SqlConnection con2 = new SqlConnection(ConnectionString);
con2.Open();
cmdUpdateMates.Connection = con2;
cmdUpdateMates.CommandText = "ProcessedVessSched";
cmdUpdateMates.CommandType = CommandType.StoredProcedure;
cmdUpdateMates.Parameters.AddWithValue("#VesselSched", NAVVesselScheduleCode);
cmdUpdateMates.Parameters.AddWithValue("#LineNo", LineNo);
cmdUpdateMates.ExecuteNonQuery();
i++;
Console.WriteLine("Created/Updated" + " " + i);
}
}
catch (Exception e)
{
InitialiseCRMConnection = true;
InfoLogger.Exception(e);
LogMessage("Exception " + e);
}
}
}
}
catch (SqlException e)
{
InfoLogger.Exception(e);
LogMessage("SQL Exception " + e);
}
catch (Exception e)
{
InitialiseCRMConnection = true;
InfoLogger.Exception(e);
LogMessage("Exception " + e);
}
}
public void LogMessage(string Message)
{
LogEventInfo myEvent = new LogEventInfo(LogLevel.Debug, "", Message);
myEvent.LoggerName = logger.Name;
logger.Log(myEvent);
}
private new_vesselschedule FindVessleSchedule(string NAVVesselScheduleCode, int LineNo, out bool Create)
{
QueryExpression query = new QueryExpression(new_vesselschedule.EntityLogicalName);
query.ColumnSet.AllColumns = true;
query.Criteria = new FilterExpression();
query.Criteria.AddCondition("new_navvesselschedulecode", ConditionOperator.Equal, NAVVesselScheduleCode);
query.Criteria.AddCondition("new_lineno", ConditionOperator.Equal, LineNo);
EntityCollection entitycollection = _serviceProxy.RetrieveMultiple(query);
if (entitycollection.Entities.Count == 0)
{
new_vesselschedule n = new new_vesselschedule();
n.new_navvesselschedulecode = NAVVesselScheduleCode;
n.new_lineno = LineNo;
Create = true;
return n;
}
Create = false;
return (new_vesselschedule)entitycollection.Entities[0];
}
}
}
Am I missing something here?
I found the issue in my code, I had forgotten to sent InitialiseCRMConnection = true; in my SQL Exception thus it could never go through the motions of reInitialising the connection as it would always return;
Fix:
catch (SqlException e)
{
InitialiseCRMConnection = true;
InfoLogger.Exception(e);
LogMessage("SQL Exception " + e);
}
I have a c# app (Windows Service) that fires a timer event that reads files in a directory and sends out SMS using the data in the files. Next time the event fires, it tries to move the processed files in the "Processed" directory to a "Completed" directory before processing the new files. I keep getting a "File in use by another process" exception, although I am pretty sure that I dispose of everything that uses the files. If I stop the service and start it again, the files is released. Any ideas?
//Code that fires the timer
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
namespace SmsWindowsService
{
public partial class SmsWindowsService : ServiceBase
{
private static System.Timers.Timer aTimer;
public SmsWindowsService()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("MatterCentreSMSSource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MatterCentreSMSSource", "MatterCentreSMSLog");
}
elMatterCentreSMS.Source = "MatterCentreSMSSource";
elMatterCentreSMS.Log = "MatterCentreSMSLog";
}
protected override void OnStart(string[] args)
{
string logText = string.Empty;
logText = "MatterCentreSMS Service started successfully on " + DateTime.Now;
WriteEventLog(logText);
//Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);
//Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
//Set the Interval to 5 minutes.
//aTimer.Interval = 300000;
aTimer.Interval = 60000;
aTimer.Enabled = true;
// If the timer is declared in a long-running method, use
// KeepAlive to prevent garbage collection from occurring
// before the method ends.
//GC.KeepAlive(aTimer);
GC.Collect();
}
protected override void OnStop()
{
string logText = string.Empty;
logText = "MatterCentreSMS Service stopped on " + DateTime.Now;
WriteEventLog(logText);
}
private void WriteEventLog(string logText)
{
elMatterCentreSMS.WriteEntry(logText);
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
string ex = string.Empty;
SendSms s = new SendSms();
ex = s.ProcessSms();
if (ex.Length > 1)
WriteEventLog(ex);
//ex = RestartService("SmsWindowsService", 60000);
//WriteEventLog(ex);
}
public string RestartService(string serviceName, int timeoutMilliseconds)
{
ServiceController service = new ServiceController(serviceName);
try
{
int millisec1 = Environment.TickCount;
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
// count the rest of the timeout
int millisec2 = Environment.TickCount;
timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds - (millisec2 - millisec1));
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
return "MatterCentreSMS Service successfully restarted on " + DateTime.Now;
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
}
}
//Code that reads the file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
namespace SmsWindowsService
{
class Message
{
private string filePath;
public Message(string filePath)
{
this.filePath = filePath;
}
public string readSMS(string filePath)
{
const string searchmessage = "[B-->]";
StreamReader smsmessage = new StreamReader(filePath);
try
{
FileInfo filenameinfo = new FileInfo(filePath);
if (filenameinfo.Exists == false)
throw new SMSReaderException(String.Format("SMS Message {0} cannot be found ...", filePath), filePath);
smsmessage = filenameinfo.OpenText();
string smsoutput = smsmessage.ReadToEnd();
int endpos = smsoutput.IndexOf(searchmessage);
smsoutput = smsoutput.Substring(endpos + searchmessage.Length);
smsoutput = smsoutput.Replace("&", "&");
smsoutput = smsoutput.Replace("\"", """);
smsoutput = smsoutput.Replace("'", "'");
filenameinfo = null;
smsmessage.Close();
smsmessage.Dispose();
return smsoutput;
}
catch(Exception e)
{
throw new Exception("Help", e.InnerException);
}
finally
{
smsmessage.Close();
smsmessage.Dispose();
}
}
}
public class SMSReaderException : System.IO.FileNotFoundException
{
public SMSReaderException(string message, string filename)
: base(message, filename)
{
}
}
}
//Code that connects to web service and send sms
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Net;
using System.Configuration;
using SmsWindowsService.EsendexSendSmsService;
namespace SmsWindowsService
{
class SendSms
{
string filePath = string.Empty;
string directoryPath = string.Empty;
string directoryPathProcessing = string.Empty;
string directoryPathCompleted = string.Empty;
string smsLogfileDirectory = string.Empty;
string smsLogfilePath = string.Empty;
string mattercentreSMS = string.Empty;
string messageBody = string.Empty;
string messageId = string.Empty;
string messageStatus = string.Empty;
string dateTodayString = string.Empty;
long mobileNumber;
EsendexSendSmsService.SendService send;
public SendSms()
{
directoryPath = ConfigurationSettings.AppSettings[#"directoryPath"];
directoryPathProcessing = ConfigurationSettings.AppSettings[#"directoryPathProcessing"];
directoryPathCompleted = ConfigurationSettings.AppSettings[#"directoryPathCompleted"];
smsLogfileDirectory = ConfigurationSettings.AppSettings[#"smsLogfileDirectory"];
dateTodayString = DateTime.Now.ToString("yyyy/MM/dd");
smsLogfilePath = smsLogfileDirectory + dateTodayString.Replace(#"/", "_") + ".txt";
send = new EsendexSendSmsService.SendService();
}
public string ProcessSms()
{
string ex = string.Empty;
try
{
DirectoryInfo di = new DirectoryInfo(directoryPathProcessing);
ex = MoveFilesToCompleted(directoryPathProcessing, directoryPathCompleted);
if (ex.Length > 1)
return ex;
ex = MoveFilesToProcessing(directoryPath, directoryPathProcessing);
if (ex.Length > 1)
return ex;
FileInfo[] subFilesProcessing = di.GetFiles();
foreach (FileInfo subFile in subFilesProcessing)
{
filePath = directoryPathProcessing + subFile.Name;
Message sms = new Message(filePath);
mattercentreSMS = sms.readSMS(filePath);
MessageDetails d = new MessageDetails(mattercentreSMS);
mobileNumber = d.GetMobileNumber();
messageBody = d.GetMessageBody();
ex = SetHeader();
if (ex.Length > 1)
return ex;
ex = SetProxy();
if (ex.Length > 1)
return ex;
//Send the message and get the returned messageID and send status
messageId = send.SendMessage(Convert.ToString(mobileNumber), messageBody, EsendexSendSmsService.MessageType.Text);
messageStatus = Convert.ToString(send.GetMessageStatus(messageId));
ex = WriteLogFile(messageId, subFile.Name, messageStatus);
if (ex.Length > 1)
return ex;
send.Dispose();
}
di = null;
subFilesProcessing = null;
return ex;
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
private string MoveFilesToCompleted(string directoryPathProcessing, string directoryPathCompleted)
{
DirectoryInfo din = new DirectoryInfo(directoryPathProcessing);
try
{
FileInfo[] subFiles = din.GetFiles();
foreach (FileInfo subFile in subFiles)
{
subFile.MoveTo(directoryPathCompleted + subFile.Name);
}
subFiles = null;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
finally
{
din = null;
}
}
private string MoveFilesToProcessing(string directoryPath, string directoryPathProcessing)
{
DirectoryInfo din = new DirectoryInfo(directoryPath);
try
{
FileInfo[] subFiles = din.GetFiles();
foreach (FileInfo subFile in subFiles)
{
subFile.MoveTo(directoryPathProcessing + subFile.Name);
}
subFiles = null;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
finally
{
din = null;
}
}
private string SetHeader()
{
try
{
//Setup account details in the header
EsendexSendSmsService.MessengerHeader header = new EsendexSendSmsService.MessengerHeader();
header.Account = ConfigurationSettings.AppSettings[#"smsServiceUrl"];
header.Username = ConfigurationSettings.AppSettings[#"smsServiceUsername"];
header.Password = ConfigurationSettings.AppSettings[#"smsServicePassword"];
// set the SOAP header Authentication values
send.MessengerHeaderValue = header;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
private string SetProxy()
{
try
{
//Create a web proxy object as the proxy server block direct request to esendex
WebProxy myProxy = new WebProxy(ConfigurationSettings.AppSettings[#"proxyaddress"], true);
myProxy.Credentials = new NetworkCredential(ConfigurationSettings.AppSettings[#"username"], ConfigurationSettings.AppSettings[#"password"]);
WebRequest.DefaultWebProxy = myProxy;
send.Proxy = myProxy;
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
private string WriteLogFile(string messageId, string smsFileName, string messageStatus)
{
try
{
if (File.Exists(smsLogfilePath))
{
//file is not empty - append log entry to file
using (StreamWriter writeSmsLog = File.AppendText(smsLogfilePath))
{
writeSmsLog.WriteLine(messageId + " " + smsFileName + " " + DateTime.Now + " " + messageStatus);
writeSmsLog.Close();
}
}
else
{
FileStream fs = File.OpenWrite(smsLogfilePath);
fs.Flush();
fs.Close();
fs.Dispose();
using (StreamWriter writeSmsLog = new StreamWriter(smsLogfilePath, true))
{
writeSmsLog.WriteLine("Message_ID File_Name Date_Sent Status");
writeSmsLog.WriteLine("======================================================================================================================================");
writeSmsLog.WriteLine(messageId + " " + smsFileName + " " + DateTime.Now + " " + messageStatus);
writeSmsLog.Close();
}
}
return "";
}
catch (Exception e)
{
return Convert.ToString(e);
}
}
}
}
Any ideas?
You're running a virus checker in an entirely different process. It is detecting that the file has changed and is locking it momentarily in order to check it to see if the edit you just performed to the file introduced a virus. It'll unlock it in a couple of milliseconds.
Disabling your virus checker is a bad idea. Instead, you're just going to have to live with it; write your code to be robust in a world where there are lots of processes vying for locks on files.
StreamReader smsmessage = new StreamReader(filePath);
try
{
FileInfo filenameinfo = new FileInfo(filePath);
....
smsmessage = filenameinfo.OpenText();
...
You are initializing smsmessage twice, but only disposing one of those instances. The first line constructs a StreamReader, and then you overwrite your reference to that instance with the instance created by filenameinfo.OpenText(). That leaves you with an instance that no longer has any references and hasn't been disposed. That instance might be holding a lock on the file and you have no guarantees on when it will be disposed. Even if it isn't holding a lock, you should still fix this.