将 Net Framework 4.7.1 升级到 Net 6 会降低 WCF 服务使用速度

Upgrade Net Framework 4.7.1 to Net 6 makes WCF service consumption slower

提问人:Joffrey Ferreira 提问时间:6/26/2023 最后编辑:Joffrey Ferreira 更新时间:7/5/2023 访问量:270

问:

我们正在将 .Net Framework 4.7.1 后端重写为 .Net 6,并且我们有了第一个版本。但是在本地执行性能测试时,我们观察到在相同的配置下,新后端的查询速度较慢。当使用WCF服务中的数据时,会发生这种情况:以前平均需要200毫秒,现在是650毫秒

我们在 web.config 中配置了连接的服务

<system.serviceModel>
  <diagnostics performanceCounters="Off">
    <messageLogging logMalformedMessages="true" logMessagesAtTransportLevel="true"/>
  </diagnostics>
  <bindings>
    <basicHttpBinding>
      <binding name="DocumentSecuredServiceBinding" bypassProxyOnLocal="false" receiveTimeout="00:10:00" sendTimeout="00:10:00" textEncoding="utf-8" messageEncoding="Mtom" maxReceivedMessageSize="209715200" maxBufferPoolSize="5242880" maxBufferSize="209715200">
        <security mode="Transport">
          <transport clientCredentialType="Certificate"/>
        </security>
      </binding>
    </basicHttpBinding>
  </bindings>
  <client>
    <endpoint name="DocumentServiceImpl" address="https://service/DocumentSecuredService" binding="basicHttpBinding" bindingConfiguration="DocumentSecuredServiceBinding" behaviorConfiguration="CredentialIdentificationBehavior" contract="DocumentService.DocumentSecuredService"/>
  </client>
  <behaviors>
    <endpointBehaviors>
      <behavior name="CredentialIdentificationBehavior">
        <clientCredentials>
          <clientCertificate findValue="CertName" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
        </clientCredentials>
      </behavior>
    </endpointBehaviors>
  </behaviors>
</system.serviceModel>

现在,配置是从抽象工厂中的appsettings.json加载的,并实现:

public abstract class BaseSecuredServiceFactory
{
    protected readonly X509Certificate2 _clientCertificate;

    protected readonly Binding _binding;

    protected readonly EndpointAddress _endpointAdress;

    protected BaseSecuredServiceFactory(ILoggerFactory loggerFactory, EndpointOptions option)
    {
        _clientCertificate = LoadCertificate(option.CertificateSubjectName);

        _binding = new BasicHttpBinding()
        {
            BypassProxyOnLocal = option.ByPassProxyOnLocal,
            ReceiveTimeout = option.ReceiveTimeout,
            SendTimeout = option.SendTimeout,
            TextEncoding = Encoding.UTF8,
            MessageEncoding = option.MessageEncoding,
            MaxReceivedMessageSize = option.MaxReceivedMessageSize,
            MaxBufferPoolSize = option.MaxBufferPoolSize,
            MaxBufferSize = option.MaxBufferSize,
            TransferMode = option.TransferMode,
            Security = new BasicHttpSecurity()
            {
                Mode = option.SecurityMode,
                Transport = new HttpTransportSecurity()
                {
                    ClientCredentialType = HttpClientCredentialType.Certificate
                }
            }
        };

        _endpointAdress = new EndpointAddress(option.EndpointAdress);
    }

    protected static X509Certificate2 LoadCertificate(string subjectName)
    {
        // Load certificate from store My of LocalMachine
        X509Store store = new(StoreName.My, StoreLocation.LocalMachine);
        store.Open(OpenFlags.ReadOnly);

        X509Certificate2Collection certificates = store.Certificates.Find(
            X509FindType.FindBySubjectName,
            subjectName,
            false
        );
        if (certificates.Count == 0)
        {
            throw new InvalidOperationException(
                $"The certificate with subject name '{subjectName}' could not be found."
            );
        }

        return certificates[0];
    }
}
public class DocumentSecuredServiceFactory
    : BaseSecuredServiceFactory,
        IDocumentSecuredServiceFactory
{
    public DocumentSecuredServiceFactory(
        ILoggerFactory loggerFactory,
        IOptions<DocumentEndpointOptions> options
    )
        : base(loggerFactory, options.Value) { }

    public DocumentSecuredServiceClient GetDocumentSecuredService()
    {
        DocumentSecuredServiceClient result = new(_binding, _endpointAdress);
        result.Endpoint.EndpointBehaviors.Add(new InspectorBehavior(_loggerFactory));
        result.ClientCredentials.ClientCertificate.Certificate = _clientCertificate;
        return result;
    }
}

