(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
message news:
[email protected]...
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]
- (e-mail address removed)
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