How to Improve WCF Data Services Performance - wcf

I'm new to WCF Data Services so I've been playing. After some initial tests I am disappointed by the performance of my test data service.
I realize that because a WCF DS is HTTP-based there is overhead inherent in the protocol but my tests are still way slower than I would expect:
Environment:
All on one box: Quad core 64-bit laptop with 4GB RAM running W7. Decent machine.
Small SQL database (SQLExpress 2008 R2) with 16 tables... the table under test has 243 rows.
Hosted my test service in IIS with all defaults.
Code:
I've created a Entity Framework model (DataContext) for this database (stock codegen by VS2010).
I've created a data-service based on this model.
I've created a client which has a direct service reference (ObjectContext) for this service (stock codegen by VS2010)
In the client I am also able to call the EF model directly and also use Native SQL (ADO.NET SqlConnection)
Test Plan:
Each iteration connects to the database (there is an option to reuse connections), queries for all rows in the target table ("EVENTS") and then counts them (thus forcing any deferred fetches to be performaed).
Run for 25 iterations each for Native SQL (SqlConnection/SqlCommand), Entity Framework (DataContext) and WCF Data Services (ObjectContext).
Results:
25 iterations of Native SQL: 436ms
25 iterations of Entity Framework: 656ms
25 iterations of WCF Data Services: 12110ms
Ouch. That's about 20x slower than EF.
Since WCF Data Services is HTTP, there's no opportunity for HTTP connection reuse, so the client is forced to reconnect to the web server for each iteration. But surely there's more going on here than that.
EF itself is fairly fast and it's the same EF code/model is reused for both the service and the direct-to-EF client tests. There's going to be some overhead for Xml serialization and deserialization in the data-service, but that much!?! I've had good performance with Xml serialization in the past.
I'm going to run some tests with JSON and Protocol-Buffer encodings to see if I can get better performance, but I'm curious if the community has any advice for speeding this up.
I'm not strong with IIS, so perhaps there are some IIS tweaks (caches, connection pools, etc) that can be set to improves this?

Consider deploying as a windows service instead? IIS may have ASAPI filters, rewrite rules, etc that it runs through. even if none of these are active, the IIS pipeline is so long, something may slow you down marginally.
a service should give you a good baseline of how long it takes the request to run, be packed, etc, without the IIS slowdowns

The link below has video that has some interesting WCF benchmarks and comparisons between WCF data services and Entity Framework.
http://www.relationalis.com/articles/2011/4/10/wcf-data-services-overhead-performance.html

I increased performance of our WCF Data Service API by 41% simply by enabling compression. It was really easy to do do. Follow this link that explains what to do on your IIs server: Enabling dynamic compression (gzip, deflate) for WCF Data Feeds, OData and other custom services in IIS7
Don't forget to iisReset after your change!
On the client-side:
// This is your context basically, you should have this code throughout your app.
var context = new YourEntities("YourServiceURL");
context.SendingRequest2 += SendingRequest2;
// Add the following method somewhere in a static utility library
public static void SendingRequest2(object sender, SendingRequest2EventArgs e)
{
var request = ((HttpWebRequestMessage)e.RequestMessage).HttpWebRequest;
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
}

Try setting security to "none" in the binding section in the configuration. This should make big improvement.

In order to eliminate most of the connection overhead you can try to batch all operations to the WCF DS to to see if that makes a significant difference.
NorthwindEntities context = new NorthwindEntities(svcUri);
var batchRequests =
new DataServiceRequest[]{someCustomerQuery, someProductsQuery};
var batchResponse = context.ExecuteBatch(batchRequests);
For more info see here.

WCF DataServices are for providing your disparate clients with OpenData protocol; so as you don't have to write/refactor multiple web service methods for each change request. I never advise it to be used if the entire system is microsoft technology stack based. It's meant for remote clients.

How do you pass those 25 iterations for WCF?
var WCFobj = new ...Service();
foreach(var calling in CallList)
WCFobj.Call(...)
If you call like that it means you call WCF 25 times, which consumes too many resources.
For me, I used to build up everything into a DataTable and user table name to stored procedure I'm calling; DataRow is params. When calling, just pass the DataTable in encrypted form by using
var table = new DataTable("PROC_CALLING")...
...
StringBuilder sb = new StringBuilder();
var xml = System.Xml.XmlWriter.Create(sb);
table.WriteXml(xml);
var bytes = System.Text.Encoding.UTF8.GetBytes(sb.ToString());
[optional]use GZip to bytes
WCFobj.Call(bytes);
The thing is you pass all 25 calls at once, that can save performance significantly. If the return object is same structure, just pass it as DataTable in bytes form and convert it back to DataTable.
I used to implement this methods with GZip for import/export data modules. Passing large amount of bytes is going make WCF unhappy. Its depends whatever you want to consume; computing resources or networking resources.