appsettings.json中的配置部分

// Document Secured Service configuration
{
  "ByPassProxyOnLocal": false,
  "ReceiveTimeout": "00:10:00",
  "SendTimeout": "00:10:00",
  "MessageEncoding": "Mtom",
  "MaxReceivedMessageSize": 209715200,
  "MaxBufferPoolSize": 5242880,
  "MaxBufferSize": 209715200,
  "TransferMode": 0, // Buffered
  "SecurityMode": 1,
  "HttpClientCredentialType": 5,
  "EndpointAdress": "https://service/DocumentSecuredService",
  "CertificateSubjectName": "CertName"
}

以下是在 Net 6 中从本地 wsdl 文件生成的ConnectedService.json

{
  "ExtendedData": {
    "inputs": [
      "../wsdl/DocumentSecuredServiceV002.wsdl"
    ],
    "collectionTypes": [
      "System.Array",
      "System.Collections.Generic.Dictionary`2"
    ],
    "namespaceMappings": [
      "*, BslDocumentService"
    ],
    "references": [
      "AutoMapper, {AutoMapper, 12.0.0}",
      "C:\\Source\\TIPI\\Tipi Backend\\Tipi.Backend.Web\\Tipi.Backend.Web.Services\\bin\\Debug\\net6.0\\Tipi.Backend.Web.Client.Models.dll",
      "C:\\Source\\TIPI\\Tipi Backend\\Tipi.Backend.Web\\Tipi.Backend.Web.Services\\bin\\Debug\\net6.0\\Tipi.Backend.Web.Core.dll",
      "C:\\Source\\TIPI\\Tipi Backend\\Tipi.Backend.Web\\Tipi.Backend.Web.Services\\bin\\Debug\\net6.0\\Tipi.Backend.Web.Data.dll",
      "Microsoft.AspNetCore.Cryptography.Internal, {Microsoft.AspNetCore.Cryptography.Internal, 6.0.11}",
      "Microsoft.AspNetCore.Cryptography.KeyDerivation, {Microsoft.AspNetCore.Cryptography.KeyDerivation, 6.0.11}",
      "Microsoft.AspNetCore.Identity.EntityFrameworkCore, {Microsoft.AspNetCore.Identity.EntityFrameworkCore, 6.0.11}",
      "Microsoft.Bcl.AsyncInterfaces, {Microsoft.Bcl.AsyncInterfaces, 5.0.0}",
      "Microsoft.Data.Sqlite, {Microsoft.Data.Sqlite.Core, 6.0.11}",
      "Microsoft.EntityFrameworkCore, {Microsoft.EntityFrameworkCore, 6.0.11}",
      "Microsoft.EntityFrameworkCore.Abstractions, {Microsoft.EntityFrameworkCore.Abstractions, 6.0.11}",
      "Microsoft.EntityFrameworkCore.Relational, {Microsoft.EntityFrameworkCore.Relational, 6.0.11}",
      "Microsoft.EntityFrameworkCore.Sqlite, {Microsoft.EntityFrameworkCore.Sqlite.Core, 6.0.11}",
      "Microsoft.Extensions.Caching.Abstractions, {Microsoft.Extensions.Caching.Abstractions, 6.0.0}",
      "Microsoft.Extensions.Caching.Memory, {Microsoft.Extensions.Caching.Memory, 6.0.1}",
      "Microsoft.Extensions.Configuration.Abstractions, {Microsoft.Extensions.Configuration.Abstractions, 6.0.0}",
      "Microsoft.Extensions.DependencyInjection, {Microsoft.Extensions.DependencyInjection, 6.0.1}",
      "Microsoft.Extensions.DependencyInjection.Abstractions, {Microsoft.Extensions.DependencyInjection.Abstractions, 6.0.0}",
      "Microsoft.Extensions.DependencyModel, {Microsoft.Extensions.DependencyModel, 6.0.0}",
      "Microsoft.Extensions.Identity.Core, {Microsoft.Extensions.Identity.Core, 6.0.11}",
      "Microsoft.Extensions.Identity.Stores, {Microsoft.Extensions.Identity.Stores, 6.0.11}",
      "Microsoft.Extensions.Localization.Abstractions, {Microsoft.Extensions.Localization.Abstractions, 7.0.0}",
      "Microsoft.Extensions.Logging, {Microsoft.Extensions.Logging, 6.0.0}",
      "Microsoft.Extensions.Logging.Abstractions, {Microsoft.Extensions.Logging.Abstractions, 6.0.0}",
      "Microsoft.Extensions.ObjectPool, {Microsoft.Extensions.ObjectPool, 5.0.10}",
      "Microsoft.Extensions.Options, {Microsoft.Extensions.Options, 6.0.0}",
      "Microsoft.Extensions.Primitives, {Microsoft.Extensions.Primitives, 6.0.0}",
      "Microsoft.IdentityModel.Logging, {Microsoft.IdentityModel.Logging, 6.8.0}",
      "Microsoft.IdentityModel.Protocols.WsTrust, {Microsoft.IdentityModel.Protocols.WsTrust, 6.8.0}",
      "Microsoft.IdentityModel.Tokens, {Microsoft.IdentityModel.Tokens, 6.8.0}",
      "Microsoft.IdentityModel.Tokens.Saml, {Microsoft.IdentityModel.Tokens.Saml, 6.8.0}",
      "Microsoft.IdentityModel.Xml, {Microsoft.IdentityModel.Xml, 6.8.0}",
      "Microsoft.Win32.SystemEvents, {Microsoft.Win32.SystemEvents, 7.0.0}",
      "Newtonsoft.Json, {Newtonsoft.Json, 13.0.1}",
      "NLog, {NLog, 5.0.5}",
      "NLog.Extensions.Logging, {NLog.Extensions.Logging, 5.1.0}",
      "NLog.Web.AspNetCore, {NLog.Web.AspNetCore, 5.1.5}",
      "Oracle.EntityFrameworkCore, {Oracle.EntityFrameworkCore, 6.21.90}",
      "Oracle.ManagedDataAccess, {Oracle.ManagedDataAccess.Core, 3.21.90}",
      "SQLitePCLRaw.batteries_v2, {SQLitePCLRaw.bundle_e_sqlite3, 2.0.6}",
      "SQLitePCLRaw.core, {SQLitePCLRaw.core, 2.0.6}",
      "SQLitePCLRaw.provider.e_sqlite3, {SQLitePCLRaw.provider.e_sqlite3, 2.0.6}",
      "System.Collections.Immutable, {System.Collections.Immutable, 6.0.0}",
      "System.Configuration.ConfigurationManager, {System.Configuration.ConfigurationManager, 6.0.0}",
      "System.Diagnostics.DiagnosticSource, {System.Diagnostics.DiagnosticSource, 6.0.0}",
      "System.Diagnostics.PerformanceCounter, {System.Diagnostics.PerformanceCounter, 6.0.0}",
      "System.DirectoryServices, {System.DirectoryServices, 7.0.0}",
      "System.DirectoryServices.Protocols, {System.DirectoryServices.Protocols, 5.0.1}",
      "System.Drawing.Common, {System.Drawing.Common, 7.0.0}",
      "System.Formats.Asn1, {System.Formats.Asn1, 6.0.0}",
      "System.IO, {System.IO, 4.3.0}",
      "System.Reflection.DispatchProxy, {System.Reflection.DispatchProxy, 4.7.1}",
      "System.Runtime, {System.Runtime, 4.3.0}",
      "System.Runtime.CompilerServices.Unsafe, {System.Runtime.CompilerServices.Unsafe, 6.0.0}",
      "System.Security.AccessControl, {System.Security.AccessControl, 6.0.0}",
      "System.Security.Cryptography.Cng, {System.Security.Cryptography.Cng, 4.5.0}",
      "System.Security.Cryptography.Pkcs, {System.Security.Cryptography.Pkcs, 6.0.1}",
      "System.Security.Cryptography.ProtectedData, {System.Security.Cryptography.ProtectedData, 6.0.0}",
      "System.Security.Cryptography.Xml, {System.Security.Cryptography.Xml, 6.0.1}",
      "System.Security.Permissions, {System.Security.Permissions, 7.0.0}",
      "System.Security.Principal.Windows, {System.Security.Principal.Windows, 5.0.0}",
      "System.ServiceModel, {System.ServiceModel.Primitives, 4.10.2}",
      "System.ServiceModel.Duplex, {System.ServiceModel.Duplex, 4.10.2}",
      "System.ServiceModel.Federation, {System.ServiceModel.Federation, 4.10.2}",
      "System.ServiceModel.Http, {System.ServiceModel.Http, 4.10.2}",
      "System.ServiceModel.NetTcp, {System.ServiceModel.NetTcp, 4.10.2}",
      "System.ServiceModel.Primitives, {System.ServiceModel.Primitives, 4.10.2}",
      "System.ServiceModel.Security, {System.ServiceModel.Security, 4.10.2}",
      "System.Text.Encoding, {System.Text.Encoding, 4.3.0}",
      "System.Text.Encodings.Web, {System.Text.Encodings.Web, 6.0.0}",
      "System.Text.Json, {System.Text.Json, 6.0.0}",
      "System.Threading.Tasks, {System.Threading.Tasks, 4.3.0}",
      "System.Windows.Extensions, {System.Windows.Extensions, 7.0.0}",
      "System.Xml.ReaderWriter, {System.Xml.ReaderWriter, 4.3.0}",
      "System.Xml.XmlDocument, {System.Xml.XmlDocument, 4.3.0}"
    ],
    "sync": true,
    "targetFramework": "net6.0",
    "typeReuseMode": "All"
  }
}

