I'm working with a library that does not have F# documentation, only C#. Having no familiarity with C# I'm having a bit of trouble. Reading through the documentation for NetMQ, there is one line that I'm having trouble translating:
For context, here is the full example:
using (var rep1 = new ResponseSocket("#tcp://*:5001"))
using (var rep2 = new ResponseSocket("#tcp://*:5002"))
using (var poller = new NetMQPoller { rep1, rep2 })
{
rep1.ReceiveReady += (s, a) => // ??????
{
string msg = a.Socket.ReceiveString();
a.Socket.Send("Response");
};
rep2.ReceiveReady += (s, a) => // ??????
{
string msg = a.Socket.ReceiveString();
a.Socket.Send("Response");
};
poller.Run();
}
Specifically, I don't know what rep1.ReceiveReady += (s, a) => means in the context of C# as well as how to translate it to F#. Any ideas?
Thanks.
rep.ReceiveReady += (s, a) => { /*...*/ }; is subscribing to the ReceiveReady event with a lambda function. Here is a direct F# translation:
use rep1 = new ResponseSocket("#tcp://*:5001")
use rep2 = new ResponseSocket("#tcp://*:5002")
use poller = new NetMQPoller()
poller.Add rep1
poller.Add rep2
rep1.ReceiveReady.Add (fun a -> let msg = a.Socket.ReceiveString ()
a.Socket.Send "Response")
rep2.ReceiveReady.Add (fun a -> let msg = a.Socket.ReceiveString ()
a.Socket.Send "Response")
poller.Run ()
Further reading on event handling in F# can be found in the documentation. Note, however, that F# can also treat events as observables, which is likely to be considered more idiomatic.
Related
How to create Control panel entry for Squirrel.Windows Application?
Isn't it something very trivial which such a popular tool supports out of box.
I tried using CreateUninstallerRegistryEntry but no change.
using (var mgr = new UpdateManager(updateUrl))
{
// Note, in most of these scenarios, the app exits after this method
// completes!
SquirrelAwareApp.HandleEvents(
onInitialInstall: v =>
{
mgr.**CreateUninstallerRegistryEntry**();
mgr.CreateShortcutForThisExe();
},
onAppUpdate: v => mgr.CreateShortcutForThisExe(),
onAppUninstall: v =>
{
mgr.RemoveShortcutForThisExe();
mgr.RemoveUninstallerRegistryEntry();
},
onFirstRun: () => ShowTheWelcomeWizard = true);
}
I did my best possible research. Am I missing something?
This is my first time playing with K8s api/client. I am trying to watch for events in all namespaces.
Below is the method, on running it prints:
Exception : Object reference not set to an instance of an object.
Closed
There aren't enough docs on how to use the C# client library. Can someone help me in understanding what I am doing wrong?
This is the method:
public async Task Temp() {
var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
IKubernetes client = new Kubernetes(config);
var resourceVersion = client.ListEventForAllNamespaces().ResourceVersion();
var path = $"api/v1/events";
// wait for events
while (true)
{
var eventsWatcher = await client.WatchObjectAsync<V1EventList>(
timeoutSeconds: int.MaxValue,
path: path,
resourceVersion: resourceVersion,
onEvent: new Action<WatchEventType, V1EventList>((x, y) =>
{
Console.WriteLine(x.ToString());
}),
onClosed: new Action(() =>
{
Console.WriteLine("Closed");
}),
onError: new Action<Exception>((e) =>
{
Console.WriteLine($"Exception : {e.Message}");
}));
Thread.Sleep(1000);
}
}
On a side note, I am able to watch locally using http://localhost:8080/api/v1/events?watch=1&resourceVersion=27958468 after kubectl proxy
Found the issue. I was using the wrong "path". Instead of api/v1/events it should be api/v1/watch/events. The NullReferenceException was happening within the library's watcher.cs line 149
From m$ site. I don't get the += o,a what is that ???
private void GetResponse(Uri uri, Action<Response> callback)
{
WebClient wc = new WebClient();
wc.OpenReadCompleted += (o, a) =>
{
if (callback != null)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Response));
callback(ser.ReadObject(a.Result) as Response);
}
};
wc.OpenReadAsync(uri);
}
wc.OpenReadCompleted += (o, a) => { }
This is assigning an anonymous delegate to the wc.OpenReadCompleted event. The (o,a) part are the method parameters.
o is object.
a is the EventArgs
As I can see from the signature of OpenReadCompletedEventHandler (which should be used to subscribe to OpenReadCompleted event), o is a sender and a is an instance of OpenReadCompletedEventArgs.
In general this approach of subscription to events is basically instantiating a delegate using a lambda expression, one can do this since C# 3.0.
There is a List.
I want to download each url via webclient.DownloadStringAsync
the problem I encounter is:
how do I know which e.Result corresponds to what url ?
public class ressource{
public string url { get; set; }
public string result { get; set; }
}
List<ressource> urlist = new List<ressource>();
urlist.Add(new ressource(){url="blabla", result=string.empty});
....etc
var wc= new WebClient();
foreach(var item in urlist)
{
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.DownloadStringAsync(new Uri(item.url, UriKind.Absolute));
}
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
urlist[?].result = e.Result;
}
I feel completely stuck.
Thanks for your ideas.
the problem I encounter is: how do I know which e.Result corresponds to what url ?
There are various different options for this:
UserState
You can pass in a second argument to DownloadStringAsync, which is then available via DownloadStringCompletedEventArgs.UserState. For example:
// In your loop....
var wc = new WebClient();
wc.DownloadStringAsync(new Uri(item.url, UriKind.Absolute), item);
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
var item = (ressource) e.UserState;
item.result = e.Result;
}
Multiple WebClients
You can create a new WebClient for each iteration of the loop, and attach a different event handler to it. A lambda expression is useful here:
// Note: this is broken in C# 3 and 4 due to the capture semantics of foreach.
// It should be fine in C# 5 though.
foreach(var item in urlist)
{
var wc = new WebClient();
wc.DownloadStringCompleted += (sender, args) => item.result = args.Result;
wc.DownloadStringAsync(new Uri(item.url, UriKind.Absolute));
}
DownloadStringTaskAsync
You could DownloadStringTaskAsync instead, so that each call returns a Task<string>. You could keep a collection of these - one for each element in urlist - and know which is which that way.
Alternatively, you could just fetch all the results synchronously, but I suspect you don't want to do that.
Additional information
Unfortunately, WebClient doesn't support multiple concurrent connections, so with all the options above you should create a new WebClient per iteration anyway.
Another alternative, and the one I prefer, is to use Microsoft's Reactive Framework (Rx). It handles all the background threading for you, similar to the TPL, but often easier.
Here's how I would do it:
var query =
from x in urlist.ToObservable()
from result in Observable.Using(
() => new WebClient(),
wc => Observable.Start(() => wc.DownloadString(x.url)))
select new
{
x.url,
result
};
Now to get the results back into the original urlist.
var lookup = urlist.ToDictionary(x => x.url);
query.Subscribe(x =>
{
lookup[x.url].result = x.result;
});
Simple as that.
I have a DownloadManager class that manages multiple DownloadItem objects. Each DownloadItem has events like ProgressChanged and DownloadCompleted. Usually you want to use the same event handler for all download items, so it's a bit annoying to have to set the event handlers over and over again for each DownloadItem.
Thus, I need to decide which pattern to use:
Use one DownloadItem as a template and clone it as necessary
var dm = DownloadManager();
var di = DownloadItem();
di.ProgressChanged += new DownloadProgressChangedEventHandler(di_ProgressChanged);
di.DownloadCompleted += new DownloadProgressChangedEventHandler(di_DownloadCompleted);
DownloadItem newDi;
newDi = di.Clone();
newDi.Uri = "http://google.com";
dm.Enqueue(newDi);
newDi = di.Clone();
newDi.Uri = "http://yahoo.com";
dm.Enqueue(newDi);
Set the event handlers on the DownloadManager instead and have it copy the events over to each DownloadItem that is enqeued.
var dm = DownloadManager();
dm.ProgressChanged += new DownloadProgressChangedEventHandler(di_ProgressChanged);
dm.DownloadCompleted += new DownloadProgressChangedEventHandler(di_DownloadCompleted);
dm.Enqueue(new DownloadItem("http://google.com"));
dm.Enqueue(new DownloadItem("http://yahoo.com"));
Or use some kind of factory
var dm = DownloadManager();
var dif = DownloadItemFactory();
dif.ProgressChanged += new DownloadProgressChangedEventHandler(di_ProgressChanged);
dif.DownloadCompleted += new DownloadProgressChangedEventHandler(di_DownloadCompleted);
dm.Enqueue(dif.Create("http://google.com"));
dm.Enqueue(dif.Create("http://yahoo.com"));
What would you recommend?
Why are the DownloadItems responsible for reporting progress (from an API design perspective)?
I'd say that the DownloadManager is responsible for downloading DownloadItems, and therefore also for reporting progress. (The internal implementation strategy may, of course, differ.)
I'd go with the second option:
var dm = DownloadManager
{
"http://google.com",
new DownloadItem("http://yahoo.com") { Retries = 5 }
};
dm.ProgressChanged += (sender, e) =>
Console.WriteLine("Download {0}: {1:P}", e.Uri, (double)e.Progress / 100.0);
dm.DownloadCompleted += (sender, e) =>
Console.WriteLine("Download {0}: completed!", e.Uri);
dm.DownloadAllCompleted += (sender, e) =>
Console.WriteLine("All downloads completed!");
dm.Add("http://stackoverflow.com");
dm.DownloadAllAsync();
If you happen to have a copy of the Framework Design Guideline (2nd ed.) at hand, have a look at pages 305--312 (Event-based Async Pattern).
I would say Template method pattern with a factory would be the right approach for this.