C# Fire and Forget call inside a WebMethod - c#

We have a C# WebMethod that is called synchronously by a Delphi CGI (don't ask!). This works fine except when we switch to our disaster recovery environment, which runs a lot slower. The problem is that the Delphi WinInet web request has a timeout of 30 seconds, which cannot be altered due a Microsoft-acknowledged bug. In the disaster recovery environment, the C# WebMethod can take longer than 30 seconds, and the Delphi CGI falls flat on its face.
We have now coded the C# WebMethod to recognise the environment it is in, and if it is in disaster recovery mode then we call the subsequent method in a thread and immediately respond to the CGI so that it is well within the 30 seconds. This makes sense in theory, but we are finding that these threaded calls are erratic and are not executing 100% of the time. We get about a 70% success rate.
This is clearly unacceptable and we have to get it to 100%. The threads are being called with Delegate.BeginInvoke(), which we have used successfully in other contexts, but they don't like this for some reason.... there is obviously no EndInvoke(), because we need to respond immediately to the CGI and that's the end of the WebMethod.
Here is a simplified version of the WebMethod:
[WebMethod]
public string NewBusiness(string myParam)
{
if (InDisasterMode())
{
// Thread the standard method call
MethodDelegate myMethodDelegate = new MethodDelegate(ProcessNewBusiness);
myMethodDelegate.BeginInvoke(myParam, null, null);
// Return 'ok' to caller immediately
return 'ok';
}
else
{
// Call standard method synchronously to get result
return ProcessNewBusiness(myParam);
}
}
Is there some reason that this kind of 'fire and forget' call would fail if being used in a WebService WebMethod environment? If so then is there an alternative?
Unfortunately altering the Delphi side is not an option for us - the solution must be in the C# side.
Any help you could provide would be much appreciated.

Do you try to use the "HttpContext" in your method? If so, you should store it in a local variable first... also, I'd just use ThreadPool.QueueUserWorkItem.
Example:
[WebMethod]
public string NewBusiness(string myParam)
{
if (InDisasterMode())
{
// Only if you actually need this...
HttpContext context = HttpContext.Current;
// Thread the standard method call
ThreadPool.QueueUserWorkItem(delegate
{
HttpContext.Current = context;
ProcessNewBusiness(myParam);
});
return 'ok';
}
else
{
// Call standard method synchronously to get result
return ProcessNewBusiness(myParam);
}
}

As the documentation says, EndInvoke should be always called, so you have to create a helper for doing FireAndForget operations like this one:
http://www.reflectionit.nl/Blog/default.aspx?guid=ec2011f9-7e8a-4d7d-8507-84837480092f
I paste the code:
public class AsyncHelper {
delegate void DynamicInvokeShimProc(Delegate d, object[] args);
static DynamicInvokeShimProc dynamicInvokeShim = new
DynamicInvokeShimProc(DynamicInvokeShim);
static AsyncCallback dynamicInvokeDone = new
AsyncCallback(DynamicInvokeDone);
public static void FireAndForget(Delegate d, params object[] args) {
dynamicInvokeShim.BeginInvoke(d, args, dynamicInvokeDone, null);
}
static void DynamicInvokeShim(Delegate d, object[] args) {
DynamicInvoke(args);
}
static void DynamicInvokeDone(IAsyncResult ar) {
dynamicInvokeShim.EndInvoke(ar);
}
}
We use this code successfully in our application, although it is not web.

Related

Block Controller Method while already running

I have a controller which returns a large json object. If this object does not exist, it will generate and return it afterwards. The generation takes about 5 seconds, and if the client sent the request multiple times, the object gets generated with x-times the children. So my question is: Is there a way to block the second request, until the first one finished, independent who sent the request?
Normally I would do it with a Singleton, but because I am having scoped services, singleton does not work here
Warning: this is very oppinionated and maybe not suitable for Stack Overflow, but here it is anyway
Although I'll provide no code... when things take a while to generate, you don't usually spend that time directly in controller code, but do something like "start a background task to generate the result, and provide a "task id", which can be queried on another different call).
So, my preferred course of action for this would be having two different controller actions:
Generate, which creates the background job, assigns it some id, and returns the id
GetResult, to which you pass the task id, and returns either different error codes for "job id doesn't exist", "job id isn't finished", or a 200 with the result.
This way, your clients will need to call both, however, in Generate, you can check if the job is already being created and return an existing job id.
This of course moves the need to "retry and check" to your client: in exchange, you don't leave the connection to the server opened during those 5 seconds (which could potentially be multiplied by a number of clients) and return fast.
Otherwise, if you don't care about having your clients wait for a response during those 5 seconds, you could do a simple:
if(resultDoesntExist) {
resultDoesntExist = false; // You can use locks for the boolean setters or Interlocked instead of just setting a member
resultIsBeingGenerated = true;
generateResult(); // <-- this is what takes 5 seconds
resultIsBeingGenerated = false;
}
while(resultIsBeingGenerated) { await Task.Delay(10); } // <-- other clients will wait here
var result = getResult(); // <-- this should be fast once the result is already created
return result;
note: those booleans and the actual loop could be on the controller, or on the service, or wherever you see fit: just be wary of making them thread-safe in however method you see appropriate
So you basically make other clients wait till the first one generates the result, with "almost" no CPU load on the server... however with a connection open and a thread from the threadpool used, so I just DO NOT recommend this :-)
PS: #Leaky solution above is also good, but it also shifts the responsability to retry to the client, and if you are going to do that, I'd probably go directly with a "background job id", instead of having the first (the one that generates the result) one take 5 seconds. IMO, if it can be avoided, no API action should ever take 5 seconds to return :-)
Do you have an example for Interlocked.CompareExchange?
Sure. I'm definitely not the most knowledgeable person when it comes to multi-threading stuff, but this is quite simple (as you might know, Interlocked has no support for bool, so it's customary to represent it with an integral type):
public class QueryStatus
{
private static int _flag;
// Returns false if the query has already started.
public bool TrySetStarted()
=> Interlocked.CompareExchange(ref _flag, 1, 0) == 0;
public void SetFinished()
=> Interlocked.Exchange(ref _flag, 0);
}
I think it's the safest if you use it like this, with a 'Try' method, which tries to set the value and tells you if it was already set, in an atomic way.
Besides simply adding this (I mean just the field and the methods) to your existing component, you can also use it as a separate component, injected from the IOC container as scoped. Or even injected as a singleton, and then you don't have to use a static field.
Storing state like this should be good for as long as the application is running, but if the hosted application is recycled due to inactivity, it's obviously lost. Though, that won't happen while a request is still processing, and definitely won't happen in 5 seconds.
(And if you wanted to synchronize between app service instances, you could 'quickly' save a flag to the database, in a transaction with proper isolation level set. Or use e.g. Azure Redis Cache.)
Example solution
As Kit noted, rightly so, I didn't provide a full solution above.
So, a crude implementation could go like this:
public class SomeQueryService : ISomeQueryService
{
private static int _hasStartedFlag;
private static bool TrySetStarted()
=> Interlocked.CompareExchange(ref _hasStartedFlag, 1, 0) == 0;
private static void SetFinished()
=> Interlocked.Exchange(ref _hasStartedFlag, 0);
public async Task<(bool couldExecute, object result)> TryExecute()
{
if (!TrySetStarted())
return (couldExecute: false, result: null);
// Safely execute long query.
SetFinished();
return (couldExecute: true, result: result);
}
}
// In the controller, obviously
[HttpGet()]
public async Task<IActionResult> DoLongQuery([FromServices] ISomeQueryService someQueryService)
{
var (couldExecute, result) = await someQueryService.TryExecute();
if (!couldExecute)
{
return new ObjectResult(new ProblemDetails
{
Status = StatusCodes.Status503ServiceUnavailable,
Title = "Another request has already started. Try again later.",
Type = "https://tools.ietf.org/html/rfc7231#section-6.6.4"
})
{ StatusCode = StatusCodes.Status503ServiceUnavailable };
}
return Ok(result);
}
Of course possibly you'd want to extract the 'blocking' logic from the controller action into somewhere else, for example an action filter. In that case the flag should also go into a separate component that could be shared between the query service and the filter.
General use action filter
I felt bad about my inelegant solution above, and I realized that this problem can be generalized into basically a connection number limiter on an endpoint.
I wrote this small action filter that can be applied to any endpoint (multiple endpoints), and it accepts the number of allowed connections:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class ConcurrencyLimiterAttribute : ActionFilterAttribute
{
private readonly int _allowedConnections;
private static readonly ConcurrentDictionary<string, int> _connections = new ConcurrentDictionary<string, int>();
public ConcurrencyLimiterAttribute(int allowedConnections = 1)
=> _allowedConnections = allowedConnections;
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var key = context.HttpContext.Request.Path;
if (_connections.AddOrUpdate(key, 1, (k, v) => ++v) > _allowedConnections)
{
Close(withError: true);
return;
}
try
{
await next();
}
finally
{
Close();
}
void Close(bool withError = false)
{
if (withError)
{
context.Result = new ObjectResult(new ProblemDetails
{
Status = StatusCodes.Status503ServiceUnavailable,
Title = $"Maximum {_allowedConnections} simultaneous connections are allowed. Try again later.",
Type = "https://tools.ietf.org/html/rfc7231#section-6.6.4"
})
{ StatusCode = StatusCodes.Status503ServiceUnavailable };
}
_connections.AddOrUpdate(key, 0, (k, v) => --v);
}
}
}

