gpt4 book ai didi

c# - 如何将数据作为 SoapMessage 发送并获得回复?

转载 作者:太空狗 更新时间:2023-10-29 21:31:55 25 4
gpt4 key购买 nike

我有一些数据需要以 SOAP 格式发送到服务器。该服务器将立即确认它收到了消息。几个小时后,我收到(可能来自另一台服务器)一条 SOAP 消息,其中包含有关已处理数据的信息。

我读了Stackoverflow: How to send SOAP request and receive response .然而,答案是 8 岁。尽管它们可能仍然有效,但可能有更新的技术。

而且看起来确实如此:Microsoft 有 System.Web.Services.Protocols,其中有类似 SoapMessage 的类, SoapClientMessage, SoapServerMessage 等

查看这些类,我发现很多类似 SOAP 的类( header 、扩展、客户端消息、服务器消息......通常提供的示例会告诉我这些类如何协同工作以及如何使用它们。在MSDN 文档我只能找到如何处理已经存在的 SOAP 消息的示例。

Given some data that needs to be sent, how can I wrap this data somehow in one of these SOAP classes and send this message?

这些类(class)是为了这个目的吗?还是我应该坚持使用 2011 年的方法,如上面提到的 Stackoverflow 问题所暗示的那样,您自己通过将 XML 数据格式化为 soap 格式来创建 SOAP Web 请求?

非常抱歉,通常我会写下我尝试过的东西。 las,我看不到 provided SoapMessage classes 之间的关系.我不知道如何使用它们。

评论后补充

我正在使用 Windows Server/Visual Studio(最新版本)/.NET(最新版本)/C#(最新版本)。

与服务器的通信是相互认证的。我需要用来与服务器通信的证书采用 PEM (CER/CRT) 格式。私钥是RSA。该证书由适当的 CA 颁发,服务器也将使用适当的 CA 使用的证书。所以我不需要创建新的证书(事实上,它不会被接受)。如果需要,我愿意使用 OpenSsl 等程序转换证书。

我曾尝试使用 Apache TomCat 进行通信,但我觉得这对于每天发送一条 SOAP 消息并每天等待一个答复的任务来说太过分了。

可能因为java对我来说是一个全新的技术,所以我很难看到接收到的消息的内容。那么回到 C# 和 .NET。

我正计划创建一个 DLL,供控制台应用程序使用。该函数将流中的一些数据作为输入。它将创建 soap 消息,发送它,等待消息被正确接收的回复,并等待(可能几个小时)包含处理数据结果的新 Soap 消息。为了使正确的报告和取消成为可能,我想最好使用 async-await 来完成此操作

如果不能在一个应用程序中完成发送订单和等待结果,我愿意创建一个监听输入的 Windows 服务,但我更愿意保持简单。

(虚拟)计算机将仅用于此任务,因此没有其他人需要监听端口 443。每天将发送一条订单消息,每天发送一条结果消息。

最佳答案

这是使用 HTTPS 的示例 C# 控制台客户端和服务器代码(它们在同一个示例中,但这当然仅用于演示目的)。

对于客户端,我们重用了 SoapHttpClientProtocol 类,但是对于服务器端,不幸的是,我们不能重用任何东西,因为类完全依赖于 ASP.NET (IIS) 的 HttpContext

对于服务器端,我们使用 HttpListener,因此,根据您的配置,服务器端可能需要管理员权限才能调用 HttpListenerPrefixes.Add(url).

该代码不使用客户端证书,但您可以在我放置//TODO 注释的位置添加它

该代码假定存在与使用的 url 和端口关联的证书。如果没有(使用 netsh http show sslcert 转储所有关联的证书),您可以使用此处描述的过程添加一个:https://stackoverflow.com/a/11457719/403671

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml;

namespace SoapTests
{
class Program
{
static void Main(string[] args)
{
// code presumes there is an sslcert associated with the url/port below
var url = "https://127.0.0.1:443/";
using (var server = new MyServer(url, MyClient.NamespaceUri))
{
server.Start(); // requests will occur on other threads
using (var client = new MyClient())
{
client.Url = url;
Console.WriteLine(client.SendTextAsync("hello world").Result);
}
}
}
}

[WebServiceBinding(Namespace = NamespaceUri)]
public class MyClient : SoapHttpClientProtocol
{
public const string NamespaceUri = "http://myclient.org/";

public async Task<string> SendTextAsync(string text)
{
// TODO: add client certificates using this.ClientCertificates property
var result = await InvokeAsync(nameof(SendText), new object[] { text }).ConfigureAwait(false);
return result?[0]?.ToString();
}

// using this method is not recommended, as async is preferred
// but we need it with this attribute to make underlying implementation happy
[SoapDocumentMethod]
public string SendText(string text) => SendTextAsync(text).Result;

// this is the new Task-based async model (TAP) wrapping the old Async programming model (APM)
public Task<object[]> InvokeAsync(string methodName, object[] input, object state = null)
{
if (methodName == null)
throw new ArgumentNullException(nameof(methodName));

return Task<object[]>.Factory.FromAsync(
beginMethod: (i, c, o) => BeginInvoke(methodName, i, c, o),
endMethod: EndInvoke,
arg1: input,
state: state);
}
}

// server implementation
public class MyServer : TinySoapServer
{
public MyServer(string url, string namespaceUri)
: base(url)
{
if (namespaceUri == null)
throw new ArgumentNullException(nameof(namespaceUri));

NamespaceUri = namespaceUri;
}

// must be same as client namespace in attribute
public override string NamespaceUri { get; }

protected override bool HandleSoapMethod(XmlDocument outputDocument, XmlElement requestMethodElement, XmlElement responseMethodElement)
{
switch (requestMethodElement.LocalName)
{
case "SendText":
// get the input
var text = requestMethodElement["text", NamespaceUri]?.InnerText;
text += " from server";

AddSoapResult(outputDocument, requestMethodElement, responseMethodElement, text);
return true;
}
return false;
}
}

// simple generic SOAP server
public abstract class TinySoapServer : IDisposable
{
private readonly HttpListener _listener;

protected TinySoapServer(string url)
{
if (url == null)
throw new ArgumentNullException(nameof(url));

_listener = new HttpListener();
_listener.Prefixes.Add(url); // this requires some rights if not used on localhost
}

public abstract string NamespaceUri { get; }
protected abstract bool HandleSoapMethod(XmlDocument outputDocument, XmlElement requestMethodElement, XmlElement responseMethodElement);

public async void Start()
{
_listener.Start();
do
{
var ctx = await _listener.GetContextAsync().ConfigureAwait(false);
ProcessRequest(ctx);
}
while (true);
}

protected virtual void ProcessRequest(HttpListenerContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));

// TODO: add a call to context.Request.GetClientCertificate() to validate client cert
using (var stream = context.Response.OutputStream)
{
ProcessSoapRequest(context, stream);
}
}

protected virtual void AddSoapResult(XmlDocument outputDocument, XmlElement requestMethodElement, XmlElement responseMethodElement, string innerText)
{
if (outputDocument == null)
throw new ArgumentNullException(nameof(outputDocument));

if (requestMethodElement == null)
throw new ArgumentNullException(nameof(requestMethodElement));

if (responseMethodElement == null)
throw new ArgumentNullException(nameof(responseMethodElement));

var result = outputDocument.CreateElement(requestMethodElement.LocalName + "Result", NamespaceUri);
responseMethodElement.AppendChild(result);
result.InnerText = innerText ?? string.Empty;
}

protected virtual void ProcessSoapRequest(HttpListenerContext context, Stream outputStream)
{
// parse input
var input = new XmlDocument();
input.Load(context.Request.InputStream);

var ns = new XmlNamespaceManager(new NameTable());
const string soapNsUri = "http://schemas.xmlsoap.org/soap/envelope/";
ns.AddNamespace("soap", soapNsUri);
ns.AddNamespace("x", NamespaceUri);

// prepare output
var output = new XmlDocument();
output.LoadXml("<Envelope xmlns='" + soapNsUri + "'><Body/></Envelope>");
var body = output.SelectSingleNode("//soap:Body", ns);

// get the method name, select the first node in our custom namespace
bool handled = false;
if (input.SelectSingleNode("//x:*", ns) is XmlElement requestElement)
{
var responseElement = output.CreateElement(requestElement.LocalName + "Response", NamespaceUri);
body.AppendChild(responseElement);

if (HandleSoapMethod(output, requestElement, responseElement))
{
context.Response.ContentType = "application/soap+xml; charset=utf-8";
context.Response.StatusCode = (int)HttpStatusCode.OK;
var writer = new XmlTextWriter(outputStream, Encoding.UTF8);
output.WriteTo(writer);
writer.Flush();
handled = true;
}
}

if (!handled)
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
}
}

public void Stop() => _listener.Stop();
public virtual void Dispose() => _listener.Close();
}
}

关于c# - 如何将数据作为 SoapMessage 发送并获得回复?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55568246/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com