2010-11-03 4 views
0

J'ai une application qui utilise WebServices pour envoyer des enregistrements de base de données (en tant que tableau) au client, mais même en envoyant seulement 1000 enregistrements, il semble être vraiment lent.C# WebService Compression

Le serveur fonctionne sur un IIS 7 et le client est une application WPF. Fondamentalement, comment puis-je accélérer cela. Dois-je écrire une classe ou un code de compression personnalisé? Y at-il juste un paramètre que j'active/désactive sur le serveur IIS et/ou les fichiers de configuration du client? En ce moment, il faut environ 4-7 secondes pour retourner ces 1000 enregistrements. Donc, quand nous lions dans les tables qui peuvent éventuellement renvoyer 10 000 à 40 000 enregistrements, je ne veux pas que l'utilisateur reste là pendant des minutes à attendre des données.

Voici un exemple du code:

Foo.svc:

namespace Foo.Server 
{ 
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)] 
    public sealed class FooService : IFoo 
    { 
     public SelectRecordsResponse SelectRecords(SelectRecordsRequest request) 
     { 
      //I tested to ensure that this isn't my bottleneck 
      FooBar[] records = ...; //Stores 1000 records 

      return new SelectRecordsResponse(records); 
     } 
    } 
} 

FooCommon.cs:

namespace Foo 
{ 
    [ServiceContract(Namespace = "http://www.company.com/Services/Foo", ConfigurationName = "IFoo")] 
    [ServiceKnownType(typeof(AbstractEntity))] 
    [XmlSerializerFormat(SupportFaults = true, Style = OperationFormatStyle.Document, Use = OperationFormatUse.Literal)] 
    public interface IFoo 
    { 
     [OperationContract(Action = "http://www.company.com/Services/Foo/SelectRecords", 
          ReplyAction = "http://www.company.com/Services/Foo/SelectRecordsReply", 
          Name = "SelectRecords")] 
     [ServiceKnownType(typeof(FooBar))] 
     [return: MessageParameter(Name = "Response")] 
     SelectRecordsResponse SelectRecords([MessageParameter(Name = "Request")]SelectRecordsRequest request); 
    } 

    [MessageContract(WrapperName = "SelectRecordsRequest", WrapperNamespace = "http://www.company.com/Services/Foo/", IsWrapped = true)] 
    public sealed class SelectRecordsRequest 
    { 
     public SelectRecordsRequest() 
     { 
     } 
    } 

    [MessageContract(WrapperName = "SelectRecordsResponse", WrapperNamespace = "http://www.company.com/Services/Foo/", IsWrapped = true)] 
    public sealed class SelectRecordsResponse 
    { 
     public SelectRecordsResponse() 
     { 
      Init(); 
     } 

     public SelectRecordsResponse(FooBar[] records = null) 
     { 
      Init(records); 
     } 

     private void Init(FooBar[] records = null) 
     { 
      Records = records ?? new FooBar[0]; 
     } 

     [MessageBodyMember(Namespace = "http://www.company.com/Services/Foo/", Order = 0, Name = "Records")] 
     [XmlArray(ElementName = "SelectRecordsArray", Form = XmlSchemaForm.Qualified)] 
     [XmlArrayItem(typeof(FooBar), ElementName = "SelectRecordsFooBar", Form = XmlSchemaForm.Qualified, IsNullable = true)] 
     private FooBar[] Records { get; set; } 
    } 
} 

FooClient.cs:

namespace Foo.Client 
{ 
    public interface IFooChannel : IFoo, IClientChannel 
    { 
    } 

    public sealed class FooClient : ClientBase<IFoo>, IFoo 
    { 
     public FooClient(String endpointConfigurationName) : 
      base(endpointConfigurationName) 
     { 
     } 

     public FooBar[] SelectRecords() 
     { 
      SelectRecordsRequest request = new SelectRecordsRequest(); 
      SelectRecordsResponse response = ((IFoo)(Client)).SelectRecords(request); 

      return response.Records; 
     } 

     SelectRecordsResponse IFoo.SelectRecords(SelectRecordsRequest request) 
     { 
      return Channel.SelectRecords(request); 
     } 
    } 
} 
+1

Si une requête renvoie 40000 enregistrements au client, la requête est probablement erronée. Le résultat devrait probablement être agrégé ou filtré avant de le renvoyer au client. –

+0

Vous devez implémenter "pagination". Il n'y a aucun moyen pour vous de renvoyer * jamais * 40 000 enregistrements d'un seul coup. –

+0

Je travaille certainement sur la mise en filtrage et la pagination, mais il y a des cas où le client veut que CHAQUE DISQUE soit visible dans une grille de données à la fois.Quoi qu'il en soit, 100 enregistrements ou 40 000, je vais toujours avoir besoin de mettre en œuvre une sorte de compression. –

Répondre

0

Il semble que le meilleur La façon de réduire le temps alloué était une suggestion dans les commentaires, c'est-à-dire paginer les données de manière à ce qu'elles ne soient pas envoyées autant. Je suis d'accord en utilisant quelque chose d'autre que la sérialisation XML va accélérer les choses, mais pas assez. En outre, l'utilisation d'autres sérialisations n'était pas acceptable car nous devions utiliser une méthode de sérialisation interop, au cas où nous aurions un client Java à la place.

0

Avez-vous envisagé d'utiliser Microsoft Synchronization Services qui fonctionne sur WCF?

Je l'ai utilisé dans le passé pour synchroniser les données vers le client et vers le serveur avec un nombre similaire d'enregistrements. Il vous permet de filtrer les données en fonction de certains critères et de permettre un téléchargement incrémentiel.

Cependant, même en utilisant les services de synchronisation, j'ai remarqué un ralentissement massif lors de la synchronisation de grandes quantités de données. C'est parce que par défaut les données sont sérialisées en Xml, j'ai résolu cela en utilisant le binary encoder à la place.

2

Selon toute probabilité, votre goulot d'étranglement des performances est la sérialisation et la désérialisation de l'objet SelectRecordsResponse. Je peux offrir plusieurs façons de le rendre plus rapide, dans l'ordre du moins au plus difficile:

  1. Utilisez le protocole NetTcp
  2. Utiliser le codage binaire des messages.
  3. Assurez-vous que vous utilisez DataContract sérialiseur au lieu de Xml sérialiseur
  4. Ecrire un custom serializer - cela devrait être votre dernier recours, mais probablement vous permettra de faire la plus grande amélioration de la performance