使用 .NET 7 的 SOAP:生成的内容与原始版本不同

问题描述 投票:0回答:1

我正在将遗留项目从 .Net Framework 4.6.1 转换为 .Net 7。
该项目使用 SOAP 服务并且是 VB 项目,因此使用添加“Web 引用”向导添加服务,但使用 .Net Core+,只有 C# 项目可以添加“连接服务”。
我已经使用向导和遗留项目的 WSDL 添加了“连接服务”,但生成的代码与原始代码不同,即方法签名不同,它们甚至缺少参数或有额外的参数,但我不知道不知道这些额外的参数是什么,也不知道如何传入参数。

一个示例是带有额外“TrustedUsersHeader”的方法

LoadReports

public System.Threading.Tasks.Task<REService.LoadReportResponse> LoadReportAsync(REService.TrustedUserHeader TrustedUserHeader, string Report, string HistoryID)
{
    REService.LoadReportRequest inValue = new REService.LoadReportRequest();
    inValue.TrustedUserHeader = TrustedUserHeader;
    inValue.Report = Report;
    inValue.HistoryID = HistoryID;
    return ((REService.ReportExecutionServiceSoap)(this)).LoadReportAsync(inValue);
}

原来生成的代码没有这个头:

'''<remarks/>
<System.Web.Services.Protocols.SoapHeaderAttribute("TrustedUserHeaderValue"),  _
    System.Web.Services.Protocols.SoapHeaderAttribute("ExecutionHeaderValue", Direction:=System.Web.Services.Protocols.SoapHeaderDirection.Out),  _
    System.Web.Services.Protocols.SoapHeaderAttribute("ServerInfoHeaderValue", Direction:=System.Web.Services.Protocols.SoapHeaderDirection.Out),  _
    System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices/Loa"& _ 
    "dReport", RequestNamespace:="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices", ResponseNamespace:="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices", Use:=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle:=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)>  _
Public Function LoadReport(ByVal Report As String, ByVal HistoryID As String) As <System.Xml.Serialization.XmlElementAttribute("executionInfo")> ExecutionInfo
    Dim results() As Object = Me.Invoke("LoadReport", New Object() {Report, HistoryID})
    Return CType(results(0),ExecutionInfo)
End Function

SetExecutionParametersAsync
有 2 个标头参数:

public System.Threading.Tasks.Task<REService.SetExecutionParametersResponse> SetExecutionParametersAsync(REService.ExecutionHeader ExecutionHeader, REService.TrustedUserHeader TrustedUserHeader, REService.ParameterValue[] Parameters, string ParameterLanguage)
{
    REService.SetExecutionParametersRequest inValue = new REService.SetExecutionParametersRequest();
    inValue.ExecutionHeader = ExecutionHeader;
    inValue.TrustedUserHeader = TrustedUserHeader;
    inValue.Parameters = Parameters;
    inValue.ParameterLanguage = ParameterLanguage;
    return ((REService.ReportExecutionServiceSoap)(this)).SetExecutionParametersAsync(inValue);
}
'''<remarks/>
<System.Web.Services.Protocols.SoapHeaderAttribute("TrustedUserHeaderValue"),  _
    System.Web.Services.Protocols.SoapHeaderAttribute("ExecutionHeaderValue"),  _
    System.Web.Services.Protocols.SoapHeaderAttribute("ServerInfoHeaderValue", Direction:=System.Web.Services.Protocols.SoapHeaderDirection.Out),  _
    System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices/Set"& _ 
    "ExecutionParameters", RequestNamespace:="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices", ResponseNamespace:="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices", Use:=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle:=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)>  _
Public Function SetExecutionParameters(ByVal Parameters() As ParameterValue, ByVal ParameterLanguage As String) As <System.Xml.Serialization.XmlElementAttribute("executionInfo")> ExecutionInfo
    Dim results() As Object = Me.Invoke("SetExecutionParameters", New Object() {Parameters, ParameterLanguage})
    Return CType(results(0),ExecutionInfo)
End Function
        
'''<remarks/>
Public Overloads Sub SetExecutionParametersAsync(ByVal Parameters() As ParameterValue, ByVal ParameterLanguage As String)
    Me.SetExecutionParametersAsync(Parameters, ParameterLanguage, Nothing)
End Sub
        
'''<remarks/>
Public Overloads Sub SetExecutionParametersAsync(ByVal Parameters() As ParameterValue, ByVal ParameterLanguage As String, ByVal userState As Object)
    If (Me.SetExecutionParametersOperationCompleted Is Nothing) Then
        Me.SetExecutionParametersOperationCompleted = AddressOf Me.OnSetExecutionParametersOperationCompleted
    End If
    Me.InvokeAsync("SetExecutionParameters", New Object() {Parameters, ParameterLanguage}, Me.SetExecutionParametersOperationCompleted, userState)
End Sub

最令人困惑的是

Render
方法:

public System.Threading.Tasks.Task<REService.RenderResponse> RenderAsync(REService.RenderRequest request)
{
    return base.Channel.RenderAsync(request);
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="Render", WrapperNamespace="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices", IsWrapped=true)]
public partial class RenderRequest
{
        
    [System.ServiceModel.MessageHeaderAttribute(Namespace="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices")]
    public REService.ExecutionHeader ExecutionHeader;
        
