How call the main method or restart the app console? - c#

When an exception occurs I want to restart all the processing or start the Main method, after this other method:
public void DisplayMessage(string message) {
Console.WriteLine(message, "Rebuild Log Files");
Console.WriteLine(" Press Enter to finish, or R to restar the program...");
string restart = Console.ReadLine();
if(restart.ToUpper() == "R") {
//Call the Main method or restart the app
}
Console.ReadKey();
}
Note: the main method contains some user written data.
How can I do this?

Ok you have a main
void main(...)
{
some code
}
All you need to do is...
void main()
{
runStartUpCode();
}
void runStartUpCode()
{
some code
}
Then when you need to restart the code, call runStartUpCode() again.

if(restart.ToUpper() == "R") {
Close();
System.Diagnostics.Process.Start(Application.ExecutablePath);
}

static void Main(string[] args) {
try {
// code here
} catch /* or finally */ {
DisplayMessage(/* pass in any state from Main() here */);
}
}
static void DisplayMessage(/* passed in state from Main() */) {
// original DisplayMessage() code
// if R was pressed
Main(/* put any args to pass to Main() in here */);
}

I actually just got done with this problem earlier by the time you read this post. I kind of duplicated the ORIGINAL main method, changed a few options on the original, and left the copy to call the new main method. Here is what I mean.
static void Main(string[] args)
{
Program CallingTheRealMain = new Program();
CallingTheRealMain.Main2();
}
public void Main2()
{
//Any code here
}
I originally needed to do this because I needed to loop back to the main method but couldn't because it was static. This code worked fine for me, hope it does for you too if you choose to implement it. Hope I helped. Happy coding!

DialogResult result = MessageBox.Show("Do You Really Want To Logout/Exit?", "Confirmation!", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
this.Close();
System.Diagnostics.Process.Start(Application.ExecutablePath);
}

I think your design approach should change if what your app to autorestart.... here's a Pseudocode
main (){
errorObj = null;
internalFunct(errorObj);
if(errorObj != null) return;
secondINternalFunction();
}
Running the app...
while(!errorObj){
main();
}
Why i prefer this approach, because Main, or function recall is avoided... If your working with small memory, there is not point recalling main on the stack of limited space... you have no choice but to be iterative...

New to C#, I apologize for mistakes.
Use this:
static void Restart() {
String[] n = new String[10];
n[0] = "hi";
Main(n);
}
Main takes a string array for reasons I am unaware of. Seems useless to me, because I tried removing it and nothing seemed to change. So, maybe this works too:
Try removing the string[] args part of Main() so you can just type Main(); without
issues.

Related

Multiple thread not working correctly in C#

