ChatGPT解决这个技术问题 Extra ChatGPT

在 .NET 中发送 HTTP POST 请求

如何发出 HTTP POST 请求并在正文中发送数据?


3
36 revs, 24 users 32%

有几种方法可以执行 HTTP GETPOST 请求:

方法A:HttpClient(首选)

适用于:.NET Framework 4.5+、.NET Standard 1.1+ 和 .NET Core 1.0+。

它是目前首选的方法,并且是异步的和高性能的。大多数情况下使用内置版本,但对于非常旧的平台,有一个 NuGet package

using System.Net.Http;

设置

It is recommended 为您的应用程序的生命周期实例化一个 HttpClient 并共享它,除非您有特定的理由不这样做。

private static readonly HttpClient client = new HttpClient();

有关 dependency injection 解决方案,请参阅 HttpClientFactory

POST var values = new Dictionary { { "thing1", "hello" }, { "thing2", "world" } }; var content = new FormUrlEncodedContent(values); var response = await client.PostAsync("http://www.example.com/recepticle.aspx", content); var responseString = 等待 response.Content.ReadAsStringAsync();

GET var responseString = await client.GetStringAsync("http://www.example.com/recepticle.aspx");

方法 B:第三方库

RestSharp

POST var client = new RestClient("http://example.com"); // client.Authenticator = new HttpBasicAuthenticator(username, password); var request = new RestRequest("resource/{id}"); request.AddParameter("thing1", "Hello"); request.AddParameter("thing2", "world"); request.AddHeader("header", "value"); request.AddFile("文件", 路径); var response = client.Post(request); var 内容 = 响应。内容; // 原始内容为字符串 var response2 = client.Post(request); var name = response2.Data.Name;

Flurl.Http

它是一个较新的库,带有 fluent API、测试助手、在后台使用 HttpClient,并且是可移植的。可通过 NuGet 获得。

    using Flurl.Http;

POST var responseString = await "http://www.example.com/recepticle.aspx" .PostUrlEncodedAsync(new { thing1 = "hello", thing2 = "world" }) .ReceiveString();

GET var responseString = await "http://www.example.com/recepticle.aspx" .GetStringAsync();

方法C:HttpWebRequest(新作品不推荐)

适用于:.NET Framework 1.1+、.NET Standard 2.0+、.NET Core 1.0+。在 .NET Core 中,它主要是为了兼容性——它包装了 HttpClient,性能较低,并且不会获得新功能。

using System.Net;
using System.Text;  // For class Encoding
using System.IO;    // For StreamReader

POST var request = (HttpWebRequest)WebRequest.Create("http://www.example.com/recepticle.aspx"); var postData = "thing1=" + Uri.EscapeDataString("hello"); postData += "&thing2=" + Uri.EscapeDataString("world"); var data = Encoding.ASCII.GetBytes(postData); request.Method = "POST"; request.ContentType = "应用程序/x-www-form-urlencoded"; request.ContentLength = data.Length;使用 (var stream = request.GetRequestStream()) { stream.Write(data, 0, data.Length); } var response = (HttpWebResponse)request.GetResponse(); var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

GET var request = (HttpWebRequest)WebRequest.Create("http://www.example.com/recepticle.aspx"); var response = (HttpWebResponse)request.GetResponse(); var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

方法D:WebClient(新作品不推荐)

这是 HttpWebRequest 的包装。 Compare with HttpClient

适用于:.NET Framework 1.1+、NET Standard 2.0+ 和 .NET Core 2.0+。

在某些情况下(.NET Framework 4.5-4.8),如果需要同步进行 HTTP 请求,仍然可以使用 WebClient

using System.Net;
using System.Collections.Specialized;

POST 使用 (var client = new WebClient()) { var values = new NameValueCollection();值[“thing1”] =“你好”;值[“thing2”] =“世界”; var response = client.UploadValues("http://www.example.com/recepticle.aspx", values); var responseString = Encoding.Default.GetString(response); }

GET 使用 (var client = new WebClient()) { var responseString = client.DownloadString("http://www.example.com/recepticle.aspx"); }


@劳埃德:HttpWebResponse response = (HttpWebResponse)HttpWReq.GetResponse();
为什么你甚至使用ASCII?如果有人需要带有 UTF-8 的 xml 怎么办?
我讨厌打死马,但你应该这样做response.Result.Content.ReadAsStringAsync()
你为什么说 WebRequest 和 WebClient 是遗留的? MSDN 并没有说它们已被弃用或其他任何东西。我错过了什么吗?
@Hiep:它们并没有被弃用,只是有更新的(在大多数情况下,更好、更灵活)的方式来发出 Web 请求。在我看来,对于简单的、非关键的操作,旧方法就可以了——但这取决于你和你最喜欢的方式。
J
J. Doe

简单的 GET 请求

using System.Net;

...

using (var wb = new WebClient())
{
    var response = wb.DownloadString(url);
}

