I'm writing a console application in C#. How can I open a webpage after 10 seconds? I already found something like
System.Diagnostics.Process.Start("http://www.stackoverflow.com")
but how can I add a timer?
You can choose from the below options depending on the application:
System.Timers.Timer
System.Windows.Forms.Timer
System.Threading.Timer
For example:
System.Threading.Thread.Sleep((int)System.TimeSpan.FromSeconds(10).TotalMilliseconds);
If you want to open this page every 10 seconds try this
Timer timer = new Timer();
timer.Interval = 10000;
timer.Tick += timer_Tick;
timer.Start();
void timer_Tick(object sender, EventArgs e)
{
System.Diagnostics.Process.Start("http://www.stackoverflow.com");
timer.Stop(); //If you don't want to show page every 10 seconds stop the timer once it has shown the page.
}
And if you want it to only show page once than you can stop the timer by using Stop() method of timer class.
Since you are trying to open url within C# using
System.Diagnostics.Process.Start I am suggesting you to read this, I copy-paste the code posted in that webpage, in case the link will be broken in same day:
public void OpenLink(string sUrl)
{
try
{
System.Diagnostics.Process.Start(sUrl);
}
catch(Exception exc1)
{
// System.ComponentModel.Win32Exception is a known exception that occurs when Firefox is default browser.
// It actually opens the browser but STILL throws this exception so we can just ignore it. If not this exception,
// then attempt to open the URL in IE instead.
if (exc1.GetType().ToString() != "System.ComponentModel.Win32Exception")
{
// sometimes throws exception so we have to just ignore
// this is a common .NET bug that no one online really has a great reason for so now we just need to try to open
// the URL using IE if we can.
try
{
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo("IExplore.exe", sUrl);
System.Diagnostics.Process.Start(startInfo);
startInfo = null;
}
catch (Exception exc2)
{
// still nothing we can do so just show the error to the user here.
}
}
}
}
Regarding the suspended execution please use Task.Delay:
var t = Task.Run(async delegate
{
await Task.Delay(TimeSpan.FromSeconds(10));
return System.Diagnostics.Process.Start("http://www.stackoverflow.com");
});
// Here you can do whatever you want without waiting to that Task t finishes.
t.Wait();// that's is a barrier and the code after t.Wait() will be executed only after t had returned.
Console.WriteLine("Task returned with process {0}, t.Result); // in case System.Diagnostics.Process.Start fails t.Result should be null
Related
I have looked all over for a solution to an issue. I have noticed that in my android app, every time I fire an event from <button Clicked="GPSToggle_Clicked">, for some reason it increments the number of times my methods get called. So after I compile and load this on my phone, I hit my "GPSToggle_Clicked" button, and then to stop hit that button again. On the first "stop", I'll get a single instance of the below output:
---------------------------------------------------------------Attempting string parsing
---------------------------------------------------------------Sending string to SubmitGeneratedGPX
---------------------------------------------------------------path: /storage/emulated/0/Download/GPX/2022-10-27-02-44-06.gpx
---------------------------------------------------------------GPX File creation success
---------------------------------------------------------------:RawBufferToJsonString: [{"Timestamp":"2022-10-27T18:43:52.849+00:00","Latitude":41.5263818,"Longitude":-81.6507923,"Altitude":153.29998779296875,"Accuracy":20.0,"VerticalAccuracy":1.7990270853042603,"Speed":null,"Course":null,"IsFromMockProvider":false,"AltitudeReferenceSystem":2},{"Timestamp":"2022-10-27T18:43:53.696+00:00","Latitude":41.5263819,"Longitude":-81.6507921,"Altitude":153.29998779296875,"Accuracy":20.0,"VerticalAccuracy":1.7697961330413818,"Speed":null,"Course":null,"IsFromMockProvider":false,"AltitudeReferenceSystem":2},{"Timestamp":"2022-10-27T18:43:54.526+00:00","Latitude":41.5263819,"Longitude":-81.6507921,"Altitude":153.29998779296875,"Accuracy":20.0,"VerticalAccuracy":1.7697961330413818,"Speed":null,"Course":null,"IsFromMockProvider":false,"AltitudeReferenceSystem":2},{"Timestamp":"2022-10-27T18:43:55.374+00:00","Latitude":41.5263819,"Longitude":-81.6507921,"Altitude":153.29998779296875,"Accuracy":20.0,"VerticalAccuracy":1.7697961330413818,"Speed":null,"Course":null,"IsFromMockProvider":false,"AltitudeReferenceSystem":2},{"Timestamp":"2022-10-27T18:43:56.21+00:00","Latitude":41.5263811,"Longitude":-81.650792,"Altitude":153.29998779296875,"Accuracy":20.0,"VerticalAccuracy":1.7160584926605225,"Speed":null,"Course":null,"IsFromMockProvider":false,"AltitudeReferenceSystem":2}]
Every subsequent time I hit start/stop on the app, I get the real-time data in the output multiplied by the number of times I've started/stopped since the last compiling.
the main app page button event thats fired:
private async void GPSToggle_Clicked(object sender, EventArgs e)
{
var LocationPermissionStatus = await Xamarin.Essentials.Permissions.RequestAsync<Xamarin.Essentials.Permissions.LocationAlways>();
var FileReadPermissionStatus = await Xamarin.Essentials.Permissions.RequestAsync<Xamarin.Essentials.Permissions.StorageRead>();
var FileWritePermissionStatus = await Xamarin.Essentials.Permissions.RequestAsync<Xamarin.Essentials.Permissions.StorageWrite>();
if(LocationPermissionStatus == Xamarin.Essentials.PermissionStatus.Denied)
{
// TODO
return;
}
// run if device is android
if(Device.RuntimePlatform == Device.Android)
{
if (!CrossGeolocator.Current.IsGeolocationAvailable || !CrossGeolocator.Current.IsGeolocationEnabled)
{
// gps is not enabled, throw alert
Console.WriteLine("---------------------------------------------------------------GPS is DISABLED");
await DisplayAlert("Error", "GPS is not enabled. You must enable GPS to use this feature", "Ok");
}
else
{
// set our IsTracking = true flag
if (!IsTracking)
{
// start background listening for GPS
await StartListening();
Console.WriteLine("---------------------------------------------------------------Listening: " + CrossGeolocator.Current.IsListening);
StartService();
Console.WriteLine("---------------------------------------------------------------Service initiated");
IsTracking = true;
Console.WriteLine("---------------------------------------------------------------Tracking initiated");
GPSToggle.Text = "Stop Tracking";
}
else
{
//
// verify that the submittal wasn't done in error, before stopping services and submitting data
bool DoneInError = await DisplayAlert("Finish?", "Are you sure you want to stop services and submit?", "No", "Yes");
if (!DoneInError)
{
await StopListening();
Console.WriteLine("---------------------------------------------------------------listening:" + CrossGeolocator.Current.IsListening);
IsTracking = false;
Console.WriteLine("---------------------------------------------------------------Tracking ceased");
// stop the gps service
StopService();
Console.WriteLine("---------------------------------------------------------------Service ceased");
// stop the background listening for gps
Console.WriteLine("---------------------------------------------------------------Attempt GPX parse from buffer obj");
GPSToggle.Text = "Start Tracking";
}
}
}
}
}
Specifically the line:
StartService();
Fires this method off within the same class, specifically the MessagingCenter.Send<>, which initiates my foreground service to handle logging the gps data into a buffer:
private void StartService()
{
var startServiceMessage = new StartServiceMessage();
MessagingCenter.Send(startServiceMessage, "ServiceStarted");
Preferences.Set("LocationServiceRunning", true);
StatusLabel.Text = "Location service has been started";
Console.WriteLine("---------------------------------------------------------------location service has been started. preferences saved");
}
and
StopService();
Fires this method off to stop the services and retrieve the gps buffer data from the foreground to the main thread:
private void StopService()
{
var stopServiceMessage = new StopServiceMessage();
MessagingCenter.Unsubscribe<App, List<Location>>(this, "GPXBufferData");
MessagingCenter.Subscribe<App, List<Location>>(this, "GPXBufferData", (sender, args) =>
{
RawGPXData = args;
Generate_CreateGPX_File(RawGPXData);
RawBufferToJsonString = GPXParse.GenerateJSON_GPXPoints(RawGPXData);
Console.WriteLine("---------------------------------------------------------------:RawBufferToJsonString: " + RawBufferToJsonString);
PromptForSubmission_GPXPoints_API();
});
Console.WriteLine("--------------------------------------------------------------------------");
MessagingCenter.Send(stopServiceMessage, "ServiceStopped");
Preferences.Set("LocationServiceRunning", false);
Console.WriteLine("---------------------------------------------------------------Location service stopped. preferences saved");
}
In the above snippet, this line is subscribed to in the GPSLocationService.cs file:
MessagingCenter.Send(stopServiceMessage, "ServiceStopped");
This is a portion of my GPSLocationService.cs file that is relevant to this:
public async Task Run(CancellationToken token)
{
int ObjCount = 0;
await Task.Run(async () => {
// if the task was stopped
// check the buffer for data, if data, send to GPXGenerator
MessagingCenter.Subscribe<StopServiceMessage>(this, "ServiceStopped",
message =>
{
if (GPSBufferObj != null)
{
Device.BeginInvokeOnMainThread(() =>
{
MessagingCenter.Unsubscribe<App, List<Location>>((App)Xamarin.Forms.Application.Current, "GPXBufferData");
MessagingCenter.Send<App, List<Location>>((App)Xamarin.Forms.Application.Current, "GPXBufferData", GPSBufferObj);
});
}
});
return;
}, token);
}
I believe I have tracked down where the issue is starting. In my StopService() method, I have the following line (just to keep track of where Im at in the buffer) and it is only sent to output once.
Console.WriteLine("--------------------------------------------------------------------------");
BUT if I place that same line within the pasted portion of my GPSLocationService.cs file, I will get the incremented output. I'm leaning towards the nested task being the issue, I wrote this based losely off of this example repro:
https://github.com/jfversluis/XFBackgroundLocationSample
You don't have MessagingCenter.Unsubscribe<StopServiceMessage> anywhere in your code. StopServiceMessage is what you are accumulating subscriptions to.
You need to make sure Unsubscribe is unsubscribing the instance that was previously subscribed to. It sounds to me like there are multiple instances of GPSLocationService. [In which case, this is no longer referring to the original instance. Unsubscribe won't do anything, unless you have the this that was originally Subscribed.]
If so, instead create an instance of GPSLocationService ONCE, and store it in a static variable. Re-use it. start/stop it, but don't discard it.
Alternatively, if you only want a message ONE TIME from each Subscribe, then Unsubscribe as soon as you receive each message:
MessagingCenter.Subscribe<StopServiceMessage>(this, "ServiceStopped",
message =>
{
MessagingCenter.Unsubscribe<StopServiceMessage>(this, "ServiceStopped");
... your code ...
});
Use this same pattern EVERYWHERE you have a Subscribe (unless you Subscribe ONLY ONE TIME at app start, as Jason suggested.)
I have an Asp.NET Web API 2. My client calls a particular action method but I need someway to set the timeout value.
I need the timeout value because I want the client to take appropriate action if the action method hasn't returned anything back in say 40 seconds. (Basically that's an arbitrary limit I've chosen...so if it hasn't completed it's job..i.e. hasn't returned back the valid JSON in 40 seconds, we're going to have to assume that something is taking way too long on Azure and we're going to perform a rollback).
Also, if the timeout has occurred I want someone way to Rollback the transaction.
If it helps, I'm using the UnitOfWorkActionFilter along with NHibernate.
The controller and action method are both asynchronous, and I'm explicitly catching the ExecuteAsync method along with the CancellationToken variable.
However, I'm unaware of a way to cancel this call OR use the CancellationToken variable.
I can post code if necessary.
I did read in a few places that since WebApi2 is asynchronous that I may not be able to cancel this!
Any recommendations on how to go about solving this?
I think setting a timeout on the request is the wrong approach as you will have no visibility of what is going on during the 40 seconds.
Rather make a ajax web request and then subsequent web requests to see if the process has completed.
For example,
Queue the request somehow with the initial request.
Write something to pick up and process the item from the queue. This also means if something goes wrong, you can just roll back at this point. You also need to store the status of the item somewhere.
Write a periodic poll in Javascript that makes another ajax request every 5 seconds to see if the request has been processed or not.
Depending on what kind of method is running on your WebApi service you could try the following:
Start a StopWatch at the start of your action
Check periodically if the elapsed time is greater than your arbitrary limit. When that happens throw an Exception (I called mine
CalculationTimeLimitExceededException)
Catch the exception and perform a rollback (assuming you want to do a rollback on the server)
Return a response (e.g. HTTP 500 with some useful information, e.g. server timeout)
Since the client gets a response within your time limit you can then handle the error on the client side.
Update (added code for PerformanceWatcher):
public class PerformanceWatcher : IDisposable
{
private System.Diagnostics.Stopwatch _sw;
private Timer _timer;
private int _maxSeconds;
public bool TimeLimitExceeded { get; private set; }
public PerformanceWatcher(int maxSeconds)
{
_maxSeconds = maxSeconds;
// start the StopWatch
_sw = System.Diagnostics.Stopwatch.StartNew();
// check every second
_timer = new Timer(1000);
_timer.AutoReset = true;
// set event-handler
_timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
_timer.Enabled = true;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
// check if time limit was reached
if (this._sw.Elapsed.TotalSeconds > _maxSeconds)
{
this.TimeLimitExceeded = true;
}
}
public void Dispose()
{
this._timer.Dispose();
}
}
You can use this class in your action:
[HttpGet]
public HttpResponseMessage GetResultFromLongRunningMethod()
{
using (PerformanceWatcher watcher = new PerformanceWatcher(10))
{
try
{
// begin long-running operation
for (int i = 0; i < 20; i++)
{
if (watcher.TimeLimitExceeded)
{
throw new TimeLimitExceededException();
}
Thread.Sleep(1000);
}
// end long-running operation
} catch (TimeLimitExceededException e)
{
return this.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Time limit exceeded");
}
}
return this.Request.CreateResponse(HttpStatusCode.OK, "everything ok");
}
The above code isn't tested; I just copied some elements from my own classes.
Update 2: Fixed a bug in the code (Exception thrown from event handler wasn't caught)
I have create a application for text to speech using Speechlib SpVoice. it is working fine with windows application.
But when i Create windows service using same code . It give me this error
System.Runtime.InteropServices.COMException (0x8004503A): Exception
from HRESULT: 0x8004503A at SpeechLib.ISpeechVoice.Speak
this is my code
public partial class LEDPlayService : ServiceBase
{
static int MessageID = 0;
static SpeechLib.SpVoice VoiceObj = new SpeechLib.SpVoice();
static System.Timers.Timer myTimer = new System.Timers.Timer();
protected override void OnStart(string[] args)
{
myTimer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
//This statement is used to set interval to 1 minute (= 60,000 milliseconds)
myTimer.Interval = 60* 1000;
// enabling the timer
myTimer.Enabled = true; ;
myTimer.AutoReset = false;
}
private static void OnElapsedTime(object source, ElapsedEventArgs e)
{
((System.Timers.Timer)source).Stop();
myTimer.Enabled = false; ;
bool result =PlayAudio("Hello prithvi");
((System.Timers.Timer)source).Start();
myTimer.Enabled = true;
// TraceService(""+DateTime.Now.TimeOfDay);
}
public static bool PlayAudio(string text)
{
bool res = false;
try
{
VoiceObj.Speak(text, SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
res = true;
}
catch(Exception e)
{
TraceService("error in sound........."+e.InnerException+e.Message+" "+e.ToString());
res = false;
}
return res;
}
}
Please help me..
It is a low-level error returned by a SAPI call, SPERR_NOT_FOUND. You are making it excessively difficult to answer the question reliably when you don't post a snippet and the stack trace of the exception. Or how you even observed it, these COM errors are normally translated to .NET exceptions.
The error code doesn't much more than "can't find what's needed to do the job". The call context ought to make it bit clear what might be missing, but we can't see this. Having this code run in a service is a cue of sorts. The user account under which this service runs matters, a lot of config for System.Speech is stored in the registry and a service is going to have a hard time finding config that's stored in HKCU instead of HKLM. Not uncommon for example if you purchased a voice and registered it. And it might well have a hard time finding hardware, like a microphone or speaker.
So first thing to try is to configure the service to run with a specific user account (like yours) instead of the default System account. Next thing to try is to use SysInternals' Process Monitor, you'll see your program search the registry for keys. Compare a good trace, one you got from running it as a desktop program, against the trace you got when running it from the service. And update your question with the required info to get a better answer.
When I try to start my c# service it says:"starting" for a second and it turns back to being "stopped"
What can be the problem? I had the same code before, and it worked but made some changes in the code now and it stopped working. Here is what I added to my code:
App Config:
<add key="cut-copy" value="copy"/>
Normal code:
private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)
{
String cut_copy = ConfigurationManager.AppSettings[#"cut-copy"];
if (cut_copy == "copy")
{
cut = false;
}
else
{
cut = true;
}
if (WaitForFileAvailable(e.FullPath, TimeSpan.FromSeconds(10)))
{
var file = Path.Combine(source, e.Name);
var copy_file = Path.Combine(target, e.Name);
var destination = Path.Combine(target, Path.ChangeExtension(source, Path.GetExtension(source)));
if (File.Exists(file))// Check to see if the file exists.
{ //If it does delete the file in the target and copy the one from the source to the target.
File.Delete(copy_file);
File.Copy(e.FullPath, Path.Combine(target, e.Name));
}
else// If it doesn't, just copy the file.
{
if (cut == true)
{
if (File.Exists(file))// Check to see if the file exists.
{ //If it does delete the file in the target and copy the one from the source to the target.
File.Delete(copy_file);
File.Move(Path.Combine(e.FullPath, e.Name), target);
}
}
else
{
if (File.Exists(file))// Check to see if the file exists.
{ //If it does delete the file in the target and copy the one from the source to the target.
File.Delete(copy_file);
File.Copy(e.FullPath, Path.Combine(target, e.Name));
}
}
//under this is more code that didn't change
}
EDIT: ONSTART:
protected override void OnStart(string[] args)
{
base.OnStart(args);
this.fileSystemWatcher1 = new System.IO.FileSystemWatcher();
((System.ComponentModel.ISupportInitialize)(this.fileSystemWatcher1)).BeginInit();
fileSystemWatcher1.Path = source;
fileSystemWatcher1.Changed += new FileSystemEventHandler(fileSystemWatcher1_Changed);
fileSystemWatcher1.Created += new FileSystemEventHandler(fileSystemWatcher1_Created);
fileSystemWatcher1.Deleted += new FileSystemEventHandler(fileSystemWatcher1_Deleted);
fileSystemWatcher1.Renamed += new RenamedEventHandler(fileSystemWatcher1_Renamed);
this.fileSystemWatcher1.EnableRaisingEvents = true;
this.fileSystemWatcher1.IncludeSubdirectories = true;
((System.ComponentModel.ISupportInitialize)(this.fileSystemWatcher1)).EndInit();
logger("Service started "+ DateTime.Now);
}
What am I doing wrong?
Usually this behavior indicates that the OnStart method ends without leaving any threads running. I have experienced that if an unhandled exception is thrown starting the service, the service doesn't go into Stopped state, but the service manager shows the "Starting service" window for 30 seconds and then fails saying it can't determine the service's state.
I'm not sure whether the FileSystemWatcher actually spawns a new thread that keeps running. You could (just to try it), also create a System.Timers.Timer that fires every 30 seconds in OnStart and stop that timer in OnStop. If the service keeps running then, you have to spawn a new thread for the FileSystemWatcher.
Usually, in OnStart you'd spawn a separate thread that does the service's work. Be it waiting for TCP connections, a timer that does things on a regular basis or any other kind of thread. If you don't do that, the service just stops as soon as there are no more threads active.
For the code, the only answer that anyone could give you are just "guessing". You better debug it yourself.
The easiest way to hit a break-point in a Windows Service is to put this line of code at the beginning of the OnStart method:
Debugger.Break();
Compile your service in Debug mode, so you can have all the necessary symbols in your executable.
Install your service
Start it from the service list.
You will get a prompt for debugging the "yourservicename.exe" program.
Say Yes-debug, Choose debugger.
Choose the correct Visual Studio version as your debugger.
Now you will be in the Debugger.Break line
Have fun
I need to have tasks running in my web application. I have been reading and most of the answers are to use the task scheduler in Windows but what I need is to have it in the web application itself.
I finally got something that almost works but I am still having some troubles:
using System;
using System.Timers;
using System.IO;
namespace ServiceIIS
{
public static class Servicios
{
public static bool serviceStarted = false;
static Timer serviceLoad = new Timer();
public static void serviceLoader()
{
if (!serviceStarted)
{
GC.KeepAlive(serviceStarted);
GC.KeepAlive(serviceLoad);
serviceStarted = true;
double Intervalo = loadData();
serviceLoad.Interval = Intervalo;
serviceLoad.Elapsed += new ElapsedEventHandler(serviceLoad_Elapsed);
serviceLoad.Enabled = true;
}
}
static void serviceLoad_Elapsed(object sender, ElapsedEventArgs e)
{
serviceLoad.Stop();
double Intervalo = loadData();
serviceLoad.Interval = Intervalo;
serviceLoad.Start();
}
static double loadData()
{
string dailyLoadTime = "00:00:00";
string log = "";
/*
loadData Code
log = resultMessage;
*/
using (StreamWriter w = File.AppendText("c:\\log.txt"))
{
writeLog(log, w);
w.Close();
}
return (Convert.ToDateTime(DateTime.Today.ToString("yyyy-MM-ddT") + dailyLoadTime).AddDays(1) - DateTime.Now).TotalMilliseconds;
}
public static void writeLog(string resultMessage, TextWriter w)
{
w.Write("\r\nLog : ");
w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
w.WriteLine(" :");
w.WriteLine(" :{0}", resultMessage);
w.WriteLine("-------------------------------");
w.Flush();
}
}
}
serviceLoader() will be called if serviceStarted is false, then I tell the garbage collector to ignore serviceStarted and serviceLoad to be cleaned.
Calling loadData() for the first time to get the data and "generate" the interval for the timer to wait until loadData() is called again. Then I create the event handler and start the timer.
Using the writeLog() procedure I know when loadData() is called. Waiting for the time it should be called (00:00:00 hours), there is no calling to loadData() but until a different time... that could be because the way I am computing the interval is not entirely correct.
Then it is called again the same day and once the next day. Finally after the second day, there is no call at all for loadData() so I suppose it is because the garbage collector deleted it, calling serviceLoader() again, loadData() is called at the same time telling me that in effect serviceStarted has been cleaned and surely serveLoad has been cleaned too.
Do you have an idea on what I am doing wrong and how could I get this working? I could not believe that there is no way to do this using IIS.
Thank you in advance for your time reading this.
Elder
It seems there is no entry point for the code you wrote. Typical aspnet entry is Page_Load but, in your purpouse, you must use Application_Start in Global.asax .
Anyway IIS web apps are not intended to host scheduled tasks, so I suggest to develop an .exe to be called by Task Scheduler ora a Windows Service instead.
You should implement this kind of logic in Windows service not IIS.