Pregunta

Estoy aprendiendo a usar las extensiones RX para una aplicación Silverlight 4 en la que estoy trabajando. Creé una aplicación de muestra para clavar el proceso y no puedo hacer que devuelva nada. Aquí está el código principal:

    private IObservable<Location> GetGPSCoordinates(string Address1)
    {
        var gsc = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService") as IGeocodeService;

        Location returnLocation = new Location();
        GeocodeResponse gcResp = new GeocodeResponse();

        GeocodeRequest gcr = new GeocodeRequest();
        gcr.Credentials = new Credentials();
        gcr.Credentials.ApplicationId = APP_ID2;
        gcr.Query = Address1;

        var myFunc = Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>(gsc.BeginGeocode, gsc.EndGeocode);
        gcResp = myFunc(gcr) as GeocodeResponse;

        if (gcResp.Results.Count > 0 && gcResp.Results[0].Locations.Count > 0)
        {
            returnLocation = gcResp.Results[0].Locations[0];
        }
        return returnLocation as IObservable<Location>;
    }

GCRESP regresa como nulo. Cualquier opinión o sugerencia sería muy apreciada.

¿Fue útil?

Solución 3

Richard (y otros),

Por lo tanto, tengo el código que devuelve la ubicación y tengo el código de llamada suscribirse. Aquí está (con suerte) el problema final. Cuando llamo a GetGpsCoordinates, la siguiente declaración se ejecuta inmediatamente sin esperar a que la suscripción finalice. Aquí hay un ejemplo en un manejador de eventos de botón OnClick.

Location newLoc = new Location();

GetGPSCoordinates(this.Input.Text).ObserveOnDispatcher().Subscribe(x =>
            {
             if (x.Results.Count > 0 && x.Results[0].Locations.Count > 0)
                  {
                     newLoc = x.Results[0].Locations[0];
                     Output.Text = "Latitude: " + newLoc.Latitude.ToString() +
  ", Longtude: " + newLoc.Longitude.ToString();
                  }
             else
                  {
                    Output.Text = "Invalid address";
                  }
});
            Output.Text = " Outside of subscribe --- Latitude: " + newLoc.Latitude.ToString() +
  ", Longtude: " + newLoc.Longitude.ToString();

La asignación de text.text que tiene lugar fuera de suscripción se ejecuta antes de que la suscripción haya terminado y muestre ceros y luego la que está dentro de la suscripción muestra la nueva información de ubicación.

El propósito de este proceso es obtener información de ubicación que luego se guardará en un registro de base de datos y estoy procesando múltiples direcciones secuencialmente en un bucle foreach. Elegí las extensiones RX como una solución para evitar el problema de la devolución de llamada Async como una trampa de codificación. Pero parece que he intercambiado una trampa por otra.

Pensamientos, comentarios, sugerencias?

Otros consejos

La fuente observable a la que se suscribe es asíncrono, por lo que no puede acceder al resultado inmediatamente después de suscribirse. Debe acceder al resultado en la suscripción.

Mejor aún, no se suscriba en absoluto y simplemente componga la respuesta:

private IObservable<Location> GetGPSCoordinates(string Address1)
{
    IGeocodeService gsc = 
        new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");

    Location returnLocation = new Location();
    GeocodeResponse gcResp  = new GeocodeResponse();

    GeocodeRequest gcr = new GeocodeRequest();
    gcr.Credentials = new Credentials();
    gcr.Credentials.ApplicationId = APP_ID2;
    gcr.Query = Address1;

    var factory = Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>(
        gsc.BeginGeocode, gsc.EndGeocode);

    return factory(gcr)
        .Where(response => response.Results.Count > 0 && 
                           response.Results[0].Locations.Count > 0)
        .Select(response => response.Results[0].Locations[0]);
}

Si solo necesita el primer valor válido (es poco probable que cambie la ubicación de la dirección), agregue un .Take(1) Entre los Where y Select.

Editar: Si desea manejar específicamente la dirección que no se encuentra, puede devolver los resultados y tener el acuerdo del consumidor con ella o puede devolver una excepción y proporcionar un OnError manejador al suscribirse. Si estás pensando en hacer lo último, usarías SelectMany:

return factory(gcr)
    .SelectMany(response => (response.Results.Count > 0 && 
        response.Results[0].Locations.Count > 0)
        ? Observable.Return(response.Results[0].Locations[0])
        : Observable.Throw<Location>(new AddressNotFoundException())
    );

Si expande el tipo de myFunc Verás que es Func<GeocodeRequest, IObservable<GeocodeResponse>>.

Func<GeocodeRequest, IObservable<GeocodeResponse>> myFunc =
    Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>
        (gsc.BeginGeocode, gsc.EndGeocode);

Entonces cuando llamas myFunc(gcr) tienes un IObservable<GeocodeResponse> Y no un GeocodeResponse. Tu codigo myFunc(gcr) as GeocodeResponse devoluciones null Porque el elenco no es válido.

Lo que debe hacer es obtener el último valor de lo observable o simplemente suscribirse. Vocación .Last() bloqueará. Si llamas .Subscribe(...) Su respuesta vendrá en el hilo de devolución de llamada.

Prueba esto:

gcResp = myFunc(gcr).Last();

Déjame saber cómo vas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top