简单的 POST 请求

using System.Net;
using System.Collections.Specialized;

...

using (var wb = new WebClient())
{
    var data = new NameValueCollection();
    data["username"] = "myUser";
    data["password"] = "myPassword";

    var response = wb.UploadValues(url, "POST", data);
    string responseInString = Encoding.UTF8.GetString(response);
}

+1 对于普通的东西 POST,有这么短的代码真是太好了。
Tim - 如果您右键单击无法解析的文字,您将找到一个 Resolve 上下文菜单,其中包含为您添加 Using 语句的操作。如果 Resolve 上下文菜单未显示,则意味着您需要先添加引用。
我接受了您的回答,因为它更简单,更清晰。
我想补充一点,POST 请求的响应变量是一个字节数组。为了获得字符串响应,您只需执行 Encoding.ASCII.GetString(response); (使用 System.Text)
此外,您可以发送一个有点复杂的数组 $_POST['user'] 为: data["user[username]"] = "myUsername";数据["用户[密码]"] = "我的密码";
E
Endorphinex

MSDN 有一个示例。

using System;
using System.IO;
using System.Net;
using System.Text;

namespace Examples.System.Net
{
    public class WebRequestPostExample
    {
        public static void Main()
        {
            // Create a request using a URL that can receive a post. 
            WebRequest request = WebRequest.Create("http://www.contoso.com/PostAccepter.aspx");
            // Set the Method property of the request to POST.
            request.Method = "POST";
            // Create POST data and convert it to a byte array.
            string postData = "This is a test that posts this string to a Web server.";
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
            // Set the ContentType property of the WebRequest.
            request.ContentType = "application/x-www-form-urlencoded";
            // Set the ContentLength property of the WebRequest.
            request.ContentLength = byteArray.Length;
            // Get the request stream.
            Stream dataStream = request.GetRequestStream();
            // Write the data to the request stream.
            dataStream.Write(byteArray, 0, byteArray.Length);
            // Close the Stream object.
            dataStream.Close();
            // Get the response.
            WebResponse response = request.GetResponse();
            // Display the status.
            Console.WriteLine(((HttpWebResponse)response).StatusDescription);
            // Get the stream containing content returned by the server.
            dataStream = response.GetResponseStream();
            // Open the stream using a StreamReader for easy access.
            StreamReader reader = new StreamReader(dataStream);
            // Read the content.
            string responseFromServer = reader.ReadToEnd();
            // Display the content.
            Console.WriteLine(responseFromServer);
            // Clean up the streams.
            reader.Close();
            dataStream.Close();
            response.Close();
        }
    }
}

由于某种原因,当我发送大量数据时它不起作用
@AnKing 有可能是服务器限制而不是客户端发送它。
P
Peter Mortensen

这是一个以 JSON 格式发送/接收数据的完整工作示例,我使用的是 Visual Studio 2013 Express 版:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;

namespace ConsoleApplication1
{
    class Customer
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public string Phone { get; set; }
    }

    public class Program
    {
        private static readonly HttpClient _Client = new HttpClient();
        private static JavaScriptSerializer _Serializer = new JavaScriptSerializer();

        static void Main(string[] args)
        {
            Run().Wait();
        }

        static async Task Run()
        {
            string url = "http://www.example.com/api/Customer";
            Customer cust = new Customer() { Name = "Example Customer", Address = "Some example address", Phone = "Some phone number" };
            var json = _Serializer.Serialize(cust);
            var response = await Request(HttpMethod.Post, url, json, new Dictionary<string, string>());
            string responseText = await response.Content.ReadAsStringAsync();

            List<YourCustomClassModel> serializedResult = _Serializer.Deserialize<List<YourCustomClassModel>>(responseText);

            Console.WriteLine(responseText);
            Console.ReadLine();
        }

        /// <summary>
        /// Makes an async HTTP Request
        /// </summary>
        /// <param name="pMethod">Those methods you know: GET, POST, HEAD, etc...</param>
        /// <param name="pUrl">Very predictable...</param>
        /// <param name="pJsonContent">String data to POST on the server</param>
        /// <param name="pHeaders">If you use some kind of Authorization you should use this</param>
        /// <returns></returns>
        static async Task<HttpResponseMessage> Request(HttpMethod pMethod, string pUrl, string pJsonContent, Dictionary<string, string> pHeaders)
        {
            var httpRequestMessage = new HttpRequestMessage();
            httpRequestMessage.Method = pMethod;
            httpRequestMessage.RequestUri = new Uri(pUrl);
            foreach (var head in pHeaders)
            {
                httpRequestMessage.Headers.Add(head.Key, head.Value);
            }
            switch (pMethod.Method)
            {
                case "POST":
                    HttpContent httpContent = new StringContent(pJsonContent, Encoding.UTF8, "application/json");
                    httpRequestMessage.Content = httpContent;
                    break;

            }

            return await _Client.SendAsync(httpRequestMessage);
        }
    }
}

