gpt4 book ai didi

c# - 如何获取服务引用以使用基于第 3 方 WSDL 的消息契约(Contract)正确生成,或者在 WF 服务项目中强制不使用消息契约(Contract)

转载 作者:IT王子 更新时间:2023-10-29 04:06:41 46 4
gpt4 key购买 nike

我有一个问题,给定第 3 方 WSDL,我可以从控制台应用程序轻松创建一个可用的服务代理,但我不能从 WF4 WF 服务。后一种情况下生成的代理显然有问题,具体涉及 2 个问题:a) 消息合约总是在没有请求或不需要时生成b) 使用了不正确的响应消息和 xml 包装器名称,导致空响应对象和反序列化失败

我面临的问题是在第 3 方 WSDL 的基础上实际生成 Reference.cs 类。在 WSDL 中有很多操作,按照出现的顺序,其中 2 个是这样的:

 <operation name="pu013">
<documentation>
<description>Check-response service</description>
<help>The service handles (cut out)</help>
</documentation>
<input message="tns:pu013Request" />
<output message="tns:SimpleResponse" />
</operation>

...
<operation name="mi102">
<documentation>
<description>Instruction insert to Matching System</description>
<help>This service (cut out)</help>
</documentation>
<input message="tns:mi102Request" />
<output message="tns:SimpleResponse" />
</operation>

Reference.cs 中的结果是以下 C#:

WorkflowService1.PSE.pu013Response pu013(WorkflowService1.PSE.pu013Request request);

...

WorkflowService1.PSE.pu013Response mi102(WorkflowService1.PSE.mi102Request request);

请注意,出于某种原因,mi102 操作是使用 pu013Response 的 INCORRECT 响应消息生成的,声明如下:

 [System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="pu013Response", WrapperNamespace="http://pse/", IsWrapped=true)]
public partial class pu013Response {

请注意 WrapperName 会阻止 XML 序列化程序识别响应,即 mi102Response,因此对于所有不是 pu013 的操作,我总是得到 NULL 响应。

此外,如果我从控制台应用程序添加引用,则不会发生这种情况。这不会生成消息契约,在这种情况下,调用和响应起作用。

有什么不同? svcutil 是否在幕后被调用?如果是这样,所使用的参数有何不同? svcutil 是否也可以用于生成 xamlx 事件,以便我可以找到命令行解决方法?

这看起来像是一个 VS/添加服务引用错误。替代方法是手动更正 Reference.cs 中的许多操作。

理想情况下,我正在寻找一种方法来轻松、自动地运行 svcutil 或添加服务引用,以便引用类正确并生成 xamlx 事件。最好能解释为什么会有差异,以及幕后发生的事情。

更新:控制台应用程序中生成的消息契约(Contract)会导致同样的问题——不正确的响应声明。如果使用参数而不是消息,问题就会消失,这是 WF 服务应用程序不可用的。

最佳答案

我在这些问题上远非权威,虽然下面的回答可能不完全适合您的问题,但我最近与服务建立无代理连接的经验可能会为您或下一个使用代理的人提供一些见解类似的问题。

首先我会看看您是否可以使用 fiddler 手动滚动 SOAP 请求,然后看看您是否能够创建正确的消息并将其发送。由于您将自动化工具描述为有问题(或者可能存在配置问题,您并没有得到这样的结果)。无论哪种方式,清楚地了解契约(Contract)的形式,并能够在 fiddler 中执行可靠的测试可能会提供清晰度。

您不一定需要依赖代理。您可以创建自己的 soap 消息并通过以下两种方式之一发送。第一个是使用 ChannelFactory。

  1. 创建您的消息正文(如果需要,消息类可以没有一个)
  2. 创建您的消息
  3. 通过 ChannelFactory 发送消息

对于第 1 步,您可以通过制作一个简单的 POCO 来反射(reflect)契约(Contract)中的预期内容来构建您的消息。您应该能够通过 WSDL 派生出该类是什么。

假设服务是这样的:

[ServiceContract(Namespace = "http://Foo.bar.car")]
public interface IPolicyService
{
[OperationContract]
PolicyResponse GetPolicyData(PolicyRequest request);
}

public class PolicyData : IPolicyService
{
public PolicyResponse GetPolicyData(PolicyRequest request)
{
var polNbr = request.REQ_POL_NBR;
return GetMyData(polNbr);
}
}

你需要这样的类:

[DataContract(Namespace = "http://Foo.bar.car")]
public class GetPolicyData
{
[DataMember]
public request request { get; set; }
}

[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/Foo.bar.car.Model.Policy")]
public class request
{
///<summary>
/// Define request parameter for SOAP API to retrieve selective Policy level data
/// </summary>
[DataMember]
public string REQ_POL_NBR { get; set; }
}

然后你会这样调用它:

    private static Message SendMessage(string id)
{
var body = new GetPolicyData {request = new request{ REQ_POL_NBR = id }};
var message = Message.CreateMessage(MessageVersion.Soap11, "http://Foo.bar.car/IPolicyService/GetPolicyData", body);
// these headers would probably not be required, but added for completeness
message.Headers.Add(MessageHeader.CreateHeader("Accept-Header", string.Empty, "application/xml+"));
message.Headers.Add(MessageHeader.CreateHeader("Content-Type", string.Empty, "text/xml"));
message.Headers.Add(MessageHeader.CreateHeader("FromSender", string.Empty, "DispatchMessage"));
message.Headers.To = new System.Uri(@"http://localhost:5050/PolicyService.svc");

var binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
MessageEncoding = WSMessageEncoding.Text,
MaxReceivedMessageSize = int.MaxValue,
SendTimeout = new TimeSpan(1, 0, 0),
ReaderQuotas = { MaxStringContentLength = int.MaxValue, MaxArrayLength = int.MaxValue, MaxDepth = int.MaxValue }
};
message.Properties.Add("Content-Type", "text/xml; charset=utf-8");
message.Properties.Remove("Accept-Encoding");
message.Properties.Add("Accept-Header", "application/xml+");

var cf = new ChannelFactory<IRequestChannel>(binding, new EndpointAddress(new Uri("http://localhost:5050/PolicyService.svc")));

cf.Open();
var channel = cf.CreateChannel();
channel.Open();

var result = channel.Request(message);

channel.Close();
cf.Close();
return result;
}

您收到的将是一条消息,您需要对其进行反序列化,并且有一些 OOTB 方法可以做到这一点,(Message.GetReaderAtBodyContents,Message.GetBody)与手动主题保持一致:

