I have a WinForms C# .NET 4.5.2 OWIN self hosted server that uses a signalr hub. In this same WinForm project I start the signalr hub as follows:
private void Form1_Load(object sender, EventArgs e) {
hubConnection = new HubConnection("http://localhost:12345/", clientParams);
hubProxy = hubConnection.CreateHubProxy("OfmControl");
hubProxy.On("Message", message => onData(message));
hubConnection.Start();
My onData method looks like this:
private void onData(dynamic message)
{
var file = new System.IO.FileInfo(message);
playVideo(file.FullName);
}
playVideo method looks like this:
private void playVideo(string file)
{
int tc6 = 0;
try
{
axWMPn[0].URL = file;
}
catch (System.Runtime.InteropServices.COMException comEx)
{
Console.WriteLine("playVideo COMException 0: " + comEx.Source + " -- " + comEx.Message);
}
}
axWMPn is an activex Windows Media Player object on the main form. When I run a separate C# signalr client program and send a filename message to this OWIN signalr sever and onData receives the filename and assigns it to axWMPn[0] per above code it always works never hits catch exception never receive a cross thread exception? I have run it hundreds of times never once received a cross thread exception and always works? But if I do the following I receive a cross thread exception every time obviously:
private void onData(dynamic message)
{
textBox1.text = message; ---> cross thread exception everytime here
var file = new System.IO.FileInfo(message);
playVideo(file.FullName);
}
I started thinking what I am doing is a cross thread violation but why does it always work why am I not receiving a thread violation in Visual Studio when I run the project in debug mode like I always do when I attempt to assign textBox1.text in onData? I have a feeling it has something to do with axWMP being an activex COM object but still seems I should eventually have a cross thread exception on this if it is?
If it is a cross thread violation do I need to do a BeginInvoke/Invoke around axWMPn[0] assignment?
Thanks for any advice...
Related
I'm new to ASP.net programming and I don't really understand the thing about multi threading . When I debug in my ASP.net app/website it shows a tab that I'm not familiar with: Parallel watch, it's something about multi threading. When I search about multi threading I only find examples about how to use multi-threading etc. The thing is, I'm not using any class for threading.
What I got in my code:
is my main page:
Index.aspx.cs:
protected void Button1_Click(object sender, EventArgs e)
{
string Message = PLC1.Connect();
lblClock.Text = Message;
}
and
protected void Timer1_Tick(object sender, EventArgs e)
{
if(PLC1.x_ConnectionEstablished)
{
string Message;
Message = PLC1.ReadDB(1, 0, 17);
if (Message == "OK")
{
lblClock.Text = "Connected and retrieved value!!";
}
else
{
lblClock.Text = Message;
}
}
else
{
lblClock.Text = "No connection! Press the button!";
}
}
my class: PLC.cs:
public string Connect()
{
int Result;
string Message;
Result = s7_S7Client.ConnectTo(s_IP, i_Rack, i_Slot);
Message = s7_S7Client.ErrorText(Result);
x_ConnectionEstablished = s7_S7Client.Connected();
return Message;
}
public string ReadDB(int a_DBnr, int a_startPos, int a_size)
{
int Result;
string Message = "";
try
{
Result = s7_S7Client.DBRead(a_DBnr, a_startPos, a_size, bArray_Buffer);
Message = s7_S7Client.ErrorText(Result);
}
catch (Exception E)
{
Message = E.Message;
}
return Message;
}
When I press the button (while debugging) it jumps to the Connect() of my PLC class. And it actually gives true on the x_ConnectionEstablished. But when my Timer triggers it doesn't go into my if-statement. Since it's saying: x_ConnectionEstablished = false.
I can add the code to the timer, but I don't want to execute the connection method each time I get in the timer(that's what I'm using this x_connectionEstablished for.
So my question is how does this threading work and how can I get my website running decently with or without the threading?
Your PLC1 and s7_S7Client appear to create some kind of persistent connection, for example through TCP sockets or a serial connection.
You don't want to create connections like this from an HTTP back-end, because HTTP is (or at least supposed to be) stateless: each request starts with a clean slate, all your variables (and thus connections) from the previous request are gone.
So I would advise wrapping this logic into a Windows Service that manages connecting to the PLC, and exposing the logic from this service through WCF.
Then your web application can issue requests, through WCF, to the service, and the service in turn talks to the PLC and maintains the connection.
My server app runs perfectly fine until I try to close it. At that point i'm getting two exceptions. I put in a try-catch to try and debug them, and go the following:
The first exception is: A blocking operation was interrupted by a call to WSACancelBlockingCall and the 2nd one is Not listening. You must call the Start() method before calling this method.
Here's a snippet from where the exception occurs:
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
try
{
TcpClient client = this.tcpListener.AcceptTcpClient(); // EXCEPTION OCCURS HERE
string clientIPAddress = "" + IPAddress.Parse(((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString());
ClientIPLabel.Text = clientIPAddress;
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString());
}
}
}
I'm not sure if it might be because I'm missing something here or not, but here's my code for closing the server app:
private void ShutdownServer_Click(object sender, EventArgs e)
{
this.tcpListener.Stop();
Application.Exit();
}
I'm also unable to run this app from a release build; it just freezes as soon as I try to run it, and I need to restart my machine in order to close it (I can close the form, but the process stays running in task manager and "end task" doesn't close it). I'm assuming these exceptions are likely what's causing that issue, since I can run the debug build just fine.
The exception is normal. It happens because you are concurrently closing a listener that is accepting at that time.
Catching that exception and throwing it away is the right choice. I would do it like this to make the catch safer:
//Stop:
isStopping = true;
this.tcpListener.Stop();
//...
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
try
{
TcpClient client = this.tcpListener.AcceptTcpClient();
//...
}
catch (Exception e)
{
if (!isStopping) throw; //don't swallow too much!
}
}
}
There is no cleaner (exception free) way to interrupt socket operations. (Yes, this is a bad situation.)
Regarding the freezing issue, this is not normal and not a .NET issue (.NET can't prevent a process from being killed, there is no such Windows API). Windows bug, OS corruption, Anti Virus, Firewall, ...
I developed a http server via console application in C# and decided to turn it into a Windows service to be able to initialize it without the need to login the machine.
I followed all the steps in How to create Windows Service and chose the account as "Local System", but when I install in my server machine and push the start button it takes a while and gives the following error:
Erro 1053: The service did not respond to the start or control request in timely fashion.
After that, the service status stays stuck in "starting" and the application don't work and I can't even stop the service anymore.
Trying to work around this problem, I changed it to "Network Service", so it started normally, but the application was not listening in the port I set when I checked in the prompt with the command "netstat -an". But the application listens normally if i run it as a console application.
So I am looking for an answer to one of these two questions:
What should I do to make the service starts properly with a Local System account?
If I decide to use Network service account, what should I care about to guarantee that my service works properly as a server?
When I converted my console application to windows service I simply put my code directly in the OnStart method. However, I realized the OnStart method should start the service, but needs to end some time to the service indeed start. So I created a thread that runs my service and let the OnStart method finish. I tested and the service worked just fine. Here is how it was the code:
protected override void OnStart(string[] args)
{
Listener(); // this method never returns
}
Here is how it worked:
protected override void OnStart(string[] args)
{
Thread t = new Thread(new ThreadStart(Listener));
t.Start();
}
But I still don't understand why the service ran (passed the "starting" status, but didn't work) when I used network service account. If anyone knows, I'll be glad to know the reason.
If you have a service that is not responding or showing pending in Windows services that you are unable to stop, use the following directions to force the service to stop.
Start -> Run or Start -> type services.msc and press Enter
Look for the service and check the Properties and identify its service name
Once found, open a command prompt. Type sc queryex [servicename]
Identify the PID (process ID)
In the same command prompt type taskkill /pid [pid number] /f
Find PID of Service
sc queryex <SERVICE_NAME>
Give result's below
SERVICE_NAME: Foo.Services.Bar TYPE : 10 WIN32_OWN_PROCESS STATE : 2 0 START_PENDING (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 PID : 3976 FLAGS :
Now Kill the Service:
taskkill /f /pid 3976
SUCESS: The process with PID 3976 has been terminated.
Check the Windows Application event log, it could contain some entries from your service's auto generated event source (which should have the same name of the service).
For me it was a while loop that looked at an external queue. The while-loop continued running until the queue was empty. Solved it by calling a timer event directly only when Environment.UserInteractive. Therefore the service could be debugged easily but when running as a service it would wait for the timers ElapsedEventHandler event.
Service:
partial class IntegrationService : ServiceBase
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private System.Timers.Timer timer;
public IntegrationService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
// Add code here to start your service.
logger.Info($"Starting IntegrationService");
var updateIntervalString = ConfigurationManager.AppSettings["UpdateInterval"];
var updateInterval = 60000;
Int32.TryParse(updateIntervalString, out updateInterval);
var projectHost = ConfigurationManager.AppSettings["ProjectIntegrationServiceHost"];
var projectIntegrationApiService = new ProjectIntegrationApiService(new Uri(projectHost));
var projectDbContext = new ProjectDbContext();
var projectIntegrationService = new ProjectIntegrationService(projectIntegrationApiService, projectDbContext);
timer = new System.Timers.Timer();
timer.AutoReset = true;
var integrationProcessor = new IntegrationProcessor(updateInterval, projectIntegrationService, timer);
timer.Start();
}
catch (Exception e)
{
logger.Fatal(e);
}
}
protected override void OnStop()
{
try
{
// Add code here to perform any tear-down necessary to stop your service.
timer.Enabled = false;
timer.Dispose();
timer = null;
}
catch (Exception e)
{
logger.Fatal(e);
}
}
}
Processor:
public class IntegrationProcessor
{
private static Logger _logger = LogManager.GetCurrentClassLogger();
private static volatile bool _workerIsRunning;
private int _updateInterval;
private ProjectIntegrationService _projectIntegrationService;
public IntegrationProcessor(int updateInterval, ProjectIntegrationService projectIntegrationService, Timer timer)
{
_updateInterval = updateInterval;
_projectIntegrationService = projectIntegrationService;
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Interval = _updateInterval;
//Don't wait for first elapsed time - Should not be used when running as a service due to that Starting will hang up until the queue is empty
if (Environment.UserInteractive)
{
OnTimedEvent(null, null);
}
_workerIsRunning = false;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
try
{
if (_workerIsRunning == false)
{
_workerIsRunning = true;
ProjectInformationToGet infoToGet = null;
_logger.Info($"Started looking for information to get");
//Run until queue is empty
while ((infoToGet = _projectIntegrationService.GetInformationToGet()) != null)
{
//Set debugger on logger below to control how many cycles the service should run while debugging.
var watch = System.Diagnostics.Stopwatch.StartNew();
_logger.Info($"Started Stopwatch");
_logger.Info($"Found new information, updating values");
_projectIntegrationService.AddOrUpdateNewInformation(infoToGet);
_logger.Info($"Completed updating values");
watch.Stop();
_logger.Info($"Stopwatch stopped. Elapsed seconds: {watch.ElapsedMilliseconds / 1000}. " +
$"Name queue items: {infoToGet.NameQueueItems.Count} " +
$"Case queue items: {infoToGet.CaseQueueItems.Count} " +
$"Fee calculation queue items: {infoToGet.FeeCalculationQueueItems.Count} " +
$"Updated foreign keys: {infoToGet.ShouldUpdateKeys}");
}
_logger.Info($"Nothing more to get from integration service right now");
_workerIsRunning = false;
}
else
{
_logger.Info($"Worker is already running! Will check back again after {_updateInterval / 1000} seconds");
}
}
catch (DbEntityValidationException exception)
{
var newException = new FormattedDbEntityValidationException(exception);
HandelException(newException);
throw newException;
}
catch (Exception exception)
{
HandelException(exception);
//If an exception occurs when running as a service, the service will restart and run again
if (Environment.UserInteractive)
{
throw;
}
}
}
private void HandelException(Exception exception)
{
_logger.Fatal(exception);
_workerIsRunning = false;
}
}
You can try to increase the windows service timeout with a key in the registry
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
"ServicesPipeTimeout"=dword:300000 (300 seconds or 5 minutes)
If it doesn't exists it has to be created.
I'm using Xamarin(mono 3.2.5) on OSX to create a C# console app that connects to the blockchain.info websocket stream. I've included the socketio4net library from NuGet and thought I followed the specs correctly, but I'm a bit new to socket.io connections in general, so please correct me on what I'm doing wrong. I get an error immediately after calling the socket.Connect() method below.
I have created a few event handlers like so:
static void SocketOpened(object sender, EventArgs e)
{
Console.WriteLine ("opened event handler");
Console.WriteLine (e.ToString());
}
static void SocketError(object sender, SocketIOClient.ErrorEventArgs e)
{
Console.WriteLine ("error event handler");
Console.WriteLine (e.Message);
}
static void SocketMessage(object sender, MessageEventArgs e)
{
Console.WriteLine ("message event handler");
Console.WriteLine (e.Message);
}
and my code is as follows:
var socket = new Client (#"ws://ws.blockchain.info:8335/inv");
socket.Opened += SocketOpened;
socket.Error += SocketError;
socket.Message += SocketMessage;
socket.Connect ();
Console.WriteLine ("handshake: " + socket.HandShake.ErrorMessage);
socket.On("connect", (fn) => {
Console.WriteLine("On.connect msg: " + fn.MessageText);
});
socket.On ("open", (fn) => {
Console.WriteLine("On.open msg: " + fn.MessageText);
});
my console output from this:
error event handler
Error initializing handshake with ws://ws.blockchain.info:8335/inv
handshake: Error getting handsake from Socket.IO host instance: An error occurred performing a WebClient request.
What have I done incorrectly? The blockchain API documentation is here: https://blockchain.info/api/api_websocket and I've tried both URLs they specify. Omitting the port number in the URL generates a different error. Instead of "error performing WebClient request", it appears to hunt for a local path to the socket server, which clearly is incorrect.
Any help from a more experienced programmer would be much appreciated
I face the same problem, on my case, its because of default internet connection at office must go through proxy.
Simply set the proxy to none with the code below, solved my problem.
System.Net.WebRequest.DefaultWebProxy = null;
I am trying to create my first Windows Service, but so sad... after I started the service manually from services.msc, the message 'the service on local computer started and then stopped. some services stop automatically is they have no work to do'
I am sure there must be some mistake in my code...
namespace ConvertService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
this.ServiceName = "ConvertService";
this.EventLog.Log = "Application";
}
static void main()
{
ServiceBase.Run(new Service1());
}
protected override void OnStart(string[] args)
{
Process pMP3 = new Process();
pMP3.StartInfo.UseShellExecute = false;
pMP3.StartInfo.RedirectStandardOutput = true;
pMP3.StartInfo.FileName = #"d:\...path...\converter.exe";
pMP3.StartInfo.Arguments = #"d:\...path...\tempamr.amr " + #"d:\...path...\tempmp3.mp3 " + #"-cmp3";
pMP3.Start();
pMP3.WaitForExit();
Process pWAV = new Process();
pWAV.StartInfo.UseShellExecute = false;
pWAV.StartInfo.RedirectStandardOutput = true;
pWAV.StartInfo.FileName = #"d:\...path...\converter.exe";
pWAV.StartInfo.Arguments = #"d:\...path...\tempmp3.mp3 " + #"d:\...path...\tempwav.wav " + #"-cwav";
pWAV.Start();
pWAV.WaitForExit();
}
protected override void OnStop()
{
}
}
}
Forgive me if i did silly mistakes. This is my very very first Windows Service.
PS. I have already ticked 'Allow service to interact with desktop'
You didn't create a running thread for the OnStart method. Basically, the service manager calls OnStart to start the service, and that call needs to finish in about 15 seconds or so. Internally, you should create a thread with a loop that actually calls your code over time. Like so:
protected CancellationTokenSource _tokenSource = null;
protected Task _thread = null;
protected override void OnStart(string[] args)
{
_tokenSource = new CancellationTokenSource();
_thread = Task.Factory.StartNew(() => DoMyServiceLogic(), TaskCreationOptions.LongRunning, _tokenSource);
}
protected override void OnStop()
{
_tokenSource.Cancel();
}
protected void DoMyServiceLogic()
{
while(!_tokenSource.Token.IsCancellationRequested)
{
// Do Stuff
}
}
Your service doesn't really follow the pattern; you're not doing things continuously, and that should be more of a console program.
Effectively, it's because your service stopped doing anything as soon as you finished the OnStart method. It's like what happens when you finish Main in a console program - the application just exited.
Check to make sure the account your service runs under can access those files (including write access for the .wav and .mp3 files).
Your code might also be causing an unhandled exception. I'm not sure, but that might be visible in the event log. You can also get your service to write out messages explicitly to the event log (like in the case of an exception); check out this link: http://www.codeproject.com/KB/dotnet/simplewindowsservice.aspx
Open eventvwr.msc. There you will see exception details on why your windows service has stopped working. By the way you should as quickly as possible leave the OnStart method because you only
have 30 seconds to finish the OnStart method.
There is a excellent article on MSDN describing "how to debug" Windows Services.