升级.NET Framework 4.7.1 到 .NET 6 会使 WCF 服务消耗变慢。

huangapple go评论69阅读模式
英文:

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

问题

We are rewriting our .Net Framework 4.7.1 backend to .Net 6 and we have a first version. But when performing performance test in local we observed that with same configuration the queries are slower with the new backend. This occurs when consuming data from WCF service: before it took an average of 200 ms, now it is 650 ms.

We had the connected services configured in our web.config.

Now configuration is loaded from appsettings.json in an abstract factory and its implementation.

Here is ConnectedService.json generated in .NET 6 from a local WSDL file.

I have updated to the latest version of System.ServiceModel packages (6.0.0). In the previous backend, it was version 4.0.0. I have used svcUtil version 2.1.0.

I have compared both service object instances and I cannot see any differences that could explain the slow performance.

I have also tried to change a few settings and to use other bindings (NetTcpBinding and WSHttpBinding) without success.

We work only on the client side of the WCF service.

Thank you in advance for your help.

EDIT: I have improved new times to 500 ms thanks to this change GitHub link.

英文:

We are rewriting our .Net Framework 4.7.1 backend to .Net 6 and we have a first version. But when performing performance test in local we observed that with same configuration the queries are slower with the new backend. This occurs when consuming data from WCF service : before it took average 200 ms, now it is 650 ms

We had the connected services configured in our 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>

Now configuration is loaded from appsettings.json in an abstract factory and its implementation :

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;
    }
}

Configuration section in 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"
}

Here is ConnectedService.json generated in Net 6 from a local wsdl file

{
"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"
}
}

I have updated to latest version System.ServiceModel packages (6.0.0). In previous backend it was 4.0.0 version. I have used svcUtil version 2.1.0

I have compared both service object instanciate and i can not see any differences that could explain the slow performances

I have also tried to change few settings and to use other bindings (NetTcpBinding and WSHttpBinding) without success

We work only on client side of WCF service

Thank you in advance for your help

EDIT
I have improved new times to 500ms thanks to this change https://github.com/dotnet/wcf/issues/5002

答案1

得分: 1

在 WCF 团队的 GitHub 上创建了一个问题后,提出了两个解决方案:

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

After creating an issue on WCF team github , two solutions have been proposed :

  • Work HttpClientFactory but it would need a lot of modifications on our code

  • Add DocumentSecuredServiceV002Client.CacheSetting = CacheSetting.AlwaysOn; before first client instance. We did this and performances were faster than our current API

huangapple
  • 本文由 发表于 2023年6月26日 22:19:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76557565.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定