When creating a .NET Core Web app C# and debugging you can opt to Launch the browser when Running the app. The console launches and then the url launches in your preferred browser. Once you close the browser tab opened by the debug session, the app process it stop and is no longer running on the machine.
When I published the app, the page does not launch automatically so I am starting a new Process to do so. I've added an event handler to the process before starting it but the since the app didn't launch the process it doesn't receive any notification when the tab has been closed.
What is the proper way to go about launching your .NET Core web app and/or handle communicating between the two?
I even tried adding a Close button but JS won't allow me to close the window as I haven't opened it.
I'm creating my Process as follows:
var p = Process.Start("cmd", "/C start http://localhost:5000");
I've tried
p.WaitForExit();
p.EventHandler += newHandler;
and I also tried using ProcessStartInfo but the only thing that is working right now is if I set a Timer and then kill the process when the timer is activated but this doesn't seem too clean.
Any advice is appreciated!
I wanted to follow-up with the process I feel is the most graceful way that I am happy with.
A few pieces of info that may be helpful in creating your own process. It was a goal of mine to use .net core to self host a client side web app which communicates with a server hosted web api.
I am using Razor views and .net core 3.1
I am using Startup and utilizing applicationLifeTime to handle OnStartup where I start the process as I described in my original post.
At this point the web app opens and if the user decides to close the browser the process doesn't know and continues to run in the background.
In order to prevent it from continuing to run and allow the user to initiate it closing, I made a few the following additions.
First, I added a timer that uses a configurable length of time via appsettings. When starting the process that opens the browser I call and set the timer that will perform an "AutoShutdown" if the process is still running after the configurable length of time that I defaulted to 1hr. I am using Enviroment.Exit(0) in the event that handles closing the running process.
My View is using a Model that contains a property who's value will be set from the page via a hidden field.
I added a Close button to the View that is displayed to the user at startup. When the user clicks close, I use jquery to set a hidden field in the view and then I use jquery to submit the form.
When the Model is received, the value set by the client's request to close is true and you can handle the close without display errors if you use a Timer and Start it almost immediately after redirecting the View to a view with a message to the client. Whether they leave it open or close it, the process will have closed. Example of how I did it below.
Finally, in Main.cs I put a check in to check if there is an existing process running and close it before starting a new one. I added this because the client may not always close the browser and/or they may attempt to start it before the "AutoShutdown" timer has kicked in.
This is more "hacky" then I would like but I couldn't find anything else that didn't throw and show Bad Request when trying to use Envirnoment.Exit(0) when the client is still has the view open and I was unsuccessful at being able to allow console input so that I could send close to the console.
This is how I am handling the close request from the client in my Controller
if (ui.HandleCloseApp)
{
var app = Process.GetProcessesByName("NameOfYourWebApp");
if (app.Length >= 1)
{
foreach (var p in app)
{
if (p.ProcessName == "NameOfYourWebApp")
{
p.Close();
p.Dispose();
}
}
}
var t = new System.Timers.Timer(10);
t.Elapsed += OnClose;
t.Start();
return View("Close");
}
I hope this helps someone else in creating their own "graceful" process that shouldn't be :)
I'm still open if anyone has input to share. Thx!
I have a WCF Web Service and there is one method which returns sensor lists.
When I want to consume this web service in a Console Application in Debug Mode, I got these 2 errors as;
Could not copy "obj\Debug\ConsumeHelper.pdb" to "bin\Debug\ConsumeHelper.pdb". Exceeded retry count of 10. Failed. ConsumeHelper
and
Unable to copy file "obj\Debug\ConsumeHelper.pdb" to "bin\Debug\ConsumeHelper.pdb". The process cannot access the file 'bin\Debug\ConsumeHelper.pdb' because it is being used by another process. ConsumeHelper
Also I'm adding consumer method as given below.
SensorServiceClient client =
new SensorServiceClient("WebHttpBinding_ISensorService");
Sensor[] sensor = client.getAllSensors("true");
Console.WriteLine("Sensor name is " + sensor[0].Name);
Console.ReadLine();
So, can anyone lead to me solution? Thanks for everyone.
Per your latest comment where you say
ConsumeHelper is client project and it consumes WCF service
Make sure you are not already running that project. I doubt it's already running and so the pdb file is not able to copy. Else, try running in Release mode instead of Debug mode.
0x800401E3 (MK_E_UNAVAILABLE) error occurs in my case when UAC (User Account Control) isn't set to the un-restrictive "Never Notify Me".
Microsoft.Office.Interop.Word.Application wd =
(Microsoft.Office.Interop.Word.Application)
System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
The error is thrown when the code is run after publishing and installing the project. While debugging in the editor instead, everything is fine.
Is this due to security settings or credentials ? How to write such code correctly pls ?
Win Word is open and a document is open too, of course, and this code has always worked fine with UAC set to "Never Notify Me".
Running word as a service is nasty business see for instance here . I went through quite a few problems making it work. The way I made it work was to run it in separate process which launches it only once. The main program communicates with the process by sending commands as strings to stdin of the process and waiting for response on the stdout. If the response does not come in time allotted the process is killed and restarted
I am using the Mathematica .Net/Link platform to create a web service to format and calculate math problems. However I am unable to get it working.
I create it using this code:
_Log.IpDebug("Starting the Kernel Link");
if (string.IsNullOrEmpty(_MathLinkArguments))
_InternelKernel = MathLinkFactory.CreateKernelLink();
else
_InternelKernel = MathLinkFactory.CreateKernelLink(_MathLinkArguments);
_Log.IpDebug("Kernel Link Started");
_InternelKernel.WaitAndDiscardAnswer();
The value of _MathLinkArguments is -linkmode launch -linkname \"C:\\Program Files\\Wolfram Research\\Mathematica\\7.0\\Math.exe\".
This piece of code is called from the Application_Start method of the global.asax.cs file.
When it gets to the WaitAndDiscardAnswer() call it gives the server error:
Error code: 11. Connected MathLink program has closed the link, but there might still be data underway.
Note: The SampleCode given with the .NET/Link package (both a console app and a WinForms app) works.
Edit:
I copied the console app sample code given with Mathematica into an asp.net page and it gave me the same error the first load and then on subsequent loads it gave me:
Error code: 1. MathLink connection was lost.
Edit2:
I forgot to mention that when I have procmon and task manager open while running my app, I can tell that Math.exe starts but it immediately exits, which makes those error code make complete sense...but doesn't explain why that happened.
To allow the .Net/Link to work in Asp.net (at least in IIS 7.5) you need to enable the property loadUserProfile on the app pool for the web site.
I am not entirely sure why this is the case, but from what I found while trying to debug this, there are some things that are gotten from the user's profile. I know for a fact that the default location of the kernel is, which explains why I couldn't use it with no arguments, and so I can only assume that other things are needed as well and without the profile it couldn't determine that.
But whatever the reason is this is required, it is, or at least it is a fix if you are getting similar problems like this in your own application.
I got the same error in a .Net WinForm application.
mathKernel = new MathKernel();
mathKernel.Compute("<< XYZ`XYZGraphs`");
The error occurred on loading the package straight after instantiating the MathKernel.
To resolve it you can wait a couple of seconds and then instantiating the MathKernel works fine. During this state where there might still be data underway the following conditions are both false:
if (!MathKernel.IsConnected)
{
MathKernel.Connect();
}
if (MathKernel.IsComputing)
{
MathKernel.Abort();
}
Edit:
I've recieved the error again and this time was able to determine the problem.
Using a command line open the MathKernel.exe and view the error message:
Here is the premise:
I have a desktop that I need to be able to start up and stop applications on, but cannot get remote access to. What I had in mind is setting up a service on the machine that will start/stop a list of applications as told. This windows service will periodically pole a web service for new commands and execute them accordingly.
These are my questions.
1) Is this the easiest solution? What else would you recommend?
2) How hard is it to run an exe from a windows service? How about stopping one?
This isn't for a project or anything, just something I am interested in implementing (mostly for fun). Any answers or even thoughts are appreciated. General discussion is also welcome (feel free to leave comments).
As for creating the Windows service itself in C#, see my post here.
The polling mechanism would work, but in general, I prefer event-driven processes instead of polling processes. You didn't mention what version of .NET you were using, but if it is .NET 3.0/3.5, I would suggest using WCF. When the command is posted to the web service, the web service could send the command to the Windows service to be executed. Pretty straightforward. Juval Lowy, the author of Programming WCF Services, offers a bunch of WCF examples/libraries that are free to use at his website.
So I guess PsExec is out of question?
Other than that, it's not hard to implement running of programs inside a Win service. Simply use the .NET Process class to do it, sample from my code:
ProcessStartInfo processStartInfo = new ProcessStartInfo (programExePath, commandLineArgs);
consoleLogger.WriteLine (log, Level.Debug, "Running program {0} ('{1}')", programExePath, commandLineArgs);
processStartInfo.CreateNoWindow = true;
processStartInfo.ErrorDialog = false;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
using (Process process = new Process ())
{
process.StartInfo = processStartInfo;
process.ErrorDataReceived += new DataReceivedEventHandler (process_ErrorDataReceived);
process.OutputDataReceived += new DataReceivedEventHandler (process_OutputDataReceived);
process.Start ();
process.BeginOutputReadLine ();
process.BeginErrorReadLine ();
if (false == process.WaitForExit ((int)TimeSpan.FromHours(1).TotalMilliseconds))
throw new ArgumentException("The program '{0}' did not finish in time, aborting.", programExePath);
if (process.ExitCode != 0)
throw new ArgumentException ("failed.");
}
I have done a service that starts other exe files. There are some things to consider: As a service you have no visual desktop -> no direct interaction is possible. Also, the program must be designed to run a long while.
Stopping an exe is to kill the process. Consider the usual side-effects.
It wouldn't be too difficult - you can just have it poll some webservice for a list of "banned" applications every so often, and then on another timer, have it check for a banned application that's running and kill it if it is. Here's some code to get a list of processes, and you can use the methods on the process class to launch or kill something:
http://www.vbdotnetheaven.com/UploadFile/prvn_131971/machineprocessvb11182005001454AM/machineprocessvb.aspx
The timers could run independently as well - it can check the webservice once/day for a new add/prohibited list, but then check the processes running on the computer every 2 minutes, for example.
I'll answer question 2 first:
To start or stop programs, you just need to use the System.Diagnostics.Process object, and the example code is right in the MSDN library.
For question 1:
You could have it poll a web service periodically if you want to do that.
As an alternate, you can set up the service for remoting and have it just listen on a tcp port for function calls, then write a Windows app that can use remoting to call the service. I've had to do this for a legitimate business app and it works very well.
However, I would be very irresponsible if I didn't include this warning:
Either way, setting up a computer so that it can execute arbitrary code is a bad idea and should be done very carefully. Just because it can be done doesn't mean it should be done. If you go the web service route, how are you going to ensure that someone doesn't tamper with the web service and get malicious code to execute? How do you know someone won't mess with your app.config and point the app to their own web service? In the remoting scenario, how to you ensure that some other .Net developer doesn't just create a proxy of their own?
In all honesty, I'm amazed that Microsoft even allows the System.Diagnostocs.Process to be used in a .Net application. You can literally do anything you want with it, including launching the cmd shell and executing system commands. Therefore, I'd urge you to seriously consider if this is truly necessary to do. You may be better served installing vnc or using remote desktop, or another app for remote access.
One other question you need to answer is "should the application be visible to the user on that remote machine?" If so, then you need to ensure that the service is set up to run under that user's context. otherwise, you could, for example, launch Word using the local system account, and it would never be visible to the person logged into that machine.