How to return a data before method complete execution?

I have a slow and expensive method that return some data for me:
public Data GetData(){...}
I don't want to wait until this method will execute. Rather than I want to return a cached data immediately.
I have a class CachedData that contains one property Data cachedData.
So I want to create another method public CachedData GetCachedData() that will initiate a new task(call GetData inside of it) and immediately return cached data and after task will finish we will update the cache.
I need to have thread safe GetCachedData() because I will have multiple request that will call this method.
I will have a light ping "is there anything change?" each minute and if it will return true (cachedData != currentData) then I will call GetCachedData().
I'm new in C#. Please, help me to implement this method.
I'm using .net framework 4.5.2
The basic idea is clear:
You have a Data property which is wrapper around an expensive function call.
In order to have some response immediately the property holds a cached value and performs updating in the background.
No need for an event when the updater is done because you poll, for now.
That seems like a straight-forward design. At some point you may want to use events, but that can be added later.
Depending on the circumstances it may be necessary to make access to the property thread-safe. I think that if the Data cache is a simple reference and no other data is updated together with it, a lock is not necessary, but you may want to declare the reference volatile so that the reading thread does not rely on a stale cached (ha!) version. This post seems to have good links which discuss the issues.
If you will not call GetCachedData at the same time, you may not use lock. If data is null (for sure first run) we will wait long method to finish its work.
public class SlowClass
{
private static object _lock;
private static Data _cachedData;
public SlowClass()
{
_lock = new object();
}
public void GetCachedData()
{
var task = new Task(DoStuffLongRun);
task.Start();
if (_cachedData == null)
task.Wait();
}
public Data GetData()
{
if (_cachedData == null)
GetCachedData();
return _cachedData;
}
private void DoStuffLongRun()
{
lock (_lock)
{
Console.WriteLine("Locked Entered");
Thread.Sleep(5000);//Do Long Stuff
_cachedData = new Data();
}
}
}
I have tested on console application.
static void Main(string[] args)
{
var mySlow = new SlowClass();
var mySlow2 = new SlowClass();
mySlow.GetCachedData();
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
mySlow.GetData();
mySlow2.GetData();
}
mySlow.GetCachedData();
Console.Read();
}
Maybe you can use the MemoryCache class,
as explained here in MSDN

Making a infinite loop in .Net MVC

I need a operations which needs to run every x seconds forever, and to achieve this I did:
protected void Application_Start()
{
InitialieOnce.Initialize();
}
public static class InitialieOnce
{
private static bool initialized = false;
public static void Initialize()
{
if (initialized == false)
{
initialized = true;
Thread t = new Thread(x => CheckStatus());
t.IsBackground = true;
t.Start();
}
}
private static void CheckStatus()
{
//My script goes here.
Thread.Sleep(8000);
CheckStatus();
}
}
After some time (about 5 minutes) I get this error:
"An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll"
Can this error be related to how I made my infinite loop?
If yes, is there a better way to achieve this, can I fix it, or is this code ok?
You are calling "CheckStatus" recursively. So every 8 seconds there will be one more entry on your call stack:
CheckStatus() -> CheckStatus() -> CheckStatus() -> and so on.. until you get a StackOverflowException.
Instead you should use
while (true)
{
/* Your Code */
Thread.Sleep(8000);
}
Please also note that by default IIS will unload your application if there was no request in 15 minutes, resulting in your thread being killed.
Consider creating a Windows service for such a thing, instead of abusing IIs..
I don't know where, but I read that IIs isn't good for creating long living services like in javas servers.
I would also suggest creating a Windows service for that, something like a daemon. You can create a service that will just call a special action on your application on regular intervals. The rest of the work will be done within your MVC application. Have a look at this post for an example.

