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}]");
}
}
Related
I am using a c++ dll to do some background computation and I am trying to get it to report progress back to my calling C# code.
To do that, I've registered a callback method that accepts a StringBuilder as a parameter (found on the web that this was a proper way of doing it).
Here is my ´c++´ code :
// --------------------------------------------
// ----------------- C++ CODE -----------------
// --------------------------------------------
// ----------------- dll api methods
// a custom class to contain some progress report stuff... basically, most important is
// that it contains the callback as ProgressCallback _callback;
CustomEventHandler* _eventHandler = NULL;
// definition of the callback type
typedef void(__stdcall* ProgressCallback)(char* log);
// method to register the callback method
int __stdcall SetCallbackFunction(ProgressCallback callback) {
// from https://stackoverflow.com/a/41910450/2490877
#pragma EXPORT_FUNCTION
// I encapsulated the callback into a custom class
_eventHandler = new CustomEventHandler();
_eventHandler->setEventHandler(callback);
// test all is ok => no problem at this stage, all works great, the
// passed-in callback is called with correct message.
logToCallback("All is ok while testing the method. So far so good!!");
return 0;
}
// the long and slow method (note that I might call it several times from c# during the
// one run
int __stdcall DoLooongStuff() {
// from https://stackoverflow.com/a/41910450/2490877
#pragma EXPORT_FUNCTION
// ------ this is a LOOOONG method that regualrly logs stuff via the callback,
// here an example....
char buf[1000];
sprintf_s(buf, "This is a sample progress log with some formats :%i %i %g", 1, 2, 3.1415);
logToCallback(buf);
// --- the above works a few times without any problem
return 0;
}
//--- this is a static method I use to send progress messages back
static void logToCallback(char* message) {
if (_eventHandler) {
_eventHandler->logToCallback(message);
}
}
// --------------- CustomEventHandlerClass
// ------- class declaration ------
class CustomEventHandler {
public:
void setEventHandler(ProgressCallback callback);
void logToCallback(char* message);
protected:
ProgressCallback _callback;
}
// ----- class implementation
// set the callback method
void CustomEventHandler::setEventHandler(ProgressCallback callback) {
_callback = callback;
}
void CustomEventHandler::logToCallback(char* message) {
if (_callback) {
_callback(message); // <========= this is where the debugger stops:
// no more info than the annoying System.ExecutionEngineException...
// I've tried to pass a constant message like "1234" but got the same issue...
//_callback("1234");
// if however I remove the call to the callback, I don't get errors
// (I know this doesn't mean I don't have any...)
}
}
Now for the calling c# code, I'm using the following code:
// --------------------------------------------
// ----------------- C# CODE ------------------
// --------------------------------------------
// ----- the delegate type to be passed to the dll
public delegate bool CallbackFunction([MarshalAs(UnmanagedType.LPStr)] StringBuilder log);
// ----- prepare to load the dll's methods (I only show the SetCallback code here, other api methods
// are declared and loaded the same way)
private delegate int _SetCallbackFunction_(CallbackFunction func);
private _SetCallbackFunction_ SetCallbackFunction_Dll;
public int SetCallbackFunction(CallbackFunction func) {
return SetCallbackFunction_Dll(func);
}
// loading methods
private T GetDelegate<T>(string procName) where T : class {
IntPtr fp = GetProcAddress(_dllHandle, procName);
return fp != IntPtr.Zero ? Marshal.GetDelegateForFunctionPointer(fp, typeof(T)) as T : null;
}
async Task loadDllMethods() {
// load the delegates => great, it works!
SetCallbackFunction_Dll = GetDelegate<_SetCallbackFunction_>("SetCallbackFunction");
// set callback in DLL, calls the delegate once successfully...
SetCallbackFunction(cSharpCallback);
await doTask();
}
async Task doTask() {
// start the long dll method, that fires the callback to monitor progress
while (someConditionIsMet) {
DoLooongStuff(); // => calls the dll with registered callback!
}
}
// the actual callback
bool cSharpCallback(StringBuilder strBuilder) {
// this is called a few times successfully with the expected message!
Console.WriteLine(strBuilder.ToString());
return true;
}
I've searched over differrent threads to find out the error. I had an error due to too small ´buf´ sizes, so I just made sure it is large enough. I've also teted that ´&_callback´ is always pointing at the same place (it is!).
I am out of search options, any help will be much appreciated. Note that I am note an expert in dll integration, Marshalling etc, I put references I found the hints!
You need to insure the delegate you pass to C++ is alive as long as the callback is being used in C++. You are responsible for holding delegate C# object alive as long as the corresponding C++ callback is used:
someField = new CallbackFunction(cSharpCallback);
SetCallbackFunction(someField);
Better yet, just use Scapix Language Bridge, it generates C++ to C# bindings (including callbacks), completely automatically. Disclaimer: I am the author of Scapix Language Bridge.
I found the answer to my question, thanks to this post:
In order to keep the unmanaged function pointer alive (guarding against GC), you need to hold an instance of the delegate in a variable
So the modified code is ONLY in C#
// -------------- PREVIOUS CODE
async Task loadDllMethods() {
// load the delegates => great, it works!
SetCallbackFunction_Dll = GetDelegate<_SetCallbackFunction_>("SetCallbackFunction");
// set callback in DLL, calls the delegate once successfully...
SetCallbackFunction(cSharpCallback);
await doTask();
}
// -------------- WORKING CODE!!!!
// add static reference....
static CallbackFunction _callbackInstance = new CallbackFunction(cSharpCallback); // <==== Added reference to prevent GC!!!
async Task loadDllMethods() {
// load the delegates => great, it works!
SetCallbackFunction_Dll = GetDelegate<_SetCallbackFunction_>("SetCallbackFunction");
// create callback!!!
SetCallbackFunction(_callbackInstance); // <====== pass the instance here, not the method itself!!!
await doTask();
}
NOTE: I also changed StringBuilder to string !
I have a function which takes an object of a custom class. A member of this object should store an identifier of that function (or a 'reference' to that function) so that the function can determine whether it was called before with this object.
What is a suitable identfier for this purpose?
I am not necessarily talking about the function name, because overloaded functions share the same name, so this doesn't work.
Is the function address (as used für delegates) a proper way? I am pretty sure that this will work, but not 100% sure. Or may the function be moved around by the garbage collector like regular objects?
Is there maybe another, better way to get a 'function ID'?
Edit
Here's an example to demonstrate my requirement (pseudo-code used):
void WorkerFunction (CFuncStep i_oFS)
{
if (i_oFS.FunctionID == WorkerFunction.FunctionID)
{
// continue work
}
else
{
// start work
i_oFS.FunctionID = WorkerFunction.FunctionID;
}
if (finished_work)
i_oFS.FunctionID = null;
}
The purpose is saving the operation state and later continuing an operation in a called function. This makes sense in cases e.g. where the function does network communication and has to wait for the reply. The func returns immediately so that the thread can do other work. Later it comes back to fetch the reply.
I could use a separate thread, but I want to avoid the overhead of thread sync here, because it would not just be 1 add. thread, but quite some.
#BenVoigt: Thanks for the hint at MethodHandle!
This is absolutely what I needed. I found a usage example at the SO post 'Can you use reflection to find the name of the currently executing method?'
Here's my solution:
using namespace System::Reflection;
ref class CFuncStep
{
public:
int m_iStep;
MethodBase^ m_oMethod;
String^ m_sName;
};
void workerfunction (CFuncStep^ i_oFS)
{
MethodBase^ oMethod = MethodBase::GetCurrentMethod ();
if (oMethod != i_oFS->m_oMethod)
{
i_oFS->m_iStep = 1;
i_oFS->m_oMethod = MethodBase::GetCurrentMethod ();
i_oFS->m_sName = i_oFS->m_oMethod->Name;
}
switch (i_oFS->m_iStep)
{
case 1:
case 2:
case 3:
i_oFS->m_iStep++;
break;
case 4:
i_oFS->m_iStep = 0;
i_oFS->m_oMethod = nullptr;
i_oFS->m_sName = nullptr;
}
};
int main()
{
CFuncStep^ oFS = gcnew CFuncStep;
do
{
workerfunction (oFS);
}
while (oFS->m_iStep > 0);
return 0;
}
I have a Javascript Windows 8 App. I am writing a WinRT Component DLL using C# for interfacing with a database.
For all functions such as OpenDB, ExecuteUpdate, ExecuteQuery (returning one row, returning one column value), I have done a IASyncOperation and am pretty successful.
But for processing each row in a big resultset, one by one, I need to pass in a callback function from javascript to the C# WinRT Component DLL. so the code is like,
My.WinRT.Component.Object.processEachRowASyc(query, arguments, function(row) {
/* Row specific processing */
}).then(function(result) {
/* Process after Entire Row processing is Complete */
});
I have written the RT Component such as this,
namespace mydb
{
public void delegate MyJSCallback(string msg);
public class Database {
public static IAsyncOperation<Database> OpenDB(string dbFile)
{
/* Open DB */
}
public IAsyncOperation<Database> ProcessEachRowASync(string sql,[ReadOnlyArray()] object[] arg, MyJSCallback myJSCallback)
{
return Task<Database>.Run(() =>
{
/* Query Processing */
IDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
string toRet = "{\"Name\":\"Raju\", \"Age\":\"21\"}";
//Javascript callback function called.
myJSCallback(toRet);
}
return this;
}).AsAsyncOperation();
}
}
}
Now, I am getting a typecasting error when I execute this from Visual Studio, I am sure I am erring somewhere in declaring the delegate or somewhere else,
Can somebody please enlighten me on where I am doing wrong and how this could be corrected.
URL for downloading a sample project for this is, http://sdrv.ms/18ff3Hl
To simplify this further, I have written another function in the RTComponent showing just the callback error, the code is as follows in the RT Component
public delegate void SQLite3JSNoCallback();
public IAsyncOperation<int> GetLastInsertRowId(SQLite3JSNoCallback someCallback)
{
return Task<int>.Run(() =>
{
someCallback();
return 0;
}).AsAsyncOperation();
}
Now the error occurs in while performing someCallback(), the error is as same as the above screenshot with the change of the delegate alone. "Unable to cast object of the type 'mydb.SQLite3JSNoCallback' to 'mydb.SQLite3JSNoCallback'."
This happens because of asynchronicity, as you have noticed. I have found that by invoking the callback on the UI thread, it will now work as expected.
WinRT component:
public delegate void DoStuffCallback(int num);
public sealed class Test
{
public void ShowStuffOnOutput(int x, int y, DoStuffCallback callback)
{
Debug.WriteLine("pre-callback");
Debug.WriteLine(x);
Task.Run(() =>
{
callback(15);
});
Debug.WriteLine("post-callback");
Debug.WriteLine(y);
}
}
Javascript universal app
var obj = new CallbackComponent.Test();
obj.showStuffOnOutput(1, 2, function(num) {
console.log("callback in JS!");
console.log(num);
});
Solution:
Switch to
CoreApplication.MainView.CoreWindow.
Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
{
callback(15);
});
When I removed the IASyncOperation from the function, the js callback worked without issue.
There seems to be a problem because I am having a blocking callback function sent as the parameter, I believe. Can any one clarify how it can work with IASyncOperation present in my function.
Should I send in an ASyncCallback function to the C# RT Component to be able to get a callback.
Still the answer remains for the above problem to make the RT Component's function a blocking function if you need a javascript callback to successfully work,
Regards,
Jay
I am in the process of refactoring "synchronous" code (i.e. uses Windows events to wait until some other thread finished doing something) to "asynchronous" code (using delegates to implement a callback mechanism).
In the sync code, I sometimes have local variables that I need to use after the wait is over. When code like that goes async, those local variables are lost (the callback handler can't access them). I can store them as class attributes, but it feels wasteful.
In C++, I use std::bind to work around this. I just add as many parameters as local variables needed to the callback handler, and bind them when I call the async method. For example, let's say that the async method callback receives an object of type CallbackParam and the caller uses two local variables of type LocalA and LocalB.
void AsyncClass::MethodWhichCallsAsyncMethod(){
LocalA localVarA;
LocalB localVarB;
// OnAsyncMethodDone will need localVarA and localVarB, so we bind them
AsyncMethod( std::bind( &AsyncClass::OnAsyncMethodDone, this, std::placeholders::_1, localVarA, localVarB ) );
}
void AsynClass::AsyncMethod( std::function<void(CallbackParam)> callback ){
CallbackParam result;
//Compute result...
if( callback )
callback( result );
}
void AsyncClass::OnAsyncMethodDone( CallbackParam p, LocalA a, LocalB b ){
//Do whatever needs to be done
}
Is there some sort of equivalent to this in C# and VB.NET? Using delegates or something else?
UPDATE: For completeness' sake, here is the C# equivalent of my example based on #lasseespeholt's answer:
using System;
public class AsyncClass {
public void MethodWhichCallsAsyncMethod() {
var a = new LocalA();
var b = new LocalB();
//Anonymous callback handler (equivalent to AsyncClass::OnAsyncMethodDone)
Action<CallbackParam> callback = result => {
//Do what needs to be done; result, a and b can be accessed
};
AsyncMethod( callback );
}
private void AsyncMethod( Action<CallbackParam> callback ) {
var result = new CallbackParam();
//Compute result...
if( callback != null )
callback( result );
}
}
UPDATE: This should almost certainly not be used. Use the async/await keywords in C#
You can exploit closures like the following:
void MethodWhichCallsAsyncMethod()
{
int foo = 1;
AsyncCallback callback = result =>
{
Console.WriteLine(foo); // Access to foo
};
AsyncMethod(callback);
}
void AsyncMethod(AsyncCallback callback)
{
IAsyncResult result = null; // Compute result
callback(result);
}
The compiler generates a class which contains "foo" so you don't save anything with this approach, but it's clean.
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.