A
Adam

这里有一些非常好的答案。让我发布一种使用 WebClient() 设置标题的不同方法。我还将向您展示如何设置 API 密钥。

        var client = new WebClient();
        string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + ":" + passWord));
        client.Headers[HttpRequestHeader.Authorization] = $"Basic {credentials}";
        //If you have your data stored in an object serialize it into json to pass to the webclient with Newtonsoft's JsonConvert
        var encodedJson = JsonConvert.SerializeObject(newAccount);

        client.Headers.Add($"x-api-key:{ApiKey}");
        client.Headers.Add("Content-Type:application/json");
        try
        {
            var response = client.UploadString($"{apiurl}", encodedJson);
            //if you have a model to deserialize the json into Newtonsoft will help bind the data to the model, this is an extremely useful trick for GET calls when you have a lot of data, you can strongly type a model and dump it into an instance of that class.
            Response response1 = JsonConvert.DeserializeObject<Response>(response);

有用,谢谢。顺便说一句,上面设置标头属性的技术似乎也适用于较旧的(已弃用?) HttpWebRequest 方法。例如 myReq.Headers[HttpRequestHeader.Authorization] = $"Basic {credentials}";
P
Peter Mortensen

到目前为止我发现的简单(单行,无错误检查,无等待响应)解决方案:

(new WebClient()).UploadStringAsync(new Uri(Address), dataString);‏

谨慎使用!


那是相当糟糕的。我不推荐它,因为没有任何类型的错误处理并且调试它很痛苦。此外,这个问题已经有了很好的答案。
@Hooch 其他人可能对这种类型的答案感兴趣,即使它不是最好的答案。
同意,唯一有用的上下文是代码打高尔夫球和谁在 C# 打高尔夫球;)
我写这个答案是为了寻找基于 http 的日志记录解决方案,我想其他一些人可能会发现它同样有用。
P
Peter Mortensen

此解决方案只使用标准 .NET 调用。

测试:

在企业 WPF 应用程序中使用。使用 async/await 来避免阻塞 UI。

与 .NET 4.5+ 兼容。

无参数测试(需要在后台使用“GET”)。

使用参数进行测试(需要在后台使用“POST”)。

使用标准网页(例如 Google)进行测试。

使用基于 Java 的内部 Web 服务进行测试。

参考:

// Add a Reference to the assembly System.Web

代码:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;

private async Task<WebResponse> CallUri(string url, TimeSpan timeout)
{
    var uri = new Uri(url);
    NameValueCollection rawParameters = HttpUtility.ParseQueryString(uri.Query);
    var parameters = new Dictionary<string, string>();
    foreach (string p in rawParameters.Keys)
    {
        parameters[p] = rawParameters[p];
    }

    var client = new HttpClient { Timeout = timeout };
    HttpResponseMessage response;
    if (parameters.Count == 0)
    {
        response = await client.GetAsync(url);
    }
    else
    {
        var content = new FormUrlEncodedContent(parameters);
        string urlMinusParameters = uri.OriginalString.Split('?')[0]; // Parameters always follow the '?' symbol.
        response = await client.PostAsync(urlMinusParameters, content);
    }
    var responseString = await response.Content.ReadAsStringAsync();

    return new WebResponse(response.StatusCode, responseString);
}

private class WebResponse
{
    public WebResponse(HttpStatusCode httpStatusCode, string response)
    {
        this.HttpStatusCode = httpStatusCode;
        this.Response = response;
    }
    public HttpStatusCode HttpStatusCode { get; }
    public string Response { get; }
}

不带参数调用(在后台使用“GET”):

 var timeout = TimeSpan.FromSeconds(300);
 WebResponse response = await this.CallUri("http://www.google.com/", timeout);
 if (response.HttpStatusCode == HttpStatusCode.OK)
 {
     Console.Write(response.Response); // Print HTML.
 }

使用参数调用(在幕后使用“POST”):

 var timeout = TimeSpan.FromSeconds(300);
 WebResponse response = await this.CallUri("http://example.com/path/to/page?name=ferret&color=purple", timeout);
 if (response.HttpStatusCode == HttpStatusCode.OK)
 {
     Console.Write(response.Response); // Print HTML.
 }

P
Peter Mortensen

如果您喜欢 fluent API,您可以使用 Tiny.RestClient。可在 NuGet 获得。

var client = new TinyRestClient(new HttpClient(), "http://MyAPI.com/api");
// POST
var city = new City() { Name = "Paris", Country = "France" };
// With content
var response = await client.PostRequest("City", city)
                           .ExecuteAsync<bool>();

i
ikwillem

还有另一种方法:

using (HttpClient httpClient = new HttpClient())
using (MultipartFormDataContent form = new MultipartFormDataContent())
{
    form.Add(new StringContent(param1), "param1");
    form.Add(new StringContent(param2), "param2");
    using (HttpResponseMessage response = await httpClient.PostAsync(url, form))
    {
        response.EnsureSuccessStatusCode();
        string res = await response.Content.ReadAsStringAsync();
        return res;
    }
}

这样您就可以轻松发布流。


一个解释将是有序的。例如,它有什么不同?与其他一些答案相比,有什么优点和缺点?来自 the Help Center“...总是解释为什么你提出的解决方案是合适的以及它是如何工作的”。请通过 editing (changing) your answer 回复,而不是在评论中(没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的)。
P
Peter Mortensen

当使用 Windows.Web.Http 命名空间时,对于 POST 而不是 FormUrlEncodedContent,我们编写 HttpFormUrlEncodedContent。响应也是 HttpResponseMessage 的类型。其余为 Evan Mulawski wrote down


P
Peter Mortensen

为什么这不完全是微不足道的?执行请求不是,尤其是不处理结果。似乎还涉及一些 .NET 错误 - 请参阅 Bug in HttpClient.GetAsync should throw WebException, not TaskCanceledException

我最终得到了这段代码:

static async Task<(bool Success, WebExceptionStatus WebExceptionStatus, HttpStatusCode? HttpStatusCode, string ResponseAsString)> HttpRequestAsync(HttpClient httpClient, string url, string postBuffer = null, CancellationTokenSource cts = null) {
    try {
        HttpResponseMessage resp = null;

        if (postBuffer is null) {
            resp = cts is null ? await httpClient.GetAsync(url) : await httpClient.GetAsync(url, cts.Token);

        } else {
            using (var httpContent = new StringContent(postBuffer)) {
                resp = cts is null ? await httpClient.PostAsync(url, httpContent) : await httpClient.PostAsync(url, httpContent, cts.Token);
            }
        }

        var respString = await resp.Content.ReadAsStringAsync();
        return (resp.IsSuccessStatusCode, WebExceptionStatus.Success, resp.StatusCode, respString);

    } catch (WebException ex) {
        WebExceptionStatus status = ex.Status;
        if (status == WebExceptionStatus.ProtocolError) {
            // Get HttpWebResponse so that you can check the HTTP status code.
            using (HttpWebResponse httpResponse = (HttpWebResponse)ex.Response) {
                return (false, status, httpResponse.StatusCode, httpResponse.StatusDescription);
            }
        } else {
            return (false, status, null, ex.ToString());
        }

    // https://devblogs.microsoft.com/dotnet/net-5-new-networking-improvements/
    } catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException) {
        return (false, ex.ToString(), null, WebExceptionStatus.Timeout);

    } catch (TaskCanceledException ex) {
        return (false, ex.ToString(), null, WebExceptionStatus.RequestCanceled);

    } catch (Exception ex) {
        return (false, WebExceptionStatus.UnknownError, null, ex.ToString());
    }
}