I create parallel process and DataTable dtUser have two rows, it should create two browser:
Parallel.ForEach(dtUser.AsEnumerable(), items =>
OpenBrowser(items["user"].ToString(), items["pass"].ToString()));
Lapsoft_OneDriver browser;
public void OpenBrowser(string username, string password)
{
browser = new Lapsoft_OneDriver(Browsers.Chrome);
browser.GoToUrl(link);
browser.FindElementById("txtUserName").SendKeys(username);
browser.FindElementById("txtpassword").SendKeys(password);
}
It create two Chrome process but only first process running line code block:
browser.GoToUrl(link);
browser.FindElementById("txtUserName").SendKeys(username);
browser.FindElementById("txtpassword").SendKeys(password);
The second process only initializes new browser and not do anything.
If I change this line:
browser = new Lapsoft_OneDriver(Browsers.Chrome);
to
var browser = new Lapsoft_OneDriver(Browsers.Chrome);
It's working.
But another method continues to use variable browser to execute other code.
So, I must declare global variable Lapsoft_OneDriver browser out of a function to use in another method use it.
My problem is:
Why using Lapsoft_OneDriver browser; it create two Chrome process but only first process active, it will insert to browser.FindElementById("txtUserName") two values of variable username and second process not do anything?
Updated:
When to change the code, I have any problem.
I will add more code of frmMain_Load:
private void frmMain_Load(object sender, EventArgs e)
{
thread = new LThread();
thread.StartedEvent += new LThread.startDelegate(AllCaseProgram);
numLog = int.Parse(dtSetting.Rows[0]["num_Log"].ToString());
}
int numProcess;
private void AllCaseProgram(object args)
{
try
{
switch (numProcess)
{
case 0:
Parallel.ForEach(dtUser.AsEnumerable(), items => Start(items["user"].ToString(), items["pass"].ToString()));
break;
case 1:
ClickCart();
break;
case 2:
Result();
break;
}
}
catch (Exception ex)
{
if (browser != null)
browser.Cleanup();
numProcess = 0;
AllCaseProgram(null);
}
}
At event of button StartProgram()_Click. I start Thread like: thread.Start();
You said: should be add this function to my program.
public static void Start(string user, string pwd)
{
var test = new frmMain();
test.OpenBrowser(user, pwd);
test.ClickCart();
}
My update question is:
Seem function Start(string user, string pwd) should be change to function AllCaseProgram include all switch case.
And variable numLog in frmMain_Load have values = 3. In function test.ClickCart() I also use this variable but values auto change to 0.
Have any issues with code? Thanks.
And LThread class is:
public class LThread : BackgroundWorker
{
#region Members
public delegate void startDelegate(string ID);
public event startDelegate StartedEvent;
private static int RandNumber(int Low, int High)
{
Random rndNum = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), System.Globalization.NumberStyles.HexNumber));
int rnd = rndNum.Next(Low, High);
return rnd;
}
protected override void OnDoWork(DoWorkEventArgs e)
{
StartedEvent(RandNumber(100,10000).ToString()); //put whatever parameter suits you or nothing
base.OnDoWork(e);
e.Result = e.Argument;
}
BackgroundWorker bwThread;
// Main thread sets this event to stop worker thread:
public Boolean bwIsRun;
int m_time_delay = 10000;
Delegate m_form_method_run;
Delegate m_form_method_stop;
Form m_type_form;
#endregion
#region Functions
public void Start()
{
try
{
bwIsRun = true;
this.RunWorkerAsync();
}
catch { }
}
public void Stop()
{
try
{
bwIsRun = false;
}
catch { }
}
private void StartToListen(object sender, DoWorkEventArgs e)
{
while (true)
{
Thread.Sleep(m_time_delay);
if (bwIsRun == true)
{
m_type_form.Invoke(m_form_method_run);
}
else
{
BackgroundWorker bwAsync = sender as BackgroundWorker;
if (bwAsync.CancellationPending)
{
e.Cancel = true;
return;
}
break;
}
}
}
#endregion
}
You should encapsulate your state for each test run. That way you'll have a class that has the responsibility the start a browser, execute one or more actions, while keeping all the required state belonging to a single run private for just one instance, while you can have a many instances as you like (if resources permit).
// this is NOT a winform, this is a new and seperate class ...
// don't try to mix this with an WinForm, that will fail
public class BrowserTestRunner
{
// only this Test instances uses this browser
Lapsoft_OneDriver browser;
private void OpenBrowser(string username, string password)
{
browser = new Lapsoft_OneDriver(Browsers.Chrome);
browser.GoToUrl(link);
browser.FindElementById("txtUserName").SendKeys(username);
browser.FindElementById("txtpassword").SendKeys(password);
// you probably want to click on something here
}
// some other test
private void ClickCart()
{
browser.FindElementById("btnCart").Click();
}
// add other actions here
// this starts the test for ONE browser
public static void Start(string user, string pwd)
{
var runner = new BrowserTestRunner();
runner.OpenBrowser(user, pwd);
// wait for stuff, check data, prepare the next steps
// for example
// runner.ClickCart();
// other actons here
}
}
Now you can create as many Test class instances as you like, while each instance of the class manages its own internal state, without interfering with other instances:
Parallel.ForEach(dtUser.AsEnumerable(), items =>
BrowserTestRunner.Start(items["user"].ToString(), items["pass"].ToString()));
If you want to start that from your backgroundworker do:
private void AllCaseProgram(object args)
{
try
{
switch (numProcess)
{
case 0:
Parallel.ForEach(
dtUser.AsEnumerable(),
items => BrowserTestRunner.Start(items["user"].ToString(), items["pass"].ToString()));
break;
case 1:
ClickCart();
break;
case 2:
Result();
break;
}
}
catch (Exception ex)
{
if (browser != null)
browser.Cleanup();
numProcess = 0;
AllCaseProgram(null);
}
}
By all means: don't start the main form again. Just separate your WinForm from the code you use to operate the browser. That does mean that you have to move the code that interacts with the browser to the BrowserTestRunner. Don't try in keeping the logic for your selenium stuff in the WinForm class because that is doomed to fail. As you are already experiencing.
What you got here is sort of a race condition. You got two threads not getting along when handling a single field in the class. Your problem is only that you don't have sufficient space to store all the browser instances you require.
What happens is basically that the first thread enters the method, creates a instance of the chrome browser and stores it in the variable. Then the second thread enters the function and does the same thing. But it also stores the instance in the same variable. Now the first thread continues and goes to a link. But the instance it is working with is already replaced by the second thread. And so on. This may happen with the threads the other way around or the overlapping may happen after more lines where handled. But it is bound to go wrong.
The way to resolve it, is as you noticed to make the variable local by adding a var. This way both threads are working with distinct variables.
Now you said you need the variable in another function. The question is: Do you need both? Do you need only one? Do you need a specific one?
In case you need only one, you just store the variable in the global variable by adding a line like this in your function:
this.browser = browser;
So it would look like this in total:
Lapsoft_OneDriver browser;
public void OpenBrowser(string username, string password)
{
var localBrowser = new Lapsoft_OneDriver(Browsers.Chrome);
localBrowser.GoToUrl(link);
localBrowser.FindElementById("txtUserName").SendKeys(username);
localBrowser.FindElementById("txtpassword").SendKeys(password);
this.browser = localBrowser;
}
I changed the name of the local browser variable, so it gets clearer what variable is used. Do note that either one of the created browsers could end up in the variable.
In case you need a specific one you have to determine if you have the correct one and store the result after this.
If you need both you have to store them in a list. The namespace System.Collections.Concurrent offers lists that can be handled by multiple threads at once.

