Action.Invoke on an instanced class? - c#

Basically what I'm doing is I'm creating a temporary buffer that writes data to a byte[] and then returns the size of the buffer; I'm then using this to attempt to de-segmentate my code over a network. (Trying to get my C# Client to work properly with Netty's FrameDecoder class)
Basically, I'm storing all of my Actions in a List to be called over the network once I find the buffer-size(Dynamic)
public void SendBuffer(DataOutputStream ClientOuput)
{
ClientOuput.WriteInt(GetBufferSize());
foreach (Action a in executionList)
{
// What Do?
}
}
My problem is I need to Invoke the method inside of the DataOutputStream that's passed through the SendBuffer parameters, so something like
ClientOutput.a.invoke();
What's the best way to do this?

It's not that clear what you are asking but I try to answer anyway. So you have bunch of actions (defined somewhere) that you want to be executed by instance of DataOutputStream? Then you could do something like:
public async void SendBuffer(DataOutputStream clientOuput)
{
var executionList = new List<Action>()
{
() => { Debug.WriteLine("whatyousay"); Thread.Sleep(1500); },
() => { Debug.WriteLine("allyourbase"); Thread.Sleep(1500); },
};
clientOuput.WriteInt(1);
foreach (Action action in executionList)
await clientOuput.Execute(action);
Debug.WriteLine("arebelongtous");
}
Here DataOutputStream is just
public class DataOutputStream
{
// await and actions will be executed in given order, non-blocking
public Task Execute(Action action)
{
return Task.Run(action);
}
// fire & forget, non-blocking
public void BeginInvoke(Action action)
{
action.BeginInvoke(callback => {}, null);
}
// blocking
public void Invoke(Action action)
{
action.Invoke();
}
public void WriteInt(int integer)
{
Debug.WriteLine("int:{0}", integer);
}
}

Related

Generic Timer/Worker Function

I want to be able to perform workloads at intervals.
I want to be able to make this class generic so I can pass it whatever "workload" I want and my timer function just does it. I also would like a means of "returning" the workload response back to the caller.
As an example. Let's say I have a series of classes I have built that download data from a JSON API, or scrape a web page. This web scraper/API downloader needs to download pages from a site at different intervals. Each page will take a different number of parameters. I have found something online that indicates setting the Elapsed event to a delegate. This "may"work but I need to have the passed in delegate "dynamic" itself. So the Start method below which accepts a Func won't be correct from a "generic" standpoint, which is what I am after.
The solution itself is just an example of a line of thinking. Am open to other generic alternatives that help me achieve this.
public abstract class TimerWorkerDelegate : IDisposable, ITimerWorker
{
protected System.Timers.Timer DataTimer;
public virtual void Start(Func<string> callback,double interval)
{
DataTimer = new System.Timers.Timer();
DataTimer.Interval = interval;
DataTimer.Elapsed += delegate {
callback();
};
if (!DataTimer.Enabled)
DataTimer.Enabled = true;
//IDisposable code
}
}
I might not understand 100% what you are REALLY trying to achieve, but... maybe something like.
public class Worker<T>
{
public event EventHandler<T> OnCompleted;
public Worker()
{}
public Worker(Func<T> fn, int interval)
{
Func = fn;
Interval = interval;
}
public async void Start()
{
if (Func == null)
throw new ArgumentNullException();
while (true)
{
await Task.Delay(Interval);
try
{
var result = Func();
OnCompleted(this, result);
}
catch
{
return; // handle
}
}
}
public Func<T> Func { get; set; }
public int Interval { get; set; }
}
And then usage in Console tester app as
public static void Main(string[] args)
{
var worker = new Worker<string>
{
Interval = 1000,
Func = () => { return string.Format("did some work at {0}", DateTime.Now); }
};
worker.OnCompleted += (sender, result) => { Console.WriteLine(result); };
worker.Start();
Console.ReadLine();
}
If you're open to using a library you could look at System.Reactive
With it you could setup something very easily to accomplish what you are looking to do.
Below is a very rudimentary implementation of something that could work for you:
void Main()
{
var scheduled = Schedule(
TimeSpan.FromSeconds(1),
() => Console.WriteLine($"The current time is: {DateTime.Now}"));
Console.ReadLine();
// Dispose will stop the scheduled action
scheduled.Dispose();
}
public IDisposable Schedule<T>(TimeSpan interval, Func<T> func)
=> Observable.Interval(interval).Subscribe(_ => func());
public IDisposable Schedule(TimeSpan interval, Action action)
=> Observable.Interval(interval).Subscribe(_ => action());

