I think I remember this exception bug; you must have an old version of the
library.
Please download the latest version form
http://Wintellect.com/PowerThreading.aspx.
-- Jeffrey Richter (http://Wintellect.com)
-----Original Message-----
From: rkevinburton@... [mailto:rkevinburton@...]
Sent: Thursday, June 18, 2009 1:26 PM
To: PowerThreading@yahoogroups.com
Cc: Jeffrey Richter (Wintellect LLC)
Subject: RE: [PowerThreading] Simple asynchronous WCF call
I get this same exception when I run an unmodified version of the TimeoutDemo.
Has this demo changed?
private static IEnumerator<Int32> TimeoutDemo(AsyncEnumerator ae, String[]
urls) {
ae.ThrowOnMissingDiscardGroup(true);
Int32 numOps = s_urls.Length;
// Issue asynchronous web request operation(s)
for (Int32 n = 0; n < numOps; n++) {
WebRequest wr = WebRequest.Create(urls[n]);
wr.BeginGetResponse(ae.End(0, CompleteWebRequest), wr);
}
ae.SetCancelTimeout(1000, null); // Process what we can in 1 second
Int32 opsComplete = 0;
for (; opsComplete < numOps; opsComplete++) {
yield return 1;
if (ae.IsCanceled()) break; // Timeout expired
Console.WriteLine(CompleteWebRequest(ae.DequeueAsyncResult()));
}
Console.WriteLine(" Timer expired, num ops completed=" + opsComplete);
}
#endregion
Exception occurs with the BeginGetResponse call.
Kevin
---- rkevinburton@... wrote:
> I found some problems. I am getting an exception that the 'argument is null'
in these lines:
>
> ae.ThrowOnMissingDiscardGroup(true);
> Proxy.BeginExecuteRequest(requests, ae.End(0,
AsyncGetCatalogHandler));
> ae.SetCancelTimeout(10000, "Timeout");
>
> The debugger does not step into the Proxy.GetExecuteRequest so I am guessing
the ae.End() is not being called correctly.
>
> Kevin
>
> ---- rkevinburton@... wrote:
> > Thank you for your help. I am obviously new to using this library:
> >
> > I seem to be able to get my head aroung the 'TimeoutDemo' better than the
'CancellationDemo'
> >
> > Based on what I understood from your comments ere is the modified code:
> >
> > #region AsyncGetCatalogHandler
> > private static MessageResponseBaseType[]
AsyncGetCatalogHandler(IAsyncResult ar)
> > {
> > BsiServicesClient client = (BsiServicesClient)ar.AsyncState;
> > return client.EndGetBsiServicesDataMessage(ar);
> > }
> > #endregion
> > #region AsyncGetCatalogHandler
> > private static IEnumerator<Int32>
AsyncGetCatalogHandler(AsyncEnumerator<MessageResponseBaseType> ae,
List<MessageRequestBaseType> requests)
> > {
> > ae.ThrowOnMissingDiscardGroup(true);
> > Proxy.BeginExecuteRequest(requests, ae.End(0,
AsyncGetCatalogHandler));
> > ae.SetCancelTimeout(10000, "Timeout");
> > // Will wait until cancel or timeout or normai return
> > yield return 1;
> >
> > Object cancelValue;
> > if (ae.IsCanceled(out cancelValue))
> > {
> > ErrorResponseType errorResponse = new ErrorResponseType();
> >
> > errorResponse.Message = string.Format("Cancel {0}",
cancelValue);
> > errorResponse.Detail = string.Format("Cancel {0}",
cancelValue);
> > errorResponse.CorrelationId =
System.Guid.NewGuid().ToString();
> > errorResponse.Code = "TimeoutOrCancel";
> > ae.Result = errorResponse;
> > }
> > else
> > {
> > AsyncGetCatalogHandler(ae.DequeueAsyncResult());
> > }
> > }
> > #endregion
> > #region TestAsynchGetCatalogs
> > [TestMethod]
> > public void TestAsynchGetCatalogs()
> > {
> > List<MessageRequestBaseType> requests = new
List<MessageRequestBaseType>();
> > GetCatalogsRequestType request = new GetCatalogsRequestType();
> > requests.Add(request);
> > List<MessageResponseBaseType> responses = new
List<MessageResponseBaseType>();
> > AsyncEnumerator<MessageResponseBaseType> ae = new
AsyncEnumerator<MessageResponseBaseType>();
> > IAsyncResult result = ae.BeginExecute(AsyncGetCatalogHandler(ae,
requests),
> > delegate(IAsyncResult ar)
> > {
> >
responses.Add(ae.EndExecute(ar));
> >
Debug.WriteLine("AsyncEnumerator is done");
> > });
> > while (!result.AsyncWaitHandle.WaitOne(500, false))
> > {
> > ae.Cancel("Canceled on " + DateTime.Now.ToLongTimeString());
> > return;
> > }
> > foreach (MessageResponseBaseType response in responses)
> > {
> > if (response is ErrorResponseType)
> > {
> > Assert.Fail(((ErrorResponseType)response).Detail);
> > }
> > else
> > {
> > // Get the response (not an error)
> > GetCatalogsResponseType catalogResponse = response as
GetCatalogsResponseType;
> > Debug.WriteLine(string.Format("There are {0} catalogs",
catalogResponse.Catalogs.Length));
> > }
> > }
> > }
> > #endregion
> >
> > The thing that I don't seem to understand yet is this. I am passing a List<>
of requests and for each request I should get a response. The web service is
programmed to return the list of responses synchronously to the list of
requests. But, I want to enumerate through each of the responses one at a time.
Do I need to modify the above further to accomplish this?
> >
> > Thanks again.
> >
> > Kevin
> >
> > ---- "Jeffrey Richter (Wintellect LLC)" <JeffreyR@...> wrote:
> > > · In the iterator, if you are using cancel/timeout,
then, when calling “Proxy.BeginExecuteRequest(requests, ae.End(), null);”,
you should call the overload the of the End method that takes a discard group
and a callback so that cleanup can occur. The callback should be
Proxy.EndExecuteRequest.
> > >
> > > · Inside the iterator, you need to call
Proxy.EndExecuteRequest(ae.DequeueAsyncResult()) at some point when the
operation actually completes so you can process the result (assuming that
cancel/timeout) didn’t occur.
> > >
> > > · You do not use foreach with AsyncEnumerator –
none of my samples show attempt at doing this.
> > >
> > > Now, I’m a bit at a loss for how to help you because I don’t’ how
you want to use this. You are setting a timeout of 500ms when you call WaitOne
but you also set a timeout of 10000ms inside the iterator. The 500ms will
(almost) always win.
> > > And, you have the thread that calls WaitOne is blocked waiting for the
operation to complete – this defeats the purpose of using my AE and you are
synchronously waiting for an async operation to complete.
> > > At some point, you need to call AE’s EndExecute; it is best for perf
reasons to call this in a callback method passed to AE’s BeginExecute.
> > > -- Jeffrey Richter (http://Wintellect.com<http://wintellect.com/>)
> > >
> > > From: PowerThreading@yahoogroups.com
[mailto:PowerThreading@yahoogroups.com] On Behalf Of rkevinburton@...
> > > Sent: Thursday, June 18, 2009 11:05 AM
> > > To: PowerThreading@yahoogroups.com
> > > Subject: [PowerThreading] Simple asynchronous WCF call
> > >
> > >
> > >
> > >
> > >
> > > I coded up what I think should be a simple asynchronous WCF call.
> > >
> > > Initiation:
> > >
> > > List<MessageRequestBaseType> requests = new
List<MessageRequestBaseType>();
> > > GetCatalogsRequestType request = new GetCatalogsRequestType();
> > > requests.Add(request);
> > > AsyncEnumerator<MessageResponseBaseType> ae = new
AsyncEnumerator<MessageResponseBaseType>();
> > > IAsyncResult result = ae.BeginExecute(AsyncGetCatalogHandler(ae,
requests), null);
> > > while (!result.AsyncWaitHandle.WaitOne(500, false))
> > > {
> > > ae.Cancel("Canceled on " + DateTime.Now.ToLongTimeString());
> > > return;
> > > }
> > > foreach (MessageResponseBaseType response in ae)
> > > {
> > > if (response is ErrorResponseType)
> > > {
> > > Assert.Fail(((ErrorResponseType)response).Detail);
> > > }
> > > else
> > > {
> > > // Get the response (not an error)
> > > GetCatalogsResponseType catalogResponse = response as
GetCatalogsResponseType;
> > > Debug.WriteLine(string.Format("There are {0} catalogs",
catalogResponse.Catalogs.Length));
> > > }
> > > }
> > >
> > > Asynch delegate:
> > >
> > > #region AsyncGetCatalogHandler
> > > private static IEnumerator<Int32>
AsyncGetCatalogHandler(AsyncEnumerator<MessageResponseBaseType> ae,
List<MessageRequestBaseType> requests)
> > > {
> > > ae.ThrowOnMissingDiscardGroup(true);
> > > ae.SetCancelTimeout(10000, "Timeout");
> > > Proxy.BeginExecuteRequest(requests, ae.End(), null);
> > > // Will wait until cancel or timeout or normal return
> > > yield return 1;
> > >
> > > Object cancelValue;
> > > if (ae.IsCanceled(out cancelValue))
> > > {
> > > ErrorResponseType errorResponse = new ErrorResponseType();
> > >
> > > errorResponse.Message = string.Format("Cancel {0}", cancelValue);
> > > errorResponse.Detail = string.Format("Cancel {0}", cancelValue);
> > > errorResponse.CorrelationId = System.Guid.NewGuid().ToString();
> > > errorResponse.Code = "TimeoutOrCancel";
> > > ae.Result = errorResponse;
> > > }
> > > else
> > > {
> > > Debug.Assert(false); // Should never get here
> > > }
> > > }
> > > #endregion
> > >
> > > The first problem is that the foreach loop fails to compile. It says that
> > >
> > > Error 3 foreach statement cannot operate on variables of type
AsyncEnumerator<MessageResponseBaseType>' because
AsyncEnumerator<MessageResponseBaseType>' does not contain a public definition
for 'GetEnumerator' C:\...\BsiMessageTestProject\MessageTest.cs 10259 13
BsiMessageTestProject
> > >
> > > Shouldn't AsyncEnumerator<> have GetEnumerator?
> > >
> > > Other than that does this code seem reasonable?
> > >
> > > Thank you.
> > >
> > > Kevin
> > >
> >
>