things to try:
1) results encoding: use binary encoding of your WCF channel if possible, see http://msdn.microsoft.com/en-us/magazine/ee294456.aspx -- alternately use compression: http://programmerpayback.com/2009/02/18/speed-up-your-app-by-compressing-wcf-service-responses/
2) change your service instance behavior, see http://msdn.microsoft.com/en-us/magazine/cc163590.aspx#S6 -- try InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple - if you can verify that your service is built in a thread safe way.
Regarding your benchmark, I think you should simulate more realistic load (including concurrent users) and ignore outliers, the first request to IIS will be really slow (it has to load all the DLLs)

Related

How to convert a LinqExpression into OData query URI

There are a lot of answers on how to convert ODataQuery into an Expression or into a Lambda, but what I need is quite the opposite, how to get from a Linq Expression the OData query string.
Basically what I want is to transcend the query to another service. For example, having 2 services, where your first service is not persisting anything and your second service is the one that will return the data from a database. Service1 sends the same odata request to Service2 and it can add more parameters to the original odata request to Service2
What I would like:
public IActionResult GetWeatherForecast([FromServices] IWeatherForcastService weatherForcastService)
{
//IQueryable here
var summaries = weatherForcastService.GetSummariesIQ();
var url = OdataMagicHelper.ConvertToUri(summaries);
var data = RestClient2.Get(url);
return data;
}
OP Clarified the request: generate OData query URLs from within the API itself.
Usually, the queries are so specific or simple, that it's not really necessary to try and generate OData urls from within the service, the whole point of the service configuration is to publish how the client could call anything, so it's a little bit redundant or counter-intuitive to return complex resource query URLs from within the service itself.
We can use Simple.OData.Client to build OData urls:
If the URL that we want to generate is:
{service2}/api/v1/weather_forecast?$select=Description
Then you could use Simple.OData.Client:
string service2Url = "http://localhost:11111/api/v1/";
var client = new ODataClient(service2Url);
var url = await client.For("weather_forecast")
.Select("Description")
.GetCommandTextAsync();
Background, for client-side solutions
If your OData service is a client for another OData Service, then this advice is still relevant
For full linq support you should be using OData Connected Services or Simple.OData.Client. You could roll your own, or use other derivatives of these two but why go to all that effort to re-create another wheel.
One of the main drivers for a OData Standard Compliant API is that the meta data is published in a standard format that clients can inspect and can generate consistent code and or dynamic queries to interact with the service.
How to choose:
Simple.OData.Client provides a lightweight framework for dynamically querying and submitting data to OData APIs. If you already have classes that model the structure of the API then you can use typed linq style query syntax, if you do not have a strongly typed model but you do know the structure of the API, then you can use either the untyped or dynamic expression syntax to query the API.
If you do not need full compile-time validation of your queries or you already have the classes that represent the resources served by the API then this is a simple enough interface to use.
This library is perfect for use inside your API logic if you have need of generating complex URLs in a strongly typed style of code without trying to generate a context to manage the connectivity to the server.
NOTE: Simple.OData.Client is sometimes less practical when developing against a large API that is rapidly evolving or that does not have a strict versioned route policy. If the API changes you will need to diligently refactor your code to match and will have to rely on extensive regression testing.
OData Connected Services follows a pattern where some or all of the API is modelled in the client with strongly typed client side proxy interfaces. These are POCO classes that have the structure necessary to send to and receive data from the server.
The major benefit to this method is that the POCO structures, requests and responses are validated against the schema of the API. This effectively gives you full intellisense support for the API and allows you to explor it's structure, the generated code becomes your documentation. It also gives you compile time checking and runtime safety.
The general development workflow after the API is deployed or updated is:
Download the $metadata document
Select the Operations and Types from the API that you want to model
Generate classes to represent the selected DTO Types as defined in the document, so all the inputs and outputs.
Now you can start using the code.
In VS 2022/19/17 the Connected Services interface provides a simple wizard for establishing the initial connection and for updating (or re-generating) when you need to.
The OData Connected Service or other client side proxy generation pattern suits projects under these criteria:
The API definition is relatively stable
The API definition is in a state of flux
You consume many endpoints
You don't want to manually code the types to serialize or deserialze payloads
Full disclosure, I prefer the connected service approach, but I have my own generation scripts. However if you are trying to generate OData query urls from inside your API, its not really an option, it creates a messy recursive dependency... just don't go there.
Connected services is the low-(manual)-code and lazy approach that is perfect for a stable API, generate once and never do it again. But the Connected Service architecture is perfect for a rapidly changing API because it will manage the minute changes to the classes for you, you just need to update your client side proxy classes more frequently.

