C# 如何使用基于第三方WSDL的消息契约正确生成服务引用,或者在WF服务项目中强制不生成消息契约
我有一个问题,给定第三方WSDL,我可以从控制台应用程序轻松创建一个有效的服务代理,但从WF4 WF服务我不能。后一种情况下生成的代理显然有缺陷,具体涉及两个问题: a) 消息协定总是在未请求或不需要时生成 b) 使用了不正确的响应消息和xml包装器名称,导致响应对象为空且反序列化失败 我面临的问题是在第三方WSDL的基础上实际生成Reference.cs类。在WSDL中有许多操作,按照出现的顺序,其中2个操作如下:C# 如何使用基于第三方WSDL的消息契约正确生成服务引用,或者在WF服务项目中强制不生成消息契约,c#,web-services,visual-studio-2012,wsdl,workflow-foundation-4,C#,Web Services,Visual Studio 2012,Wsdl,Workflow Foundation 4,我有一个问题,给定第三方WSDL,我可以从控制台应用程序轻松创建一个有效的服务代理,但从WF4 WF服务我不能。后一种情况下生成的代理显然有缺陷,具体涉及两个问题: a) 消息协定总是在未请求或不需要时生成 b) 使用了不正确的响应消息和xml包装器名称,导致响应对象为空且反序列化失败 我面临的问题是在第三方WSDL的基础上实际生成Reference.cs类。在WSDL中有许多操作,按照出现的顺序,其中2个操作如下: 检查响应服务 服务处理(剪切) ... 向匹配系统插入指令 此服务(断开)
检查响应服务
服务处理(剪切)
...
向匹配系统插入指令
此服务(断开)
这会在Reference.cs中产生以下结果:
请注意,出于某种原因,mi102操作是使用pu013Response的错误响应消息生成的,声明如下:
[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的操作,我总是得到空响应
此外,如果从控制台应用程序添加引用,则不会发生这种情况。这不会生成消息契约,在本例中,调用和响应是有效的
有什么不同?svcutil是否在幕后被调用?如果是,所使用的参数有什么不同?svcutil也可以用来生成xamlx活动,这样我就可以找到一个命令行解决方法了吗
这看起来像是VS/Add服务引用错误。另一种方法是手动更正Reference.cs中的许多操作
理想情况下,我正在寻找一种方法来轻松、自动地运行svcutil或添加服务引用,以便引用类正确并生成xamlx活动。一个很好的解释是为什么会有差异,以及在幕后发生了什么
更新:
控制台应用程序中生成的消息协定会导致相同的问题-响应声明不正确。如果使用参数而不是消息(WF服务应用程序无法提供消息),问题就会消失。我在这些问题上远远不是权威,尽管下面的回答可能不完全适合您的问题,我最近与服务建立proxyless连接的经验可能会为您或下一个有类似问题的人提供一些见解 首先,我想看看您是否可以使用fiddler手动滚动SOAP请求,看看您是否能够创建正确的消息并将其发送出去。因为您将自动化工具描述为有缺陷的(或者可能存在配置问题,您并没有得到正确的答案)。无论哪种方式,对合同的形式有一个清晰的理解,并且能够在fiddler中执行一个可靠的测试可以提供清晰的信息 您不一定需要依赖于使用代理。您可以创建自己的soap消息,并通过以下两种方式之一发送它。首先是使用ChannelFactory
[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;
}
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
这被称为:
return ClientHelper.Post("http://localhost:5050/PolicyService.svc", "http://Foo.bar.car/IPolicyService/GetPolicyData", "GetPolicyData", "REQ_POL_NBR", id);
在Fiddler中测试它看起来像这样:
[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;
}
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
正文:
1.
同样,这个答案并不是试图解决如何以不同的方式调用svcuti,而是为了避免完全调用它,所以我希望编辑之神不会因此而责备我;-)
我上面的代码是受到比我更好的开发人员的启发,但我希望它能有所帮助
我建议您使用命令行实用程序生成wsdl代理,并在项目中添加生成的代理文件。它将在每个项目中工作,您可以从output.config中找到所需的配置,这些配置将从命令行实用程序生成
如果您需要wsdl命令和选项,那么我可以为您提供。您是否尝试将其添加为Web引用而不是服务引用?它可以解决第三方服务的一些问题。看一看:在一个WF服务项目中,Web引用不可用。我已经设法在这一项目上与Microsoft打开了一张技术支持票证,所以我正在等待他们怎么说。这里有多个问题,其中之一是我从服务器(第三方)收到的实际SOAP消息也忽略了SimpleResponse,并发送回pu013Response、mi102Response等。我认为这是根据WSDL规范的默认行为。您是否尝试使用svcutil生成代理?这也提供了一种控制服务代理命名空间的好方法。我不确定这是否能解决您的问题,但我经历过,从VS添加服务/web引用有时会在代理文件中添加额外的代码。pu013Response确实具有相同的结构是。问题是,所有重用pu013Response的人都无法再对SOAP响应进行反序列化,而SOAP响应是。。。。这不是手动更正代理帮助的地方
<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>