I have a really strange problem with one of my WCF services. I'm pretty sure that most people who have experimented with WCF services have had an EndpointNotFoundException thrown when an endpoint had not been set up correctly in one of their configuration files. From the EndpointNotFoundException class page on MSDN:
The exception that is thrown when a remote endpoint could not be found or reached.
Further on, it continues:
The endpoint may not be found or reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
This does not reflect my situation. So it seems that receiving an EndpointNotFoundException when working with WCF is not unusual, but this Exception is not thrown when first trying to access the service... instead, it is thrown only when trying to call one of the operations of the service:
using (ExportConfirmationServiceClient client = new ExportConfirmationServiceClient(
"WebHttpBinding_IExportConfirmationService")) // <-- Exception is NOT thrown here
{
...
component releaseConfirmation = DeserializeTestXmlFile(filePath);
client.AddExportConfirmation("5051275066302", releaseConfirmation);
// Exception is thrown on call to service operation on line above
...
}
Interestingly, the Exception message also includes the name of the operation in the mentioned file path:
There was no endpoint listening at http://domain/Folder/ServiceName.svc/OperationName that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
The inner Exception has the following message:
The remote server returned an error: (404) Not Found.
This is particularly confusing for me as I can successfully browse to the service URL and see the default You have created a service page:
Also, if I navigate to the path in the Exception message, I see an Endpoint not found message on the page:
However, if I navigate to any operation page of one of my other, working WCF services, I get a standard 400 Bad Request error from the browser, even though the operation works fine. So it would seem to me as if this original EndpointNotFoundException could be a red herring... I'm really not sure though, as I've not spent much time working with WCF.
I'll show my web.config (server side) here just in case anyone needs to see it:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="Midas.WebConfirmations.ExportConfirmationServiceBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webHttp">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
<services>
<service name="Midas.WebConfirmations.ExportConfirmationService" behaviorConfiguration="Midas.WebConfirmations.ExportConfirmationServiceBehaviour">
<endpoint address="" binding="webHttpBinding" contract="Midas.WebConfirmations.IExportConfirmationService" behaviorConfiguration="webHttp" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
This is the client App.config (bear in mind that this references two WCF services):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IDataService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
<webHttpBinding>
<binding name="WebHttpBinding_IExportConfirmationService" allowCookies="true" maxReceivedMessageSize="20000000" maxBufferSize="20000000" maxBufferPoolSize="20000000">
<readerQuotas maxDepth="32" maxArrayLength="200000000" maxStringContentLength="200000000"/>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Midas.WebConfirmations.ExportConfirmationServiceBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webEndpointBehavior">
<webHttp defaultBodyStyle="Wrapped" defaultOutgoingResponseFormat="Xml" helpEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://devbucket.ministryofsound.mos.local/MidasWebServices/DataService.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IDataService" contract="Midas.WebServiceClients.IDataService" name="BasicHttpBinding_IDataService" />
<endpoint address="http://devbucket.ministryofsound.mos.local/MidasWebConfirmations/ExportConfirmationService.svc" binding="webHttpBinding" bindingConfiguration="WebHttpBinding_IExportConfirmationService" behaviorConfiguration="webEndpointBehavior" contract="IExportConfirmationService" name="WebHttpBinding_IExportConfirmationService" />
</client>
</system.serviceModel>
</configuration>
So if any of the great minds that frequent Stack Overflow could shed some light on this problem for me, I'd greatly appreciate it.
UPDATE >>>
In response to the first few comments, I suspected that the problem could be caused by an Exception being thrown from the server side code, so I simplified the operation code dramatically... now all it does is this, but I still get the same error:
public void AddExportConfirmation(string upc, component ingestionFeedback)
{
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.OK;
}
Also, I did set up tracing, but it only worked on the client side, so it only told me what I already knew. I will have a look at the link you provided #BigDaddy, in case it shows how to set up tracing on the server side.
In response to Tewr, I generated the service client using svcutil.exe, but I also tried adding a service reference and letting Visual Studio create the reference for me... both methods resulted in the same error. Also, I have been updating the service references all day, as I've been making changes. The includeExceptionDetailInFaults="true" setting didn't make any difference, but I'll try adding a dummy operation to the service and try to view it in the browser.
UPDATE 2 >>>
Ok, so I added a simple getter method to the service and updated the references all round like #Tewr suggested. This has just made me more confused... the method:
[XmlSerializerFormat()]
[OperationContract]
[WebGet()]
string GetString();
The implementation just returns a string and I see that value when I access the service in a web browser:
However, I still get the same error from code, even when calling this same new operation... what does that mean?
UPDATE 3 >>>
After taking the advice from the comments, I set up a Service Trace on the service again... I still couldn't get the one working on the server, but on the client, it did output a trace file. In that file, I see an InvalidOperationException with the following message:
Envelope Version 'EnvelopeNone (http://schemas.microsoft.com/ws/2005/05/envelope/none)' does not support adding Message Headers.
I'm just researching this now, so if you know what this error is about, please let me know.
The problem with WCF is that it is so complex, the Exceptions cover so many different errors each and the Exception messages are so vague. From my limited experience, it seems like an error message will say one thing, but it will often be wholly, or partly irrelevant to your actual problem. So I basically kept fixing errors, which unlocked new Exceptions (and I still haven't come to the end of them yet!), but for the purpose of this question, there is an answer.
So it turned out that the original EndpointNotFoundException was actually thrown because there was an unhandled Exception in the AddExportConfirmation service method implementation. Once I had simplified the code (as in the first question update), that particular Exception went away and was replaced with the next one.
My WCF service configuration:
<system.net>
<connectionManagement>
<add address ="*" maxconnection="500"/>
</connectionManagement>
</system.net>
<bindings>
<basicHttpBinding>
<binding name="customBasicHttpBinding"
maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"
transferMode="StreamedResponse">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
<security mode="None"/>
</binding>
</basicHttpBinding>
<webHttpBinding>
<binding name="customWebBinding" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
<security mode="None">
</security>
</binding>
</webHttpBinding>
</bindings>
<serviceBehaviors>
<behavior name="soapBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<dataContractSerializer maxItemsInObjectGraph="6553600"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceThrottling maxConcurrentCalls="100"
maxConcurrentInstances="100" maxConcurrentSessions="100" />
</behavior>
</serviceBehaviors>
<services>
<service behaviorConfiguration="soapBehavior" name="Service.Service">
<endpoint name="soap"
address=""
binding="basicHttpBinding" bindingConfiguration="customBasicHttpBinding"
contract="ServiceModel.IService"/>
<endpoint
address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
As you can see I set up throttling parameter to handle 100 concurrent instances.
For a test purpose I created dummy method on my interface that looks something like this
[OperationContract]
string Test(){
return "test response time";
}
When I'm trying to call this method, it uses 100 parallel request ats once response time is very bad:
Now running 100 parallel requests...
ResponseTimes: 0,45205P, 10,047P, 0,43304P, 0,86609P, 1,33913P, 0,91409P, 1,34713P, 1,75718P, 1,37414P, 1,80718P, 1,80618P, 2,22622P, 2,64426P, 2,22822P, 2,62626P, 2,68127P, 3,0453P, 3,10731P, 3,47635P, 3,51035P, 3,91039P, 3,94039P, 3,9544P, 4,36844P, 4,34943P, 4,78748P, 4,37144P, 4,82248P, 4,79048P, 5,25052P, 4,81948P, 5,67657P, 5,25253P, 5,71657P, 5,67357P, 6,13761P, 5,70257P, 6,56566P, 6,12361P, 7,0117P, 6,53065P, 7,43674P, 6,9517P, 7,86679P, 7,36974P, 7,81778P, 8,29483P, 8,75988P, 8,71587P, 8,24182P, 8,70187P, 9,16392P, 9,12991P, 9,19492P, 9,57596P, 9,65797P, 10,08201P, 10,45205P, 10,52505P, 10,48905P, 10,9521P, 10,89709P, 11,37714P, 11,81118P, 11,32413P, 11,76418P, 11,83918P, 12,18222P, 12,31723P, 12,60526P, 12,75128P, 13,0423P, 13,17132P, 13,48935P, 13,64836P, 13,91039P, 14,07141P, 14,32843P, 14,48945P, 14,78548P, 14,91149P, 15,20652P, 15,33153P, 15,62856P, 15,75558P, 16,0516P, 16,19262P, 16,48265P, 16,61866P, 16,91169P, 17,05471P, 17,33773P, 17,48375P, 17,74677P, 17,92079P, 18,15782P, 18,34183P, 18,58086P, 18,77388P, 19,0069P,
0 request(s) failed.
Average response time:9,20126
Why are results so bad, I tried to change AppPool Worker Process count but no luck, can anyone tell what I'm missing, what is setting limits?
I'm using WCF 4.0, IIS7.5 on a Windows Server 2008R2 machine.
Thank you
It is difficult to provide much insight regarding communication performance issues without detailed information about the service, configuration and environment. At the least, you may way to provide the service binding, the ServiceBehaviorAttribute and information about the client configuration.
From years of conducting WCF performance testing and optimization, we have seen “similar” issues as you described … despite having 100 concurrent connections, the service does not seem to “respond” efficiently, even though the server resources do not seem busy. In our case, the “delay” was associated with a slow, “cold” startup and the time taken by the .NET thread pool to allocate threads.
The following article discusses our issue:
http://blogs.msdn.com/b/dmetzgar/archive/2011/05/04/wcf-scales-up-slowly-with-bursts-of-work.aspx
Good luck.
I just finished a big, industrial scale WCF project that employed throttling and found that throttling doesn't always yield the results you expect. We set up our WCF web servce on a production-grade virtual server, then we created a test harness that emulated 1000+ virtual clients on a multi-threaded program. Once we were ready, we ran, and re-ran, tests over and over using a bunch of different throttling settings from 1 - 1000, but were surprised by the results.
For instance, you'd think that running your web service with 200 max concurrent connections would be twice as fast as 100 max connections, but that's not what we found for settings for things like:
-max concurrent sessions
-max concurrent calls
-max concurrent instances
In reality, there wasn't much of a performance (callsProcessed/second) difference between MaxConcurrentSessions=10 and MaxConcurrentSessions=1000. The calls processed per second was about the same, only the memory usage was different. Same thing with other throttle settings.
The fastest setting we found for throttling? No setting at all; basically, let the System.ServiceModel library handle everything. That's the fastest that we found after days of testing.
As far as your performance is concerned, what I would do is try and figure out where the bottle necks are. For instance, if your WCF service is using SQL to retrieve data, try eliminating SQL and just return a static dataset and see if your time dramatically improves. If it does, then maybe you need to work on the database side of things. If it doesn't, maybe there's a problem processing your SOAP messages.