Stop self hosted server from client - c#

I have just started learning WCF. Currently i am working on a project where i am "self hosting" server on console application and the client is a WPF application.
COntracts
[ServiceContract]
public interface IDemoValue
{
[OperationContract]
double IncrementByHundred(double val);
}
Server
class Program
{
static void Main(string[] args)
{
using(ServiceHost host=new ServiceHost(typeof(WcfServiceDemos.DemoValue)))
{
host.Open();
Console.WriteLine("Host is running at {0}", DateTime.Now.ToString());
Thread.Sleep(2000);
}
}
}
</pre></code>
As from the code is clear that i am trying to Host WcfSericesDemos.DemoValue class.
CLIENT
//Event to start server (on button click)
private void Button_Click(object sender, RoutedEventArgs e)
{
object val1 = regKey.GetValue("SERVER");
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.FileName = val1.ToString();
try
{
using (Process proc = Process.Start(startInfo))
{
double inputValue = Convert.ToDouble(Input.Text);
//Here IncrementByHundred(inputValue) is a method from DemoValue which iam trying to expose through WCF
OutPut.Content = server.IncrementByHundred(inputValue);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Now my problem is Server is closing before the IncrementByHundred() method is Invoked.
So bottom line ,i want to stop the server from client side after IncrementByHundred() has finished its task.
FYI: I have tried working Console.Readline() in the server,that does the job by server is still running ,but i want to close the server once IncrementByHundred() method has done its job.
Thanks in advance

Related

SignalR Remote connection to RemoteDesktop

Simple situation. How to connect to SignalR server app which is in my remote desktop server(Ports enabled) using client which is in my computer. Connection works perfect while in local host, as soon as I put my remote machine IP it gives error 400.
Server side:
namespace SignalRHub
{
class Program
{
static void Main(string[] args)
{
string url = #"http://localhost:8080/";
using (WebApp.Start<Startup>(url))
{
Console.WriteLine(string.Format("Server running at {0}", url));
Console.ReadLine();
}
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
[HubName("TestHub")]
public class TestHub : Hub
{
public void DetermineLength(string message)
{
Console.WriteLine(message);
string newMessage = string.Format(#"{0} has a length of: {1}", message, message.Length);
Clients.All.ReceiveLength(newMessage);
}
}
}
Client side
namespace SignalRClient
{
class Program
{
static void Main(string[] args)
{
IHubProxy _hub;
//string url = #"http://localhost:8080/";
string url = #"http://111.11.11.111:8080";
var connection = new HubConnection(url);
_hub = connection.CreateHubProxy("TestHub");
try
{
connection.Start().Wait();
Console.WriteLine("Connection OK. Connected to: "+url);
}
catch (Exception e)
{
Console.WriteLine(e);
Console.ReadLine();
throw;
}
_hub.On("ReceiveLength", x => Console.WriteLine(x));
string line = null;
while ((line = System.Console.ReadLine()) != null)
{
_hub.Invoke("DetermineLength", line).Wait();
}
Console.Read();
}
}
}
Error it gives:
"System.AggregateException: One or more errors occurred. ---> Microsoft.AspNet.SignalR.Client.HttpClientException: StatusCode: 400, ReasonPhrase: 'Bad Request'"
I know there are similar topics but since I am only familiar with C# console and Windows apps only, would be great to found a solution for connection for app to app kind of thing. My RDP server is fully reachable I have databases and other services running there, so the problem is obviously in code. I have changed the IP in post by the way so its not real..
P.S. if I use url = #"http://*8080/" in server side, the compiler gives "HttpListenerException: Access is denied" ...
Problem solved by opening connection in server side using CMD as administrator and putting:
netsh http add urlacl http://*:8080/ user=EVERYONE
Also make sure ports are opened in firewall.
.NET application development WebSocket services in ISS has to be enabled too.

WPF programme not running correctly when run silently

I have written a small programme to perform a quick configuration on a client machine and it needs to be able to run with a GUI and silently from the command line. If I run it with the GUI then it works perfectly, if however I try to run it without then it just hangs.
I have traced the problem to this section of code:
string arg = "/C:\"setup.exe /qn ADD_OPINSIGHTS_WORKSPACE=1 OPINSIGHTS_WORKSPACE_ID=" + workSpaceID + " OPINSIGHTS_WORKSPACE_KEY=" + workSpaceKey + " AcceptEndUserLicenseAgreement=1\"";
log.Info(arg);
// Use ProcessStartInfo class
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "MMASetup-AMD64.exe";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = arg;
try
{
log.Info("try entered");
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(startInfo))
{
log.Info("Install started");
exeProcess.WaitForExit(30000);
log.Info("Install exit code: " + (exeProcess.ExitCode).ToString());
return (exeProcess.ExitCode).ToString();
}
}
catch (Exception e)
{
log.Error("MMA install threw an error: ", e);
return e.Message;
}
This method is in a seperate class to the GUI and silent code and is run in exactly the same way yet only reaches "Install started" when run silently. I know that the exe does finish so I have tried using the code in this solution but had the same problem:
ProcessStartInfo hanging on "WaitForExit"? Why?
I had the same Problem.
I made a startup class:
public partial class Startup {
// WPF App
private App _app;
[STAThread]
public static void Main(string[] args) {
try {
//Do what you need
//Check the args
//Start your setup silent
//start the WPF App if need it
this._app = new App();
this._app.InitializeComponent();
this._app.Run();
} catch (Exception ex) {
//Logging ex
}
}
After that you must change your Application Startup Object to the Startup Class.
I was running all of my work asynchronously and because I was not loading the GUI thread Windows was treating the application like a console app. Whereas a GUI thread would call other asynchronous methods and wait for them to finish a console application calls the methods and then closes because it has nothing left to do. The solution was to explicitly make the main thread wait like this:
public static void Main(string[] args)
{
try
{
Install().Wait();
}
catch (Exception ex)
{
}
}
private static async Task Install()
{}

How to restart a windows service after an unhandled exception occurs

I have a console application which is an FTP server. This console application works fine. Now, I want to run this FTP Server using Windows Service.
I have an unhandled exception trapper which traps an unhandled exception. After this exception occurs, I want to stop the service, destruct the class for FTP Server, delay it for 10 seconds and restart the service.
Following is my code (The ftp server and service works fine if there is no unhandled exception but I want to successfully stop and restart the service. This code stops the service fine but doesn't restart it). Any ideas?
public partial class FTPService : ServiceBase
{
private static FtpServer _ftpServer;
public FTPService(string[] args)
{
InitializeComponent();
string eventSourceName = "Ftp Server Events";
eventLog1 = new System.Diagnostics.EventLog();
string logName = "Ftp Server Log";
if (args.Count() > 0)
{
eventSourceName = args[0];
}
if (args.Count() > 1)
{
logName = args[1];
}
eventLog1 = new System.Diagnostics.EventLog();
if (!System.Diagnostics.EventLog.SourceExists(eventSourceName))
{
System.Diagnostics.EventLog.CreateEventSource(eventSourceName, logName);
}
eventLog1.Source = eventSourceName;
eventLog1.Log = logName;
if (!System.Diagnostics.EventLog.SourceExists("Ftp Server Events"))
{
System.Diagnostics.EventLog.CreateEventSource(
"Ftp Server Events", "Ftp Server Log");
}
this.ServiceName = "FTP Service";
this.AutoLog = true;
}
public static void Main(string[] args)
{
ServiceBase.Run(new FTPService(new string[0]));
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
var database = new Database(); // Gets database details as FTP server tals to database.
var configurationManager = new ConfigurationManagerWrapper(); // Same as above
_ftpServer = new FtpServer(new Assemblies.Ftp.FileSystem.StandardFileSystemClassFactory(database, configurationManager));
_ftpServer.Start(); //Starts the service (FTP Server works fine if there is no handled exception)
eventLog1.WriteEntry("Started");
FtpServerMessageHandler.Message += MessageHandler_Message;
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
}
protected override void OnStop()
{
_ftpServer.Stop(); // This calls the destructor for FTP Server, to close any TCP Listening connections, etc
base.OnStop(); // Here I stop the service itself.
eventLog1.WriteEntry("Stopped");
Thread.Sleep(10000);
}
protected void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) // unhandled exception handler
{
eventLog1.WriteEntry(e.ExceptionObject.ToString());
Thread.Sleep(5000);
OnStop(); // Calls onstop which stops FTP Server and destroys previous objects of FTP server
var serviceMgr = new ServiceController();
serviceMgr.Start(); // Here I want to restart the service (it doesn't work)
}
}
Try following:
services.msc -> your Service-> Properties -> Recovery
set properties for you
-> Save -> your Service -> restart

TcpListener.AcceptSocket() fails in a Windows Service

I have an instance of the following code that executes correctly in Debug or as a standalone Windows application:
TcpListener tcpListener = new TcpListener(IPAddress.Any, 4554);
tcpListener.Start();
while (true)
{
try
{
using (Socket socket = tcpListener.AcceptSocket())
{
// Code here is reached in Debug or as a Console Application
// but not as a Windows Service
}
}
catch (SocketException se)
{
// This is never reached
}
catch (Exception ex)
{
// This is never reached
}
finally
{
// This is never reached in the Windows Service
}
}
However, when I install it as a Windows Service, it crashes on tcpListener.AcceptSocket(), and logs the following to the Event Viewer:
An unhandled exception ('System.Net.Sockets.SocketException') occurred in MyService.exe [768]. Just-In-Time debugging this exception failed with the following error: The operation attempted is not supported.
Even trying to catch the exception I am unable to log anything more. Stepping through code in Debug accomplishes nothing because the code successfully blocks the application and waits for a client connection.
Is there a way to implement this for a Windows Service?
usr's advice (and this answer) led me to a bug in the code. The ServiceBase class contained the following:
protected override void OnStart(string[] args)
{
_worker = new Thread(ExecuteService);
_worker.Start();
}
private void ExecuteService()
{
for (;;)
{
if (_stop.WaitOne(1000))
{
new TcpServer().StartTcpServer();
return;
}
}
}
The correct implementation was to remove the for loop, which was re-instantiating the listener. Here is the final code:
protected override void OnStart(string[] args)
{
_worker = new Thread(ExecuteService);
_worker.Start();
}
private static void ExecuteService()
{
new TcpServer().StartTcpServer();
}

C# Process StandardOutput. How to send Output from the ran EXE?

I have two programs, one is a game and one is a launcher for the game. I created the launcher, in the first place, to receive basic information from the game and detect any kind of exit (crashes, Task Manager process stop, etc)
I will attach my current code for the process runner, it seems like all solutions on the internet, but what I can't figure out is how to make the game send information to the launcher. I tried Console.WriteLine("login=..."); but it doesn't seem to send anything.
private void button1_Click(object sender, EventArgs e)
{
using (Process exeProcess = Process.Start(new ProcessStartInfo() { UseShellExecute = false,
FileName = "Game.exe",
WorkingDirectory = Environment.CurrentDirectory,
RedirectStandardOutput = true}))
{
string output = "";
while (!exeProcess.HasExited)
{
try
{
output += exeProcess.StandardOutput.ReadToEnd() + "\r\n";
}
catch (Exception exc)
{
output += exc.Message + "::" + exc.InnerException + "\r\n";
}
}
MessageBox.Show(output);
}
}
With respect to your code, by adding the following line you can obtain error messages that were thrown by the game.
RedirectStandardError = true,
If you are developing your game in .NET you can return appropriate error codes as follows. Based on the error code you can then display appropriate messages in you launcher
enum GameExitCodes
{
Normal=0,
UnknownError=-1,
OutOfMemory=-2
}
//Game Application
static void Main(string[] args)
{
try
{
// Start game
Environment.ExitCode = (int)GameExitCodes.Normal;
}
catch (OutOfMemoryException)
{
Environment.ExitCode = (int)GameExitCodes.OutOfMemory;
}
catch (Exception)
{
Environment.ExitCode = (int)GameExitCodes.UnknownError;
}
}
NOTE: You can take a look at this open source game launcher developed in C# as a reference or modify it as per your needs.
EDIT: Added info as per comment
There are multiple ways to enable communication between between 2 .NET processes. They are
Anonymous Pipes
Named Pipes
Using Win32 WM_COPYDATA
MSMQ

Categories