这将根据 postBuffer 是否为空来执行 GET 或 POST。

如果 Success 为真,则响应将在 ResponseAsString 中。

如果 Success 为 false,您可以检查 WebExceptionStatusHttpStatusCodeResponseAsString 来尝试查看问题所在。


我已经为此工作太久了。 Soooo 远非微不足道......在 Java 中我需要大约 6-8 行。
P
Peter Mortensen

这是 HTTPS Web 请求的示例。您可以在 PHP 脚本中回显任何结果。最后,PHP 回显字符串将在 C# 客户端显示为警报。

string url = "https://mydomain.ir/test1.php";
StringBuilder postData = new StringBuilder();
postData.Append(String.Format("{0}={1}&", HttpUtility.HtmlEncode("username"), HttpUtility.HtmlEncode("ali")));
postData.Append(String.Format("{0}={1}", HttpUtility.HtmlEncode("password"), HttpUtility.HtmlEncode("123456789")));
StringContent myStringContent = new StringContent(postData.ToString(), Encoding.UTF8, "application/x-www-form-urlencoded");
HttpClient client = new HttpClient();
HttpResponseMessage message = client.PostAsync(url, myStringContent).GetAwaiter().GetResult();
string responseContent = message.Content.ReadAsStringAsync().GetAwaiter().GetResult();

DisplayAlert("Your Feedback", responseContent, "OK");

PHP服务器端:

<?php
  if (isset($_POST["username"]) && $_POST["username"] == "ali") {
    echo "Yes, hi Ali";
  }
  else {
    echo "No, where is Ali?";
  }
?>

结果将是“是的,你好 Ali”。

这适用于 Xamarin 表单。对于 C# .NET 应用程序,将 DisplayAlert 替换为:

MessageBox.show(responseContent);

P
Peter Mortensen

.NET Core 中,您可以使用以下代码进行 POST 调用。在这里,我向此代码添加了一些额外的功能,因此您可以使您的代码在代理后面工作,并使用网络凭据(如果有)。

另外在这里我提到您可以更改消息的编码。

