首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HttpResponseMessage无反应

HttpResponseMessage无反应
EN

Stack Overflow用户
提问于 2018-02-18 13:56:09
回答 2查看 786关注 0票数 2

我有MVC项目,服务如下:

代码语言:javascript
复制
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查看:

代码语言:javascript
复制
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();
        }
    }
}

当我在调试器中遇到这一行时:

代码语言:javascript
复制
HttpResponseMessage response = await client.GetAsync(path);

程序从调试器退出,浏览器中没有响应。

在控制台应用程序中编写的相同代码可以工作。

在VS输出中是响应成功的消息:

代码语言:javascript
复制
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"}}}}

在浏览器控制台输出:

代码语言:javascript
复制
[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()

谢谢你帮忙。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-02-18 14:12:51

您应该始终保持代码异步,而不是尝试混合同步和异步代码。

代码语言:javascript
复制
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;
        }
    }
}

控制器操作也应该是异步的。

代码语言:javascript
复制
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();
        }
    }
}

也就是说,服务也应该是抽象的。

代码语言:javascript
复制
public interface ICompService {
    Task<string> GetProductAsync(string path)
}

public class CompService : ICompService {
    //...code removed for brevity
}

然后注入控制器而不是手动创建它。

代码语言:javascript
复制
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();
    }
}

参考异步/等待-异步编程的最佳实践

票数 2
EN

Stack Overflow用户

发布于 2018-02-18 15:13:59

你现在陷入僵局了。与控制台应用程序不同,ASP.Net应用程序在同步上下文中运行。当您使用GetResult()进行阻塞时,将捕获该上下文。然后,在GetProductAsync中,等待被阻塞的上下文。在完成GetResult之前,它不能恢复,直到等待完成才能解决问题。

@NKosi的答案应该可以解决这个问题,您没有理由拥有任何同步代码。

只作示范

您可以通过显式地允许您的等待程序在不同的上下文上运行来破解代码。您不应该在生产中这样做,这不是一个修复。如果维护CompService的人不小心,它可能会失败。

若要等待不同的上下文,请更改以下内容:

代码语言:javascript
复制
 var timeServer = await compService.GetProductAsync("api/time");

对此:

代码语言:javascript
复制
 var timeServer = await compService.GetProductAsync("api/time").ConfigureAwait(false);

我提到这一点只是为了帮助您了解代码中正在发生的事情。不要用这种方式“修理”它,继续前进。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48852453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档