إنشاء واجهة برمجة تطبيقات عميل REST باستخدام ملحقات تفاعلية (RX)

StackOverflow https://stackoverflow.com/questions/2833306

  •  26-09-2019
  •  | 
  •  

سؤال

أحاول الحصول على رأسي حول حالات الاستخدام الصحيحة للملحقات التفاعلية (RX). الأمثلة التي تستمر في الظهور هي أحداث واجهة المستخدم (السحب والإسقاط ، الرسم) ، والاقتراحات بأن RX مناسبة للتطبيقات/العمليات غير المتزامنة مثل مكالمات خدمة الويب.

أنا أعمل على تطبيق حيث أحتاج إلى كتابة واجهة برمجة تطبيقات عميل صغيرة لخدمة REST. أحتاج إلى استدعاء أربع نقاط نهائية للراحة ، وثلاثة للحصول على بعض البيانات المرجعية (المطارات وشركات الطيران والأوضع) ، والرابع هي الخدمة الرئيسية التي ستمنحك أوقات الرحلة لمطار معين.

لقد أنشأت فصولًا تعرض خدمات البيانات المرجعية الثلاث ، والأساليب تبدو مثل هذا:

public Observable<IEnumerable<Airport>> GetAirports()
public Observable<IEnumerable<Airline>> GetAirlines()
public Observable<IEnumerable<Status>> GetStatuses()
public Observable<IEnumerable<Flights>> GetFlights(string airport)

في طريقة GetFlights الخاصة بي ، أريد أن تعقد كل رحلة مرجعًا للمطار الذي تغادر منه ، وشركة الطيران التي تعمل في الرحلة. للقيام بذلك ، أحتاج إلى أن تكون البيانات من GetAirports و GetAirlines متاحة. ستتم إضافة كل مطار وشركة طيران وحالة إلى Dictionar (أي قاموس) حتى أتمكن بسهولة من ضبط المرجع عند تحليل كل رحلة.

flight.Airport = _airports[flightNode.Attribute("airport").Value]
flight.Airline = _airlines[flightNode.Attribute("airline").Value]
flight.Status = _statuses[flightNode.Attribute("status").Value]

يبدو أن عملي الحالي الآن:

public IObservable<IEnumerable<Flight>> GetFlightsFrom(Airport fromAirport)
{
    var airports = new AirportNamesService().GetAirports();
    var airlines = new AirlineNamesService().GetAirlines();
    var statuses = new StatusService().GetStautses();


    var referenceData = airports
        .ForkJoin(airlines, (allAirports, allAirlines) =>
                            {
                                Airports.AddRange(allAirports);
                                Airlines.AddRange(allAirlines);
                                return new Unit();
                            })
        .ForkJoin(statuses, (nothing, allStatuses) =>
                            {
                                Statuses.AddRange(allStatuses);
                                return new Unit();
                            });

    string url = string.Format(_serviceUrl, 1, 7, fromAirport.Code);

    var flights = from data in referenceData
                    from flight in GetFlightsFrom(url)
                    select flight;

    return flights;
}

private IObservable<IEnumerable<Flight>> GetFlightsFrom(string url)
{
    return WebRequestFactory.GetData(new Uri(url), ParseFlightsXml);
}

يعتمد التنفيذ الحالي على إجابة سيرجي ، ويستخدم ForkJoin لضمان التنفيذ المتسلسل وأن يتم تحميل البيانات المرجعية قبل الرحلات الجوية. هذا التنفيذ مخصص أكثر أناقة من الاضطرار إلى إطلاق حدث "محول" مثل "عملي السابق".

هل كانت مفيدة؟

المحلول

أعتقد ، إذا كنت تتلقى قائمة بالكيانات من كل مكالمة راحة ، فيجب أن تحتوي مكالمتك على توقيع مختلف قليلاً - فأنت لا تراقب كل قيمة في مجموعة الإرجاع ، فأنت تراقب حدث إكمال المكالمة. لذلك بالنسبة للمطارات ، يجب أن يكون لها التوقيع:

public IObservable<Aiports> GetAirports()

تتمثل الخطوة التالية في تشغيل الثلاثة الأولى بالتوازي وانتظر كل منهم:

var ports_lines_statuses = 
    Observable.ForkJoin(GetAirports(), GetAirlines(), GetStatuses());

الخطوة الثالثة هي إنشاء ما سبق قابلاً للاستيعاب مع GetFlights ():

var decoratedFlights = 
  from pls in ports_lines_statuses
  let airport = MyAirportFunc(pls)
  from flight in GetFlights(airport)
  select flight;

تحرير: ما زلت لا أفهم سبب عودة خدماتك

IObservable<Airport> 

بدلاً من

IObservable<IEnumerable<Airport>>

AFAIK ، من الباقي اتصل عليك الحصول على جميع الكيانات في وقت واحد - ولكن ربما تقوم بالترحيل؟ على أي حال ، إذا كنت تريد أن تقوم RX بعمل التخزين المؤقت ، يمكنك استخدام .BufferWithCount ():

    var allAirports = new AirportNamesService()
        .GetAirports().BufferWithCount(int.MaxValue); 
...

ثم يمكنك تطبيق forkjoin:

var ports_lines_statuses =  
    allAirports
        .ForkJoin(allAirlines, PortsLinesSelector)
        .ForkJoin(statuses, ...

سوف تحتوي PORTS_LINES_STATUSES على حدث واحد على الجدول الزمني والذي سيحتوي على جميع البيانات المرجعية.

تحرير: إليك واحدة أخرى ، باستخدام ListObservable الطازجة (أحدث إصدار فقط):

allAiports = airports.Start(); 
allAirlines = airlines.Start();
allStatuses = statuses.Start();

...
whenReferenceDataLoaded =
  Observable.Join(airports.WhenCompleted()
                 .And(airlines.WhenCompleted())
                 .And(statuses.WhenCompleted())
                 Then((p, l, s) => new Unit())); 



    public static IObservable<Unit> WhenCompleted<T>(this IObservable<T> source)
    {
        return source
            .Materialize()
            .Where(n => n.Kind == NotificationKind.OnCompleted)
            .Select(_ => new Unit());
    }

نصائح أخرى

حالة الاستخدام هنا تعتمد على السحب - iEnumerable على ما يرام. إذا كنت تريد أن تقول ، قم بإخطار مكان وجود رحلة جديدة ، ثم لفت مكالمة قائمة على السحب داخل الملاحظة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top