我已更新到最新版本的System.ServiceModel软件包(6.0.0)。在以前的后端,它是 4.0.0 版本。我使用了 svcUtil 版本 2.1.0

我已经比较了两个服务对象实例化,我看不出任何可以解释性能缓慢的差异

我还尝试更改一些设置并使用其他绑定(NetTcpBinding 和 WSHttpBinding)但没有成功

我们只在 WCF 服务的客户端工作

提前感谢您的帮助

编辑由于此更改,我已将新时间提高到 500 毫秒 https://github.com/dotnet/wcf/issues/5002

asp.net 性能 asp.net-core WCF

评论

0赞 Ihdina 6/27/2023
推荐使用 gRPC:learn.microsoft.com/en-us/dotnet/architecture/... gRPC 示例:github.com/grpc/grpc-dotnet/tree/master/examples
0赞 Joffrey Ferreira 6/28/2023
不幸的是,我们不管理服务器 API,它不支持 gRPC
0赞 Panagiotis Kanavos 6/28/2023
ConnectetService.json 中的版本是 4.10.2,而不是 6.0。您是否尝试过在安装 6.0 软件包后重新创建代理/服务引用?您指出的问题已在接近 6.0 版本时关闭
0赞 Panagiotis Kanavos 6/28/2023
无论如何,在 2023 年,SOAP 是传统技术。.NET Core 起初甚至没有适当的支持。全局工具首次出现在 .NET Core 2.1 中,服务器端 WCF 实际上是一个社区项目 CoreWCF。对 SOAP(以及 WCF)的兴趣根本不够,因此它无法获得与 REST 或 gRPC 相同的资源或社区贡献。如果服务器支持更现代的 API,请考虑迁移到它。商业服务已经弃用了他们的SOAP服务,转而支持RESTsvcutil
0赞 Joffrey Ferreira 6/29/2023
是的,我已经重新创建了引用,但性能仍然很慢,不幸的是,我们客户的 API 只支持 SOAP,所以我们坚持使用它。他们会将 API 迁移到 REST,但他们不知道何时。我想在那之前我们将不得不继续使用 .Net Framework,或者我们优化我们的算法以补偿性能损失

答:

1赞 Joffrey Ferreira 7/5/2023 #1

在WCF团队github上创建问题后,提出了两种解决方案:

  • 使用 HttpClientFactory,但它需要对我们的代码进行大量修改
  • 在第一个客户端实例之前添加。我们这样做了,性能比我们当前的 API 更快DocumentSecuredServiceV002Client.CacheSetting = CacheSetting.AlwaysOn;