Performance with Silverlight calling WCF service

I'm having an issue where calling a WCF web service from Silverlight is very slow. The situation is very similar to the one outlined in http://forums.silverlight.net/t/148027.aspx/1 . Like that poster, I have set up a simple Silverlight Application project and a simple Console Application project. In each, I added a service reference to my WCF service and added a few test calls to the service. However, the time it takes for each call to go out is drastically different. The console app makes the call on the order of milliseconds. The Silverlight app makes it anywhere from 3-5 seconds.
In the post I linked to above, when the poster changed his service to use binary message encoding, the speed gap disappeared. However, in my situation, the large speed gap remains regardless of whether I'm using binary message encoding or text message encoding.
What could account for this speed difference? I've verified through fiddler that both the request and response are being binary-encoded when I have it configured to use my binary endpoint. I've also verified that the slow speed persists through multiple consecutive web service calls, so it can't just be spin-up time. The problem has to be on the Silverlight side somewhere.
Here's a snippet of the code that I'm using to measure the time difference:
var proxy = new WCFRef.WebServicesClient("binary");
var callbegin = DateTime.Now;
proxy.CallWSMethodAsync();
var callend = DateTime.Now;
var span = callend.Subtract(callbegin);
Debug.WriteLine("call time: " + span.Seconds + "." + span.Milliseconds + " sec");
The timespan captured in that code is the span I was talking about with the large difference between console (few milliseconds) and SL (few seconds).
A few months ago we also hit this speed bump from WCF.
Why it is slow we do not know.
I guess SOAP in general is a bit slow (lots of overhead) aswell as the serializers that aren't all that performant.
We've recently switched to a REST architecture (service stack, but web API/asp.net mvc work fine aswell. We simply liked Service stack a bit more) and our performance went up from anywhere from 2x to 15x the speed.
WCF is terribly slow at accepting and serialize/deserialize request.
I'm guessing silverlight with it's stripped down .net has something to do with it.
We also did some test with pure the serializer. We got a huge boost from switching out the xml/binary serializer that wcf uses to a costum JSON serializer. Alas it's not easy to switch out the serializer in WCF with silverlight.

Can you use WCF Data Services (ne OData, ne Astoria, ne ADO.NET Data Service) with NetTcpBinding?

