How to set object to AsyncState and pass it into AsyncCallback method - c#

Two questions:
How do I pass arguments to the AsyncCallback method?
How do I invoke the AsyncCallback method?
Here's the background:
I am working on an old project in .NET Framework 3.5. I want to create an async method doing some works without blocking current thread. Since the project is an old version Async Await key words are not available, I plan to do all parallel works including some database queries and api calling in AsyncCallback method. I know AsyncState can be used to convey arguments. Because I need multiple arguments, I plan to include these arguments into an object and set the object to AsyncState, so I can cast AsyncState as the object to be used in AsyncCallback method. I didn't find a good way. I've found this link, but I don't use HttpWebRequest.
public Class ArgumentObject
{
public string A{get;set;}
public string B{get;set;}
...
}
public void CallBack(IAsyncResult result, ArgumentObject arObj)
{
Console.WriteLn(arObj.A);
Console.WriteLn(arObj.B);
}
The following are the code which call the AsyncCallBack method.
var argumentsObj=new ArgumentObject{ A="argument1", B="argument2"..};
AsyncCallback callback = (IAsyncResult result) => CallBack(result, argumentsObj);
// How do I know it is triggered? I set the break point into CallBack method, but it never goes to there.
Any idea or correction is appreciated.

Update:
I finally found a way to pass arguments. I use a delegate and call BeginInvoke method.
static int DoSomething(string s, int t)
{
Console.WriteLine(s+t.ToString());
return 0;
}// this is the delegate method, you can define it anyway.
public delegate int MyDelegate(string s, int t);
MyDelegate x = new MyDelegate(DoSomething);
AsyncCallback callback = new AsyncCallback(CallBack);
var argumentsObj=new ArgumentObject{ A="argument1", B="argument2"..};
IAsyncResult ar = x.BeginInvoke("hello", 12, callback, argumentsObj);
// in my case, the first two parameters are not important, only the last two are important.
Now in Callback method I can cast the AsyncState into argument object:
var obj = (CallBackObj)result.AsyncState;
In CallBack method, don't forget to call EndInvoke method in order to guarantee not to leak memory or handles
MyDelegate x = (MyDelegate)((AsyncResult)result).AsyncDelegate;
x.EndInvoke(result);

Related

How are methods with arguments invoked?