C# How to end an infinite loop that also recieves user input with the press of Escape in Console Application

I have just started learning C# and I'm practicing some basic coding in the console application and I'm trying to make a program that adds two integers together by using an infinite loop and a method. But I want to be able to end the loop by pressing escape but the problem is, is when I press any key besides escape after the loop has completed for the first time, the program crashes. It says "Input string was not in a correct format." Any suggestions would be greatly appreciated!
Thanks!
namespace ConsoleApplication2
{
class Program
{
static void Addxy(int x, int y)
{
Console.WriteLine(x+y);
}
static void Main(string[] args)
{
while(true)
{
Addxy(Convert.ToInt32(Console.ReadLine()), Convert.ToInt32(Console.ReadLine()));
ConsoleKeyInfo end;
end = Console.ReadKey();
if (end.Key == ConsoleKey.Escape)
break;
else
{
}
}
}
}
}
You have two Console.ReadLine() before Console.ReadKey(). So the first two inputs should be numerals followed by the Escape key to terminate the program. Remember to press Enter after the first two numeral entry.
You could use break to end the loop, but a more elegant way would be to define a variable that determines if the loop should keep running. Here is my suggestion for your problem:
static void Main(string[] args)
{
bool keepLooping = true;
while (keepLooping)
{
//Do your stuff here
if (Console.ReadKey().Key == ConsoleKey.Escape)
{
keepLooping = false;
}
}
}
or an even shorter version if you prefer that:
static void Main(string[] args)
{
bool keepLooping = true;
while (keepLooping)
{
//Do your stuff here
keepLooping = Console.ReadKey().Key != ConsoleKey.Escape;
}
}

