Can't find the DbAsyncResult type. What's going on?

  • Thread starter Thread starter Carl Johansson
  • Start date Start date
C

Carl Johansson

Running my application (C# VS 2008 Pro) causes an InvalidCastException with
the following message:

"Unable to cast object of type 'System.Data.Common.DbAsyncResult' to type
'System.Runtime.Remoting.Messaging.AsyncResult'."

However, VS intellisense is unable to find the DbAsyncResult type, I can't
find DbAsyncResult in the help files, I can't find DbAsyncResult in the VS
"Object Browser"
window, and I find next to nothing on the web and in the newsgroups. What's
going on???

The exception occurs inside a delegate method of type System.AsyncCallback
which looks like this:

private static void SqlServerDone(System.IAsyncResult itfAR)
{
// InvalidCastException next!
System.Runtime.Remoting.Messaging.AsyncResult ar =
(System.Runtime.Remoting.Messaging.AsyncResult)itfAR;
System.Data.SqlClient.SqlCommand sqlCm =
(System.Data.SqlClient.SqlCommand)ar.AsyncDelegate;

using (System.Data.SqlClient.SqlDataReader sqlDr =
sqlCm.EndExecuteReader(itfAR))
{
...
}
}

Regards Carl Johansson


__________ Information from ESET Smart Security, version of virus signature database 4434 (20090917) __________

The message was checked by ESET Smart Security.

http://www.eset.com
 
Carl said:
Running my application (C# VS 2008 Pro) causes an InvalidCastException with
the following message:

"Unable to cast object of type 'System.Data.Common.DbAsyncResult' to type
'System.Runtime.Remoting.Messaging.AsyncResult'."

However, VS intellisense is unable to find the DbAsyncResult type, I can't
find DbAsyncResult in the help files, I can't find DbAsyncResult in the
VS "Object Browser"
window, and I find next to nothing on the web and in the newsgroups. What's
going on???
System.Data.Common.DbAsyncResult is an internal type of the System.Data
assembly. This is why it's not documented and IntelliSense is mute.
The exception occurs inside a delegate method of type System.AsyncCallback
which looks like this:

private static void SqlServerDone(System.IAsyncResult itfAR)
{
// InvalidCastException next!
System.Runtime.Remoting.Messaging.AsyncResult ar =
(System.Runtime.Remoting.Messaging.AsyncResult)itfAR;
System.Data.SqlClient.SqlCommand sqlCm =
(System.Data.SqlClient.SqlCommand)ar.AsyncDelegate;
As the error is trying to tell you, "itfAR" is not of type
"System.Runtime.Remoting.Messaging.AsyncResult". Why would you even assume
it is?
using (System.Data.SqlClient.SqlDataReader sqlDr =
sqlCm.EndExecuteReader(itfAR))

No. Pass the command like this:

command.BeginExecuteReader(SqlServerDone, command);

Now you can access the command in the callback:

private static void SqlServerDone(System.IAsyncResult asyncResult) {
SqlCommand command = (SqlCommand) asyncResult.AsyncState;
using (SqlDataReader dataReader = command.EndExecuteReader(asyncResult)) {
...

}
}

You do not ever cast the asyncResult parameter to anything, because those
types are internal to the classes that expose the asynchronous methods. You
pass information by passing a state object in the .Begin() method and
accessing that as the .AsyncState of the IAsyncResult in the asynchronous
delegate.
 
Jeroen,

thanks for your reply! Your solution is very practical and straight forward!

As the error is trying to tell you, "itfAR" is not of type
"System.Runtime.Remoting.Messaging.AsyncResult". Why would you even assume
it is?

Learning about asynchronous delegates I actually picked up this technique
from Andrew Troelsen's book "Pro C# 2008 and the .NET 3.5 Platform". There I
learned that the delegate instance was lurking inside the
System.IAsyncResult parameter of the callback method. Something like this:

using System;
using System.Runtime.Remoting.Messaging;

namespace AsynchronousDelegateDemo
{
class Program
{
delegate int MyDelegate(int i);

static void Main(string[] args)
{
MyDelegate md = new MyDelegate(IncInt);
md.BeginInvoke(1, new AsyncCallback(CallBack), "Press [ENTER] to
exit...");

Console.WriteLine("Wait for worker thread to finish...");
Console.ReadLine();
}

static void CallBack(IAsyncResult itfAR)
{
AsyncResult ar = (AsyncResult)itfAR;
MyDelegate md = (MyDelegate)ar.AsyncDelegate;
int i = md.EndInvoke(itfAR);
Console.WriteLine("\ni: {0}", i);
Console.Write(itfAR.AsyncState);
}

static int IncInt(int i)
{
System.Threading.Thread.Sleep(3000);
i++;
return i;
}
}
}

I thought it was rather neat (Uh?) and somehow (wrongfully) thought I could
use this same technique within the callback method passed to the
BeginExecuteReader() method. The advantage would be that I could pass some
arbitrary state data to the "stateObject" parameter of the
BeginExecuteReader() method, rather than the delegate instance.

Anyway, using your approach, which I guess is the only approach in this
context, I could create a new class or struct named "CallbackData", let is
state data point to the delegate instance as well as my arbitrary state data
and pass an instance of it to the "stateObject" parameter.

Regards Carl Johansson


__________ Information from ESET Smart Security, version of virus signature database 4439 (20090918) __________

The message was checked by ESET Smart Security.

http://www.eset.com
 
Carl said:
Jeroen,

thanks for your reply! Your solution is very practical and straight
forward!

As the error is trying to tell you, "itfAR" is not of type
"System.Runtime.Remoting.Messaging.AsyncResult". Why would you even
assume it is?

Learning about asynchronous delegates I actually picked up this
technique from Andrew Troelsen's book "Pro C# 2008 and the .NET 3.5
Platform". There I learned that the delegate instance was lurking inside
the System.IAsyncResult parameter of the callback method. Something like
this:

using System;
using System.Runtime.Remoting.Messaging;

namespace AsynchronousDelegateDemo
{
class Program
{
delegate int MyDelegate(int i);

static void Main(string[] args)
{
MyDelegate md = new MyDelegate(IncInt);
md.BeginInvoke(1, new AsyncCallback(CallBack), "Press [ENTER]
to exit...");

Console.WriteLine("Wait for worker thread to finish...");
Console.ReadLine();
}

static void CallBack(IAsyncResult itfAR)
{
AsyncResult ar = (AsyncResult)itfAR;
MyDelegate md = (MyDelegate)ar.AsyncDelegate;
int i = md.EndInvoke(itfAR);
Console.WriteLine("\ni: {0}", i);
Console.Write(itfAR.AsyncState);
}

static int IncInt(int i)
{
System.Threading.Thread.Sleep(3000);
i++;
return i;
}
}
}

I thought it was rather neat (Uh?)

This technique doesn't generalize (it applies only to .BeginInvoke()), so
while neat, it's not particularly useful. I recommend you focus on the
general pattern for asynchronous callbacks instead, where you can use only
IAsyncResult and have no knowledge of the actual type.
Anyway, using your approach, which I guess is the only approach in this
context, I could create a new class or struct named "CallbackData", let
is state data point to the delegate instance as well as my arbitrary
state data and pass an instance of it to the "stateObject" parameter.
This is the usual approach. On the other hand, because delegates can
represent instance methods as well as static methods, you don't need to pass
state if there is only ever one callback active, as you can just make it
part of the object the delegate belongs to:

class Foo {
int state1;
string state2;

void Bar() {
...
command.BeginExecuteReader(commandComplete, command);
...
}

void commandComplete(IAsyncResult asyncResult) {
SqlCommand command = (SqlCommand) asyncResult.AsyncState;
using (var reader = command.EndExecuteReader(asyncResult)) {
// use state1 and state2 here
}
}
}

But because you don't know when "commandComplete" executes, this code is not
thread-safe and it becomes hard to reason about the state. This is why you
usually encapsulate the state the callback needs in a separate object that's
not subject to these issues.
 
Back
Top