asp.net核心剃须刀页面调用其余服务以及如何等待响应。

时间:2018-11-29 21:28:43

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

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

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


  }

} }

2 个答案:

答案 0 :(得分: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();
}

答案 1 :(得分:0)

与您自己的代码最接近的代码是以下代码段:

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

但是,这不是一个好的重构代码。但是可以做到的。