I am developing a windows service that contains the FileSystemWatcher. Once file creates, I have to make some network calls to a web API.
Please look at below code lines.
watcher.Created += new FileSystemEventHandler((object source, FileSystemEventArgs e) => { ProcessCreateEvent(e); });
Event handler
private async void ProcessCreateEvent(FileSystemEventArgs e){
// make some network calls and do certain tasks
// network calls doing asynchronously
}
I did in deep about the FileSystemWatcher and I understand that it is not the good practice to handle the network call in ProcessCreateEvent method. So how can I allocate the separate thread for each file change?
Events already support async, so you can just do something like:
watcher.Created += this.ProcessCreateEvent;
private async void ProcessCreateEvent(object sender, FileSystemEventArgs e)
{
var result = await asyncApi.GetStuffAsync();
}
You don't need to spin up another Task unless the non-async stuff you are doing in the event handler is expensive.
I think it can simply be done by making ProcessCreateEvent asynchronous like this:
private async Task ProcessCreateEvent(FileSystemEventArgs e)
{
// make some network calls and do certain tasks
// network calls doing asynchronously
await Task.Run(async () => {
var client = new HttpClient();
var response = await client.GetAsync("http://localhost:54522/api/values");
var result = await response.Content.ReadAsStringAsync();
});
}
Related
I've been trying to make a function run asynchronously to prevent the window from freezing everytime it pings a new address but when I tried to implement it, VS said that I can't use the await operator as it's current state. Any suggestions?
public MainWindow()
{
//var reader = new Mp3FileReader(#"Resources\Audio\02 Connecting.flac");
MediaFoundationReader sound = new MediaFoundationReader(#"Resources\Audio\Connecting.mp3");
var waveOut = new WaveOut(); // or WaveOutEvent()
waveOut.Init(sound);
waveOut.Play();
InitializeComponent();
ContentRendered += (s, e) => { await Connecting(); };
}
private async Task Connecting()
{
AutoResetEvent waiter = new AutoResetEvent(false);
IPAddress ip = IPAddress.Parse("23.185.0.1");
var pingSender = new Ping();
pingSender.PingCompleted += PingCompletedCallback;
pingSender.SendAsync(ip, 1000, waiter);
}
The issue is that you're trying to use await in a synchronous delegate:
ContentRendered += (s, e) => { await Connecting(); };
To use the await keyword, you'll need an asynchronous delegate defined, to then add it to the event.
This should work - note the async keyword which enables the use of the await keyword:
ContentRendered += async (s, e) => { await Connecting(); };
You should also await the asynchronous pingSender.SendAsync method:
await pingSender.SendAsync(ip, 1000, waiter);
Unless you are using the Connecting asynchronous method in more than one places, it is probably preferable from a maintainability point of view to attach a classic event handler to the ContentRendered event:
ContentRendered += ContentRenderedHandler;
//...
private async void ContentRenderedHandler(object sender, EventArgs e)
{
IPAddress ip = IPAddress.Parse("23.185.0.1");
var pingSender = new Ping();
PingReply pingReply = await pingSender.SendPingAsync(ip, 1000);
// Use the `pingReply` here
}
This is essentially the same with what Ermiya Eskandary suggests in their answer, with the only difference being that the presence on an async void method is visible and explicit. The use of async void here is correct, because the method is an event handler. It's a good idea to be explicit though, because async void methods are too often misused, resulting in unexpected behavior, or compiler warnings, or both.
Update: Your code makes use of the anachronistic PingCompleted + SendAsync approach. The Ping class offers the newer SendPingAsync API (.NET Framework 4.5 and later), that can be consumed directly with async-await.
I have a thread and want to update a list with the progress, but form control arent thread safe. So I learn how solve with this article.
The problem is there are many more sources and each source have his own list to display the progress. So how I make every listbox has his own ThreadSafeSetText() method to clean the code?
delegate void SetTextCallback(string text);
private async void btnRun_Click(object sender, EventArgs e)
{
await Task.Run(() =>
{
importSource1();
});
//await Task.Run(() =>
//{
// importSource2();
//});
}
private void importSource1()
{
// db stuff in a Parallel.For
SetText("Result");
}
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.lstImportSource1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.lstImportSource1.Items.Insert(0, text);
}
}
Based on the comment that ImportSource is a method which executes database procedures, my suggestion use async-await aproach.
Async-await was designed for more effective resource usage when your code executes operations which "touches" external resources (database, file system, web api etc).
Because during execution of database query(for example) your method "do nothing", it only send request and wait for the response. Creating new thread which "do nothing" considered as wasting resources.
With async-await operation will be executed on one thread(most of the time) where you can simply use UI controls.
You can create own asynchronous method for every procedure
public async Task ExecuteProcedure1Async()
{
using (var connection = new SqlConnection("connection string"))
using (var command = new SqlCommand("dbo.sqlProcedure1", connection))
{
command.CommandType = CommandType.StoredProcedure;
// Here execution will send request to the database
// and be returned to the caller of this method
await connection.OpenAsync();
// Continue after OpenAsync is completes and
// Here execution will again will be returned to the caller
await command.ExecuteCommandAsync();
// Continues after ExecuteCommandAsync is completed
}
}
Similar methods can be created for another stored procedures
Below all procedures will executes "almost" simultaneously.
Because we will send requests without waiting for responses
and wait only when all procedures completes
private async Task ImportSource1Async()
{
// Because asynchronoud method returns Task
// We can create collection of tasks and "await" them all
// after they have been started
var tasks = new[]
{
ExecuteProcedure1Async(),
ExecuteProcedure2Async(),
ExecuteProcedure3Async()
};
await Task.WhenAll(tasks);
}
Then you can combine all ImportSourceAsync methods together in the button_click eventhandler and use UI controls.
private async void btnRun_Click(object sender, EventArgs e)
{
await ImportSource1Async();
lstImportSource1.Items.Insert(0, "Import source 1 complete");
await ImportSource2Async();
lstImportSource1.Items.Insert(0, "Import source 2 complete");
await ImportSource3Async();
lstImportSource1.Items.Insert(0, "Import source 3 complete");
}
I want to use TaskCompletionSource to wrap MyService which is a simple service:
public static Task<string> ProcessAsync(MyService service, int parameter)
{
var tcs = new TaskCompletionSource<string>();
//Every time ProccessAsync is called this assigns to Completed!
service.Completed += (sender, e)=>{ tcs.SetResult(e.Result); };
service.RunAsync(parameter);
return tcs.Task;
}
This code is working well for the first time. But the second time I call ProcessAsync simply the event handler for the Completed is assign again (the same service variable is used every time) and thus it will execute twice! and the second time it throws this exception:
attempt transition task final state when already completed
I'm not sure, should I declare the tcs as a class level variable like this:
TaskCompletionSource<string> tcs;
public static Task<string> ProccessAsync(MyService service, int parameter)
{
tcs = new TaskCompletionSource<string>();
service.Completed -= completedHandler;
service.Completed += completedHandler;
return tcs.Task;
}
private void completedHandler(object sender, CustomEventArg e)
{
tcs.SetResult(e.Result);
}
I have to wrap many methods with different return types and this way I have to write lost of code, variables, event handlers so I'm not sure if this is the best practice in this scenarios. So is there any better way of doing this job?
The issue here is that the Completed event is raised on each action but the TaskCompletionSource can only be completed once.
You can still use a local TaskCompletionSource (and you should). You just need to unregister the callback before completing the TaskCompletionSource. That way this specific callback with this specific TaskCompletionSource will never be called again:
public static Task<string> ProcessAsync(MyService service, int parameter)
{
var tcs = new TaskCompletionSource<string>();
EventHandler<CustomEventArg> callback = null;
callback = (sender, e) =>
{
service.Completed -= callback;
tcs.SetResult(e.Result);
};
service.Completed += callback;
service.RunAsync(parameter);
return tcs.Task;
}
This will also solve the possible memory leak that you have when your service keeps references to all these delegates.
You should keep in mind though that you can't have multiple of these operations running concurrently. At least not unless you have a way to match requests and responses.
It appears that MyService will raise the Completed event more than once. this causes SetResult to be called more than once which causes your error.
You have 3 options that I see. Change the Completed event to only be raised once (Seems odd that you can complete more than once), change SetResult to TrySetResult so it does not throw a exception when you try to set it a 2nd time (this does introduce a small memory leak as the event still gets called and the completion source still tries to be set), or unsubscribe from the event (i3arnon's answer)
An alternative solution to i3arnon's answer would be:
public async static Task<string> ProcessAsync(MyService service, int parameter)
{
var tcs = new TaskCompletionSource<string>();
EventHandler<CustomEventArg> callback =
(s, e) => tcs.SetResult(e.Result);
try
{
contacts.Completed += callback;
contacts.RunAsync(parameter);
return await tcs.Task;
}
finally
{
contacts.Completed -= callback;
}
}
However, this solution will have a compiler generated state machine. It will use more memory and CPU.
I have a web request (HttpRequest) which triggers a third library scanning method on my server that has an event handler attached to it:
scanner.OnScanComplete += scanner_OnScanComplete;
The web request will invoke scanner.Scan(files) but how can I force (or hook) the request to wait and get the results from scanner_OnScanComplete when the scan process is complete so it can return data to clients without having to send another web request to get this data?
void DoWork(HttpRequst request, var files)
{
var scanner = new Scanner()
scanner.OnScanComplete += scanner_OnScanComplete;
scan(files)
}
void scanner_OnScanComplete(object sender, EventArgs e)
{
var scanCompleted = true;
//Return scanCompleted somehow to the DoWork thread above
}
Do you have to use a HttpHandler or can you use other api's?
If you can use MVC4 or later then you can use an asynchronous Action Method to do this easily. Look here for an example of how to use them.
In addition to using an async Action Method you may need a way to await the event from the scanner. Using a Task Completion source as in this answer may be a good way to do that.
One way to do what you want is to store the completion of the task in a boolean member.
The boolean shall be marked volatile to avoid threading issues.
The risk of the approach is to lead to timeouts on client side if the scan processing is too long.
private volatile bool _finished;
void DoWork(HttpRequst request, var files)
{
var scanner = new Scanner();
scanner.OnScanComplete += scanner_OnScanComplete;
_finished= false;
scan(files)
while (!_finished) // wait for the scan completion
System.Threading.Thread.Sleep(1000); // avoid consuming 100% cpu
var scanData = Dothescanwork();
//Return scanData somehow to the DoWork thread above
}
void scanner_OnScanComplete(object sender, EventArgs e)
{
_finished= true;
}
I've been writing Windows Phone 8 code that calls a SOAP web service backend. From what I've read, the typical pattern is this:
var client = new KitchenPCSoapClient();
client.LogonCompleted += client_LogonCompleted;
client.LogonAsync(username, password);
To me, this just seems counter intuitive. If I call LogonAsync multiple times with the same client, I don't necessarily want it to use the same LogonCompleted callback every time.
What I'd like is a pattern more like JavaScript, where you pass in a reference to the callback function. More like:
var client = new KitchenPCSoapClient();
client.LogonAsync(username, password, client_LogonCompleted);
Is there a way to implement such a pattern, or should I just force myself to get used to setting the LogonCompleted property before I call LogonAsync, or set the userState property if I want to differentiate between different contexts?
You can make use of Dispatcher and call the function on UI side for this ...
I am doing like this
callback function
private void AddPricesHandler(CompletedEventArgs response, Exception e)
{
//your code gose here
}
Call proxy calss function
Proxy.AddData(AddPricesHandler, request);
proxy class calling webservice
public void AddData(Action<CompletedEventArgs, Exception> callback, IPVWorkflowService.CreateEditDeletePriceSourceRequest request)
{
_workflowProxy.CreateEditDeletePriceSourceAsync(request, callback);
_workflowProxy.CreateEditDeletePriceSourceCompleted+=new EventHandler<CreateEditDeletePriceSourceCompletedEventArgs>(_workflowProxy_CreateEditDeletePriceSourceCompleted);
}
completer function use dispatcher to call callback function
void _workflowProxy_CreateEditDeletePriceSourceCompleted(object sender, CreateEditDeletePriceSourceCompletedEventArgs e)
{
try
{
this.dispatcher.BeginInvoke((Action)(() =>
{
(e.UserState as Action<CompletedEventArgs, Exception>)(e, null);
}));
}
catch (Exception ex)
{
this.dispatcher.BeginInvoke((Action)(() =>
{
(e.UserState as Action<CompletedEventArgs, Exception>)(e, ex);
}));
}
finally
{
_workflowProxy.CreateEditDeletePriceSourceCompleted -= _workflowProxy_CreateEditDeletePriceSourceCompleted;
_workflowProxy = null;
}
}
The beauty of Async/Await is that you don't have to write callbacks, you just write code that looks like synchronous, but in the background it's executed asynchronously:
var client = new KitchenPCSoapClient();
await client.LogonAsync(username, password);
// you get here after the async logon is completed
// do stuff after logon
But if you really want to use callbacks, you can just use the method ContinueWith on the Task object, that is returned from asynchronous method:
var client = new KitchenPCSoapClient();
Task task = client.LogonAsync(username, password);
// this method is called when async execution of task is finished
task.ContinueWith(client_LogonCompleted);