Văn Lộc Văn Lộc - 4 months ago 10
C# Question

How to create n Object base on DataTable.Rows.Count in C#?

All code below only to create two processes. While I need to create n process to open Chrome browser and run

OpenNRowsInData(user, pwd)
based on
dtUser.Rows.Count
because this is dynamic.

And I don't know why
OpenNRowsInData(user, pwd);
always only get first rows.

I have a
DataTable
range from 1-7 rows.

Typically, I was usually using to create two objects.

static myObject[] browser = new myObject[] {
new myObject(Browsers.Chrome, 0),
new myObject(Browsers.Chrome, 0)
};

Thread t1, t2;

t1 = new Thread(new ThreadStart(AllCase))
{
Name = "Thread1"
};
t1.Start();

t2 = new Thread(new ThreadStart(AllCase))
{
Name = "Thread2"
};
t2.Start();


In class
AllCase
:

static int[] stepRun = { 0, 0 };
private void AllCase()
{
int idx = int.Parse(Thread.CurrentThread.Name.Replace("Thread", "")) - 1;
switch (stepRun[idx])
{
case 0:
foreach (DataRow row in dtUser.Rows)
{
user = row["user"].ToString();
pwd = row["pwd"].ToString();
OpenNRowsInData(user, pwd);
}
break;
case 1:
ClickBuy();
break;
}
}


And in another, before I using parallel process. Currently, I don't want to use it.

Parallel.ForEach(
dtUser.AsEnumerable(),
items => OpenNRowsInData(items["user"].ToString(), items["pwd"].ToString()));


I want to get only columns
user
and
pwd
.

Tried with code, I tried to add a parameter in
action()
method like:
action(string user, string pwd)
.

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
if (source == null) throw new ArgumentNullException("source");
if (action == null) throw new ArgumentNullException("action");

foreach (T item in source)
{
action(item);
}
}


Updated:

Add class
OpenNRowsInData(string username, string password)
:

private void OpenNRowsInData(string username, string password)
{
int idx = int.Parse(Thread.CurrentThread.Name.Replace("Thread", "")) - 1;
try
{
browser[idx].DeleteAllCookies();
browser[idx].GoToUrl(link);
browser[idx].waittingID("txtUserName", 15);
browser[idx].FindElementById("txtUserName").SendKeys(username);
browser[idx].FindElementById("txtpassword").SendKeys(password);
browser[idx].FindElementById("btnlogin").Click();
stepRun[idx] = 1;
AllCase();
}
}

Answer

And I don't know why OpenNRowsInData(user, pwd); always only get first rows.

It seems for me that your second threat is too fast. Before the first can finish it will execute ClickBuy(); so only the first row can be processed.

try to do it one step after the other

AllCase(0, 0);
AllCase(1, 0);


private void AllCase(int case, int browserNr)
{
    switch (case)
    {
        case 0:
            foreach (DataRow row in dtUser.Rows)
            {
                user = row["user"].ToString();
                pwd = row["pwd"].ToString();
                OpenNRowsInData(user, pwd, browserNr);
            }
            break;
        case 1:
            ClickBuy();
            break;
    }
}

private void OpenNRowsInData(string username, string password, int browserNr)
{      
    try
    {
        browser[browserNr].DeleteAllCookies();
        browser[browserNr].GoToUrl(link);
        browser[browserNr].waittingID("txtUserName", 15);
        browser[browserNr].FindElementById("txtUserName").SendKeys(username);
        browser[browserNr].FindElementById("txtpassword").SendKeys(password);
        browser[browserNr].FindElementById("btnlogin").Click();
    }
}

If you want to do it for both browsers try running a loop on the array:

for(int j = 0; j < browser.Length;j++)
{
    AllCase(0, j);
    AllCase(1, j);
}

This time parallelisation would actually pay off. Because you could do the same stuff in both browsers at the same time, but it seems you should not do both AllCase - cases in the same browser at the same time, because they are consecutive

EDIT:

After your edit it seems that when you go in your loop the first time you set in OpenNRowsInData at the position 0

stepRun[idx] = 1;

and then call again

AllCase();

this time it will execute

    case 1:
        ClickBuy();
        break;

on the second iteration it will try again to switch on

switch (stepRun[idx])

but this time it will find a 1 on the position 0 in stepRun. For all and never go back in the case to call OpenNRowsInData. This is why you get only the first row.

EDIT 2:

if you want to do it at the same time in both browsers you can make a routine that executes the two cases of AllCase and this routine you can run in 2 separate threads:

public void doEverything(int browserIndex)
{
    AllCase(0, browserIndex);
    AllCase(1, browserIndex);
}

and start the threads like this:

for(int j = 0; j < browser.Length;j++)
{
    int brInd = j;
    Thread t= new Thread(()=>doEverything(brInd));
    t.Start();
}

you could also pass the entire browser object to the method and pass it further down to OpenNRowsInData and use it there