System.IObservable<string> to System.IObservable<System.Collections.Generic.List<string>> - linq

How can I convert System.IObservable<string> to System.IObservable<System.Collections.Generic.List<string>>?
public static IObservable<List<string>> GetUrlList(Uri url) {
var result = (from request in Observable.Return(GetWebRequest(url, false))
from response in Observable.FromAsyncPattern<WebResponse>(
request.BeginGetResponse, request.EndGetResponse)()
from item in GetUrlCollection(response).ToObservable()
select item);
return result;
}
Here the type of the item is "list of string". I need to convert that to IObservable List of strings. How can I achieve this?

Try this:
public static IObservable<List<string>> GetUrlList(Uri url)
{
var result = (
from request in Observable.Return(
GetWebRequest(url, false))
from response in Observable.FromAsyncPattern<WebResponse>(
request.BeginGetResponse, request.EndGetResponse)()
from item in GetUrlCollection(response)
.ToObservable()
.ToArray()
select item
.ToList());
return result;
}
My only concern with this whole approach is that your GetUrlCollection(response) is returning an enumerable. You really should code this to return an observable.

Hmmm I think Observable.Start is your friend here. You have a bunch of code that it looks like you are forcing into Observable Sequences, when they really don't look like they are.
Remember Rx is designed to work with sequences of push data. You seem to have a sequence of 1 that happens to be a List. TPL/Task/async would be a good fit here.
If you do want to use Rx, I would suggest avoiding boucing around between IEnumable and IObservable. Doing so is a quick way to creating nasty race conditions and confusing the next developer.
public static IObservable<List<string>> GetUrlList(Uri url)
{
return Observable.Start(()=>
{
var request = GetWebRequest(url, false);
return GetUrlCollection(request);//Code change here??
});
}
Here you can happily be synchronous in your Observable.Start delegate. This should be a lot easier for the next guy to understand (i.e. this is a single value sequence with the UrlCollection as the value).

Related

How do I refactor a traditional synchronous loop with RxJS?

I'm new to RxJS and trying to wrap my brain around how I should be writing my code. I'm trying to write a function that extends an existing http which returns an observable array of data. I'd like to then loop over the array and make an http request on each object and return the new array with the modified data.
Here's what I have so far:
private mapEligibilitiesToBulk(bulkWarranties: Observable<any[]>): Observable<IDevice[]> {
const warranties: IDevice[] = [];
bulkWarranties.subscribe((bulk: any[]) => {
for (let warranty of bulk) {
// Check if another device already has the information
const foundIndex = warranties.findIndex((extended: IDevice) => {
try {
return warranty.device.stockKeepingId.equals(extended.part.partNumber);
} catch (err) {
return false;
}
});
// Fetch the information if not
if (foundIndex > -1) {
warranty.eligibilityOptions = warranties[foundIndex];
} else {
this.getDevices(warranty.device.deviceId.serialNumber).subscribe((devices: IDevice[]) => {
warranty = devices[0];
}); // http request that returns an observable of IDevice
}
warranties.push(warranty);
}
});
return observableOf(warranties);
}
Currently, my code returns an observable array immediately, however, its empty and doesn't react the way I'd like. Any advice or recommended reading would be greatly appreciated!
Without knowing a lot more about your data and what would make sense, it is impossible to give you the exact code you would need. However, I made some assumptions and put together this StackBlitz to show one possible way to approach this. The big assumption here is that the data is groupable and what you are actually trying to achieve is making only a single http call for each unique warranty.device.stockKeepingId.
I offer this code as a starting point for you, in the hopes it gets you a little closer to what you are trying to achieve. From the StackBlitz, here is the relevant method:
public mapEligibilitiesToBulk(bulk: Warranty[]): Observable<IDevice[]> {
return from(bulk).pipe(
tap(warranty => console.log('in tap - warranty is ', warranty)),
groupBy(warranty => warranty.device.stockKeepingId),
mergeMap(group$ => group$.pipe(reduce((acc, cur) => [...acc, cur], []))),
tap(group => console.log('in tap - group is ', group)),
concatMap(group => this.getDevices(group[0].device.deviceId.serialNumber)),
tap(device => console.log('in tap - got this device back from api: ', device)),
toArray()
)
}
A couple of things to note:
Be sure to open up the console to see the results.
I changed the first parameter to an array rather than an observable, assuming you need a complete array to start with. Let me know if you want this to extend an existing observable, that is quite simple to achieve.
I put in some tap()s so you can see what the code does at two of the important points.
In the StackBlitz currently the getDevices() returns the same thing for every call, I did this for simplicity in mocking, not because I believe it would function that way. :)