HttpClient client = GetHttpClient(_config);

if (headers != null)
{
    foreach (var header in headers)
    {
        client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);
    }
}

client.BaseAddress = new Uri(baseAddress);

Encoding encoding = Encoding.UTF8;

var result = await client.PostAsync(url, new StringContent(body, encoding, "application/json")).ConfigureAwait(false);
if (result.IsSuccessStatusCode)
{
    return new RequestResponse { severity = "Success", httpResponse = result.Content.ReadAsStringAsync().Result, StatusCode = result.StatusCode };
}
else
{
    return new RequestResponse { severity = "failure", httpResponse = result.Content.ReadAsStringAsync().Result, StatusCode = result.StatusCode };
}


public HttpClient GetHttpClient(IConfiguration _config)
{
    bool ProxyEnable = Convert.ToBoolean(_config["GlobalSettings:ProxyEnable"]);

    HttpClient client = null;
    if (!ProxyEnable)
    {
        client = new HttpClient();
    }
    else
    {
        string ProxyURL = _config["GlobalSettings:ProxyURL"];
        string ProxyUserName = _config["GlobalSettings:ProxyUserName"];
        string ProxyPassword = _config["GlobalSettings:ProxyPassword"];
        string[] ExceptionURL = _config["GlobalSettings:ExceptionURL"].Split(';');
        bool BypassProxyOnLocal = Convert.ToBoolean(_config["GlobalSettings:BypassProxyOnLocal"]);
        bool UseDefaultCredentials = Convert.ToBoolean(_config["GlobalSettings:UseDefaultCredentials"]);

        WebProxy proxy = new WebProxy
        {
            Address = new Uri(ProxyURL),
            BypassProxyOnLocal = BypassProxyOnLocal,
            UseDefaultCredentials = UseDefaultCredentials,
            BypassList = ExceptionURL,
            Credentials = new NetworkCredential(ProxyUserName, ProxyPassword)
        };

        HttpClientHandler handler = new HttpClientHandler { Proxy = proxy };
        client = new HttpClient(handler, true);
    }
    return client;
}

P
Peter Mortensen

这是我在 .NET 4.8 中用来发出 HTTP POST 请求的内容。使用此代码,可以一次异步发送多个 POST 请求。

在每个请求结束时都会引发一个事件。并且在所有请求结束时也会引发另一个事件。

下面是核心类:

Imports System.ComponentModel
Imports System.Text.RegularExpressions
Imports System.Timers
Imports System.Windows.Forms
Imports AeonLabs
Imports AeonLabs.Environment
Imports Newtonsoft.Json

