469,954 Members | 1,699 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,954 developers. It's quick & easy.

Async Design Question

Hello -

I am trying to write a class that has an async BeginX and EndX, plus the
regular X syncronous method. Delegates seemed like the way to go,
however, I still am having problems getting exactly what I want. Here are
my goals

1. I would like the IAsyncResult that is returned by the Begin function to
be able to be waited on or polled to check for completion.
2. The Begin function would take a callback, and the async process would
call it when the task is complete.
3. I would like to have events such as ProgressChanged that get fired as the
async process progresses.
4. The async process should be able to be cancled with a function CancelX.
5. Multiple async tasks should be able to be performed at the same time.

Are delegates the way to go? Can anyone provide me with a quick example on
how to implement this.

Thanks,
Shawn
Nov 17 '05 #1
10 2754
Shawn,

I believe that all but the last request will be able to be handled with
delegates.

Basically, create a private delegate that has the same signature as your
synchronous method. When compiled, the delegate will create BeginInvoke and
EndInvoke methods which can be used to make the call asynchronously. Then,
all you have to do is expose the methods (BeginXXX and EndXXX) with the same
signatures as the corresponding methods on the delegate.

When those methods are called, you just channel the call to a delegate
instance and return the appropriate IAsyncResult. The delegate, of course,
points to your synchronous method implementation.

The thing is, you have to store the delegate in your class instance, and
can only have one async operation at a time being performed. The reason for
this is that the delegate instance is linked to the IAsyncResult returned
from the call to BeginInvoke, and if you create a new one, it will not work.
This is the reason #5 can not be implemented. You can get around this by
creating another instance of your class, and having that perform the async
operation.

For 3 and 4, that is up to you to create the progress events and the
cancel method. Basically, you would have a flag somewhere which indicates
whether or not the operation should be cancelled. As your synchronous
method is run, it checks the flag (access to the flag should be synchronized
through the lock statement) and if the flag is set, cancel the operation,
and exit the method.

Of course, if the method has a main loop that runs, it becomes very
obvious where to check the flag to see if it is a cancelled operation.

Hope this helps.

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Shawn Meyer" <me@me.com> wrote in message
news:Ok**************@TK2MSFTNGP10.phx.gbl...
Hello -

I am trying to write a class that has an async BeginX and EndX, plus the
regular X syncronous method. Delegates seemed like the way to go,
however, I still am having problems getting exactly what I want. Here are
my goals

1. I would like the IAsyncResult that is returned by the Begin function to
be able to be waited on or polled to check for completion.
2. The Begin function would take a callback, and the async process would
call it when the task is complete.
3. I would like to have events such as ProgressChanged that get fired as
the
async process progresses.
4. The async process should be able to be cancled with a function CancelX.
5. Multiple async tasks should be able to be performed at the same time.

Are delegates the way to go? Can anyone provide me with a quick example
on
how to implement this.

Thanks,
Shawn

