Windows service webs server cannot connect to other machines - c#

I am attempting to design a windows service that contains a web server to do basic get request handling. Requests from the localhost work just find but I am unable to process requests from other machines. On python, setting the IP address to 0.0.0.0 allows the server to process requests from any IP on the network. I have found examples that use http://*:port/ or http://+:port/ to obtain this functionality in C# but these have not worked for me.
I am currently starting a HttpListener (WebServer.cs) when the windows service (UsherService.cs) receives its start command. If there is a better way to do this, I'd appreciate that answer as well.
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace UsherService
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new UsherService()
};
ServiceBase.Run(ServicesToRun);
}
}
}
UsherService.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace UsherService
{
public partial class UsherService : ServiceBase
{
WebServer ws;
public UsherService()
{
InitializeComponent();
}
public static string SendResponse(HttpListenerRequest request)
{
return string.Format("<HTML><BODY>My web page.<br>{0}</BODY></HTML>", DateTime.Now);
}
protected override void OnStart(string[] args)
{
try
{
ws = new WebServer(SendResponse, "http://*:5000/");
ws.Run();
System.IO.File.AppendAllText(#"C:\Users\kburd\Desktop\WriteText.txt", "Started Successfully");
}
catch(Exception e)
{
System.IO.File.AppendAllText(#"C:\Users\kburd\Desktop\WriteText.txt", e.Message);
}
}
protected override void OnStop()
{
System.IO.File.AppendAllText(#"C:\Users\kburd\Desktop\WriteText.txt", "Stopped Successfully");
}
}
}
WebServer.cs
using System;
using System.Net;
using System.Text;
using System.Threading;
public class WebServer
{
private readonly HttpListener _listener = new HttpListener();
private readonly Func<HttpListenerRequest, string> _responderMethod;
public WebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
{
if (!HttpListener.IsSupported)
throw new NotSupportedException(
"Needs Windows XP SP2, Server 2003 or later.");
// URI prefixes are required
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// A responder method is required
if (method == null)
throw new ArgumentException("method");
foreach (string s in prefixes)
{
_listener.Prefixes.Add(s);
System.IO.File.AppendAllText(#"C:\Users\kburd\Desktop\WriteText2.txt", s);
}
_responderMethod = method;
_listener.Start();
}
public WebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
: this(prefixes, method) { }
public void Run()
{
ThreadPool.QueueUserWorkItem((o) =>
{
Console.WriteLine("Webserver running...");
try
{
while (_listener.IsListening)
{
ThreadPool.QueueUserWorkItem((c) =>
{
var ctx = c as HttpListenerContext;
try
{
string rstr = _responderMethod(ctx.Request);
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
catch { } // suppress any exceptions
finally
{
// always close the stream
ctx.Response.OutputStream.Close();
}
}, _listener.GetContext());
}
}
catch { } // suppress any exceptions
});
}
public void Stop()
{
_listener.Stop();
_listener.Close();
}
}

The firewall was blocking the localhost from communicating to other devices on the network. I had to allow for communication over that port

Related

Windows Service is not logging actions

What Im actualy trying to do is to create a windows service, that will be listening to one exact IP adress and port and after receiving message write information to the file.
Here is the code:
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.Threading.Tasks;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;
namespace Active_service
{
public partial class Service1 : ServiceBase
{
const int port = 8005;
static TcpListener listener;
public Service1()
{
InitializeComponent();
this.CanStop = true;
this.CanPauseAndContinue = true;
this.AutoLog = true;
File.AppendAllText("Log.txt","\n Initialized" + " " + DateTime.Now.ToString());
}
protected override void OnStart(string[] args)
{
File.AppendAllText("Log.txt","\n Started!");
Thread listen_thread = new Thread(new ThreadStart(Listen));
listen_thread.Start();
}
public void Listen()
{
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"),port);
Socket listen_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
listen_socket.Bind(ipPoint);
listen_socket.Listen(10);
File.AppendAllText("Log.txt", "\n Listening!");
while (true)
{
Socket handler = listen_socket.Accept();
StringBuilder builder = new StringBuilder();
int bytes = 0;
byte[] data = new byte[256];
do
{
bytes = handler.Receive(data);
builder.Append(Encoding.Unicode.GetString(data, 0, bytes));
}
while (handler.Available > 0);
File.AppendAllText("Log.txt","\n Message received:" + builder.ToString());
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
catch (Exception ex)
{
File.AppendAllText("Log.txt","\n " + ex.Message);
}
}
protected override void OnStop()
{
File.AppendAllText("Log.txt", "Stopped!");
}
protected override void OnPause()
{
base.OnPause();
}
protected override void OnContinue()
{
base.OnContinue();
}
}
}
The problem is: When I'm compiling code, line "\n Initialized!" is added to the file, but after I'm setting up the service it's accepting TPC communication (no error throwed after I'm sending message from other software), but nothing is added to "Log.txt", even "Initialized" message.
What I'm doing wrong?

SynchronizationContext is null in OnStart method of WindowsService

I am trying to create a background Task for my windows service (it is already installed via InstallUtil.exe) and use SynchronizationContext to send some messages to the main Service thread.
Unfortunately SynchronizationContext.Current is always null on service start.
I've saw some questions around the topic and hints on why SynchronizationContext is null in various scenarios (e.g. in Winforms, WPF apps) but no clue about the Windows services.
How can I resolve this issue?
Below the code:
using Lextm.SharpSnmpLib.Messaging;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SnmpTrapListenerService
{
public partial class SnmpTrapListenerService : ServiceBase
{
public Listener Listener { get; set; }
public CancellationTokenSource CancellationTokenSource { get; set; }
public Task PulseTask { get; set; }
public SynchronizationContext SyncContext { get; set; }
public SnmpTrapListenerService()
{
//Debugging windows service.
Debugger.Launch();
InitializeComponent();
Debug.WriteLine($"Main service threadId: {Thread.CurrentThread.ManagedThreadId}");
}
protected override void OnStart(string[] args)
{
try
{
CancellationTokenSource = new CancellationTokenSource();
SyncContext = SynchronizationContext.Current; //Here I'm getting always null.
PulseTask = new Task(x =>
{
Debug.WriteLine($"Pulse task threadId: {Thread.CurrentThread.ManagedThreadId}");
while (true)
{
var context = (SynchronizationContext)x;
context.Post(new SendOrPostCallback(y => DoSomethingOnServiceMainThread()), null);
Debug.WriteLine($"Alive at {DateTime.Now.ToLongTimeString()}");
Thread.Sleep(5000);
}
}, SyncContext, CancellationTokenSource.Token);
PulseTask.Start();
Listener = new Listener();
Listener.AddBinding(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 162)); //IP address of listener system
Listener.MessageReceived += Listener_MessageReceived;
Listener.StartAsync();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
Debug.WriteLine("Service started");
}
private static void Listener_MessageReceived(object sender, MessageReceivedEventArgs e)
{
File.AppendAllText("servicelog.log", "Version :" + e.Message.Version + "\n");
File.AppendAllText("servicelog.log", "Version :" + e.Message.Scope.Pdu.Variables[4].Data.ToString() + "\n");
}
protected override void OnStop()
{
CancellationTokenSource.Cancel();
Listener.Stop();
Debug.WriteLine("Service stopped");
}
private void DoSomethingOnServiceMainThread()
{
//Some work that needs to be done one Service main thread.
}
}
}
Console and Service applications do not have a default SynchronizationContext. This is because there is no "UI" thread that is pumping messages constantly while the application runs.
The question is why do you need a synchronization context?

Invoke or BeginInvoke cannot be called on a control until the window handle has been created. C# win form

hi i want to change label when i type in my browser one link. I create wcf service and i use one thread to change label in main form. Now when i click url in browser http://:5001/Connect i get this error for a reason. I dont understand the error here.
Invoke or BeginInvoke cannot be called on a control until the window
handle has been created.InvalidOperationException was unhandled
Must create object CashDesk_Form ? What must to do. Here is my codes:
MY FORM
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using System.Threading;
namespace tameio
{
public partial class CashDesk_Form : Form
{
//Αντικείμενα
ServiceHost host;
public WCFService wcf;
//Μεταβλητές
string WCFPort = "5001";
//(ΔΗΜΙΟΥΡΓΟΣ) του Server
public CashDesk_Form()
{
InitializeComponent();
Thread startServerThread = new Thread(StartWCFServer);
startServerThread.IsBackground = true;
startServerThread.Start();
this.FormClosed += new FormClosedEventHandler(CashDesk_Form_FormClosed);
}
void CashDesk_Form_FormClosed(object sender, FormClosedEventArgs e)
{
if (host != null)
{
try { host.Close(); }
catch { }
host = null;
}
else MessageBox.Show("Ο Server είναι ήδη Απενεργοποιημένος");
}
public void AddNewConnection()
{
Thread clientThread = new Thread(new ThreadStart(_AddNewConnection));
clientThread.IsBackground = true;
clientThread.Start();
}
public void _AddNewConnection()
{
if (!IsHandleCreated)
this.CreateControl();
// ----> Exception here
this.Invoke((MethodInvoker)delegate
{
lbl_connectClients.Text = "ASDASDASD";
});
}
//(FUNCTION) - > Εκκίνηση του Server
private void StartWCFServer()
{
if (host == null)
{
Uri baseAddress = new Uri("http://localhost:" + WCFPort + "/");
host = new ServiceHost(typeof(WCFService), baseAddress);
host.AddServiceEndpoint(typeof(IWCFService), new WSHttpBinding(), "Services");
try
{
host.Open();
}
catch (Exception e)
{
if (e.GetType().FullName.ToString() == "System.InvalidOperationException") return;
else
{
MessageBox.Show("Βεβαιωθείτε ότι έχετε δικαιώματα διαχειριστή σε αυτόν τον υπολογιστή");
}
}
}
else
{
MessageBox.Show("Υπήρξε πρόβλημα κατά του άνοιγμα του WCF Server. Είτε ο WCF Server είναι Ενεργός, είτε το Port: " + WCFPort + " χρεισιμοποιείτε κάπου αλλού, είτε η IP του δικτύου δεν είναι σωστή");
}
}
private void button1_Click(object sender, EventArgs e)
{
}
}
}
WCFService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace tameio
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
public class WCFService : CashDesk_Form, IWCFService
{
public string connect()
{
AddNewConnection();
return "Έχετε συνδεθεί επιτυχώς με την εφαρμογή του ταμείου";
}
}
}
IWCFService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;
namespace tameio
{
[ServiceContract]
public interface IWCFService
{
[OperationContract(Name = "SendMessage")]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "Connect")]
//UriTemplate = "Send?Message={txt}")]
string connect();
}
}
Try and move the startup of the service to a later time:
public partial class CashDesk_Form : Form
{
public CashDesk_Form()
{
InitializeComponent();
this.FormClosed += new FormClosedEventHandler(CashDesk_Form_FormClosed);
}
protected override void OnShown(EventArgs e)
{
//at this point the handle *is* created
base.OnShown(e);
Thread startServerThread = new Thread(StartWCFServer);
startServerThread.IsBackground = true;
startServerThread.Start();
}
}
The exception you are getting i becuase you are starting up the WCF service in your forms constructor. At that point the handle for the Form has not yet been created - and therefore calling Connect could lead the the exception you are getting

What's wrong my windows service on windows 2012?

I have written multiple windows services in one exe & created setup/deployment package to install on destination server (windows 2012). I can see all services in Services & able to start them but it is not performing required action..Weird!!
Program.cs
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new service1(),
new service2(),
new service3()
};
ServiceBase.Run(ServicesToRun);
service1.cs
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.Configuration;
using System.Net;
using System.Xml;
using System.IO;
namespace MyService
{
partial class service1: ServiceBase
{
public service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
StreamWriter str = new StreamWriter("D:\\temp\\Text1.txt", true);
str.WriteLine("text");
str.Close();
try
{
//more functionality
EventLog.WriteEntry("done", "done desc", EventLogEntryType.Information);
}
}
catch (Exception ex)
{
EventLog.WriteEntry("Error", ex.Message, EventLogEntryType.Error);
}
}
protected override void OnStop()
{
base.OnStop();
}
}
}
When I start service1 manually, it doesn't perform any action..Neither I see text file getting created nor any error/info in event log. What's wrong? Am I missing something wrong???
Appreciate for help!

