[英]No response from HttpResponseMessage
我有如下服務的MVC項目:
namespace comp.Services
{
public class CompService
{
public HttpClient client = new HttpClient();
public CompService()
{
client.BaseAddress = new Uri("someapiurl");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
protected async Task<string> GetProductAsync(string path)
{
var resp = "nothing here";
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
resp = await response.Content.ReadAsStringAsync();
}
return resp;
}
public string GetProduct(string path)
{
return GetProductAsync(path).GetAwaiter().GetResult();
}
}
}
和actionResult來查看:
namespace comp.Controllers
{
public class HomeController : Controller
{
public CompService compService;
public HomeController()
{
compService = new CompService();
}
public ActionResult About()
{
var timeServer = compService.GetProduct("/api/time");
ViewBag.timeServer = timeServer;
return View();
}
}
}
在調試器中遇到此行:
HttpResponseMessage response = await client.GetAsync(path);
程序從調試器退出,瀏覽器中沒有響應。
在控制台應用程序中編寫的相同代碼有效。
在VS輸出中是響應成功的消息:
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2018-02-18T13:48:31","tags":{"ai.internal.sdkVersion":"rddf:2.2.0-738","ai.internal.nodeName":"DESKTOP-xxxxx","ai.cloud.roleInstance":"DESKTOP-xxxxx"},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"/api/v1/time","id":"xxxxx=","data":"https://api.xxx.com/api/v1/time","duration":"00:00:01.3150000","resultCode":"200","success":true,"type":"Http","target":"xxx","properties":{"DeveloperMode":"true"}}}}
在瀏覽器控制台輸出中:
[14:51:33 GMT+0100 (Central European Standard Time)] Browser Link: Failed to send message to browser link server:
Error: SignalR: Connection must be started before data can be sent. Call .start() before .send()
感謝幫助。
您實際上應該始終保持代碼異步,而不是嘗試混合同步和異步代碼
namespace comp.Services {
public class CompService {
static HttpClient client = new HttpClient();
static CompService() {
client.BaseAddress = new Uri("someapiurl");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<string> GetProductAsync(string path) {
var resp = string.Empty;
using(var response = await client.GetAsync(path)) {
if (response.IsSuccessStatusCode) {
resp = await response.Content.ReadAsStringAsync();
}
}
return resp;
}
}
}
控制器動作也應設為異步
namespace comp.Controllers {
public class HomeController : Controller {
private CompService compService;
public HomeController() {
compService = new CompService();
}
public async Task<ActionResult> About() {
var timeServer = await compService.GetProductAsync("api/time");
ViewBag.timeServer = timeServer;
return View();
}
}
}
也就是說,服務也應該抽象
public interface ICompService {
Task<string> GetProductAsync(string path)
}
public class CompService : ICompService {
//...code removed for brevity
}
並注入到控制器中,而不是手動創建。
public class HomeController : Controller {
private ICompService compService;
public HomeController(ICompService compService) {
this.compService = compService;
}
public async Task<ActionResult> About() {
var timeServer = await compService.GetProductAsync("api/time");
ViewBag.timeServer = timeServer;
return View();
}
}
您所遇到的是一個僵局。 與控制台應用程序不同,ASP.Net應用程序在同步上下文中運行。 當您使用GetResult()
阻止時,將捕獲該上下文。 然后,在GetProductAsync
,您等待被阻止的上下文。 它必須等到GetResult
完成后才能恢復,而GetResult
必須等到等待完成后才能解決。
@NKosi的答案應該可以解決問題,沒有理由讓您擁有任何同步代碼。
您可以通過明確允許等待在其他上下文中運行來破解您的代碼,以使其正常工作。 您不應該在生產中執行此操作,這不是解決方法。 如果有人不小心維護CompService
它可能會失敗。
要等待不同的上下文,請更改此:
var timeServer = await compService.GetProductAsync("api/time");
對此:
var timeServer = await compService.GetProductAsync("api/time").ConfigureAwait(false);
我提到這一點只是為了幫助您了解代碼中正在發生的事情。 不要以這種方式“修復”它並繼續前進。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.