Nov 17 '05 #2
(I'm not the Original Poster)

:: The reason for this is that the delegate instance is linked
:: to the IAsyncResult returned from the call to BeginInvoke,
:: and if you create a new one, it will not work. This is the
:: reason #5 can not be implemented. You can get around
:: this by creating another instance of your class, and having
:: that perform the async operation.

This is a curious remark. I don't recall reading this in the MSDN
documentation.

I created a data access component about 2 1/2 years ago (long before ADO.NET
2.0 was ever announced and even before the data access application block
ever existed) that has ability to execute readers, scalars, datasets,
datatables, and nonqueries asyncronously (I am more than happy to provide
the source code if anyone wants it, C#, and very neat and tidy). This same
component has been in 3 production environments over the years and in each
invenvironment there are close to about 3 million page requests per day. It
uses delegates internally to execute the async results, in much the same way
you described below. The only difference between what you describe and the
behaviors we receive, are that I can indeed execute as many commands as I
want simultaneously to return a datatable and all the results come back with
their proper results and the requests don't get queued. For example, if I
execute 10 commands at the same time async (on the same object instance,
delegate instance) and each command requires 3 seconds to complete, then I
only need to wait roughly 3 seconds before I have the results for all 10
commands properly.

I'm curious what you mean by your above statement?

Here's my source to demonstrate what I'm saying:

private void button1_Click(object sender, System.EventArgs e)
{
SqlDataHelper data = null;
DataTable x = null;
DataTable y = null;
DataTable z = null;
DataTable t = null;

try
{
data = new SqlDataHelper(connectionString);

IAsyncResult ar1 = data.BeginExecuteTable("SELECT * FROM Orders",
false);
IAsyncResult ar2 = data.BeginExecuteTable("SELECT TOP 5000 * FROM
Invoices", false);
IAsyncResult ar3 = data.BeginExecuteTable("SELECT TOP 10000 * FROM
AuditLog", false);

// Do something while the other 3 are still fetching
//
t = data.ExecuteTable("SELECT * FROM SalesGroups", false);

foreach (DataRow row in t.Rows)
{
row[0] = 0;
}

data.BeginExecuteReader("SELECT TOP 5 * FROM InventoryPieces", false,
new AsyncCallback(CallbackMethod));

// Now we synchronize
//
x = data.EndExecuteTable(ar1);
y = data.EndExecuteTable(ar2);
z = data.EndExecuteTable(ar3);

MessageBox.Show(t.Rows.Count.ToString());
MessageBox.Show(x.Rows.Count.ToString());
MessageBox.Show(y.Rows.Count.ToString());
MessageBox.Show(z.Rows.Count.ToString());
}
finally
{
if (data != null)
{
data.Dispose();
}
}
}

public void CallbackMethod(IAsyncResult ar)
{
SqlDataHelper data = null;
IDataReader result = null;
int count = 0;

try
{
data = new SqlDataHelper(connectionString);

result = data.EndExecuteReader(ar);

while (result.Read()) count++;
result.Close();

MessageBox.Show("Callback: " + count.ToString());
}
catch (Exception ex)
{
throw;
}
finally
{
if (data != null)
{
data.Dispose();
}
}
}
If you would like to see my data access component I'll provide you a link to
download the source code.
Thanks,
Shawn


"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.com> wrote in
message news:O$**************@tk2msftngp13.phx.gbl...
Shawn,

I believe that all but the last request will be able to be handled with delegates.

Basically, create a private delegate that has the same signature as your synchronous method. When compiled, the delegate will create BeginInvoke and EndInvoke methods which can be used to make the call asynchronously. Then, all you have to do is expose the methods (BeginXXX and EndXXX) with the same signatures as the corresponding methods on the delegate.

When those methods are called, you just channel the call to a delegate
instance and return the appropriate IAsyncResult. The delegate, of course, points to your synchronous method implementation.

The thing is, you have to store the delegate in your class instance, and can only have one async operation at a time being performed. The reason for this is that the delegate instance is linked to the IAsyncResult returned
from the call to BeginInvoke, and if you create a new one, it will not work. This is the reason #5 can not be implemented. You can get around this by
creating another instance of your class, and having that perform the async
operation.

For 3 and 4, that is up to you to create the progress events and the
cancel method. Basically, you would have a flag somewhere which indicates
whether or not the operation should be cancelled. As your synchronous
method is run, it checks the flag (access to the flag should be synchronized through the lock statement) and if the flag is set, cancel the operation,
and exit the method.

Of course, if the method has a main loop that runs, it becomes very
obvious where to check the flag to see if it is a cancelled operation.

Hope this helps.

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Shawn Meyer" <me@me.com> wrote in message
news:Ok**************@TK2MSFTNGP10.phx.gbl...
Hello -

I am trying to write a class that has an async BeginX and EndX, plus the
regular X syncronous method. Delegates seemed like the way to go,
however, I still am having problems getting exactly what I want. Here are my goals

1. I would like the IAsyncResult that is returned by the Begin function to be able to be waited on or polled to check for completion.
2. The Begin function would take a callback, and the async process would
call it when the task is complete.
3. I would like to have events such as ProgressChanged that get fired as
the
async process progresses.
4. The async process should be able to be cancled with a function CancelX. 5. Multiple async tasks should be able to be performed at the same time.

Are delegates the way to go? Can anyone provide me with a quick example
on
how to implement this.

Thanks,
Shawn


Nov 17 '05 #3
Okay, I correct myself, I am creating a different delegate instance each
time the command is created, so it isn't reusing the same instance.
#region ExecuteTable Asynchronous

public virtual IAsyncResult BeginExecuteTable(
string sqlQuery,
bool storedProcedure
)
{
ExecuteTableDelegate result = new
ExecuteTableDelegate(this.ExecuteTableAsync);
return result.BeginInvoke(sqlQuery, storedProcedure, null, null);
}

public virtual IAsyncResult BeginExecuteTable(
string sqlQuery,
bool storedProcedure,
AsyncCallback callback
)
{
ExecuteTableDelegate result = new
ExecuteTableDelegate(this.ExecuteTableAsync);
return result.BeginInvoke(sqlQuery, storedProcedure, callback, result);
}
public virtual DataTable EndExecuteTable(IAsyncResult ar)
{
ExecuteTableDelegate result = null;

if (ar.AsyncState != null)
{
result = (ExecuteTableDelegate)ar.AsyncState;
}
else
{
result = (ExecuteTableDelegate)((AsyncResult)ar).AsyncDeleg ate;
}

ar.AsyncWaitHandle.WaitOne();
return result.EndInvoke(ar);
}

protected virtual DataTable ExecuteTableAsync(
string sqlQuery,
bool storedProcedure
)
{
DbAsyncBase data = (DbAsyncBase)GetNewDalInstance();
DataTable result = null;

try
{
AsyncCounter++;

foreach(IDbDataParameter param in Parameters)
{
data.Parameters.Add(param);
}

result = data.ExecuteTable(sqlQuery, storedProcedure);
}
finally
{
if (data != null)
{
data.Dispose();
}

AsyncCounter--;
}

return result;
}
#endregion


"Shawn B." <le****@html.com> wrote in message
news:%2******************@TK2MSFTNGP09.phx.gbl...
(I'm not the Original Poster)

:: The reason for this is that the delegate instance is linked
:: to the IAsyncResult returned from the call to BeginInvoke,
:: and if you create a new one, it will not work. This is the
:: reason #5 can not be implemented. You can get around
:: this by creating another instance of your class, and having
:: that perform the async operation.

This is a curious remark. I don't recall reading this in the MSDN
documentation.

I created a data access component about 2 1/2 years ago (long before ADO.NET 2.0 was ever announced and even before the data access application block
ever existed) that has ability to execute readers, scalars, datasets,
datatables, and nonqueries asyncronously (I am more than happy to provide
the source code if anyone wants it, C#, and very neat and tidy). This same component has been in 3 production environments over the years and in each
invenvironment there are close to about 3 million page requests per day. It uses delegates internally to execute the async results, in much the same way you described below. The only difference between what you describe and the behaviors we receive, are that I can indeed execute as many commands as I
want simultaneously to return a datatable and all the results come back with their proper results and the requests don't get queued. For example, if I
execute 10 commands at the same time async (on the same object instance,
delegate instance) and each command requires 3 seconds to complete, then I
only need to wait roughly 3 seconds before I have the results for all 10
commands properly.

I'm curious what you mean by your above statement?

Here's my source to demonstrate what I'm saying:

private void button1_Click(object sender, System.EventArgs e)
{
SqlDataHelper data = null;
DataTable x = null;
DataTable y = null;
DataTable z = null;
DataTable t = null;

try
{
data = new SqlDataHelper(connectionString);

IAsyncResult ar1 = data.BeginExecuteTable("SELECT * FROM Orders",
false);
IAsyncResult ar2 = data.BeginExecuteTable("SELECT TOP 5000 * FROM
Invoices", false);
IAsyncResult ar3 = data.BeginExecuteTable("SELECT TOP 10000 * FROM
AuditLog", false);

// Do something while the other 3 are still fetching
//
t = data.ExecuteTable("SELECT * FROM SalesGroups", false);

foreach (DataRow row in t.Rows)
{
row[0] = 0;
}

data.BeginExecuteReader("SELECT TOP 5 * FROM InventoryPieces", false,
new AsyncCallback(CallbackMethod));

// Now we synchronize
//
x = data.EndExecuteTable(ar1);
y = data.EndExecuteTable(ar2);
z = data.EndExecuteTable(ar3);

MessageBox.Show(t.Rows.Count.ToString());
MessageBox.Show(x.Rows.Count.ToString());
MessageBox.Show(y.Rows.Count.ToString());
MessageBox.Show(z.Rows.Count.ToString());
}
finally
{
if (data != null)
{
data.Dispose();
}
}
}

public void CallbackMethod(IAsyncResult ar)
{
SqlDataHelper data = null;
IDataReader result = null;
int count = 0;

try
{
data = new SqlDataHelper(connectionString);

result = data.EndExecuteReader(ar);

while (result.Read()) count++;
result.Close();

MessageBox.Show("Callback: " + count.ToString());
}
catch (Exception ex)
{
throw;
}
finally
{
if (data != null)
{
data.Dispose();
}
}
}
If you would like to see my data access component I'll provide you a link to download the source code.
Thanks,
Shawn


"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.com> wrote in message news:O$**************@tk2msftngp13.phx.gbl...
Shawn,

I believe that all but the last request will be able to be handled with
delegates.

Basically, create a private delegate that has the same signature as

your
synchronous method. When compiled, the delegate will create BeginInvoke

and
EndInvoke methods which can be used to make the call asynchronously.

Then,
all you have to do is expose the methods (BeginXXX and EndXXX) with the

same
signatures as the corresponding methods on the delegate.

When those methods are called, you just channel the call to a delegate
instance and return the appropriate IAsyncResult. The delegate, of

course,
points to your synchronous method implementation.

The thing is, you have to store the delegate in your class instance,

and
can only have one async operation at a time being performed. The reason

for
this is that the delegate instance is linked to the IAsyncResult returned from the call to BeginInvoke, and if you create a new one, it will not

work.
This is the reason #5 can not be implemented. You can get around this by creating another instance of your class, and having that perform the async operation.

For 3 and 4, that is up to you to create the progress events and the
cancel method. Basically, you would have a flag somewhere which indicates whether or not the operation should be cancelled. As your synchronous
method is run, it checks the flag (access to the flag should be

synchronized
through the lock statement) and if the flag is set, cancel the operation, and exit the method.

Of course, if the method has a main loop that runs, it becomes very
obvious where to check the flag to see if it is a cancelled operation.

Hope this helps.

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Shawn Meyer" <me@me.com> wrote in message
news:Ok**************@TK2MSFTNGP10.phx.gbl...
Hello -

I am trying to write a class that has an async BeginX and EndX, plus the regular X syncronous method. Delegates seemed like the way to go,
however, I still am having problems getting exactly what I want. Here

are my goals

1. I would like the IAsyncResult that is returned by the Begin function to
be able to be waited on or polled to check for completion.
2. The Begin function would take a callback, and the async process
would call it when the task is complete.
3. I would like to have events such as ProgressChanged that get fired as the
async process progresses.
4. The async process should be able to be cancled with a function

CancelX. 5. Multiple async tasks should be able to be performed at the same time.
Are delegates the way to go? Can anyone provide me with a quick example on
how to implement this.

Thanks,
Shawn



Nov 17 '05 #4
Shawn,

I was a bit off my rocker when I responded to this. You could do this.
My thought was that a different delegate would be created for each
invocation of the asynchronous method, which would require the instances to
be stored on the class level, and then when you called the EndXXX method, it
would throw an exception, because the IAsyncResult implementation would not
match with the delegate that created it.

However, a simple workaround would be to just create one delegate, and
have that handle all of the asynchronous calls.

The only problem that exists for #5 is that if this is allowed, then the
progress and the cancel methods would have to have some way of indicating
which asynchronous call is being updated or cancelled.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Shawn B." <le****@html.com> wrote in message
news:%2******************@TK2MSFTNGP09.phx.gbl...
(I'm not the Original Poster)

:: The reason for this is that the delegate instance is linked
:: to the IAsyncResult returned from the call to BeginInvoke,
:: and if you create a new one, it will not work. This is the
:: reason #5 can not be implemented. You can get around
:: this by creating another instance of your class, and having
:: that perform the async operation.

This is a curious remark. I don't recall reading this in the MSDN
documentation.

I created a data access component about 2 1/2 years ago (long before
ADO.NET
2.0 was ever announced and even before the data access application block
ever existed) that has ability to execute readers, scalars, datasets,
datatables, and nonqueries asyncronously (I am more than happy to provide
the source code if anyone wants it, C#, and very neat and tidy). This
same
component has been in 3 production environments over the years and in each
invenvironment there are close to about 3 million page requests per day.
It
uses delegates internally to execute the async results, in much the same
way
you described below. The only difference between what you describe and
the
behaviors we receive, are that I can indeed execute as many commands as I
want simultaneously to return a datatable and all the results come back
with
their proper results and the requests don't get queued. For example, if I
execute 10 commands at the same time async (on the same object instance,
delegate instance) and each command requires 3 seconds to complete, then I
only need to wait roughly 3 seconds before I have the results for all 10
commands properly.

I'm curious what you mean by your above statement?

Here's my source to demonstrate what I'm saying:

private void button1_Click(object sender, System.EventArgs e)
{
SqlDataHelper data = null;
DataTable x = null;
DataTable y = null;
DataTable z = null;
DataTable t = null;

try
{
data = new SqlDataHelper(connectionString);

IAsyncResult ar1 = data.BeginExecuteTable("SELECT * FROM Orders",
false);
IAsyncResult ar2 = data.BeginExecuteTable("SELECT TOP 5000 * FROM
Invoices", false);
IAsyncResult ar3 = data.BeginExecuteTable("SELECT TOP 10000 * FROM
AuditLog", false);

// Do something while the other 3 are still fetching
//
t = data.ExecuteTable("SELECT * FROM SalesGroups", false);

foreach (DataRow row in t.Rows)
{
row[0] = 0;
}

data.BeginExecuteReader("SELECT TOP 5 * FROM InventoryPieces", false,
new AsyncCallback(CallbackMethod));

// Now we synchronize
//
x = data.EndExecuteTable(ar1);
y = data.EndExecuteTable(ar2);
z = data.EndExecuteTable(ar3);

MessageBox.Show(t.Rows.Count.ToString());
MessageBox.Show(x.Rows.Count.ToString());
MessageBox.Show(y.Rows.Count.ToString());
MessageBox.Show(z.Rows.Count.ToString());
}
finally
{
if (data != null)
{
data.Dispose();
}
}
}

public void CallbackMethod(IAsyncResult ar)
{
SqlDataHelper data = null;
IDataReader result = null;
int count = 0;

try
{
data = new SqlDataHelper(connectionString);

result = data.EndExecuteReader(ar);

while (result.Read()) count++;
result.Close();

MessageBox.Show("Callback: " + count.ToString());
}
catch (Exception ex)
{
throw;
}
finally
{
if (data != null)
{
data.Dispose();
}
}
}
If you would like to see my data access component I'll provide you a link
to
download the source code.
Thanks,
Shawn


"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.com> wrote
in
message news:O$**************@tk2msftngp13.phx.gbl...
Shawn,

I believe that all but the last request will be able to be handled

with
delegates.

Basically, create a private delegate that has the same signature as

your
synchronous method. When compiled, the delegate will create BeginInvoke

and
EndInvoke methods which can be used to make the call asynchronously.

Then,
all you have to do is expose the methods (BeginXXX and EndXXX) with the

same
signatures as the corresponding methods on the delegate.

When those methods are called, you just channel the call to a
delegate
instance and return the appropriate IAsyncResult. The delegate, of

course,
points to your synchronous method implementation.

The thing is, you have to store the delegate in your class instance,

and
can only have one async operation at a time being performed. The reason

for
this is that the delegate instance is linked to the IAsyncResult returned
from the call to BeginInvoke, and if you create a new one, it will not

work.
This is the reason #5 can not be implemented. You can get around this by
creating another instance of your class, and having that perform the
async
operation.

For 3 and 4, that is up to you to create the progress events and the
cancel method. Basically, you would have a flag somewhere which
indicates
whether or not the operation should be cancelled. As your synchronous
method is run, it checks the flag (access to the flag should be

synchronized
through the lock statement) and if the flag is set, cancel the operation,
and exit the method.

Of course, if the method has a main loop that runs, it becomes very
obvious where to check the flag to see if it is a cancelled operation.

Hope this helps.

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Shawn Meyer" <me@me.com> wrote in message
news:Ok**************@TK2MSFTNGP10.phx.gbl...
> Hello -
>
> I am trying to write a class that has an async BeginX and EndX, plus
> the
> regular X syncronous method. Delegates seemed like the way to go,
> however, I still am having problems getting exactly what I want. Here are > my goals
>
> 1. I would like the IAsyncResult that is returned by the Begin function to > be able to be waited on or polled to check for completion.
> 2. The Begin function would take a callback, and the async process
> would
> call it when the task is complete.
> 3. I would like to have events such as ProgressChanged that get fired
> as
> the
> async process progresses.
> 4. The async process should be able to be cancled with a function CancelX. > 5. Multiple async tasks should be able to be performed at the same
> time.
>
> Are delegates the way to go? Can anyone provide me with a quick
> example
> on
> how to implement this.
>
> Thanks,
> Shawn
>
>



Nov 17 '05 #5
I would love to see the code! It sounds very similar to what I am trying to
do.

Thanks much.
Shawn
Nov 17 '05 #6
Shawn,

The reason this works for you is that you are passing the IAsyncResult
implementation, which happens to have a reference back to the delegate that
created it. Personally, I don't think that this is a good idea, since it
wastes the slot for information, should you need to pass that around (and I
wouldn't recommend this as standard practice).

However, as you show in your code, you can always cast the IAsyncResult
implementation to the AsyncResult instance which has a reference to the
delegate that created it. It is better to use this, and free up the slot
that has the data in it.

Also, your call to WaitOne on the AsyncWaitHandle property on the async
result is not needed. When you call EndInvoke, if the call hasn't
completed, it will block until it is.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Shawn B." <le****@html.com> wrote in message
news:uM**************@tk2msftngp13.phx.gbl...
Okay, I correct myself, I am creating a different delegate instance each
time the command is created, so it isn't reusing the same instance.
#region ExecuteTable Asynchronous

public virtual IAsyncResult BeginExecuteTable(
string sqlQuery,
bool storedProcedure
)
{
ExecuteTableDelegate result = new
ExecuteTableDelegate(this.ExecuteTableAsync);
return result.BeginInvoke(sqlQuery, storedProcedure, null, null);
}

public virtual IAsyncResult BeginExecuteTable(
string sqlQuery,
bool storedProcedure,
AsyncCallback callback
)
{
ExecuteTableDelegate result = new
ExecuteTableDelegate(this.ExecuteTableAsync);
return result.BeginInvoke(sqlQuery, storedProcedure, callback, result);
}
public virtual DataTable EndExecuteTable(IAsyncResult ar)
{
ExecuteTableDelegate result = null;

if (ar.AsyncState != null)
{
result = (ExecuteTableDelegate)ar.AsyncState;
}
else
{
result = (ExecuteTableDelegate)((AsyncResult)ar).AsyncDeleg ate;
}

ar.AsyncWaitHandle.WaitOne();
return result.EndInvoke(ar);
}

protected virtual DataTable ExecuteTableAsync(
string sqlQuery,
bool storedProcedure
)
{
DbAsyncBase data = (DbAsyncBase)GetNewDalInstance();
DataTable result = null;

try
{
AsyncCounter++;

foreach(IDbDataParameter param in Parameters)
{
data.Parameters.Add(param);
}

result = data.ExecuteTable(sqlQuery, storedProcedure);
}
finally
{
if (data != null)
{
data.Dispose();
}

AsyncCounter--;
}

return result;
}
#endregion


"Shawn B." <le****@html.com> wrote in message
news:%2******************@TK2MSFTNGP09.phx.gbl...
(I'm not the Original Poster)

:: The reason for this is that the delegate instance is linked
:: to the IAsyncResult returned from the call to BeginInvoke,
:: and if you create a new one, it will not work. This is the
:: reason #5 can not be implemented. You can get around
:: this by creating another instance of your class, and having
:: that perform the async operation.

This is a curious remark. I don't recall reading this in the MSDN
documentation.

I created a data access component about 2 1/2 years ago (long before

ADO.NET
2.0 was ever announced and even before the data access application block
ever existed) that has ability to execute readers, scalars, datasets,
datatables, and nonqueries asyncronously (I am more than happy to provide
the source code if anyone wants it, C#, and very neat and tidy). This

same
component has been in 3 production environments over the years and in
each
invenvironment there are close to about 3 million page requests per day.

It
uses delegates internally to execute the async results, in much the same

way
you described below. The only difference between what you describe and

the
behaviors we receive, are that I can indeed execute as many commands as I
want simultaneously to return a datatable and all the results come back

with
their proper results and the requests don't get queued. For example, if
I
execute 10 commands at the same time async (on the same object instance,
delegate instance) and each command requires 3 seconds to complete, then
I
only need to wait roughly 3 seconds before I have the results for all 10
commands properly.

I'm curious what you mean by your above statement?

Here's my source to demonstrate what I'm saying:

private void button1_Click(object sender, System.EventArgs e)
{
SqlDataHelper data = null;
DataTable x = null;
DataTable y = null;
DataTable z = null;
DataTable t = null;

try
{
data = new SqlDataHelper(connectionString);

IAsyncResult ar1 = data.BeginExecuteTable("SELECT * FROM Orders",
false);
IAsyncResult ar2 = data.BeginExecuteTable("SELECT TOP 5000 * FROM
Invoices", false);
IAsyncResult ar3 = data.BeginExecuteTable("SELECT TOP 10000 * FROM
AuditLog", false);

// Do something while the other 3 are still fetching
//
t = data.ExecuteTable("SELECT * FROM SalesGroups", false);

foreach (DataRow row in t.Rows)
{
row[0] = 0;
}

data.BeginExecuteReader("SELECT TOP 5 * FROM InventoryPieces", false,
new AsyncCallback(CallbackMethod));

// Now we synchronize
//
x = data.EndExecuteTable(ar1);
y = data.EndExecuteTable(ar2);
z = data.EndExecuteTable(ar3);

MessageBox.Show(t.Rows.Count.ToString());
MessageBox.Show(x.Rows.Count.ToString());
MessageBox.Show(y.Rows.Count.ToString());
MessageBox.Show(z.Rows.Count.ToString());
}
finally
{
if (data != null)
{
data.Dispose();
}
}
}

public void CallbackMethod(IAsyncResult ar)
{
SqlDataHelper data = null;
IDataReader result = null;
int count = 0;

try
{
data = new SqlDataHelper(connectionString);

result = data.EndExecuteReader(ar);

while (result.Read()) count++;
result.Close();

MessageBox.Show("Callback: " + count.ToString());
}
catch (Exception ex)
{
throw;
}
finally
{
if (data != null)
{
data.Dispose();
}
}
}
If you would like to see my data access component I'll provide you a link

to
download the source code.
Thanks,
Shawn


"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.com> wrote

in
message news:O$**************@tk2msftngp13.phx.gbl...
> Shawn,
>
> I believe that all but the last request will be able to be handled

with
> delegates.
>
> Basically, create a private delegate that has the same signature as

your
> synchronous method. When compiled, the delegate will create
> BeginInvoke

and
> EndInvoke methods which can be used to make the call asynchronously.

Then,
> all you have to do is expose the methods (BeginXXX and EndXXX) with the

same
> signatures as the corresponding methods on the delegate.
>
> When those methods are called, you just channel the call to a delegate > instance and return the appropriate IAsyncResult. The delegate, of

course,
> points to your synchronous method implementation.
>
> The thing is, you have to store the delegate in your class
> instance,

and
> can only have one async operation at a time being performed. The
> reason

for
> this is that the delegate instance is linked to the IAsyncResult returned > from the call to BeginInvoke, and if you create a new one, it will not

work.
> This is the reason #5 can not be implemented. You can get around this by > creating another instance of your class, and having that perform the async > operation.
>
> For 3 and 4, that is up to you to create the progress events and
> the
> cancel method. Basically, you would have a flag somewhere which indicates > whether or not the operation should be cancelled. As your synchronous
> method is run, it checks the flag (access to the flag should be

synchronized
> through the lock statement) and if the flag is set, cancel the operation, > and exit the method.
>
> Of course, if the method has a main loop that runs, it becomes very
> obvious where to check the flag to see if it is a cancelled operation.
>
> Hope this helps.
>
> --
> - Nicholas Paldino [.NET/C# MVP]
> - mv*@spam.guard.caspershouse.com
>
> "Shawn Meyer" <me@me.com> wrote in message
> news:Ok**************@TK2MSFTNGP10.phx.gbl...
> > Hello -
> >
> > I am trying to write a class that has an async BeginX and EndX, plus the > > regular X syncronous method. Delegates seemed like the way to go,
> > however, I still am having problems getting exactly what I want.
> > Here

are
> > my goals
> >
> > 1. I would like the IAsyncResult that is returned by the Begin function
to
> > be able to be waited on or polled to check for completion.
> > 2. The Begin function would take a callback, and the async process

would > > call it when the task is complete.
> > 3. I would like to have events such as ProgressChanged that get fired as > > the
> > async process progresses.
> > 4. The async process should be able to be cancled with a function

CancelX.
> > 5. Multiple async tasks should be able to be performed at the same time. > >
> > Are delegates the way to go? Can anyone provide me with a quick example > > on
> > how to implement this.
> >
> > Thanks,
> > Shawn
> >
> >
>
>



Nov 17 '05 #7
> The reason this works for you is that you are passing the IAsyncResult
implementation, which happens to have a reference back to the delegate that created it. Personally, I don't think that this is a good idea, since it
wastes the slot for information, should you need to pass that around (and I wouldn't recommend this as standard practice).

However, as you show in your code, you can always cast the IAsyncResult implementation to the AsyncResult instance which has a reference to the
delegate that created it. It is better to use this, and free up the slot
that has the data in it.
I will attempt to make changes as necessary to see if this can work on one
delegate instance. My memory doesn't serve anymore, but there was a reason
I did it this way after a bit of trial and error. If there's a better way,
I'll gladly make the necessary changes. This begs the question, if one
delegate instance can hold one result, how am I going to achieve the effect
of multiple executing commands?
Also, your call to WaitOne on the AsyncWaitHandle property on the async result is not needed. When you call EndInvoke, if the call hasn't
completed, it will block until it is.

I dissagree (regarding my situation but not in general). When the WaitOne
call isn't there, the same sample code I posted earlier won't work properly.
There will be unpredictable results, for example, it seems that each of the
ar1, ar2, ar3 references gets confused regarding what result it should
actually have. Sometimes all ar1, ar2, ar3 have the same results as ar1,
other times ar1 will contain ar2 and ar3 will contain ar1 results and so on.
The only way to get reliable results is to either call WaitOne yourself and
then EndExecute*, or, to have it done automatically for you (which I'm doing
here since I'm a fan of less work for the developer using the component). I
don't dissagree that when you call EndInvoke it is done (thats what I read
all the time), but for some reason, in this case, it causes unreliable
results so I had to put it there.
Thanks,
Shawn
Nov 17 '05 #8
> However, as you show in your code, you can always cast the
IAsyncResult
implementation to the AsyncResult instance which has a reference to the
delegate that created it. It is better to use this, and free up the slot
that has the data in it.


Could you elaborate on this more, specifically, when you say "it is better
to use this, and free upt he slot that has the data in it".
Thanks,
Shawn
Nov 17 '05 #9
Shawn,

Basically, the last parameter when you call BeginXXX is a state that
gets passed around during the asynchronous call. You use it to place the
IAsyncResult implementation in there. However, this isn't needed, because
the implementation holds a reference to the original delegate that created
it, which is what you are using it for in the first place.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Shawn B." <le****@html.com> wrote in message
news:eh**************@TK2MSFTNGP10.phx.gbl...
However, as you show in your code, you can always cast the

IAsyncResult
implementation to the AsyncResult instance which has a reference to the
delegate that created it. It is better to use this, and free up the slot
that has the data in it.


Could you elaborate on this more, specifically, when you say "it is better
to use this, and free upt he slot that has the data in it".
Thanks,
Shawn

Nov 17 '05 #10
Oh, I knew that. I just for some reason wasn't connecting your statement
with that in my brain. However, you did say that you would recommend doing
things the way I am, such as creating a new delegate each call. What other
ways could I achieve the same?

Thanks,
Shawn

"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.com> wrote in
message news:%2****************@TK2MSFTNGP15.phx.gbl...
Shawn,

Basically, the last parameter when you call BeginXXX is a state that
gets passed around during the asynchronous call. You use it to place the
IAsyncResult implementation in there. However, this isn't needed, because
the implementation holds a reference to the original delegate that created
it, which is what you are using it for in the first place.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Shawn B." <le****@html.com> wrote in message
news:eh**************@TK2MSFTNGP10.phx.gbl...
However, as you show in your code, you can always cast the

IAsyncResult
implementation to the AsyncResult instance which has a reference to the
delegate that created it. It is better to use this, and free up the slot that has the data in it.


Could you elaborate on this more, specifically, when you say "it is better to use this, and free upt he slot that has the data in it".
Thanks,
Shawn


Nov 17 '05 #11

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

6 posts views Thread by Vanessa | last post: by
3 posts views Thread by Angus | last post: by
reply views Thread by Paul Hadfield | last post: by
3 posts views Thread by Giulio Petrucci | last post: by
3 posts views Thread by Ryan Liu | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.