解决 同步使用HttpClient

罗伯特·NZ

活跃的成员
已加入
2020年6月26日
留言内容
34
编程经验
Beginner
的建议 跳伞 为了我的 上一个问题 将我定向到HttpClient,现在我成功地向CICS Web服务发送了一条消息,并收到了包含以下代码的响应。这是基于 HttpClient教程

我如何进行转换,以便第22行等待响应,如果请求超时或存在其他问题,则会引发错误。

C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
using System.Text;

namespace MyJSv
{
    public class JSPG2Client
    {
        static readonly HttpClient client = new HttpClient();
        public async Task Post(IJSPG2 ijspg2)
        {
            try
            {
                var json = JsonConvert.SerializeObject(ijspg2);
                json = "{\"JSPG2\" : {\"IJSPG2\" : " + json + "}}";
                var data = new StringContent(json, Encoding.UTF8, "application/json");
                var url = "http://localhost:9003/cics/services/JSPG2";
                var response = 等待 client.PostAsync(url, data);
                String result = response.Content.ReadAsStringAsync().Result;
                Console.WriteLine(result);
            }
            catch(HttpRequestException e)
            {
                Console.WriteLine("\nException Caught!");
                Console.WriteLine("Message :{0} ", e.Message);
            }
        }
    }
}

我当前的测试使用调试从按钮的click事件(在下面)启动后逐步调试Post,但是控制使JSPG2Client.Post立即执行第22行。
C#:
        private void btnEnquire_Click(object sender, EventArgs e)
        {
            ijspg2.JZ_Function = "E";
            ijspg2.JZ_Employee.EMPNO = txtEmpno.Text;
            jspg2Client.Post(ijspg2);
        }
我真的很想将Post方法的签名更改为
公开帖子(IJSPG2 ijspg2,参考OJSPG2 ojspg2)
尽可能简化界面。

感谢您的帮助,
罗伯特
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,501
地点
悉尼,澳大利亚
编程经验
10+
我如何进行转换,以便第22行等待响应,如果请求超时或存在其他问题,则会引发错误。
看起来它已经做到了。如果不是,您怎么可能从响应中读取内容?
 

罗伯特·NZ

活跃的成员
已加入
2020年6月26日
留言内容
34
编程经验
Beginner
看起来它已经做到了。如果不是,您怎么可能从响应中读取内容?
正如我所说,我目前正在使用调试逐步测试。测试到达第22行(​​下面为= 1):-
C#:
                var response = 等待 client.PostAsync(url, data);
                String result = response.Content.ReadAsStringAsync().Result;
当您在此行上单击F10时,突出显示消失,并且重新出现该窗体。如果您等待一秒钟左右,服务将响应,该表格将消失,并且#23行将突出显示。再次单击F10,第23行在结果中输入一个可以检查的值:这是我期望从Web服务获得的JSON代码。