I'm looking at creating a data query WCF service over a slow satellite connection and I really like WCF Data Services. The problem I see is that HTTP is a very verbose format and since everything I'm doing is internal and .NET, is it possible to use NetTcpBinding instead to reduce some of the overhead?
Is this even possible? Advisable?
While researching this on my own, i ran across the MSDN article on Self-Hosted WCF Data Services. This article notes that you can host the service with DataServiceHost which still requires HTTP (it's derived from WebServiceHost).
But you can also roll your own host using IDataServiceHost. Here's an excerpt from the MSDN article:
For cases where the WCF host
implementation is too restrictive, you
can also define a custom host for a
data service. Any class that
implements IDataServiceHost interface
can be used as the network host for a
data service. A custom host must
implement the IDataServiceHost
interface and be able to handle the
following basic responsibilities of
the data service host:
Provide the data service with the service root path.
Process request and response headers information to the appropriate
IDataServiceHost member implementation.
Handle exceptions raised by the data service.
Validate parameters in the query string.
The article seems to suggest that MS has properly segrated data-service responsibilities from network interface responsibilities. If that's so, then I should be able to write a NetTcpDataServiceHost. Has anyone ever written a IDataServerHost? Any suggestions?
No, WCF Data Services are built on top of REST, and REST itself is very intimately and completely based on the HTTP verbs like GET, PUT, POST etc. - you cannot run those over NetTcp, since those are intrinsically tied to the HTTP protocol stack.
Maybe there are other options for you to reduce the data being transmitted? Tweak your objects - trim the fat, if you can - both on the number of rows retrieved at once, and the number of attributes/data fields transmitted. That's probably you're most promising approach.

WCF ChannelFactory vs generating proxy

Just wondering under what circumstances would you prefer to generate a proxy from a WCF service when you can just invoke calls using the ChannelFactory?
This way you won't have to generate a proxy and worry about regenerating a proxy when the server is updated?
Thanks
There are 3 basic ways to create a WCF client:
Let Visual Studio generate your proxy. This auto generates code that connects to the service by reading the WSDL. If the service changes for any reason you have to regenerate it. The big advantage of this is that it is easy to set up - VS has a wizard and it's all automatic. The disadvantage is that you're relying on VS to do all the hard work for you, and so you lose control.
Use ChannelFactory with a known interface. This relies on you having local interfaces that describe the service (the service contract). The big advantage is that can manage change much more easily - you still have to recompile and fix changes, but now you're not regenerating code, you're referencing the new interfaces. Commonly this is used when you control both server and client as both can be much more easily mocked for unit testing. However the interfaces can be written for any service, even REST ones - take a look at this Twitter API.
Write your own proxy - this is fairly easy to do, especially for REST services, using the HttpClient or WebClient. This gives you the most fine grain control, but at the cost of lots of service API being in strings. For instance: var content = new HttpClient().Get("http://yoursite.com/resource/id").Content; - if the details of the API change you won't encounter an error until runtime.
Personally I've never liked option 1 - relying on the auto generated code is messy and loses too much control. Plus it often creates serialisation issues - I end up with two identical classes (one in the server code, one auto generated) which can be tided up but is a pain.
Option 2 should be perfect, but Channels are a little too limiting - for instance they completely lose the content of HTTP errors. That said having interfaces that describe the service is much easier to code with and maintain.
I use ChannelFactory along with MetadataResolver.Resolve method. Client configuration is a bother, so I get my ServiceEndpoint from the server.
When you use ChannelFactory(Of T), T is either the original contract that you can get from a reference in you project or a generated contract instance. In some projects, I generated the code from a Service Reference because I could not add a reference to the contract dll. You can even generate an asynch contract with the service reference and use that contract interface with ChannelFactory.
The main point of using ChannelFactory for me was to get rid of the WCF client config information. In the sample code below, you can see how to achieve a WCF client without config.
Dim fixedAddress = "net.tcp://server/service.svc/mex"
Dim availableBindings = MetadataResolver.Resolve(GetType(ContractAssembly.IContractName), New EndpointAddress(fixedAddress))
factoryService = New ChannelFactory(Of ContractAssembly.IContractName)(availableBindings(0))
accesService = factoryService.CreateChannel()
In my final project, the availableBindings are checked to use net.tcp or net.pipe if available. That way, I can use the best available binding for my needs. I only rely on the fact that a metadata endpoint exist on the server.
I hope this helps
BTW, this is done using .NET 3.5. However it does work also with 4.0.
Well in order to use ChannelFactory<T> you must be willing to share contract assemblies between the service and the client. If this is okay with you then ChannelFactory<T> can save you some time.
The proxy will build async functions for which is kind of nice.
My answer is a kind of summary of Keith's and Andrew Hare's answers.
If you do not control server, but have only WSDL/URL- generate proxy using Visual Studio or svcutil. (Note that Visual Studio sometimes failed, when svcutil works better).
When you control both server and client, share interfaces/contracts and call ChannelFactory
.
It's not just a matter of time saved. Using the WSDL generated proxy is dangerous because if you forget to update the service reference you can leave the solution in an inconsistent state. Everything compiles but the service contract is broken. I definetly suggest to use a ChannelFactory whenever possible, you make your life much easier.
A possible alternative could be to write a prebuild script that calls the SVCUtil utility to create the proxy everytime you build your project, but anyway ChannelFactory is much more neat and elegant.

How to unit test a WCF server/client?

I have a WCF server that is a library assembly. (I am writing it so I can mock the level below it) It is called var a client helper class that is in a different assembly. As the data that is transferred is complex and the server has to send call-backs to the clients I wish to test the WCF code in isolation.
(I am only interested in the TCP channel or NamePipe channel)
I do not wish to mock WCF, as the risk I am trying to control is my usage of WCF.
It there a easy way to
Load my WCF server into a different app domain
(I could load the WCF server into the main app domain, but then I it harder to prove that the objects were serialized correctly rather than just pointer moved about.)
Setup all the WCF config so the client class can call it (most likely named pipes or TCP)
And use it in some nunit test
I rather not have my unit tests depending on config file.
I expect (hope) that there are some util classes for setting up WCF unit test that I can just pass the type of my server class to and will give me back a client factory that connects to the server.
Am I going about this the wrong way, e.g there a better way of testing my communication layer and usage of WCF?
It is by far the easiest approach if you spin up the service in-proc, because then you don't need to write a lot of complex synchronization code to determine when the service is running and when it isn't.
Don't worry about pointers being passed around - they won't (unless you choose the new in-proc binding in WCF 4). It's the binding that determines how and if objects are serialized. Named pipes are excellent for this purpose.
I always spin up a new ServiceHost in each test case inside a using statement, which effectively guarantees that the host is running before calls are being made to it, and that it is properly closed after each test. This last part is important because it ensures test independence.
You may also want to look at a series of blog posts I wrote about a very similar subject.
You can use SOA Cleaner for testing your WCF. Take a look at http://xyrow.com
no installation is needed. It's not unit testing, but it can be very helpful (you can have it run on your build, as it supports command line too).