Close task before run again

I working on real-time search. At this moment on property setter which is bounded to edit text, I call a method which calls API and then fills the list with the result it looks like this:
private string searchPhrase;
public string SearchPhrase
{
get => searchPhrase;
set
{
SetProperty(ref searchPhrase, value);
RunOnMainThread(SearchResult.Clear);
isAllFriends = false;
currentPage = 0;
RunInAsync(LoadData);
}
}
private async Task LoadData()
{
var response = await connectionRepository.GetConnections(currentPage,
pageSize, searchPhrase);
foreach (UserConnection uc in response)
{
if (uc.Type != UserConnection.TypeEnum.Awaiting)
{
RunOnMainThread(() =>
SearchResult.Add(new ConnectionUser(uc)));
}
}
}
But this way is totally useless because of it totally mashup list of a result if a text is entering quickly. So to prevent this I want to run this method async in a property but if a property is changed again I want to kill the previous Task and star it again. How can I achieve this?
Some informations from this thread:
create a CancellationTokenSource
var ctc = new CancellationTokenSource();
create a method doing the async work
private static Task ExecuteLongCancellableMethod(CancellationToken token)
{
return Task.Run(() =>
{
token.ThrowIfCancellationRequested();
// more code here
// check again if this task is canceled
token.ThrowIfCancellationRequested();
// more code
}
}
It is important to have this checks for cancel in the code.
Execute the function:
var cancellable = ExecuteLongCancellableMethod(ctc.Token);
To stop the long running execution use
ctc.Cancel();
For further details please consult the linked thread.
This question can be answered in many different ways. However IMO I would look at creating a class that
Delays itself automatically for X (ms) before performing the seach
Has the ability to be cancelled at any time as the search request changes.
Realistically this will change your code design, and should encapsulate the logic for both 1 & 2 in a separate class.
My initial thoughts are (and none of this is tested and mostly pseudo code).
class ConnectionSearch
{
public ConnectionSearch(string phrase, Action<object> addAction)
{
_searchPhrase = phrase;
_addAction = addAction;
_cancelSource = new CancellationTokenSource();
}
readonly string _searchPhrase = null;
readonly Action<object> _addAction;
readonly CancellationTokenSource _cancelSource;
public void Cancel()
{
_cancelSource?.Cancel();
}
public async void PerformSearch()
{
await Task.Delay(300); //await 300ms between keystrokes
if (_cancelSource.IsCancellationRequested)
return;
//continue your code keep checking for
//loop your dataset
//call _addAction?.Invoke(uc);
}
}
This is basic, really just encapsulates the logic for both points 1 & 2, you will need to adapt the code to do the search.
Next you could change your property to cancel a previous running instance, and then start another instance immediatly after something like below.
ConnectionSearch connectionSearch;
string searchPhrase;
public string SearchPhrase
{
get => searchPhrase;
set
{
//do your setter work
if(connectionSearch != null)
{
connectionSearch.Cancel();
}
connectionSearch = new ConnectionSearch(value, addConnectionUser);
connectionSearch.PerformSearch();
}
}
void addConnectionUser(object uc)
{
//pperform your add logic..
}
The code is pretty straight forward, however you will see in the setter is simply cancelling an existing request and then creating a new request. You could put some disposal cleanup logic in place but this should get you started.
You can implement some sort of debouncer which will encapsulate the logics of task result debouncing, i.e. it will assure if you run many tasks, then only the latest task result will be used:
public class TaskDebouncer<TResult>
{
public delegate void TaskDebouncerHandler(TResult result, object sender);
public event TaskDebouncerHandler OnCompleted;
public event TaskDebouncerHandler OnDebounced;
private Task _lastTask;
private object _lock = new object();
public void Run(Task<TResult> task)
{
lock (_lock)
{
_lastTask = task;
}
task.ContinueWith(t =>
{
if (t.IsFaulted)
throw t.Exception;
lock (_lock)
{
if (_lastTask == task)
{
OnCompleted?.Invoke(t.Result, this);
}
else
{
OnDebounced?.Invoke(t.Result, this);
}
}
});
}
public async Task WaitLast()
{
await _lastTask;
}
}
Then, you can just do:
private readonly TaskDebouncer<Connections[]> _connectionsDebouncer = new TaskDebouncer<Connections[]>();
public ClassName()
{
_connectionsDebouncer.OnCompleted += OnConnectionUpdate;
}
public void OnConnectionUpdate(Connections[] connections, object sender)
{
RunOnMainThread(SearchResult.Clear);
isAllFriends = false;
currentPage = 0;
foreach (var conn in connections)
RunOnMainThread(() => SearchResult.Add(new ConnectionUser(conn)));
}
private string searchPhrase;
public string SearchPhrase
{
get => searchPhrase;
set
{
SetProperty(ref searchPhrase, value);
_connectionsDebouncer.Add(RunInAsync(LoadData));
}
}
private async Task<Connection[]> LoadData()
{
return await connectionRepository
.GetConnections(currentPage, pageSize, searchPhrase)
.Where(conn => conn.Type != UserConnection.TypeEnum.Awaiting)
.ToArray();
}
It is not pretty clear what RunInAsync and RunOnMainThread methods are.
I guess, you don't actually need them.

MVVM + WCF Async callbacks

I have a WCF service (IMyService) that I wrap into a service (ICentralService), so that I have one central service that I can inject in my ViewModels. This would give me the advantage of changing/adding things at one location just before the WCF service is called.
Now because I need to make an async wcf call, my viewmodel also needs to be async. I'm have a callback from my viewmodel, but my CentralService also has its own callback to call the End... method.
Question: what is the best way to pass my viewmodel-callback to the EndTest method in the central service, so that this EndTest method could notify the callback on the viewmodel?
Or maybe there is a better way?
I could directly inject IMyService in my ViewModel but then I don't have a central location (CentralService) where I can manipulate/inject data before sending it to the server via WCF.
Note: I'm on .NET 4.0, can't use "await", I'm also using WCF IAsyncResult Model (server-side).
Code:
[ServiceContract(....)]
public interface IMyService {
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginTest(int x, AsyncCallback, object state);
int EndTest(IAsyncResult result);
}
public interface ICentralService {
void WorkItAsync(int x, AsyncCallback callback);
}
public class CentralService : ICentralService
{
private IMyService _Srv;
public CentralService(IMyService srv)
{
_Srv = srv;
}
public void WorkItAsync(int x, AsyncCallback callback)
{
// callback is the callback from my viewmodel
_Srv.BeginTest(x, new AsyncCallback(WorkItCompleted));
}
private void WorkItCompleted(IAsyncResult r)
{
// ...
int result = _Srv.EndTest(r);
// Need to call callback from viewmodel now to notify it is ready.
}
}
public class SomeViewModel : INotifyPropertyChanged
{
private ICentralService _Central;
public SomeViewModel(ICentralService central) {
_Central = central;
}
private void A() {
_Central.WorkItAsync(5, new AsyncCallback(B));
}
private void B(object test) {
// do something with the result
}
}
UPDATE:
I've managed to wrap my IMyService into my ICentralService and pass the result from WCF (IMyService) to my viewmodel via ICentralService.
First attempt/idea, but this did not return my "dataResult" value to my viewmodel:
public void WorkItAsync(int x, AsyncCallback callback)
{
var task = Task<int>.Factory.StartNew(() =>
{
int dataResult = -1;
_Srv.BeginTest(x, (ar) => {
dataResult = _Srv.EndTest(ar);
}, null);
return dataResult ;
});
if (callback != null)
task.ContinueWith((t) => callback(t));
return task;
}
Second attempt (works):
public void WorkItAsync(int x, AsyncCallback callback)
{
TaskCompletionSource<int> tcs1 = new TaskCompletionSource<int>();
Task<int> t1 = tcs1.Task;
Task<int>.Factory.StartNew(() =>
{
int dataResult = -1;
_Srv.BeginTest(x, (ar) => {
dataResult = _Srv.EndTest(ar);
tcs1.SetResult(dataResult);
}, null);
return dataResult;
});
if (callback != null)
t1.ContinueWith((t) => callback(t));
return t1;
}
I'm not sure if this is a good solution using the TaskCompletionSource, but for now it seems to works. (Too bad I have to return a useless -1 dataResult value).
The second update looks pretty good, but I think you can use TaskFactory.FromAsync to avoid the TaskCompletionSource for now. Here is a reference page for FromAsync with examples. I haven't tested this, but the method may look something like this:
public interface ICentralService
{
// Just use .ContinueWith to call a completion method
Task<int> WorkItAsync(int x);
}
public class CentralService : ICentralService
{
private IMyService _Srv;
public CentralService(IMyService srv)
{
_Srv = srv;
}
public Task<int> WorkItAsync(int x)
{
// Callback is handled in ViewModel using ContinueWith
return Task<int>.Factory.FromAsync(_Src.BeginTest, _Src.EndTest, x);
}
}
public class SomeViewModel : INotifyPropertyChanged
{
private ICentralService _Central;
public SomeViewModel(ICentralService central)
{
_Central = central;
}
private void A()
{
_Central.WorkItAsync(5)
.ContinueWith(prevTask =>
{
// Handle or throw exception - change as you see necessary
if (prevTask.Exception != null)
throw prevTask.Exception;
// Do something with the result, call another method, or return it...
return prevTask.Result;
});
}
}
You could use lambdas:
public void WorkItAsync(int x, AsyncCallback callback)
{
// callback is the callback from my viewmodel
_Srv.BeginTest(x, ar=>{
int result = _Srv.EndTest(ar);
callback(ar);
});
}
ar will be your IAsyncResult if needed. You could even run multiple requests in parallel, because the callback variable will be in local scope for each of the parallel calls.

SychronizationContext.Post usage

I have a producer/consumer pattern, where I need to inform the producer when the item has been consumed sucessfully. Basically a producer gives me an TransportTask an Action<TransportTask> to call when its ready. What I want to do is post it in the same SyncContext where it came from.
public class TaskProcessAgent : ITaskProcessAgent
{
private Dictionary<TransportTask, Tuple<Action<TransportTask>, SynchronizationContext>> m_tasks = new Dictionary<TransportTask, Tuple<Action<TransportTask>, SynchronizationContext>>();
private BlockingCollection<TransportTask> m_taskQueue = new BlockingCollection<TransportTask>();
private TaskCoordinator m_coordinator;
public TaskProcessAgent(TaskCoordinator coordinator)
{
m_coordinator = coordinator;
m_coordinator.OnTaskReady += OnTaskReady;
Task.Factory.StartNew(() =>
{
foreach (var _task in m_taskQueue.GetConsumingEnumerable())
ProcessTask(_task);
},
TaskCreationOptions.LongRunning);
}
public void Process(TransportTask task, Action<TransportTask> onReady)
{
lock (m_tasks)
{
m_tasks.Add(task, Tuple.Create(onReady, SynchronizationContext.Current ?? new SynchronizationContext()));
}
m_taskQueue.Add(task);
}
public void SetCompleted(TransportTask task)
{
m_coordinator.SetCompleted(task);
}
private void OnTaskReady(TransportTask task)
{
m_tasks[task].Item2.Post(p => m_tasks[task].Item1(task), null);
}
private void ProcessTask(TransportTask transportTask)
{
m_coordinator.AddTask(transportTask);
}
}
Here OnTaskReady will be called by TaskCoordinator from it's own thread. What I want is to call the callback from the same SychronizationContext which called Process.
I'm not sure it's going to work and I need to write a lot more code to get to a point where I can test whether it works. The crucial line is m_tasks[task].Item2.Post(p => m_tasks[task].Item1(task), null); and I'm not sure it works this way.

How to implement generic callbacks using the C# Task Parallel Library and IProducerConsumerCollection?

I have a component that submits requests to a web-based API, but these requests must be throttled so as not to contravene the API's data limits. This means that all requests must pass through a queue to control the rate at which they are submitted, but they can (and should) execute concurrently to achieve maximum throughput. Each request must return some data to the calling code at some point in the future when it completes.
I'm struggling to create a nice model to handle the return of data.
Using a BlockingCollection I can't just return a Task<TResult> from the Schedule method, because the enqueuing and dequeuing processes are at either ends of the buffer. So instead I create a RequestItem<TResult> type that contains a callback of the form Action<Task<TResult>>.
The idea is that once an item has been pulled from the queue the callback can be invoked with the started task, but I've lost the generic type parameters by that point and I'm left using reflection and all kinds of nastiness (if it's even possible).
For example:
public class RequestScheduler
{
private readonly BlockingCollection<IRequestItem> _queue = new BlockingCollection<IRequestItem>();
public RequestScheduler()
{
this.Start();
}
// This can't return Task<TResult>, so returns void.
// Instead RequestItem is generic but this poses problems when adding to the queue
public void Schedule<TResult>(RequestItem<TResult> request)
{
_queue.Add(request);
}
private void Start()
{
Task.Factory.StartNew(() =>
{
foreach (var item in _queue.GetConsumingEnumerable())
{
// I want to be able to use the original type parameters here
// is there a nice way without reflection?
// ProcessItem submits an HttpWebRequest
Task.Factory.StartNew(() => ProcessItem(item))
.ContinueWith(t => { item.Callback(t); });
}
});
}
public void Stop()
{
_queue.CompleteAdding();
}
}
public class RequestItem<TResult> : IRequestItem
{
public IOperation<TResult> Operation { get; set; }
public Action<Task<TResult>> Callback { get; set; }
}
How can I continue to buffer my requests but return a Task<TResult> to the client when the request is pulled from the buffer and submitted to the API?
First, you can return Task<TResult> from Schedule(), you just need to use TaskCompletionSource for that.
Second, to get around the genericity issue, you can hide all of it inside (non-generic) Actions. In Schedule(), create an action using a lambda that does exactly what you need. The consuming loop will then execute that action, it doesn't need to know what's inside.
Third, I don't understand why are you starting a new Task in each iteration of the loop. For one, it means you won't actually get any throttling.
With these modifications, the code could look like this:
public class RequestScheduler
{
private readonly BlockingCollection<Action> m_queue = new BlockingCollection<Action>();
public RequestScheduler()
{
this.Start();
}
private void Start()
{
Task.Factory.StartNew(() =>
{
foreach (var action in m_queue.GetConsumingEnumerable())
{
action();
}
}, TaskCreationOptions.LongRunning);
}
public Task<TResult> Schedule<TResult>(IOperation<TResult> operation)
{
var tcs = new TaskCompletionSource<TResult>();
Action action = () =>
{
try
{
tcs.SetResult(ProcessItem(operation));
}
catch (Exception e)
{
tcs.SetException(e);
}
};
m_queue.Add(action);
return tcs.Task;
}
private T ProcessItem<T>(IOperation<T> operation)
{
// whatever
}
}

Categories

Resources