簡體   English   中英

HttpResponseMessage沒有響應

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

參考Async / Await-異步編程最佳實踐

您所遇到的是一個僵局。 與控制台應用程序不同,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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM