C# 如何将我的aysnc帖子转换为同步?

C# 如何将我的aysnc帖子转换为同步?,c#,http-post,C#,Http Post,我编写了一个C#程序,它异步地向供应商发出API调用,以生成提交令牌。然后将该令牌附加到任何表单post负载,以验证其完整性。作为一个独立的.NET4.6.1应用程序,它非常有用。我遇到的问题是将它集成到我的CMS中。在与CMS支持人员交谈后,他们要求我将其改为同步操作。我在转换代码时遇到问题。特别是关于在检索令牌后发布表单的部分 这是我最初编写的源代码。显然,AppID和机密已被删除 using Newtonsoft.Json; using Newtonsoft.Json.Linq; usin

我编写了一个C#程序,它异步地向供应商发出API调用,以生成提交令牌。然后将该令牌附加到任何表单post负载,以验证其完整性。作为一个独立的.NET4.6.1应用程序,它非常有用。我遇到的问题是将它集成到我的CMS中。在与CMS支持人员交谈后,他们要求我将其改为同步操作。我在转换代码时遇到问题。特别是关于在检索令牌后发布表单的部分

这是我最初编写的源代码。显然,AppID和机密已被删除

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI;

namespace FormSubmission
{
    public partial class _Default : Page
    {
        protected async void Page_Load(object sender, EventArgs e)
        {
            var start = new Start();
            await start.KickOff();
        }

        public class Start
        {

            public async Task<String> KickOff()
            {
                var auth = new Authentication();
                var token = await auth.Authenticate();

                // return await Task.FromResult(token);
                // //Task.FromResult(token);
                if (!String.IsNullOrEmpty(token))
                {
                    var form = new FormSubmission();
                    var formFields = new Form();
                    formFields.createMethod = "SubmitForm";
                    formFields.email = "email@email.com";
                    formFields.mobile = "555-555-5555";
                    formFields.remark = "Hello, hope this works";
                    formFields.attr.attr3 = "mnc";
                    formFields.attr.attr6 = "1000";
                    formFields.attr.attr10 = "first name";
                    formFields.attr.attr11 = "lastname";
                    formFields.attr.attr14 = "City";
                    formFields.attr.attr15 = "State";
                    formFields.attr.attr18 = "USA";
                    formFields.attr.attr25 = "USA";
                    formFields.attr.attr28 = "Newsletter";

                    var serializer = JsonSerializer.Create();

                    var optionsString = new StringBuilder();
                    var writer = new StringWriter(optionsString);

                    serializer.Serialize(writer, formFields);

                    await form.Submit(token, optionsString.ToString());
                }

                return await Task.FromResult("");

            }
        }

        public class Authentication 
        {
            private const string appId = "XXXXXXXXXXXXX";
            private const string secret = "XXXXXXXXXXXXXXXXXXXXXX";

            public async Task<String> Authenticate()
            {
                string url = "https://api-url-goes-here";
                string token = "";

                try
                {

                    using (var client = new HttpClient())
                    {
                        var responseMessage = await client.GetAsync(url + appId + "&secret=" + secret);
                        var content = await responseMessage.Content.ReadAsStringAsync();
                        var contentObject = JObject.Parse(content);
                        token = contentObject["access_token"].ToString();
                        return token;
                    };
                }
                catch (Exception e)
                {
                    throw new Exception("Access token not found");
                }

            }
        }

        public class FormSubmission
        {

            public async Task Submit(string token, string json)
            {
                using (var client = new HttpClient())
                {
                    var message = await client.PostAsync(
                        "https://api-url-goes-here/access_token=" + token,
                        new StringContent(json, Encoding.UTF8, "application/json"));

                    var content = await message.Content.ReadAsStringAsync();
                    Console.Write(content);
                }
            }
        }
    }
}
正如你所看到的,它应该是相同的代码。我在submitForm类的Submit方法中遇到的问题。当我运行程序并打开fiddler时,我可以看到获取令牌的请求。并收到一个令牌。是submitForm类给了我问题。我甚至没有在fiddler中看到POST请求。有人能帮我吗

这是给我出问题的班级

public class submitForm
{
    public void Submit(string token, string json)
    {
        using (var client = new HttpClient())
        {
            var message = client.PostAsync("https://api-url-goes-here/v1/customers?access_token=" + token,
                new StringContent(json, Encoding.UTF8, "application/json"));

        }
    }
}
这并不像您预期的那样,因为
消息
现在是一项
任务
,而不是您希望的响应,因为您没有等待
后同步
完成