C# Restarting a console application

I've created a small application that does a small conversion. At the end of the program I've created a method that allows the user to make another calculation if they press 'r'. All I want it to do is if they press r, take them back to the beginning of Main, else terminate program. I do not want to use goto. This is what I've got so far, and the error I'm getting.
http://puu.sh/juBWP/c7c3f7be61.png
I recommend you use another function instead of Main(). Please refer to the code below:
static void Main(string[] args)
{
doSomething();
}
public static void WouldYouLikeToRestart()
{
Console.WriteLine("Press r to restart");
ConsoleKeyInfo input = Console.ReadKey();
Console.WriteLine();
if (input.KeyChar == 'r')
{
doSomething();
}
}
public static void doSomething()
{
Console.WriteLine("Do Something");
WouldYouLikeToRestart();
}
A while loop would be a good fit, but since you say the program should run and then give the user the option to run again, an even better loop would be a Do While. The difference between while and Do While is that Do While will always run at least once.
string inputStr;
do
{
RunProgram();
Console.WriteLine("Run again?");
inputStr = Console.ReadLine();
} while (inputStr == "y");
TerminateProgram();
In your case, you want to repeat something so of course you should use a while loop. Use a while loop to wrap all your code up like this:
while (true) {
//all your code in the main method.
}
And then you prompt the user to enter 'r' at the end of the loop:
if (Console.ReadLine () != "r") {//this is just an example, you can use whatever method to get the input
break;
}
If the user enters r then the loop continues to do the work. break means to stop executing the stuff in the loop.

Error appending text in ( nonexistant ) textbox due to async callback

I have written some code that works quite well : the program opens an async socket with the server, and writes in a textarea whatever the server sends.
The problem is, when i close the form, I get a lot of errors, because the callback is trying to write in the textarea that, obviously, is not there anymore.
Here is the method that writes on the textarea :
private void appendText(string s)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(appendText), new object[] { s });
return;
}
SocketStream.AppendText(s + "\r\n");
}
and here is the part of the callback's code calling said method :
string[] arr = txt.Split(new char[1]);
foreach (string t in arr)
{
if (!String.IsNullOrEmpty(t) && !String.IsNullOrWhiteSpace(t))
{
appendText( t);
}
}
is there a way to prevent those errors from happening?
I've already tried adding a
if(SocketStream != null)
but it didn't seemed to work.
When you close your form you probably need to stop reading from your Async socket, as well as stop writing to your TextBox. You'll need to have some state, some boolean perhaps, that makes all the processes stop. Now I don't know the specifics of your situation, but you could think of something like:
public class YourForm
{
private bool _formClosing = false; // Keep track of form closing
public YourForm()
{
this.FormClosing += FormClosingHandler;
}
protected void FormClosingHandler(object sender, FormClosingEventArgs e)
{
_formClosing = true;
}
private void appendText(string s)
{
if (_formClosing) // If form is closing, we dont want to append anymore
return;
if (InvokeRequired)
{
this.Invoke(new Action<string>(appendText), new object[] { s });
return;
}
SocketStream.AppendText(s + "\r\n");
}
// Socket handling; also check for _formClosing
}
You need to include the same check for your socket as well, to stop it from reading more data and gracefully disposing of the socket/connection. Again I'm making some assumptions/guesses here, but this might push you in the right direction.
Can you unsubscribe from the callback event before you close the Form?
You can do this with the -= operator, in the Closing handler of your Form.

Replacing all usages of a method (Introduce Indirection)