    /// <summary>
/// Class MessageTransform.
/// </summary>
public static class MessageTransform
{
/// <summary>
/// Gets the envelope.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>XDocument.</returns>
public static XDocument GetEnvelope(Message message)
{
using (var memoryStream = new MemoryStream())
{
var messageBuffer = message.CreateBufferedCopy(int.MaxValue);
var xPathNavigator = messageBuffer.CreateNavigator();

var xmlWriter = XmlWriter.Create(memoryStream);
xPathNavigator.WriteSubtree(xmlWriter);
xmlWriter.Flush();
xmlWriter.Close();

memoryStream.Position = 0;
var xdoc = XDocument.Load(XmlReader.Create(memoryStream));
return xdoc;
}
}

/// <summary>
/// Gets the header.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>XNode.</returns>
public static XNode GetHeader(Message message)
{
var xdoc = GetEnvelope(message);

var strElms = xdoc.DescendantNodes();
var header = strElms.ElementAt(1);

return header;
}

/// <summary>
/// Gets the body.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="localName">Name of the local.</param>
/// <param name="namespaceName">Name of the namespace.</param>
/// <returns>IEnumerable&lt;XElement&gt;.</returns>
public static IEnumerable<XElement> GetBody(Message message, string localName, string namespaceName)
{
var xdoc = GetEnvelope(message);

var elements = xdoc.Descendants(XName.Get(localName, namespaceName));

return elements;
}
}

或者您可以手动构建肥皂信封并使用 WebClient:

using System.Net; 
using System.Xml.Linq;

public static class ClientHelper
{
public static string Post(string targetUrl, string action, string method, string key, string value)
{
var request = BuildEnvelope(method, key, value);
using (var webClient = new WebClient())
{
webClient.Headers.Add("Accept-Header", "application/xml+");
webClient.Headers.Add("Content-Type", "text/xml; charset=utf-8");
webClient.Headers.Add("SOAPAction", action);
var result = webClient.UploadString(targetUrl, "POST", request);

return result;
}
}

public static string BuildEnvelope(string method, string key, string value)
{
XNamespace s = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace d = "d4p1";
XNamespace tempUri = "http://tempuri.org/";
XNamespace ns = "http://Foo.bar.car";
XNamespace requestUri = "http://schemas.datacontract.org/2004/07/Foo.bar.car.Model.Policy";
var xDoc = new XDocument(
new XElement(
s + "Envelope",
new XAttribute(XNamespace.Xmlns + "s", s),
new XElement(
s + "Body",
new XElement(
ns + method,
new XElement(requestUri + "request",
new XElement(tempUri + key, value))
)
)
)
);
// hack - finish XDoc construction later
return xDoc.ToString().Replace("request xmlns=", "request xmlns:d4p1=").Replace(key, "d4p1:" + key);
}

调用方式:

return ClientHelper.Post("http://localhost:5050/PolicyService.svc", "http://Foo.bar.car/IPolicyService/GetPolicyData", "GetPolicyData", "REQ_POL_NBR", id);

在 Fiddler 中测试它看起来像这样:

Post action:    http://localhost:5050/PolicyService.svc
Header:
User-Agent: Fiddler
SOAPAction: http://Foo.bar.car/IPolicyService/GetPolicyData
Content-type: text/xml
Host: localhost:5050
Content-Length: 381

正文:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetPolicyData xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://Foo.bar.car">
<request xmlns:d4p1="http://schemas.datacontract.org/2004/07/Foo.bar.car.Model.Policy">
<d4p1:REQ_POL_NBR>1</d4p1:REQ_POL_NBR>
</request>
</GetPolicyData>
</s:Body>
</s:Envelope>

同样,这个答案并不是要解决如何以不同方式调用 svcUtil,而是要避免完全调用它,所以我希望编辑之神不要因此而责备我 ;-)

我上面的代码受到了比我更好的开发人员的启发,但我希望它能有所帮助。

http://blogs.msdn.com/b/stcheng/archive/2009/02/21/wcf-how-to-inspect-and-modify-wcf-message-via-custom-messageinspector.aspx

关于c# - 如何获取服务引用以使用基于第 3 方 WSDL 的消息契约(Contract)正确生成,或者在 WF 服务项目中强制不使用消息契约(Contract),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19869369/

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