Need help controlling event handler synchronously in c# - c#

I have a code snippet as below:
public void PopulateItemList()
{
foreach(var item in collection)
{
bool isSuccess = GetSubItem(item.Id);
if(!isSuccess)
{
ShowError();
break;
}
}
}
public bool GetSubItem(string parentId)
{
bool isSuccess = false;
_service.Communication<ViewModel, Request, Response>((ViewModel vm, ref Request) =>
{
request.ApiName = Const.FXXXName;
request.Id = parentId;
}, (viewModel, response, error) =>
{
DoSomething();
...
isSuccess = response.IsOk; // I put a breakpoint here
}
return isSuccess; // I also put a breakpoint here
}
The prototype of Communication function is as below:
public void Communication<VM, S, R>(WebSocketOut<VM, S) send, WebSocketIn<VM, R> recv)
where is WebSocketIn and WebSocketOut are two delegates. The problem is when I debug the program, the "return isSuccess;" statement is always run before it receive the result from "response.IsOk" so the returned value of that func is always "false". In other words, the order of execution is:
return isSuccess
isSuccess = response.IsOk (after MessageReceived(WebSocket4Net) event fired)
I don't know how to make it run in reversed order. Any advice, recommendations or help will be greatly appreciated.
Thanks

You can use async/await and TaskCompletionSource
async public void PopulateItemList() //!!async keyword
{
foreach(var item in collection)
{
bool isSuccess = await GetSubItem(item.Id); //!!await
if(!isSuccess)
{
ShowError();
break;
}
}
}
public Task<bool> GetSubItem(string parentId)
{
var tcs = new TaskCompletionSource<bool>(); //!!
_service.Communication<ViewModel, Request, Response>((ViewModel vm, ref Request) =>
{
request.ApiName = Const.FXXXName;
request.Id = parentId;
}, (viewModel, response, error) =>
{
DoSomething();
...
tcs.SetResult(response.IsOk); //!!
}
return tcs.Task;
}

Try to use AutoResetEvent to wait async function complete.
public bool GetSubItem(string parentId)
{
System.Threading.AutoResetEvent autoEvent = new System.Threading.AutoResetEvent(false);
bool isSuccess = false;
ThreadPool.QueueUserWorkItem((o) =>
{
_service.Communication<ViewModel, Request, Response>((ViewModel vm, ref Request) =>
{
request.ApiName = Const.FXXXName;
request.Id = parentId;
}, (viewModel, response, error) =>
{
DoSomething();
...
isSuccess = response.IsOk; // I put a breakpoint here
autoEvent.Set();
}
});
autoEvent.WaitOne();
return isSuccess; // I also put a breakpoint here
}

Related

How can I return especific value of a static method in my the method that I am testing?

Here is the method that I am going to test and I want IsPhoneNomValid() would return false so then I would be able to assert my expectations:
public async Task<UserResponseDto> RegisterUser(RegistrationRequestDto register, CancellationToken cancelationToken)
{
// I want the IsPhoneNomValid() method, Would return "FALSE"
var isPhoneNumberValid = register.PhoneNumber.IsPhoneNomValid();
if (!isPhoneNumberValid)
return new UserResponseDto
{
Status = new StatusMaker().ErrorStatus("Some Error Message")
};
var isActiveAccountPhoneNumberExists = await IsActiveAccountPhoneNumberExist(register.PhoneNumber, cancelationToken);
if (isActiveAccountPhoneNumberExists.Status == "error")
return new UserResponseDto
{
Status = isActiveAccountPhoneNumberExists
};
}
RegisterUser_MustReturnPhoneNumberError is my Test method:
public class AccountUserTests
{
private Mock<IUserService> _userService { get; set; }
public AccountUserTests()
{
_userService = new Mock<IUserService>();
}
public async Task RegisterUser_MustReturnPhoneNumberError()
{
//Arrang
// in here I want to setup IsPhoneNomValid() would return false.
//Act
//Assert
}
}
Is there any way that I can test the static methods which are used in my main function which I am testing ?
Here is the IsPhoneNomValid() codes:
public static class Validation
{
public static bool IsPhoneNomValid(this string phoneNumber)
{
//TODO Does it need to be foreign phone numbers ?
var isMatch = Regex.Match(phoneNumber, #"^09[0-9]{9}$");
if (isMatch.Success)
return true;
return false;
}
}
You want to test your static method IsPhoneNomValid.
[Theory]
[InlineData("123456789")]
public void TestMethod(string phoneNumber)
{
bool isPhoneNumber =Validation.IsPhoneNomValid(phoneNumber);
Assert.True(isPhoneNumber);
}
With InlineData, you can test with multiple phone numbers.
The best option is to use a really invalid phone number in your case. But I have a lib SMock that can do what you want. Here is an example of usage:
public async Task RegisterUser_MustReturnPhoneNumberError()
{
Mock.Setup(context => Validation.IsPhoneNomValid(context.It.IsAny<string>()), async () =>
{
// You must test RegisterUser method in this scope
// Here Validation.IsPhoneNomValid will always return false
var result = await RegisterUser(register, ct);
Assert.AreEqual(expectedStatus, result.Status);
}).Returns(false);
}

I can't Task async and return bool

Is there any way to convert the Task to a Task async or something similar?
I'm testing code, in short learning to perform different functions of Task type and learn to use its correct operation, however I have not been able to solve this "problem", so I want to ask people who have more knowledge about the Tasks.
Task<bool>.Factory.StartNew(() => {}); -> Task<bool>.Factory.StartNew(async () => {});
Here is a summary of what I want to do
private bool completed = false;
void Tester()
{
completed = false;
int iteration = 0;
var log = new Logger();
log.Log(Logger.Level.Debug, "Starting");
try
{
var theTask = Task<bool>.Factory.StartNew( () =>
{
while (!completed)
{
log.Log(Logger.Level.Debug, "Waiting",1);
iteration++;
Thread.Sleep(400);
if (iteration>20)
{
completed = true;
return true;
}
}
return false;
}).Result;
}
catch (Exception e)
{
log.Log(Logger.Level.Error, e.ToString());
}
finally
{
log.Log(Logger.Level.Info, "Completed");
}
}
You can do it. You can see this video to understand async/await pattern: https://www.youtube.com/watch?v=il9gl8MH17s.
Try this:
class Program
{
static async Task Main(string[] args)
{
bool result = await Tester();
System.Diagnostics.Debug.WriteLine($"result: {result}");
}
private static bool completed = false;
static async Task<bool> Tester()
{
completed = false;
int iteration = 0;
//var log = new Logger();
//log.Log(Logger.Level.Debug, "Starting");
try
{
await Task.Factory.StartNew(() =>
{
while (!completed)
{
//log.Log(Logger.Level.Debug, "Waiting", 1);
iteration++;
System.Diagnostics.Debug.WriteLine($"iteration {iteration}");
Task.Delay(2000);
if (iteration > 20)
{
completed = true;
}
}
});
}
catch (Exception e)
{
//log.Log(Logger.Level.Error, e.ToString());
}
finally
{
//log.Log(Logger.Level.Info, "Completed");
}
return completed;
}
}

How to put async method in a list and invoke them iteratively?

Recently I want to implement a health check for a list of service calls. They are all async task (e.g. Task<IHttpOperationResponse<XXX_Model>> method_name(...)
I would like to put all of them into a list. I followed the answer of this post: Storing a list of methods in C# However, they are async methods.
I put it like this:
a collection of async method
List<Action> _functions = new List<Action> {
() => accountDetailsServiceProvider.GetEmployer(EmployerId),
() => accountServiceProvider.GetAccountStatus(EmployerId)
}
Can someone direct me to the right way to implement putting async methods in to a list and invoke them iteratively?
Thanks in advance!
First, you need to make your methods async. That means they must return a Task. For example:
public static async Task Foo()
{
await Task.Delay(1);
Console.WriteLine("Foo!");
}
public static async Task Bar()
{
await Task.Delay(1);
Console.WriteLine("Bar!");
}
Then to put them in a list, you must define the list as containing the right type. Since an async method actually returns something, it's a Func, not an action. It returns a Task.
var actions = new List<Func<Task>>
{
Foo, Bar
};
To invoke them, Select over the list (using Linq) to invoke them. This creates a list of Tasks in place of the list of Funcs.
var tasks = actions.Select( x => x() );
Then just await them:
await Task.WhenAll(tasks);
Full example:
public static async Task MainAsync()
{
var actions = new List<Func<Task>>
{
Foo, Bar
};
var tasks = actions.Select( x => x() );
await Task.WhenAll(tasks);
}
Output:
Foo!
Bar!
Example on DotNetFiddle
If your methods return a Boolean value, then the return type becomes Task<bool> and the rest follows suit:
public static async Task<bool> Foo()
{
await Task.Delay(1);
Console.WriteLine("Foo!");
return true;
}
public static async Task<bool> Bar()
{
await Task.Delay(1);
Console.WriteLine("Bar!");
return true;
}
var actions = new List<Func<Task<bool>>>
{
Foo, Bar
};
var tasks = actions.Select( x => x() );
await Task.WhenAll(tasks);
After you have awaited them, you can convert the tasks to their results with one more LINQ statement:
List<bool> results = tasks.Select( task => task.Result ).ToList();
I think you are just looking for something simple like this?
var myList = new List<Action>()
{
async() => { await Foo.GetBarAsync(); },
...
};
I would recommend you to change the type from Action to Func<Task> like so instead.
var myList = new List<Func<Task>>()
{
async() => { await Foo.GetBarAsync(); },
};
You can read more about why here: https://blogs.msdn.microsoft.com/pfxteam/2012/02/08/potential-pitfalls-to-avoid-when-passing-around-async-lambdas/
To invoke (simplified)
foreach (var action in myList)
{
await action.Invoke();
}
Based on the comments:
However, my task requires a boolean value for each method call,
because I have to report the status to the frontend whether the
service is down or not
Create a wrapper method for the method which will return required boolean value
public async Task<Result> Check(string name, Func<Task> execute)
{
try
{
await execute();
return new Result(name, true, string.Empty);
}
catch (Exception ex)
{
return new Result(name, false, ex.Message);
}
}
public class Result
{
public string Name { get; }
public bool Success { get; }
public string Message { get; }
public Result(string name, bool success, string message)
=> (Name, Success, Message) = (name, success, message);
}
Then you don't need to have collection of delegates, instead you will have collection of Task.
var tasks = new[]
{
Check(nameof(details.GetEmployer), () => details.GetEmployer(Id)),
Check(nameof(accounts.GetAccountStatus), () => accounts.GetAccountStatus(Id)),
};
var completed = await Task.WhenAll(tasks);
foreach (var task in completed)
{
Console.WriteLine($"Task: {task.Name}, Success: {task.Success};");
}

can a method with return type as list be called from a thread

I have a method, shown below, which calls a service.
How can I run this method through thread?
public List<AccessDetails> GetAccessListOfMirror(string mirrorId,string server)
{
List<AccessDetails> accessOfMirror = new List<AccessDetails>();
string loginUserId = SessionManager.Session.Current.LoggedInUserName;
string userPassword = SessionManager.Session.Current.Password;
using (Service1Client client = new Service1Client())
{
client.Open();
accessOfMirror = client.GetMirrorList1(mirrorId, server, null);
}
return accessOfMirror;
}
In C# 3.5 or 4.0 you can do this.
var task = Task.Factory.StartNew<List<AccessDetails>>(() => GetAccessListOfMirror(mirrorId,server))
.ContinueWith(tsk => ProcessResult(tsk));
private void ProcessResult(Task task)
{
var result = task.Result;
}
In C# 4.5 there's the await/async keywords which is some sugar for above
public async Task<List<AccessDetails>> GetAccessListOfMirror(string mirrorId,string server)
var myResult = await GetAccessListOfMirror(mirrorId, server)
Try something like this:
public async Task<List<AccessDetails>> GetAccessListOfMirror(string mirrorId, string server)
{
List<AccessDetails> accessOfMirror = new List<AccessDetails>();
string loginUserId = SessionManager.Session.Current.LoggedInUserName;
string userPassword = SessionManager.Session.Current.Password;
using (Service1Client client = new Service1Client())
{
client.Open();
Task<List<AccessDetails>> Detail = client.GetMirrorList1(mirrorId, server, null);
accessOfMirror = await Detail;
}
return accessOfMirror;
}
Below is a helper class I use, it references RX.NET.
If you include that in your project, then you can thread stuff very simply - the code above you could spin off to a separate thread as follows:
int mirrorId = 0;
string server = "xxx";
ASync.Run<List<AccessDetails>>(GetAccessListOfMirror(mirrorId,server), resultList => {
foreach(var accessDetail in resultList)
{
// do stuff with result
}
}, error => { // if error occured on other thread, handle exception here });
Worth noting: that lambda expression is merged back to the original calling thread - which is very handy if you're initiating your async operations from a GUI thread for example.
It also has another very handy method: Fork lets you spin off multiple worker threads and causes the calling thread to block until all the sub-threads are either complete or errored.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Concurrency;
namespace MyProject
{
public static class ASync
{
public static void ThrowAway(Action todo)
{
ThrowAway(todo, null);
}
public static void ThrowAway(Action todo, Action<Exception> onException)
{
if (todo == null)
return;
Run<bool>(() =>
{
todo();
return true;
}, null, onException);
}
public static bool Fork(Action<Exception> onError, params Action[] toDo)
{
bool errors = false;
var fork = Observable.ForkJoin(toDo.Select(t => Observable.Start(t).Materialize()));
foreach (var x in fork.First())
if (x.Kind == NotificationKind.OnError)
{
if(onError != null)
onError(x.Exception);
errors = true;
}
return !errors;
}
public static bool Fork<T>(Action<Exception> onError, IEnumerable<T> args, Action<T> perArg)
{
bool errors = false;
var fork = Observable.ForkJoin(args.Select(arg => Observable.Start(() => { perArg(arg); }).Materialize()));
foreach (var x in fork.First())
if (x.Kind == NotificationKind.OnError)
{
if (onError != null)
onError(x.Exception);
errors = true;
}
return !errors;
}
public static void Run<TResult>(Func<TResult> todo, Action<TResult> continuation, Action<Exception> onException)
{
bool errored = false;
IDisposable subscription = null;
var toCall = Observable.ToAsync<TResult>(todo);
var observable =
Observable.CreateWithDisposable<TResult>(o => toCall().Subscribe(o)).ObserveOn(Scheduler.Dispatcher).Catch(
(Exception err) =>
{
errored = true;
if (onException != null)
onException(err);
return Observable.Never<TResult>();
}).Finally(
() =>
{
if (subscription != null)
subscription.Dispose();
});
subscription = observable.Subscribe((TResult result) =>
{
if (!errored && continuation != null)
{
try
{
continuation(result);
}
catch (Exception e)
{
if (onException != null)
onException(e);
}
}
});
}
}
}

how to return Action<bool> inside method?

I have the following code in my class:
private static void SetUserMeta(string pUserToken, string pMetaKey, string pMetaValue, Action<bool> callback)
{
BuddyClient client = CreateBuddy();
bool rValue = false;
client.LoginAsync((user, state) =>
{
if (state.Exception != null)
{
rValue = false;
}
else
{
client.Metadata.SetAsync((result, resultState) =>
{
if (resultState.Exception != null)
{
rValue = false;
}
else
{
rValue = true;
}
}, key: pMetaKey, value: pMetaValue);
}
callback(rValue);
}, token: pUserToken);
}
and I want to get rValue and return it from my other method which is the following
public static void SetBuddyData(string pUserToken, BuddyData pMetaValue, Action<bool> callback)
{
//my problem is here and I don't know how to get and return data from SetUserMeta
return SetUserMeta(pUserToken, "SavedGameData", pMetaValue.Serialize());
}
And also I want to call this return value from my application. These codes are in my library. How can I do it?
Just pass callback to SetUserMeta like
public static void SetBuddyData(string pUserToken, BuddyData pMetaValue, Action<bool> callback)
{
SetUserMeta(pUserToken, "SavedGameData", callback);
}
And call SetBuddyData like this
SetBuddyData("my user token", myBundle, isLoggedIn => HandleUserLogin(isLoggedIn));
Where at HandleUserLogin you will process bool callback data, returned at callback(rValue); in SetUserMeta method. It's body example is shown
next
public static void HandleUserLogin(bool isLogged)
{
Console.WriteLine("user is {0} logged in", isLogged ? "" : "not");
}
You also can take advantage of method group syntax and call SetBuddyData method like:
SetBuddyData("my user token", myBundle, HandleUserLogin);

Categories

Resources