I am generally not very fond of refactoring tools. No need to get into details. Still, I occasionally try out new versions. Here is what I was trying to do while evaluating resharper 4.5 :
I needed to replace all usages of a method with a wrapper method (to be created) but I could not. I usually suck at noticing an obvious feature, is this the case? If resharper does not have this feature, do you know such tools?
Edit 2: Sample has been improved to include instance method calls.
Edit:
Here is a simple case to play.
static void Main(string[] args)
{
while(true)
{
if (Console.ReadKey().Key == ConsoleKey.Escape)
{
Thread.Sleep(10);
if (Quiting()) break;
}
Console.Beep(250, 50);
}
}
static bool Quiting()
{
if (Console.In.Peek() > 0)
{
Console.Beep(250, 150);
return false;
}
return true;
}
What I need is something like: (Edit2: added an instance sample)
private static StringBuilder _builder = new StringBuilder();
static void Main(string[] args)
{
while(true)
{
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Escape)
{
Thread.Sleep(10);
if (Quiting()) break;
}
_builder.Append(" (").Append(key.KeyChar).Append(") ");
Beep(250, 50);
}
}
static bool Quiting()
{
if (Console.In.Peek() > 0)
{
Beep(250, 150);
_builder.Append('#');
return false;
}
return true;
}
static void Beep(int frequency, int duration)
{
// finally cursor ends up here
Console.Beep(250, 50);
}
Console.Beep calls are refactored. Next lets refactor StringBuilder.Append(char) :
class Program
{
private static StringBuilder _builder = new StringBuilder();
static void Main(string[] args)
{
while(true)
{
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Escape)
{
Thread.Sleep(10);
if (Quiting()) break;
}
_builder.Append(" (").AppendUpper(key.KeyChar).Append(") ");
Beep(250, 50);
}
}
static bool Quiting()
{
if (Console.In.Peek() > 0)
{
Beep(250, 150);
_builder.AppendUpper('n');
return false;
}
return true;
}
static void Beep(int frequency, int duration)
{
// finally cursor ends up here
Console.Beep(250, 50);
}
}
static class StringBuilderExtensions
{
public static StringBuilder AppendUpper(this StringBuilder builder, char c)
{
return builder.Append(char.ToUpper(c));
}
}
Selecting from usages and maybe omitting common parameters (such as 250 above) or common instance parameters for non-extension statics shall make this feature more valuable. Hopefully, this clears up the question.
ReSharper doesn't have this as a single refactoring. I might do it as follows:
Select the contents of the method to be wrapped, and use Extract Method to create a new private method from the contents.
The original method is now a trivial wrapper around "itself". Rename it if you like, or manipulate it as you like (make it static, move to a different class, surround with try/catch, whatever).
EDIT:
Based on your edit, it seems you have an additional problem. Not only is Console.Beep not in the same class, it's not even in your class.
But if you don't mind a little search and replace, then you can put it into your own class, then proceed with the refactoring:
namespace Temporary {
public class Console {
public static void Beep(int x, int y) {System.Console.Beep(x,y);}
}
}
Then do a "Replace in Files" to replace Console.Beep with Temporary.Console.Beep, and proceed as above.
It's not included in any .NET refactoring IIRC, the tool which has such a refactoring is Eclipse, but not for .NET/C#
Assuming the wrapper method will be in the same class you can rename the current method to the name of the new wrapper method (ctrl+R+R in Resharper). This will rename all calls to this method in the solution as well. Then rename the original method back by hand (don't use Resharper or all the calls will get renamed back too) and add the wrapper method.
Based on your edit I think you will be out of luck to get the functionality that you want from any Visual Studio add-in that I've seen (beyond the simple find and replace which will get you some of the way there I guess).
Depending on how much time and effort you are willing to devote to this I'd imagine it's possible to use the DXCore framework and write a plugin that will do this kind of refactoring.
Resharper has a Search and Replace with Pattern feature. It can search and replace on patterns and expressions.
This would refactor all calls to Console.Beep() to your own method. It only replaces the usage if 250 is the first parameter:
However this would replace the usage of Console.Beep() within your own Beep method. You would have to manually replace that one usage.

Categories

Resources