Rxjs Observable.take(1) vs Subscription.unsubscribe()

Is there any differences between
Observable.pipe(take(1)).subscribe(...)
vs
const subscription = Observable.subscribe(() => {
// Do something, then
subscription.unsubscribe()
})
The take(1) approach has a number of advantages over subscribe:
Code readability (and elegance).
The second approach requires that you hold and manage extra variables.
The second approach will not invoke the complete handler. This is because .take(1) actually create a new observable which potentially yields a single item and completes.
The second approach will work for the trivial case of taking a single element, but if you need to take more then 1, take(4) will stay simple while the second approach will become hard to code.
The 3rd item is the rxjs related one, the others relate to coding style.
Have a look at a sample here.
In Angular2, I find myself using both paradigms.
The first makes the most sense inside of a method, where as the second is better used in a constructor, with a cleanup in the deconstructor.
doThing(){
this.store.select('thing').pipe(take(1))
.subscribe(item => {
otherMethod(item)
});
}
vs
class SomeClass{
public val;
private sub;
constructor(){
this.sub = this.store.select('thing')
.subscribe(item => {
this.val = item
});
}
ngDestroy() {
this.sub.unsubscribe()
}
}

Get last message of Observable with RxJS

I was wondering whether is it possible to replay or resend the last message of an Observable in RxJS.
Like:
class MyClass {
results: Observable<MyData[]>;
first: MyData;
reactToSmth() {
this.results.subscribe((data: MyData[]) => {
this.first = data[0];
});
}
reactToSmthElse() {
// doesn't exist :-)
this.results.resendLast(data: MyData[]) => {
this.first = data[1];
});
}
}
I know I can simply store data in my class so I can manipulate later, at the same time in a more complex case I would like to know if is possible to do something like that and how.
Thanks.
Well yes, it is possible and even easy. There are several options, but the simplest for what you present is probably, giving obs$ an observable, use obs$.shareReplay(1) to obtain an observable, which when subscribed to will reemit the last emitted value of obs$.

Recursive call to IObservable in Windows Phone 7 application using Rx