Public Class HttpDataCore
    Public Property url As String
    Public Property state As New environmentVarsCore
    Public Property errorMessage As String = ""
    Public Property statusMessage As String
    Public Property threadCount As Integer = 25
    Public Property numberOfRetryAttempts = 5
    Public Property queue As List(Of _queue_data_struct)
    Public Property queueBWorker As Integer() ' has the size of threadCount
    Public Property queueLock As New Object
    Public Property retryAttempts As New _retry_attempts
    Public Property dataStatistics As List(Of _data_statistics)
    Public Property loadingCounter As Integer
    Public Property CompletionPercentage As Integer ' value range 0-100
    Public Property IsBusy As Boolean

    Public Structure _queue_data_struct
        Dim vars As Dictionary(Of String, String)
        Dim filenameOrSavePath As String                  ' full address file name or full adress folder path
        Dim misc As Dictionary(Of String, String)
        Dim status As Integer                             ' -1 - completed; 0- not sent yet; 1-already sent / processing
    End Structure

    Public Structure _retry_attempts
        Dim counter As Integer
        Dim pattern As Integer
        Dim previousPattern As Integer
        Dim errorMessage As String
    End Structure

    Public Structure _data_statistics
        Dim filesize As Double
        Dim bytesSentReceived As Double
        Dim speed As Double
    End Structure

    Public WithEvents RestartQueueTimer As New Timers.Timer
    Public bwDataRequest() As BackgroundWorker

    Public Event requestCompleted(sender As Object, requestData As String) 'TODO add misc vars

    Private sendToQueue As Boolean

    Public Sub New(ByVal Optional _state As environmentVarsCore = Nothing, ByVal Optional _url As String = "")
        queue = New List(Of _queue_data_struct)
        dataStatistics = New List(Of _data_statistics)
        loadingCounter = 0
        sendToQueue = False
        If _state IsNot Nothing AndAlso _url.Equals("") Then
            url = _state.ServerBaseAddr & _state.ApiServerAddrPath
        ElseIf Not _url.Equals("") Then
            url = _url
        Else
            Throw New System.Exception("Initialization err: state and url cannot be both null at same time")
        End If

        If _state IsNot Nothing Then
            state = _state
        End If
    End Sub

    Public Sub loadQueue(ByVal vars As Dictionary(Of String, String), ByVal Optional misc As Dictionary(Of String, String) = Nothing, ByVal Optional filenameOrSavePath As String = Nothing)
        Dim queueItem As New _queue_data_struct
        queueItem.vars = New Dictionary(Of String, String)
        queueItem.misc = New Dictionary(Of String, String)

        queueItem.vars = vars
        queueItem.status = 0
        queueItem.misc = misc
        queueItem.filenameOrSavePath = filenameOrSavePath
        queue.Add(queueItem)
    End Sub

    Public Sub clearQueue()
        loadingCounter = 0
        queue = New List(Of _queue_data_struct)
    End Sub

    Public Sub startRequest()
        If bwDataRequest(0) Is Nothing Then
            Throw New Exception("You need to call initialze first")
            Exit Sub
        End If

        'startSendQueue()
        IsBusy = True

        AddHandler RestartQueueTimer.Elapsed, New ElapsedEventHandler(AddressOf QueueTimerTick)
        With RestartQueueTimer
            .Enabled = True
            .Interval = 500
            .Start()
        End With
    End Sub

    Private Sub QueueTimerTick(ByVal sender As Object, ByVal e As ElapsedEventArgs)
        If QueuesToComplete(queue).Equals(0) And QueuesToSend(queue).Equals(0) Then
            RestartQueueTimer.Stop()
            queue = New List(Of _queue_data_struct)
            RaiseEvent requestCompleted(Me, Nothing)
            IsBusy = False
            Exit Sub
        End If

        If retryAttempts.counter >= numberOfRetryAttempts Then 'ToDo a retry number of attempts before quits
            Threading.Thread.CurrentThread.CurrentUICulture = Globalization.CultureInfo.GetCultureInfo(state.currentLang)
            Dim MsgBox As messageBoxForm
            MsgBox = New messageBoxForm(retryAttempts.errorMessage & ". " & My.Resources.strings.tryAgain & " ?", My.Resources.strings.question, MessageBoxButtons.YesNo, MessageBoxIcon.Question)
            If MsgBox.ShowDialog() = DialogResult.Yes Then
                Dim retry As _retry_attempts
                With retry
                    .counter = 0
                    .previousPattern = -1
                    .pattern = 0
                    .errorMessage = ""
                End With
                retryAttempts = retry
                startSendQueue()
            Else
                RestartQueueTimer.Stop()
                queue = New List(Of _queue_data_struct)
                RaiseEvent requestCompleted(Me, Nothing)
                IsBusy = False
                Exit Sub
            End If
            Exit Sub
        ElseIf Not sendToQueue And QueuesToSend(queue) > 0 Then
            startSendQueue()
        End If
    End Sub

    Private Sub startSendQueue()
        sendToQueue = True
        While QueuesToSend(queue) > 0
            For shtIndex = 0 To threadCount
                For i = 0 To queue.Count - 1
                    If Not bwDataRequest(shtIndex).IsBusy Then
                        SyncLock queueLock
                            If queue.ElementAt(i).status.Equals(0) Then
                                Dim data As New _queue_data_struct
                                data.vars = queue.ElementAt(i).vars
                                data.status = 1
                                data.misc = queue.ElementAt(i).misc
                                data.filenameOrSavePath = queue.ElementAt(i).filenameOrSavePath
                                queue(i) = data
                                queueBWorker(shtIndex) = i
                                dataStatistics(shtIndex) = (New _data_statistics)

                                bwDataRequest(shtIndex).RunWorkerAsync(queue(i))
                                Threading.Thread.Sleep(50)
                            End If
                        End SyncLock
                    End If
                Next i
            Next shtIndex
        End While
        sendToQueue = False
    End Sub

    Public Function QueuesToSend(queue As List(Of _queue_data_struct)) As Integer
        Dim counter As Integer = 0
        For i = 0 To queue.Count - 1
            If queue(i).status.Equals(0) Then
                counter += 1
            End If
        Next i
        Return counter
    End Function

    Public Function QueuesToComplete(queue As List(Of _queue_data_struct)) As Integer
        Dim counter As Integer = 0
        For i = 0 To queue.Count - 1
            If queue(i).status.Equals(1) Then
                counter += 1
            End If
        Next i
        Return counter
    End Function

    Public Function QueuesMultiHash(queue As List(Of _queue_data_struct)) As Integer
        Dim counter As Integer = 0
        For i = 0 To queue.Count - 1
            If queue(i).status.Equals(1) Then
                counter += i
            End If
        Next i
        Return counter
    End Function

    Public Function IsBase64String(ByVal s As String) As Boolean
        s = s.Trim()
        Return (s.Length Mod 4 = 0) AndAlso Regex.IsMatch(s, "^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None)
    End Function

    '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    Public Function ConvertDataToArray(key As String, fields As String(), response As String) As Dictionary(Of String, List(Of String))
        If GetMessage(response).Equals("1001") Then
            Threading.Thread.CurrentThread.CurrentUICulture = Globalization.CultureInfo.GetCultureInfo(state.currentLang)
            errorMessage = "{'error':true,'message':'" & My.Resources.strings.errorNoRecordsFound & "'}"
            Return Nothing
        End If
        Try
            Dim jsonResult = JsonConvert.DeserializeObject(Of Dictionary(Of String, Object))(response)
            If jsonResult.ContainsKey(key) Then
                If Not jsonResult.Item(key).item(0).Count.Equals(fields.Length) Then
                    Threading.Thread.CurrentThread.CurrentUICulture = Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                    errorMessage = "{'error':true,'message':'" & My.Resources.strings.JsonFieldsMismatch & ". table(" & key & "'}"
                    Return Nothing
                Else
                    Dim results = New Dictionary(Of String, List(Of String))
                    For k = 0 To fields.Length - 1
                        Dim fieldValues As List(Of String) = New List(Of String)
                        For i = 0 To jsonResult.Item(key).Count - 1
                            fieldValues.Add(jsonResult.Item(key).item(i).item(k).ToString)
                        Next i
                        results.Add(fields(k), fieldValues)

                    Next k
                    Return results
                End If
            Else
                Threading.Thread.CurrentThread.CurrentUICulture = Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                errorMessage = "{'error':true,'message':'" & My.Resources.strings.JsonkeyNotFound & " (" & key & "'}"
                Return Nothing
            End If
        Catch ex As Exception
            errorMessage = "{'error':true,'message':'" & ex.ToString & "'}"
            errorMessage = ex.ToString
            Return Nothing
        End Try
    End Function
End Class

AeonLabs.Envoriment 是具有集合或字段和属性的类。

下面的一个是用于发出 POST 请求:

Imports System.ComponentModel
Imports System.IO
Imports System.Net
Imports System.Text
Imports System.Web
Imports System.Web.Script.Serialization
Imports System.Windows.Forms
Imports AeonLabs.Environment
Imports AeonLabs.Security

Public Class HttpDataPostData
    Inherits HttpDataCore

    Public Event updateProgress(sender As Object, misc As Dictionary(Of String, String))

    Public Event dataArrived(sender As Object, requestData As String, misc As Dictionary(Of String, String))

    Public Sub New(ByVal Optional _state As environmentVarsCore = Nothing, ByVal Optional _url As String = "")
        MyBase.New(_state, _url)
    End Sub

    Public Sub initialize(ByVal Optional _threadCount As Integer = 0)
        If Not _threadCount.Equals(0) Then
            threadCount = _threadCount
        End If

        ReDim bwDataRequest(threadCount)
        ReDim queueBWorker(threadCount)

        For shtIndex = 0 To threadCount
            dataStatistics.Add(New _data_statistics)

            bwDataRequest(shtIndex) = New System.ComponentModel.BackgroundWorker
            bwDataRequest(shtIndex).WorkerReportsProgress = True
            bwDataRequest(shtIndex).WorkerSupportsCancellation = True

            AddHandler bwDataRequest(shtIndex).DoWork, AddressOf bwDataRequest_DoWork
            AddHandler bwDataRequest(shtIndex).RunWorkerCompleted, AddressOf bwDataRequest_RunWorkerCompleted
        Next shtIndex
        Dim retry As _retry_attempts
        With retry
            .counter = 0
            .previousPattern = -1
            .pattern = 0
            .errorMessage = ""
        End With
        retryAttempts = retry
    End Sub

    Private Sub bwDataRequest_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs)

        ' Find out the Index of the bWorker that called this DoWork (could be cleaner, I know)
        Dim Y As Integer
        Dim Index As Integer = Nothing
        For Y = 0 To UBound(bwDataRequest)
            If sender.Equals(bwDataRequest(Y)) Then
                Index = Y
                Exit For
            End If
        Next Y

        Dim queue As _queue_data_struct
        queue = e.Argument

        Dim vars As New Dictionary(Of String, String)
        vars = queue.vars

        'TODO translation need to be local
        If Not System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable() Then
            Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(state.currentLang)
            e.Result = "{'error':true,'message':'" & My.Resources.strings.errorNoNetwork & "'}"
            Exit Sub
        End If
        If vars Is Nothing Then
            e.Result = "{'error':true,'message':'missconfiguration vars'}"
            Exit Sub
        End If

        If Not vars.ContainsKey("id") Then
            vars.Add("id", state.userId)
        End If
        If Not vars.ContainsKey("pid") Then
            Dim appId As New FingerPrint
            vars.Add("pid", appId.Value)
        End If
        If Not vars.ContainsKey("language") Then
            vars.Add("language", state.currentLang)
        End If
        If Not vars.ContainsKey("origin") Then
            vars.Add("origin", state.softwareAccessMode)
        End If

        Dim serializer As New JavaScriptSerializer()
        Dim json As String = serializer.Serialize(vars)
        Dim encryption As New AesCipher(state)
        Dim encrypted As String = HttpUtility.UrlEncode(encryption.encrypt(json))
        Dim PostData = "origin=" & state.softwareAccessMode & "&data=" & encrypted
        Dim request As WebRequest = WebRequest.Create(url)
        Dim responseFromServer As String = ""
        Dim decrypted As String = ""

        request.Method = "POST"
        Dim byteArray As Byte() = Encoding.UTF8.GetBytes(PostData)
        request.ContentType = "application/x-www-form-urlencoded"
        request.Headers.Add("Authorization", state.ApiHttpHeaderToken & "-" & state.softwareAccessMode)
        request.ContentLength = byteArray.Length
        Try
            Dim dataStream As Stream = request.GetRequestStream()
            dataStream.Write(byteArray, 0, byteArray.Length)
            dataStream.Close()
            Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
            dataStream = response.GetResponseStream()
            Dim reader As New StreamReader(dataStream)
            responseFromServer = reader.ReadToEnd()
            reader.Close()
            dataStream.Close()
            response.Close()

            If response.StatusCode = HttpStatusCode.Accepted Or response.StatusCode = 200 Then
                If IsBase64String(responseFromServer) And Not responseFromServer.Equals("") Then
                    decrypted = encryption.decrypt((responseFromServer)).Replace("\'", "'")
                Else
                    Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                    decrypted = "{'error':true,'encrypted':false,'message':'" & My.Resources.strings.contactingCommServer & " |" & responseFromServer & "|'}"
                End If
            Else
                Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                decrypted = "{'error':true,'message':'" & My.Resources.strings.contactingCommServer & " (" & response.StatusCode & ")', 'statuscode':'" & response.StatusCode & "'}"
            End If
        Catch ex As Exception
            Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(state.currentLang)
            decrypted = "{'error':true,'message':'" & My.Resources.strings.contactingCommServer & " (" & ex.Message.ToString.Replace("'", "\'") & ")'}"
        End Try

        e.Result = decrypted.Replace("\'", "'")
    End Sub

    Private Sub bwDataRequest_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs)
        ' Find out the Index of the bWorker that called this DoWork (could be cleaner, I know)
        Dim Y As Integer
        Dim Index As Integer = Nothing
        Dim data As New _queue_data_struct

        For Y = 0 To UBound(bwDataRequest)
            If sender.Equals(bwDataRequest(Y)) Then
                Index = Y
                Exit For
            End If
        Next Y

        If IsResponseOk(e.Result, "statuscode") Then
            data = New _queue_data_struct
            data = queue(queueBWorker(Index))
            data.status = 0 're queue the file
            SyncLock queueLock
                queue(queueBWorker(Index)) = data
            End SyncLock
            Dim errorMsg As String = GetMessage(e.Result)
            Dim retry As _retry_attempts
            With retry
                .counter = retryAttempts.counter
                .previousPattern = retryAttempts.previousPattern
                .pattern = retryAttempts.pattern
                .errorMessage = retryAttempts.errorMessage
            End With
            retry.errorMessage = If(retryAttempts.errorMessage.IndexOf(errorMsg) > -1, retryAttempts.errorMessage, retryAttempts.errorMessage & System.Environment.NewLine & errorMsg)

            retry.pattern = QueuesMultiHash(queue)
            If retry.previousPattern.Equals(retry.pattern) Then
                retry.counter += 1
            Else
                retry.counter = 1
                retry.previousPattern = retryAttempts.pattern
            End If

            retryAttempts = retry
            Exit Sub
        End If

        data = New _queue_data_struct
        data = queue(queueBWorker(Index))
        data.status = -1 'completed sucessfully status
        SyncLock queueLock
            queue(queueBWorker(Index)) = data
        End SyncLock

        loadingCounter += 1
        CompletionPercentage = (loadingCounter / queue.Count) * 100
        statusMessage = "Loading data from the cloud..."
        RaiseEvent updateProgress(Me, queue(queueBWorker(Index)).misc)
        RaiseEvent dataArrived(Me, e.Result, queue(queueBWorker(Index)).misc)
    End Sub
End Class

Aoenlabs.Security 是一个用于发送使用标准加密算法加密的 POST 数据的类。


P
Peter Mortensen

如果您需要发布 JSON 消息正文,可以使用以下内容。假设你有一个名为 m 的类实例。

string jsonMessage = JsonConvert.SerializeObject(m);

// Make POST call
using (HttpClient client = new HttpClient())
{
    HttpRequestMessage requestMessage = new
    HttpRequestMessage(HttpMethod.Post, "<url here>");
    requestMessage.Content = new StringContent(jsonMessage, Encoding.UTF8, "application/json");
    HttpResponseMessage response = client.SendAsync(requestMessage).Result;
    if (response.StatusCode == System.Net.HttpStatusCode.OK)
    {
        // Do something here
    }
}