what does callback mean? [duplicate]

What's a callback and how is it implemented in C#?
I just met you,
And this is crazy,
But here's my number (delegate),
So if something happens (event),
Call me, maybe (callback)?
In computer programming, a callback is executable code that is passed as an argument to other code.
—Wikipedia: Callback (computer science)
C# has delegates for that purpose. They are heavily used with events, as an event can automatically invoke a number of attached delegates (event handlers).
A callback is a function that will be called when a process is done executing a specific task.
The usage of a callback is usually in asynchronous logic.
To create a callback in C#, you need to store a function address inside a variable. This is achieved using a delegate or the new lambda semantic Func or Action.
public delegate void WorkCompletedCallBack(string result);
public void DoWork(WorkCompletedCallBack callback)
{
callback("Hello world");
}
public void Test()
{
WorkCompletedCallBack callback = TestCallBack; // Notice that I am referencing a method without its parameter
DoWork(callback);
}
public void TestCallBack(string result)
{
Console.WriteLine(result);
}
In today C#, this could be done using lambda like:
public void DoWork(Action<string> callback)
{
callback("Hello world");
}
public void Test()
{
DoWork((result) => Console.WriteLine(result));
DoWork(Console.WriteLine); // This also works
}
Definition
A callback is executable code that
is passed as an argument to other code.
Implementation
// Parent can Read
public class Parent
{
public string Read(){ /*reads here*/ };
}
// Child need Info
public class Child
{
private string information;
// declare a Delegate
delegate string GetInfo();
// use an instance of the declared Delegate
public GetInfo GetMeInformation;
public void ObtainInfo()
{
// Child will use the Parent capabilities via the Delegate
information = GetMeInformation();
}
}
Usage
Parent Peter = new Parent();
Child Johny = new Child();
// Tell Johny from where to obtain info
Johny.GetMeInformation = Peter.Read;
Johny.ObtainInfo(); // here Johny 'asks' Peter to read
Links
more details for C#.
A callback is a function pointer that you pass in to another function. The function you are calling will 'callback' (execute) the other function when it has completed.
Check out this link.
If you referring to ASP.Net callbacks:
In the default model for ASP.NET Web
pages, the user interacts with a page
and clicks a button or performs some
other action that results in a
postback. The page and its controls
are re-created, the page code runs on
the server, and a new version of the
page is rendered to the browser.
However, in some situations, it is
useful to run server code from the
client without performing a postback.
If the client script in the page is
maintaining some state information
(for example, local variable values),
posting the page and getting a new
copy of it destroys that state.
Additionally, page postbacks introduce
processing overhead that can decrease
performance and force the user to wait
for the page to be processed and
re-created.
To avoid losing client state and not
incur the processing overhead of a
server roundtrip, you can code an
ASP.NET Web page so that it can
perform client callbacks. In a client
callback, a client-script function
sends a request to an ASP.NET Web
page. The Web page runs a modified
version of its normal life cycle. The
page is initiated and its controls and
other members are created, and then a
specially marked method is invoked.
The method performs the processing
that you have coded and then returns a
value to the browser that can be read
by another client script function.
Throughout this process, the page is
live in the browser.
Source: http://msdn.microsoft.com/en-us/library/ms178208.aspx
If you are referring to callbacks in code:
Callbacks are often delegates to methods that are called when the specific operation has completed or performs a sub-action. You'll often find them in asynchronous operations. It is a programming principle that you can find in almost every coding language.
More info here: http://msdn.microsoft.com/en-us/library/ms173172.aspx
Dedication to LightStriker:
Sample Code:
class CallBackExample
{
public delegate void MyNumber();
public static void CallMeBack()
{
Console.WriteLine("He/She is calling you. Pick your phone!:)");
Console.Read();
}
public static void MetYourCrush(MyNumber number)
{
int j;
Console.WriteLine("is she/he interested 0/1?:");
var i = Console.ReadLine();
if (int.TryParse(i, out j))
{
var interested = (j == 0) ? false : true;
if (interested)//event
{
//call his/her number
number();
}
else
{
Console.WriteLine("Nothing happened! :(");
Console.Read();
}
}
}
static void Main(string[] args)
{
MyNumber number = Program.CallMeBack;
Console.WriteLine("You have just met your crush and given your number");
MetYourCrush(number);
Console.Read();
Console.Read();
}
}
Code Explanation:
I created the code to implement the funny explanation provided by LightStriker in the above one of the replies. We are passing delegate (number) to a method (MetYourCrush). If the Interested (event) occurs in the method (MetYourCrush) then it will call the delegate (number) which was holding the reference of CallMeBack method. So, the CallMeBack method will be called. Basically, we are passing delegate to call the callback method.
Please let me know if you have any questions.
Probably not the dictionary definition, but a callback usually refers to a function, which is external to a particular object, being stored and then called upon a specific event.
An example might be when a UI button is created, it stores a reference to a function which performs an action. The action is handled by a different part of the code but when the button is pressed, the callback is called and this invokes the action to perform.
C#, rather than use the term 'callback' uses 'events' and 'delegates' and you can find out more about delegates here.
callback work steps:
1) we have to implement ICallbackEventHandler Interface
2) Register the client script :
String cbReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context");
String callbackScript = "function UseCallBack(arg, context)" + "{ " + cbReference + ";}";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "UseCallBack", callbackScript, true);
1) from UI call Onclient click call javascript function for EX:- builpopup(p1,p2,p3...)
var finalfield= p1,p2,p3;
UseCallBack(finalfield, ""); data from the client passed to server side by using UseCallBack
2) public void RaiseCallbackEvent(string eventArgument) In eventArgument we get the passed data
//do some server side operation and passed to "callbackResult"
3) GetCallbackResult() // using this method data will be passed to client(ReceiveServerData() function) side
callbackResult
4) Get the data at client side:
ReceiveServerData(text) , in text server response , we wil get.
A callback is a function passed as an argument to another function. This technique allows a function to invoke the parameter function argument and even to pass a value back to the caller. A callback function can be designed to run before/after the function has finished and can pass a value.
It is a kind of construct where you call a long running function and ask him to call you back once it has finished with can return a parameter result to the caller.
It's like someone calls you in the middle of your work asking for status and you say "you know what give me 5 min and i will call you back" and at the end you call him to update. If you are a function the caller just added and passed another function that you invoked at the end. This can simpley be written in C# as:
public void VinodSrivastav(Action statusUpdate){
//i am still here working..working
//i have finished, calling you
statusUpdate();
}
//invokes
stackoverflow.VinodSrivastav((cam) => {
Console.Write("Is it finished");
});
The one simple example is the iterator function where the return will be multiple times, one can argue that we have yield for it:
public void IntreationLoop(int min, int max,Action<int> Callback)
{
for(int i = min;i<= max;i++)
Callback(i);
}
//call
IntreationLoop(5,50,(x) => { Console.Write(x); }); //will print 5-50 numbers
In the code above the function return type is void but it has an Action<int> callback which is called and sends each item from the loop to the caller.
The same thing can be done with if..else or try..catch block as:
public void TryCatch(Action tryFor,Action catchIt)
{
try{
tryFor();
}
catch(Exception ex)
{
Console.WriteLine($"[{ex.HResult}] {ex.Message}");
catchIt();
}
}
And call it as:
TryCatch(()=>{
int r = 44;
Console.WriteLine("Throwing Exception");
throw new Exception("something is wrong here");
}, ()=>{
Console.WriteLine("It was a mistake, will not try again");
});
In 2022 we have Func & Action doing the same, please see the demo code below which shows how this can be be used:
void Main()
{
var demo = new CallbackDemo();
demo.DoWork(()=> { Console.WriteLine("I have finished the work"); });
demo.DoWork((r)=> { Console.WriteLine($"I have finished the work here is the result {r}"); });
demo.DoWork(()=> { Console.WriteLine($"This is passed with func"); return 5;});
demo.DoWork((f)=> { Console.WriteLine($"This is passed with func and result is {f}"); return 10;});
}
// Define other methods and classes here
public class CallbackDemo
{
public void DoWork(Action actionNoParameter)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
actionNoParameter(); //execute
Console.WriteLine($"[The Actual Result is {result}]");
}
public void DoWork(Action<int> actionWithParameter)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
actionWithParameter(result); //execute
Console.WriteLine($"[The Actual Result is {result}]");
}
public void DoWork(Func<int> funcWithReturn)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
int c = funcWithReturn(); //execute
result += c;
Console.WriteLine($"[The Actual Result is {result}]");
}
public void DoWork(Func<int,int> funcWithParameter)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
result += funcWithParameter(result); //execute
Console.WriteLine($"[The Actual Result is {result}]");
}
}

