I have an application that uses WebServices to send database records (as an array) to the client, yet even when sending only 1000 records it seems to be really slow.
The server is runn开发者_StackOverflow中文版ing on an IIS 7 and the client is a WPF application. Basically, how do I speed this up. Do I have to write a custom compression class or code? Is there just a setting I turn on/off on the IIS server and/or the client config files? Right now it takes about 4-7 seconds to return these 1000 records. So when we tie into the tables that can possibly return 10,000 - 40,000 records I don't want the user to sit there for minutes waiting for data.
Here's an example of the 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);
}
}
}
In all likelihood, your performance bottleneck is the serialization and deserialization of the SelectRecordsResponse object. I can offer several ways to make it faster, in order from least to most difficult:
- Use the NETTCP protocol
- Use binary message encoding.
- Make sure you're using DataContract Serializer instead of Xml Serializer
- Write a custom serializer - this should be your last resort but will probably allow you to make the largest performance improvement
Have you considered using Microsoft Synchronization Services which works over WCF?
I have used it in the past to sync data down to the client and up to the server with a similar number of records. It allows you to filter data based on certain criteria and allow for incremental downloading.
However even when using Sync Services I did notice a massive slow down when syncing large amounts of data. This is because by default the data is serialized to Xml, I resolved this using the binary encoder instead.
It seems that the best way to reduce down the alloted time was a suggestion in the comments, that is paginating the data so that not as much is sent down. I do agree using something other than XML serialization will speed things up, but not enough. Also, using other serializations wasn't acceptable since we had to go with an interop serialization method, in case we ever come out with a Java client instead.
精彩评论