    [System.ServiceModel.MessageHeaderAttribute(Namespace="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices")]
    public REService.TrustedUserHeader TrustedUserHeader;
        
    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices", Order=0)]
    public string Format;
        
    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices", Order=1)]
    public string DeviceInfo;
        
    public RenderRequest()
    {
    }
        
    public RenderRequest(REService.ExecutionHeader ExecutionHeader, REService.TrustedUserHeader TrustedUserHeader, string Format, string DeviceInfo)
    {
        this.ExecutionHeader = ExecutionHeader;
        this.TrustedUserHeader = TrustedUserHeader;
        this.Format = Format;
        this.DeviceInfo = DeviceInfo;
    }
}

大部分参数都没有了,那么如何传入呢?

<System.Web.Services.Protocols.SoapHeaderAttribute("TrustedUserHeaderValue"),  _
    System.Web.Services.Protocols.SoapHeaderAttribute("ExecutionHeaderValue"),  _
    System.Web.Services.Protocols.SoapHeaderAttribute("ServerInfoHeaderValue", Direction:=System.Web.Services.Protocols.SoapHeaderDirection.Out),  _
    System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices/Ren"& _ 
    "der", RequestNamespace:="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices", ResponseNamespace:="http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices", Use:=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle:=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)>  _
Public Function Render(ByVal Format As String, ByVal DeviceInfo As String, ByRef Extension As String, ByRef MimeType As String, ByRef Encoding As String, ByRef Warnings() As Warning, ByRef StreamIds() As String) As <System.Xml.Serialization.XmlElementAttribute("Result", DataType:="base64Binary")> Byte()
    Dim results() As Object = Me.Invoke("Render", New Object() {Format, DeviceInfo})
    Extension = CType(results(1),String)
    MimeType = CType(results(2),String)
    Encoding = CType(results(3),String)
    Warnings = CType(results(4),Warning())
    StreamIds = CType(results(5),String())
    Return CType(results(0),Byte())
End Function

也许我添加了错误的 WSDL 或者我不理解标头?
我注意到为“Render”方法生成的 VB 代码使用

ByRef
关键字,因此这些是“out”参数,也许标头就像字典,我可以从中获取“Out”参数?

有谁对 .Net Core+ 中的 SOAP 有更多经验可以帮助我吗?

c# vb.net soap .net-7.0
1个回答
0
投票

我们有大约 80 个这样的遗留 Web 服务客户端,我们构建为 .NET 4.8、6.0 和 7.0,并作为(公司内部)NuGet 包发布,最适合我们的解决方案是完全忘记 VS 自动化并执行它 -仍然是自动的,但可以通过预构建步骤完全控制何时以及如何生成内容。

我们使用 Visual Studio 解决方案,其中每个服务引用都有一个项目(在 C# 中,但 VB.NET 应该就可以了)。该解决方案和服务参考项目有 3 种构建配置(

Debug
Release
SvcRef
)。使用
SvcRef
构建时,通过使用参数
svcutil.exe
调用
/targetClientVersion:Version35
,在预构建步骤中重新生成服务引用(完整批次见下文)。

只要有可能,我们还会增强每个 Web 客户端,以使用方法

CheckAccess
(通过单独文件中的部分类)实现接口,该方法允许我们始终在监控工具中 ping 相同的接口方法,以检查 Web 服务是否可用还活着。

每个服务引用程序集还提供一个工厂类,该工厂类返回给定环境(

Test
/
Integration
/
Prod
等)的完全配置的客户端实例,以隐藏有关端点 URL、通信所需的所有知识正确使用 Web 服务所需的协议、身份验证和代理身份验证详细信息(可能仅在生产环境中支持
https
,但在必须通过简单的
http
等方式使用 Web 服务的测试环境中不支持)。

但我有点得意忘形,这里的批处理类似于我们在预构建步骤中使用的批处理:

@ECHO OFF
PUSHD "$(ProjectDir)"
SETLOCAL

ECHO $(ConfigurationName)
IF /I "$(ConfigurationName)" NEQ "SvcRef" GOTO EOF
IF /I "$(TargetFramework)" NEQ "NET48" GOTO EOF

"..\..\BuildTools\svcutil.exe" "https://server.domain.tld/site/myservice.svc?singleWsdl" /language:VB /out:".\Reference.vb" /namespace:"*,Company.ServiceReference.Product.Service" /serializable /config:.\Sample.config /collectionType:System.Collections.Generic.List`1 /targetClientVersion:Version35

:EOF
ENDLOCAL
POPD

对于服务引用重新生成,我们指向

Test
环境的相应 Web 服务,其中包括尚未上线的未来界面更改。

为此,您需要在

svcutil.exe
的子文件夹中复制
<repository-root>\BuildTools
,并将解决方案放在
<repository-root>
的子文件夹中(我们使用
<repository-root>\Source
)。

如果批处理失败,请在 Visual Studio 外部使用不同的设置尝试

svcutil.exe
调用。有些引用我们必须使用 DataContractSerialization 构建,有些则不然,有些服务支持
singleWsdl
,其他服务仅在 URL 中支持
wsdl
等。

感兴趣的 C# 程序员的其他信息:在 C# 中,我们还会在生成的

Reference.cs
文件前添加
#nullable disable
#pragma warning disable CS1591

© www.soinside.com 2019 - 2024. All rights reserved.