Handling URL Protocol without application restarts

My question is all about URL Protocols.
I have registered a URL Protocol called mcm, but I noticed that everytime I run it from any web browser, t creates a new instance of the application. Is there any way to handle the protocol request in an already running instance?
For example, when uTorrent is using the torrent protocol It handles the request immediately without running the app again. I couldn't really find anything interesting about it, so I am asking here...
Here is the code I use to register the protocol:
private static void RegisterUrlProtocol()
{
UnregisterUrlProtocol();
RegistryKey rKey = Registry.ClassesRoot.OpenSubKey(UrlProtocol, true);
if (rKey == null)
{
rKey = Registry.ClassesRoot.CreateSubKey(UrlProtocol);
rKey.SetValue("", "URL: MazCraft Protocol");
rKey.SetValue("URL Protocol", "");
rKey = rKey.CreateSubKey(#"shell\open\command");
rKey.SetValue("", "\"" + Application.ExecutablePath + "\" %1");
}
if (rKey != null)
{
rKey.Close();
}
}
And the code to read the arguments:
private static bool CheckForProtocolMessage()
{
string[] arguments = Environment.GetCommandLineArgs();
if (arguments.Length > 1)
{
string[] args = arguments[1].Split(':');
args[1] = args[1].Replace("//", "");
if (args[0].Trim().ToUpper() == "MCM" && args.Length > 1)
{
string[] actionDetail = args[1].Split('=');
if (actionDetail[0].Trim().ToUpper() == "INSTALL" && actionDetail.Length > 1)
{
string id = actionDetail[1].Trim().Replace("/", "");
Funcs.ID = id;
return true;
}
}
}
return false;
}
Any help would be greatly appreciated :)
Greetings.
You could use a Mutex to detect an instance of the application that is already running and send the data over to the existing instance via Named Pipes.
Hope the following example helps.
you can swap out the named pipes object (in this case string) for whatever serializable object you like.
NamedPipe.cs
namespace SingleInstanceNP
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.IO;
public class NamedPipe<T> : IDisposable
{
#region Attribute and Properties
private string _pipeName;
private NamedPipeServerStream _pipeServer;
private bool _disposed;
private Thread _thread;
private bool _started;
#endregion
#region Constructors
public NamedPipe(NameTypes pipeType)
{
_disposed = false;
_started = false;
_pipeName = pipeType.ToString();
_thread = new Thread(Main);
_thread.SetApartmentState(ApartmentState.STA);
_thread.Name = "NamePipe: " + pipeType.ToString() + " Thread";
_thread.IsBackground = true;
}
~NamedPipe()
{
Dispose();
}
#endregion
#region Events
public delegate void Request(T t);
public event Request OnRequest;
#endregion
#region Public Methods
public static void Send(NameTypes pipeType, T t)
{
using (var npc = new NamedPipeClientStream(".", pipeType.ToString(), PipeDirection.Out))
{
var bf = new BinaryFormatter();
npc.Connect();
bf.Serialize(npc, t);
}
}
public static T Recieve(NameTypes pipeType)
{
using (var nps = new NamedPipeServerStream(pipeType.ToString(), PipeDirection.In))
{
return Recieve(nps);
}
}
public void Start()
{
if (!_disposed && !_started)
{
_started = true;
_thread.Start();
}
}
public void Stop()
{
_started = false;
if (_pipeServer != null)
{
_pipeServer.Close();
// disposing will occur on thread
}
}
public void Dispose()
{
_disposed = true;
Stop();
if (OnRequest != null)
OnRequest = null;
}
#endregion
private void Main()
{
while (_started && !_disposed)
{
try
{
using (_pipeServer = new NamedPipeServerStream(_pipeName))
{
T t = Recieve(_pipeServer);
if (OnRequest != null && _started)
OnRequest(t);
}
}
catch (ThreadAbortException)
{ }
catch (System.IO.IOException iox)
{
Console.WriteLine("ERROR: {0}", iox.Message);
Thread.Sleep(TimeSpan.FromSeconds(30));
}
catch (Exception ex)
{
Console.WriteLine("ERROR: {0}", ex.Message);
return;
}
}
}
private static T Recieve(NamedPipeServerStream nps)
{
var bf = new BinaryFormatter();
try
{
nps.WaitForConnection();
var obj = bf.Deserialize(nps);
if (obj is T)
return (T)obj;
}
// Catch the IOException that is raised if the pipe is
// broken or disconnected.
catch (IOException e)
{
Console.WriteLine("ERROR: {0}", e.Message);
}
return default(T);
}
#region Enums
public enum NameTypes
{
PipeType1
}
#endregion
}
}
Program.cs
Please give credit for the APP GUID to What is a good pattern for using a Global Mutex in C#?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Threading;
namespace SingleInstanceNP
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// get application GUID as defined in AssemblyInfo.cs
string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
// unique id for global mutex - Global prefix means it is global to the machine
string mutexId = string.Format("Global\\{{{0}}}", appGuid);
using (var mutex = new Mutex(false, mutexId))
{
try
{
if (!mutex.WaitOne(0, false))
{
//signal existing app via named pipes
NamedPipe<string>.Send(NamedPipe<string>.NameTypes.PipeType1, "test");
Environment.Exit(0);
}
else
{
// handle protocol with this instance
Application.Run(new Form1());
}
}
finally
{
mutex.ReleaseMutex();
}
}
}
}
}
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SingleInstanceNP
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// start listening for named pipe connections
var namedPipeString = new NamedPipe<string>(NamedPipe<string>.NameTypes.PipeType1);
namedPipeString.OnRequest += new NamedPipe<string>.Request(namedPipeString_OnRequest);
namedPipeString.Start();
}
void namedPipeString_OnRequest(string t)
{
MessageBox.Show(t);
}
}
}

Categories