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 running 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);
}
}
}
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.