【问题标题】:asp.net core razor page calling rest service and how to wait for response.asp.net core razor page调用rest服务以及如何等待响应。
【发布时间】:2018-11-29 21:28:43
【问题描述】:

我有一个剃须刀页面,它调用休息服务来查找所提供地址的地理编码。该调用在完成查找时使用事件触发回调。一切正常,但时间已过。回调完成时,页面已经绘制完毕,我需要回调的结果才能正确绘制页面。

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Northwind.ModelsDB;
using System.Runtime.Serialization.Json;
using BingMapsRESTToolkit;
using System.Net;

namespace Northwind.Pages.CustomerPages
{

public class DetailsModel : PageModel
{
  private readonly Northwind.ModelsDB.NorthwindContext _context;
  private readonly IOptions<MyConfig> config;
  public string BingMapKey { get; private set; }
  public double latitude { get; private set; }
  public double longitude { get; private set; }
  public string query { get; private set; }
  public VIndividualCustomer VIndividualCustomer { get; private set; }

  public DetailsModel(Northwind.ModelsDB.NorthwindContext context, IOptions<MyConfig> configg)
  {
     _context = context;
     this.config = configg;
     BingMapKey = config.Value.BingMapKey;
  }

  public async Task<IActionResult> OnGetAsync(int? id)
  {
     if (id == null)
     {
        return NotFound();
     }

     VIndividualCustomer = await _context.VIndividualCustomer
        .AsNoTracking()
        .FirstOrDefaultAsync(m => m.BusinessEntityId == id);

     if (VIndividualCustomer == null)
     {
        return NotFound();
     }

     query = VIndividualCustomer.AddressLine1 + " " +
        VIndividualCustomer.AddressLine2 + ", " +
        VIndividualCustomer.City + ", " +
        VIndividualCustomer.StateProvinceName + ", " +
        VIndividualCustomer.PostalCode;
     query = "1 Microsoft Way, Redmond, WA";
     Uri geocodeRequest = new Uri(string.Format("http://dev.virtualearth.net/REST/v1/Locations?q={0}&key={1}", query, BingMapKey));
     GetResponse(geocodeRequest, (x) =>
     {
        var location = (BingMapsRESTToolkit.Location)x.ResourceSets[0].Resources[0];
        latitude = location.GeocodePoints[0].Coordinates[0];
        longitude = location.GeocodePoints[0].Coordinates[1];
     });

     return Page();
  }

  private void GetResponse(Uri uri, Action<Response> callback)
  {
     System.Net.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);


  }

} }

【问题讨论】:

  • 你希望它是一个漫长的等待还是一个短暂的等待(足够短以至于不允许用户做任何事情)?
  • 只有几秒钟。我需要 lat/long 才能正确绘制地图,否则我会得到一张 lat/long=0 的地图,它位于非洲海岸附近。

标签: c# asynchronous asp.net-core async-await webclient


【解决方案1】:

您的方法将永远不会更新,因为响应已经发送到客户端。您需要阻止该方法(改用 HttpClient)并等待响应:

public async Task<IActionResult> OnGetAsync(int? id)
{
  // this "reads" better
  if (id.HasValue)
  {
    return NotFound();
  }

  VIndividualCustomer = await _context.VIndividualCustomer
    .AsNoTracking()
    .FirstOrDefaultAsync(m => m.BusinessEntityId == id);

  if (VIndividualCustomer == null)
  {
    return NotFound();
  }

  query = VIndividualCustomer.AddressLine1 + " " +
    VIndividualCustomer.AddressLine2 + ", " +
    VIndividualCustomer.City + ", " +
    VIndividualCustomer.StateProvinceName + ", " +
    VIndividualCustomer.PostalCode;
  query = "1 Microsoft Way, Redmond, WA";

  // string interpolation
  //https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated
  var url = $"http://dev.virtualearth.net/REST/v1/Locations?q={query}&key={BingMapKey}";
  var geocodeRequest = new Uri(url);

  var ser = new DataContractJsonSerializer(typeof(Response));

  var response = await (new HttpClient()).GetAsync(geocodeRequest);
  var json = await response.Content.ReadAsStringAsync();
  var x = ser.ReadObject(json) as Response;     

  var location = (BingMapsRESTToolkit.Location)x.ResourceSets[0].Resources[0];
  latitude = location.GeocodePoints[0].Coordinates[0];
  longitude = location.GeocodePoints[0].Coordinates[1];

  return Page();
}

【讨论】:

  • 这很多,很有效。我必须做一点小改动... //var json = await response.Content.ReadAsStringAsync(); System.IO.Stream json = 等待 response.Content.ReadAsStreamAsync();
  • 确保您不要像本例中那样创建HttpClient inline 的新实例。见herehere
【解决方案2】:

你自己的代码最封闭的代码是这个sn-p:

    private async Task GetResponseAsync(Uri uri, Action<Response> callback) {
        System.Net.Http.HttpClient wc = new HttpClient();
        var response = await wc.GetAsync(uri);
        if (callback != null) {
            var stream = await response.Content.ReadAsStreamAsync();
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Response));
            callback(ser.ReadObject(stream) as Response);
        }
    }

并像这样称呼它:

 await GetResponse(geocodeRequest, (x) =>
 {
    / bla bla bla...
 });

但是,它不是一个很好的重构代码。但能胜任。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 2020-08-14
    • 2020-12-02
    • 2020-12-30
    相关资源
    最近更新 更多