使用 Rx 对 Bing 地图中的地址进行地理编码

发布于 2024-10-22 21:47:34 字数 1033 浏览 12 评论 0 原文

我正在学习如何使用我正在开发的 Silverlight 4 应用程序的 Rx 扩展。我创建了一个示例应用程序来确定该过程,但我无法让它返回任何内容。 这是主要代码:

    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 返回为 null。任何想法或建议将不胜感激。

I am learning to use the Rx extensions for a Silverlight 4 app I am working on. I created a sample app to nail down the process and I cannot get it to return anything.
Here is the main code:

    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 comes back as null. Any thoughts or suggestions would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

兔姬 2024-10-29 21:47:34

您订阅的可观察源是异步的,因此您无法在订阅后立即访问结果。您需要访问订阅中的结果。

更好的是,根本不订阅,只需编写响应:

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]);
}

如果您只需要第一个有效值(地址的位置不太可能更改),则添加 .Take(1)WhereSelect 之间。

编辑:如果您想专门处理未找到的地址,您可以返回结果并让使用者处理它,也可以返回异常并提供 OnError订阅时的处理程序。如果您考虑执行后者,则可以使用 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())
    );

The observable source you are subscribing to is asynchronous, so you can't access the result immediately after subscribing. You need to access the result in the subscription.

Better yet, don't subscribe at all and simply compose the response:

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]);
}

If you only need the first valid value (the location of the address is unlikely to change), then add a .Take(1) between the Where and Select.

Edit: If you want to specifically handle the address not being found, you can either return results and have the consumer deal with it or you can return an Exception and provide an OnError handler when subscribing. If you're thinking of doing the latter, you would use 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())
    );
话少心凉 2024-10-29 21:47:34

如果展开 myFunc 的类型,您会看到它是 Func>

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

因此,当您调用 myFunc(gcr) 时,您得到的是 IObservable,而不是 GeocodeResponse。您的代码 myFunc(gcr) as GeocodeResponse 返回 null,因为转换无效。

您需要做的是获取可观察值的最后一个值,或者只是进行订阅。调用 .Last() 将阻塞。如果您调用 .Subscribe(...) 您的响应将通过回调线程传递。

试试这个:

gcResp = myFunc(gcr).Last();

让我知道你进展如何。

If you expand out the type of myFunc you'll see that it is Func<GeocodeRequest, IObservable<GeocodeResponse>>.

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

So when you call myFunc(gcr) you have an IObservable<GeocodeResponse> and not a GeocodeResponse. Your code myFunc(gcr) as GeocodeResponse returns null because the cast is invalid.

What you need to do is either get the last value of the observable or just do a subscribe. Calling .Last() will block. If you call .Subscribe(...) your response will come thru on the call back thread.

Try this:

gcResp = myFunc(gcr).Last();

Let me know how you go.

寄离 2024-10-29 21:47:34

理查德(和其他人),

所以我有返回位置的代码,并且有订阅的调用代码。这是(希望)最后一期。当我调用 GetGPSCooperatives 时,下一条语句将立即执行,而无需等待订阅完成。以下是按钮 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();

在订阅外部进行的 Output.Text 赋值在订阅完成之前执行并显示零,然后订阅内部的 1 显示新的位置信息。

此过程的目的是获取位置信息,然后将其保存在数据库记录中,并且我在 Foreach 循环中按顺序处理多个地址。我选择 Rx Extensions 作为解决方案,以避免异步回调作为编码陷阱的问题。但看来我已经把一个陷阱换成了另一个陷阱。

想法、评论、建议?

Richard (and others),

So I have the code returning the location and I have the calling code subscribing. Here is (hopefully) the final issue. When I call GetGPSCoordinates, the next statement gets executed immediately without waiting for the subscribe to finish. Here's an example in a button OnClick event handler.

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();

The Output.Text assignment that takes place outside of Subscribe executes before the Subscribe has finished and displays zeros and then the one inside the subscribe displays the new location info.

The purpose of this process is to get location info that will then be saved in a database record and I am processing multiple addresses sequentially in a Foreach loop. I chose Rx Extensions as a solution to avoid the problem of the async callback as a coding trap. But it seems I have exchanged one trap for another.

Thoughts, comments, suggestions?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文