How to call asynchronous services synchronously in Silverlight

I have a silverlight 5 app that depends on several asynchronous calls to web services to populate the attributes of newly created graphics. I am trying to find a way to handle those asynchronous calls synchronously. I have tried the suggestions listed in this article and this one. i have tried the many suggestions regarding the Dispatcher object. None have worked well, so I am clearly missing something...
Here is what I have:
public partial class MainPage : UserControl {
AutoResetEvent waitHandle = new AutoResetEvent(false);
private void AssignNewAttributeValuesToSplitPolygons(List<Graphic> splitGraphics)
{
for (int i = 0; i < splitGraphics.Count; i++)
{
Graphic g = splitGraphics[i];
Thread lookupThread1 = new Thread(new ParameterizedThreadStart(SetStateCountyUtm));
lookupThread1.Start(g);
waitHandle.WaitOne();
Thread lookupThread2 = new Thread(new ParameterizedThreadStart(SetCongressionalDistrict));
lookupThread1.Start(g);
waitHandle.WaitOne();
}
private void SetStateCountyUtm(object graphic)
{
this.Dispatcher.BeginInvoke(delegate() {
WrapperSetStateCountyUtm((Graphic)graphic);
});
}
private void WrapperSetStateCountyUtm(Graphic graphic)
{
GISQueryEngine gisQEngine = new GISQueryEngine();
gisQEngine.StateCountyUtmLookupCompletedEvent += new GISQueryEngine.StateCountyUtmLookupEventHandler(gisQEngine_StateCountyUtmLookupCompletedEvent);
gisQEngine.PerformStateCountyUtmQuery(graphic.Geometry, graphic.Attributes["clu_number"].ToString());
}
void gisQEngine_StateCountyUtmLookupCompletedEvent(object sender, StateCountyUtmLookupCompleted stateCountyUtmLookupEventArgs)
{
string fred = stateCountyUtmLookupEventArgs.
waitHandle.Set();
}
}
public class GISQueryEngine
{
public void PerformStateCountyUtmQuery(Geometry inSpatialQueryGeometry, string cluNumber)
{
QueryTask queryTask = new QueryTask(stateandCountyServiceURL);
queryTask.ExecuteCompleted += new EventHandler<QueryEventArgs>(queryTask_StateCountyLookupExecuteCompleted);
queryTask.Failed += new EventHandler<TaskFailedEventArgs>(queryTask_StateCountyLookupFailed);
Query spatialQueryParam = new ESRI.ArcGIS.Client.Tasks.Query();
spatialQueryParam.OutFields.AddRange(new string[] { "*" });
spatialQueryParam.ReturnGeometry = false;
spatialQueryParam.Geometry = inSpatialQueryGeometry;
spatialQueryParam.SpatialRelationship = SpatialRelationship.esriSpatialRelIntersects;
spatialQueryParam.OutSpatialReference = inSpatialQueryGeometry.SpatialReference;
queryTask.ExecuteAsync(spatialQueryParam, cluNumber);
}
//and a whole bunch of other stuff i can add if needed
}
If I leave the 'waitHandle.WaitOne()' method uncommented, no code beyond that method is ever called, at least that I can see with the step through debugger. The application just hangs.
If I comment out the 'waitHandle.WaitOne()', everything runs just fine - except asynchronously. In other words, when the app reads the Attribute values of the new graphics, those values may or may not be set depending on how quickly the asynch methods return.
Thanks for any help.
It's going to be rather difficult to work through a problem like this as there are a few issues you'll need to address. SL is by nature asynch so forcing it to try and work synchronously is usually a very bad idea. You shouldn't do it unless it's absolutely necessary.
Is there a reason that you cannot wait for an async. callback? From what I see you appear to be making two calls for every state that is being rendered. I'm guessing the concern is that one call must complete before the second is made? In scenarios like this, I would kick off the first async call, and in it's response kick off the second call passing along the result you'll want to use from the first call. The second call response updates the provided references.
However, in cases where you've got a significant number of states to update, this results in a rather chatty, and difficult to debug set of calls. I'd really be looking at creating a service call that can accept a set of state references and pass back a data structure set for the values to be updated all in one hit. (or at least grouping them up to one call per state if the batch will be too time consuming and you want to render/interact with visual elements as they load up.)

Categories

Resources