要使此同步,您有两个选项:

  • 对其调用
    .GetAwaiter().GetResult()
    。可以在之前使用的任何位置使用
    wait
    ,并且不存在该方法的同步版本。例如:
  • 下面介绍了使用
    .GetAwaiter().GetResult()
    而不仅仅是
    .Result
    的原因(基本上是因为异常是如何引发的)

    或者

  • 使用
    HttpWebRequest
    而不是
    HttpClient
    发出相同的请求,就像您在代码的另一部分中所做的那样,因此您不必处理仅异步的方法
  • 这并不像您预期的那样,因为
    消息
    现在是一项
    任务
    ,而不是您希望的响应,因为您没有等待
    后同步
    完成

    要使此同步,您有两个选项:

  • 对其调用
    .GetAwaiter().GetResult()
    。可以在之前使用的任何位置使用
    wait
    ,并且不存在该方法的同步版本。例如:
  • 下面介绍了使用
    .GetAwaiter().GetResult()
    而不仅仅是
    .Result
    的原因(基本上是因为异常是如何引发的)

    或者

  • 使用
    HttpWebRequest
    而不是
    HttpClient
    发出相同的请求,就像您在代码的另一部分中所做的那样,因此您不必处理仅异步的方法

  • 这可能不是您想要听到的,但不应该将异步方法转换为同步方法。当您使用
    GetAwaiter().GetResult()
    时,您可能会幸运地发现它们可以工作,但是存在死锁的风险,或者它们不能正常工作。您可以使用
    任务运行它们。运行
    然后运行
    GetAwaiter().GetResult()
    ,但这会使另一个线程旋转,因此效率不高,并且代码仍然处于阻塞状态。使它比同步代码慢,因为它必须旋转另一个线程。另外,它肯定会分配更多gc必须处理的内存


    您还应该使用
    async
    后缀命名异步方法

    这可能不是您想要听到的,但您不应该将异步方法转换为同步方法。当您使用
    GetAwaiter().GetResult()
    时,您可能会幸运地发现它们可以工作,但是存在死锁的风险,或者它们不能正常工作。您可以使用
    任务运行它们。运行
    然后运行
    GetAwaiter().GetResult()
    ,但这会使另一个线程旋转,因此效率不高,并且代码仍然处于阻塞状态。使它比同步代码慢,因为它必须旋转另一个线程。另外,它肯定会分配更多gc必须处理的内存


    您还应该使用
    async
    后缀命名异步方法

    这是“异步同步”,从根本上说是危险和不鼓励的。只是以适当的谨慎对待:)@MarcGravel有需要避免的危险,是的,但一旦避免,就不再危险。但是,是的,我同意这并不理想。我更新了答案,加入了另一个选项,即根本不使用
    HttpClient
    。同步使用异步方法可能会奏效。但若您使用的是外部库,那个么您可以相信它不会改变它的内部实现并导致代码中断。谢谢大家的评论。上述解决方案对我有效,因此我接受了答案。然而,我将继续第二种选择,因为从对话中可以清楚地看出,第一种选择并不理想。我还将把我的代码提交给我的cms支持团队,看看他们是否有任何建议。它比
    HttpClient
    旧,但具有非异步方法,并且仍然比
    HttpWebRequest
    更简单。下面是一个如何发送JSON的示例。并解释了
    HttpWebRequest
    WebClient
    HttpClient
    之间的区别。这是“异步同步”,从根本上讲是危险的,不鼓励使用。只是以适当的谨慎对待:)@MarcGravel有需要避免的危险,是的,但一旦避免,就不再危险。但是,是的,我同意这并不理想。我更新了答案,加入了另一个选项,即根本不使用
    HttpClient
    。同步使用异步方法可能会奏效。但若您使用的是外部库,那个么您可以相信它不会改变它的内部实现并导致代码中断。谢谢大家的评论。上述解决方案对我有效,因此我接受了答案。然而,我将继续第二种选择,因为从对话中可以清楚地看出,第一种选择并不理想。我将
    public class submitForm
    {
        public void Submit(string token, string json)
        {
            using (var client = new HttpClient())
            {
                var message = client.PostAsync("https://api-url-goes-here/v1/customers?access_token=" + token,
                    new StringContent(json, Encoding.UTF8, "application/json"));
    
            }
        }
    }
    
    public void Submit(string token, string json)
    {
        using (var client = new HttpClient())
        {
            var message = client.PostAsync("https://api-url-goes-here/v1/customers?access_token=" + token,
                new StringContent(json, Encoding.UTF8, "application/json"));
    
        }
    }
    
    public void Submit(string token, string json)
    {
        using (var client = new HttpClient())
        {
            var message = client.PostAsync(
                "https://api-url-goes-here/access_token=" + token,
                new StringContent(json, Encoding.UTF8, "application/json")).GetAwaiter().GetResult();
    
            var content = message.Content.ReadAsStringAsync().GetAwaiter().GetResult();
            Console.Write(content);
        }
    }