I am trying to call a method with arguments, but it doesn't work. I have this method:
public class AllMethods
{
//method change state and status of entity objetivovisitacao for "Propagado"
public static void changeStatus(Guid objetivoId, IOrganizationService service, int state)
{
SetStateRequest setStateRequest = new SetStateRequest
{
EntityMoniker = new EntityReference("statuscode", objetivoId),
State = new OptionSetValue(0),
Status = new OptionSetValue(911950001),
};
service.Execute(setStateRequest);
}
}
And I need to call that method, so I tried doing it this way:
AllMethods.changeStatus();
But it's wrong. Can someone explain this so that I can better understand what I'm missing here?
First create variables for the parameters of the method. Then pass them in the same order as they was declared in the method.
Guid yourObjetivoId = new Guid();
IOrganizationService yourService = New YourImplementationOfOrganizationService();
int yourState = 3;
AllMethods.changeStatus(yourObjetivoId, yourService, yourState);
From MSDN: Methods (C# Programming Guide)
The method definition specifies the names and types of any parameters
that are required.
When calling code calls the method, it provides
concrete values called arguments for each parameter.
The arguments
must be compatible with the parameter type but the argument name (if
any) used in the calling code does not have to be the same as the
parameter named defined in the method
No need to state the types of the parameters when passing them through.
You should call it like this:
AllMethods.changeStatus(objetivoId, service, state);
you need to pass the parameters, see documentation: Pass parameters c#
in your case
AllMethods.changeStatus(objetivoId, service, state);
If you declare a method like you did:
public static void changeStatus(Guid objetivoId, IOrganizationService service, int state)
you declare parameters in the parentheses. The compiler expects the necessary input when you try to call it. So you need the fitting parameters for the call of this method. It is like a key to a lock.
Guid objetivoId = // your value
IOrganizationService service = // your value
int state = // your value
then you call it like this:
AllMethods.changeStatus(objetivoId, service, state);
You don't need to declare them again in the call! it has to be done beforehand
You are doing it wrong since, you are declaring the types of the parameter here:
AllMethods.changeStatus(Guid objetivoId, IOrganizationService service, int state);
for calling this method changeStatus(...), you need to pass the variable for the parameters objetivoId, service, state.
AllMethods.changeStatus(objetivoId, service, state);
See: Passing of Parameters in C#
MSDN:
In C#, arguments can be passed to parameters either by value or by
reference.

How to get method results with AsyncCallback?

I hope you can help me with the following:
I have a WebService method which is supposed to return an array of CompensationPlanReturnReturn objects.
The method is called like this:
//This is the object I need to instanciate because it contains the method I wanna call
CompensationPlan_Out_SyncService test = new CompensationPlan_Out_SyncService();
//This is the method that is supposed to return me an array of CompensationPlanReturnReturn objects
//The data.ToArray() is the parameter the method need, then I pass the method that I wanna run when the method finishes and I dont know what to pass as the final parameter
test.BeginCompensationPlan_Out_Sync(data.ToArray(), new AsyncCallback(complete), null)
//The method description is:
public System.IAsyncResult BeginCompensationPlan_Out_Sync(CompensationPlanDataCompensationPlan[] CompensationPlanRequest, System.AsyncCallback callback, object asyncState)
//On this method I'd like to access to the resuls (the array of CompensationPlanReturnReturn) but I dont know how
private void complete(IAsyncResult result)
{
lblStatus.Text = "Complete";
}
You need to call test.EndCompensationPlan_Out_Sync(result), which will return the result of the asynchronous operation, or throw an exception if an error occurred.
Async methods breakdown into two submethods - Begin and End.
You need to call EndCompensationPlan_Out_Sync to get the actual result returned by method -
private void complete(IAsyncResult result)
{
var actualResult = test.EndCompensationPlan_Out_Sync(result);
lblStatus.Text = "Complete";
}
Try to use the AsyncState-Property and cast it the the given Type.
Like this:
cSACommand = (SACommand)Result.AsyncState;

Pass argument to AsyncCallback function?

I'm learning socket programming and I have the following function:
public void OnDataReceived(IAsyncResult asyn)
and this is how the callback gets set:
pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
The problem is I need to pass another argument to OnDataReceived callback function, how can I do this? I'm trying to make a simple tcp server and I need to track from which client the data is coming from. Any tips? Thanks!
I'm going to presume you're using System.Net.Sockets.Socket here. If you look at the overloads of BeginReceive you'll see the object parameter (named state). You can pass an arbitrary value as this parameter and it will flow through to your AsyncCallback call back. You can then acess it using the AsyncState property of IAsyncResult object passed into your callback. Eg;
public void SomeMethod() {
int myImportantVariable = 5;
System.Net.Sockets.Socket s;
s.BeginReceive(buffer, offset, size, SocketFlags.None, new new AsyncCallback(OnDataReceived), myImportantVariable);
}
private void OnDataReceived(IAsyncResult result) {
Console.WriteLine("My Important Variable was: {0}", result.AsyncState); // Prints 5
}
This is a problem I prefer to solve with anonymous delegates:
var someDataIdLikeToKeep = new object();
mySocket.BeginBlaBla(some, other, ar => {
mySocket.EndBlaBla(ar);
CallSomeFunc(someDataIdLikeToKeep);
}, null) //no longer passing state as we captured what we need in callback closure
It saves having to cast a state object in the receiving function.
When you call BeginReceive, you can pass any object as its last parameter. The same object will be made available to your callback through IAsyncResult's AsyncState property.
As MrMDavidson mentioned.
If you look at the overloads of BeginReceive you'll see the object parameter (named state)
You could pass an object array of your desired parameters to the state parameter and then deal with them later in the callback method.
client.BeginConnect(ipEndPoint, new AsyncCallback(ConnectedCallback), new object[] { parameter1, parameter2});

How to pass an action to task factory with weak reference to target

Edit: I updated my code. Would this achieve what i am aiming for?
I have a working set of methods for async calling of methods but i have a specific problem with the references i pass in via a lambda. Specifically i have a (child) window that starts an operation and registers a callback. As you might expect, even when i close this window it still gets invoked.
What i want to do is pass in a kind of "weak reference" or construct a weak reference out of the incoming action.
Thhis is the way i build my Action (example code):
static Action CreateNewAction(Action call, Action<SomeArg> callback,
Dispatcher dispatcher)
{
return delegate {
try
{
call();
var target = callback.Target
if(target != null)
dispatcher.Invoke(callback, new SomeArg());
}
catch (Exception ex)
{
// handle the ex in some way..
}
};
}
And this is how the task factory calls it:
var t = Task.Factory.StartNew(CreateNewAction(call, callback, dispatcher))
And this is how I would call it (the call just basses both the action and the callback through to the task factory as seen above):
WeakReference wr = new WeakReference(myTarget);
StartMyTaskAsync(someAction, ((MyTargetClass)wr.Target).SomeCompletedFunc);
The problem comes from this line:
StartMyTaskAsync(someAction, ((MyTargetClass)wr.Target).SomeCompletedFunc);
Specifically, this part:
((MyTargetClass)wr.Target).SomeCompletedFunc
You are materializing the target of the WeakReference to get the method that is referenced by the lambda/delegate long before you want to actually check whether or not the WeakReference has let go of the Target.
What you really want to do is pass a wrapper for your delegate, something like this (you didn't show the signature of SomeCompletedFunc so I don't know exactly what the call will be like, I'm assuming it's a parameterless void method for the purposes of this question):
StartMyTaskAsync(someAction, () => {
// Check the weak reference. If null, return.
var target = wr.Target as MyTargetClass;
// If null, return.
if (target == null) return;
// If not null, call.
target.SomeCompletedFunc();
});
This way, you check the Target of the WeakReference at the time you want to make the method call, and not when you assign the callback.

Ending asynchronous delegate invocation with partial type information

When writing async method implementations using the BeginInvoke/EndInvoke pattern the code might look something like the following (and to save you guessing this is an async wrapper around a cache):
IAsyncResult BeginPut(string key, object value)
{
Action<string, object> put = this.cache.Put;
return put.BeginInvoke(key, value, null, null);
}
void EndPut(IAsyncResult asyncResult)
{
var put = (Action<string, object>)((AsyncResult)asyncResult).AsyncDelegate;
put.EndInvoke(asyncResult);
}
This works perfectly well because it's known what the type of delegate is, so it can be cast. However it starts to get messy when you have two Put methods, because although the method returns void you seemingly have to cast it to a strongly typed delegate to end the invocation, e.g.
IAsyncResult BeginPut(string key, object value)
{
Action<string, object> put = this.cache.Put;
return put.BeginInvoke(key, value, null, null);
}
IAsyncResult BeginPut(string region, string key, object value)
{
Action<string, string, object> put = this.cache.Put;
return put.BeginInvoke(region, key, value, null, null);
}
void EndPut(IAsyncResult asyncResult)
{
var put = ((AsyncResult)asyncResult).AsyncDelegate;
var put1 = put as Action<string, object>;
if (put1 != null)
{
put1.EndInvoke(asyncResult);
return;
}
var put2 = put as Action<string, string, object>;
if (put2 != null)
{
put2.EndInvoke(asyncResult);
return;
}
throw new ArgumentException("Invalid async result", "asyncResult");
}
I'm hoping there is a cleaner way to do this, because the only thing I care about the delegate is the return type (in this case void) and not the arguments that were supplied to it. But I've racked my brains and asked others in the office, and nobody can think of the answer.
I know one solution is to write a custom IAsyncResult, but that's such a difficult task with the potential threading issues around things like lazy instantiation of the WaitHandle that I'd rather have this slightly hacky looking code than go down that route.
Any ideas on how to end the invocation without a cascading set of is checks?
I was wrong, there is a cleaner way.
You create Action( IAsyncResult ) delegates for the specific EndInvoke() method in the same context where you already know the specific type of the delegate, passing it as the AsyncState. I'm passing EndPut() as the callback for convenience.
IAsyncResult BeginPut( string key, object value ) {
Action<string, object> put = this.Put;
return put.BeginInvoke( key, value, EndPut,
new Action<IAsyncResult>( put.EndInvoke ) );
}
IAsyncResult BeginPut( string region, string key, object value ) {
Action<string, string, object> put = this.Put;
return put.BeginInvoke( region, key, value, EndPut,
new Action<IAsyncResult>( put.EndInvoke ) );
}
And then you finish it off.
void EndPut( IAsyncResult asyncResult ) {
var del = asyncResult.AsyncState as Action<IAsyncResult>;
del( asyncResult );
}
Why not avoid the problem by just going back to the more general overload:
IAsyncResult BeginPut(string key, object value) {
return this.BeginPut(null, key, value);
}
IAsyncResult BeginPut(string region, string key, object value) {
Action<string, string, object> put = this.Put;
return put.BeginInvoke(region, key, value, null, null);
}
void EndPut(IAsyncResult asyncResult) {
var put = (Action<string, string, object>)((AsyncResult)asyncResult).AsyncDelegate;
put.EndInvoke(asyncResult);
}
Edit: Please see my other answer. It can be cleaner.
I don't think there is a way to make this cleaner. You essentially made this inevitable by using the same EndPut method to end more than one type of async call. You could just as well be following the normal pattern by passing EndPut and the put delegate as the last two parameters to BeginInvoke() (callback and asyncstate), and you would still have to test what type the delegate is in order call EndInvoke().
Casting them to Delegate doesn't help at all.
I like Mark Brackett's idea. I think it comes down to these options:
Join them completely by having one overload call another. One delegate, one callback.
Separate them completely by having two callbacks for calling EndInvoke().
Aside from those, the only thing is to make your code just a little cleaner and use a switch or lookup dictionary using asyncResult.AsyncState.GetType(), passing the put delegate as that state object.

Categories