我认为代码异步运行的原因是这种行为,再加上
  • 调用语句jspg2Client.Post(ijspg2); (我的第一条消息的第二个代码示例中的#5)产生警告消息CS4014,"因为不等待此调用,所以在调用完成之前将继续执行当前方法。考虑将“ 等待”运算符应用于调用结果"。我还没有找到执行此操作的方法(及时的建议不起作用),此外,我不想以这种方式使接口复杂化。
  • 我不能将输出作为参数传递回去。如果我尝试写
    C#:
    public async Task Post(IJSPG2 ijspg2, ref OJSPG2 ojspg2)
    然后我收到消息CS1988,"异步方法不能具有ref,in或out参数"
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
Welcome to the viral nature of async/await.

You should really adopt the use of async/await to make your UI more responsive. But if you really want to get rid of the 等待 you would do on line 21 the same thing that you did on line 22:
C#:
var response = client.PostAsync(url, data).Result;
String result = response.Content.ReadAsStringAsync().Result;
通常,不建议这样做。如果该POST呼叫超时需要30秒,那么您的用户界面将被冻结30秒。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,501
地点
悉尼,澳大利亚
编程经验
10+
Welcome to the viral nature of async/await.

You should really adopt the use of async/await to make your UI more responsive. But if you really want to get rid of the 等待 you would do on line 21 the same thing that you did on line 22:
C#:
var response = client.PostAsync(url, data).Result;
String result = response.Content.ReadAsStringAsync().Result;
通常,不建议这样做。如果该POST呼叫超时需要30秒,那么您的用户界面将被冻结30秒。
我猜一个选择是使用条件编译和使用 。结果 在调试和 等待 在发布。我从来没有真正遇到过调试异步代码的问题,但是我主要在Web应用程序中使用了它,所以也许我一直在研究的场景都略有不同。
 

罗伯特·NZ

活跃的成员
已加入
2020年6月26日
留言内容
34
编程经验
Beginner
Welcome to the viral nature of async/await.

You should really adopt the use of async/await to make your UI more responsive. But if you really want to get rid of the 等待 you would do on line 21 the same thing that you did on line 22:
C#:
var response = client.PostAsync(url, data).Result;
String result = response.Content.ReadAsStringAsync().Result;
通常,不建议这样做。如果该POST呼叫超时需要30秒,那么您的用户界面将被冻结30秒。
感谢Skydiver和jmcilhinney。我现在将使用该建议,但我只是开始创建接口对象的开发任务(请参见 这个查询),我不确定结果如何。我想以对象JSPG2Client或它控制的对象中的所有内容结束,使用JSPG2Client的程序(Windows / Web / Mobile)看不到任何东西,除了它公开的属性。我不确定我能接近多远。我认为最好的解决方案可能是给JSPG2Client一个属性"Async"(布尔值)以使用原始代码或修订的同步版本。

目前,我正在为许多新概念和新语言而苦苦挣扎,因此进展缓慢。我一直被C#和VB.NET之间的差异所困扰,因此会有更多的问题,其中有些愚蠢。谢谢您的放心。

我去的时候给自己倒了一杯酒 :)
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
在.NET世界中,每个人都试图遵循的原则之一(自.NET Framework和C#诞生之初起)就是最令人惊讶的原则。通常,C#中的大多数属性都应该很便宜-例如它们不会做很多工作,不会引起副作用,并且不应抛出与setter中的验证无关的任何异常。应该使用方法而不是属性来完成工作。如果设计类库时对属性的读取或写入会在后台发生很多魔术,那么您应该重新考虑一下,或者非常大量地编写代码,并提供许多示例和说明,副作用应该是可以预期的。
 

罗伯特·NZ

活跃的成员
已加入
2020年6月26日
留言内容
34
编程经验
Beginner
在.NET世界中,每个人都试图遵循的原则之一(自.NET Framework和C#诞生之初起)就是最令人惊讶的原则。通常,C#中的大多数属性都应该很便宜-例如它们不会做很多工作,不会引起副作用,并且不应抛出与setter中的验证无关的任何异常。应该使用方法而不是属性来完成工作。如果设计类库时对属性的读取或写入会在后台发生很多魔术,那么您应该重新考虑一下,或者非常大量地编写代码,并提供许多示例和说明,副作用应该是可以预期的。
谢谢跳伞运动员,我谨记这一点。接口将抛出的唯一异常将与设置器中的验证有关,或者与Web服务发生某种故障有关(根据我开始的示例代码中的try / catch)。该项目的目的是使客户端开发人员可以通过以下方式轻松访问Web服务:
  • 以可发现的方式定义有效的字段(类)名称。如果您知道该服务已命名"JSPG2"然后您会看到它的输入消息称为"IJSPG2",而IJSPG2中的字段名称是....
  • 定义每个字段(类)可能包含的值,并提供客户端验证。因此,即使您知道记录键是EMPNO,也无需等待请求/响应即可发现它必须是数字且范围为1:999999。
  • Providing rules about 如何 access the service (GET, POST, ... what is the URL). Thus for JSPG2Client there is only POST.
  • 强制执行任何流程规则:例如,更新必须跟随查询,并且必须从查询返回校验和值。
  • 简而言之,将Web服务的所有规则封装到一个对象中,以确保系统的一致性,并在服务发展时易于更新客户端代码。
目前我在"Initial research"该项目的阶段。我的测试执行了一些规则,并且已经解决了一些早期的问题。

真正的项目是通过让Jazz生成接口,为Jazz可以生成的任何JSON Web服务实现此功能。什么时候"Initial research"更完整,可以请您回顾一下我做了什么以及下一步的建议吗?

In the meantime I think that we can mark this question as 解决 - I'll do this tomorrow when I've checked out one more thing. There'll probably be another "how to"在一天左右的时间内提出关于从setter抛出异常的问题,但我会首先尝试自己解决它。

我非常感谢您提供给我的帮助。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
There is a recent thread here (or was it DreamInCode.net?) which was asking 如何 do validation in a setter.
 

罗伯特·NZ

活跃的成员
已加入
2020年6月26日
留言内容
34
编程经验
Beginner
感谢Skydiver,本文将在下一阶段有用,因为我将注意力转移到验证属性设置的问题上。我正在标记这个问题"Resolved"现在,我已经成功地使用下面的代码运行了一个测试,该测试将一个类层次结构转换为JSON,将其发送到Web服务,获取响应,然后将其转换回另一个类层次结构。好极了!
C#:
    public class JSPG2Client
    {
        static readonly HttpClient client = new HttpClient();
        public ResponseJSPG2 Post(RequestJSPG2 ijspg2)
        {
            try
            {
                var json = JsonConvert.SerializeObject(ijspg2);
                var data = new StringContent(json, Encoding.UTF8, "application/json");
                var url = "http://localhost:9003/cics/services/JSPG2";
                var response = client.PostAsync(url, data).Result;
                String result = response.Content.ReadAsStringAsync().Result;
                var resultclass = JsonConvert.DeserializeObject<ResponseJSPG2>(result);
                return resultclass;
            }
            catch (HttpRequestException e)
            {
                var Er = new ResponseJSPG2();
                Er.JSPG2Response.OJSPG2.JZERROR.JZD_ERROR = "Exception! " + e.Message;
                return Er;
            }
        }
    }
在下一阶段,我的计划是使实际消息(RequestJSPG2和ResponseJSPG2)成为JSPG2Client的私有消息,用户将通过JSPG2Client属性进行通信。这些属性将使设置程序根据尽可能多的原始定义来验证输入。"Viewstate"校验和之类的属性不会被公开。

继续下一个问题!我开始对C#充满信心,我不再写"Dim"当我想要一个新变量时,我正在学习分号和{}的去向 :)
 
最佳 底部