We have a Windows Phone 7 application which uses a set of 3 service methods using Reactive Extensions, defined as follows:
public static class ServiceClient
{
public static IObservable<string> LookupImage(byte[] image) {...}
public static IObservable<XDocument> GetDefinition(string id) {...}
public static IObservable<Dictionary<string, byte[]>> GetFiles(string id, string[] fileNames) {...}
}
We need the WP7 application to keep calling LookupImage in the above client (each time with different set of byte[] image data) until the returned IObservable<string> is nonempty. After we get the Observable string we have to call GetDefinition and GetFiles methods (in that order).
The calls to LookupImage should happen as often as the service response is returned as opposed to being controlled by a timer as it will vary depending on network connection speed and we need to be able to send as many of these as possible.
I'd appreciate any pointers to what might be a solution to the above. As a start I have the following
private void RunLookupAndRenderLogic()
{
byte[] imageBytes = GetImageBytes();
// There are some cases where the image was not 'interesting' enough in which case GetImageBytes() returns null
if (pictureBytes != null)
{
// Where we have image data, send this to LookupImage service method
var markerLookup = ServiceClient.LookupImage(imageBytes);
markerLookup.Subscribe(id =>
{
// If the id is empty, we need to call this again.
if (String.IsNullOrEmpty(id))
{
???
}
// If we have an id, call GetDefinition and GetFiles methods of the service. No further calls to LookupImage should take place.
RenderLogic(id);
});
}
else
// If no interesting image was returned, try again
RunRecognitionAndRenderLogic();
}
Apologies if I get this wrong, but if I understand it correctly you want to Retry the call to LookupImage with the exact same argument, until it returns a value?
A naive way of solving this would be to simply call repeat and then take(1):
ServiceClient.LookupImage(imageBytes)
.Repeat()
.Take(1)
.Subscribe(id => ....);
However as Rx is single threaded by default, there is no point in this context that allows us to inject our disposal call (implicit from the Take(1)-->OnComplete()-->Auto disposal of subscription).
You can dodge this by offering some breathing space between subsequent re-subscriptions by using the CurrentThread Scheduler.
Observable.Defer(()=>
ServiceClient.LookupImage(imageBytes)
.ObserveOn(Scheduler.CurrentThread)
)
.Repeat()
.Take(1)
.Subscribe(id => ....);
There are other ways of achieving this with some good understanding of Rx and some creativity. (Most I would imagine a Scheduler)
To give you some inspriation check out the chapter on Scheduling and Threading. It covers recursion and building your own iterator which is effectively what you are trying to do.
Full code sample:
private void RunLookupAndRenderLogic()
{
byte[] imageBytes = GetImageBytes();
// There are some cases where the image was not 'interesting' enough in which case GetImageBytes() returns null
if (pictureBytes != null)
{
// Where we have image data, send this to LookupImage service method
var subscription = Observable
.Defer(()=>
ServiceClient.LookupImage(imageBytes)
.ObserveOn(Scheduler.CurrentThread)
)
.Where(id=>!String.IsNullOrEmpty(id))
.Repeat()
.Take(1)
.Subscribe(id =>
{
// If we have an id, call GetDefinition and GetFiles methods of the service. No further calls to LookupImage should take place.
RenderLogic(id);
});
//TODO: You dont offer any way to cancel this (dispose of the suscription).
//This means you could loop forever :-(
}
else
{
// If no interesting image was returned, try again
RunRecognitionAndRenderLogic();
}
}
(Disclosure: I am the author of IntroToRx.com)

How to use dispatcher

how to use dispatcher.BeginInvoke in for loop( httpwebrequest).With each dispatcher.BeginInvoke have complete before call another dispatcher.BeginInvoke. Because objects return by httpwerequest are wrong position.
No, BeginInvoke is asynchronous - you're basically adding delegates to a queue of items to be executed on the UI thread.
If you need to wait until the delegate has executed before you continue work in your background thread, you'll need to do a bit of work yourself, as Silverlight doesn't support the synchronous Dispatcher.Invoke method, or the DispatcherOperation.Wait() method. Silverlight tries to avoid synchronous approaches like this - if you can possibly redesign your code so that you don't need to wait, that would be preferable.
Being able to easily convert a synchronous sequence of operations into asynchrounous code has been a subject I've blogged about a fair bit. If you want to take up my approach you will need to add the following (relatively small) chunks of code:
The core AsyncOperationService
Code to create an AsyncOperation from the .NET Async Pattern
A couple of Extension methods for WebRequest
Here is some example code that has the flavour of what you describe in your question:-
IEnumerable<AsyncOperation> LoadSomeStuff(IList<string> urls)
{
for (string url in urls)
{
yield return AsyncOperationService.SwitchToBackgroundThread();
WebRequest req = WebRequest.Create(url);
WebResponse resp = null;
yield return req.GetResponseAsyncOp(r => resp = r);
using (resp)
{
// Do stuff with the Web Response such as construct model class instances from a stream.
}
// When ready to actually start touching the UI
yield return AsyncOperationService.SwitchToUIThread();
// Do stuff to the UI
}
}
usage:
List<string> urls = new List<string> {"pinkElephants.xml", "whileElephants.xml"}
LoadSomeStuff(urls).Run(err =>
{
if (err == null)
{
// Cool, it all worked and I probably don't need to do anything
}
else
{
// Something bad happened, lets tell the user about it in the UI somehow.
}
});
Note that this isn't the most efficient code possible. However in many cases the time it takes HTTP response to be delivered massively out-weighs the time the rest of the code uses up so the inefficiency can be quite small and well worth the reduced complexity of code.

Resources