Analyzing why WCF much slower than WSE webservice - c#

We have a web service with both WSE 3.0 endpoints and the newer WCF endpoints on .NET Framework 4.5.
WCF is using basicHttpBinding.
The problem is that the new WCF bindings appear to be significantly slower (~3x). Does it use the same mechanism under the hood?
I've read a lot about enabling WCF tracing. But when I enable that on production I get way to much information and don't really know how read e.g. the timeline in Microsoft Trace Viewer.
I would appreciate any help
Tips for finding causes of the performance difference
Idea from a theoretical standpoint, e.g. are there any major differences under the hood in how WCF processes a request?
Any tools that can help to profile WCF server
Notes:
The issue exists in production; on the test servers everything goes
fine. At first we suspected that the load balancer might be a factor,
but disabling the load balancer does not change the performance at all
The slowness could be due our application/domain layer of course.
Maybe some thread/connection pool is blocking and messages are getting
queued because of that.
In this case does anyone have an idea why the behaviour is so
different from WSE (which runs on the same application pool)? Did any
queue sizes/concurrent processing default configurations change
dramatically between WSE3.0 and WCF?
Is there a way to find out when this is happening? E.g. some perfmon counters to watch? In perfmon I just get lost choosing between the huge amount of performance counters available
Update
Here's an anonymized version of our service Web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="microsoft.web.services2" type="Microsoft.Web.Services2.Configuration.WebServicesConfiguration, Microsoft.Web.Services2, Version=2.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<system.web>
<httpRuntime executionTimeout="900" maxRequestLength="10240" />
<webServices>
<!--<wsdlHelpGenerator href="CustomizedWebServicePage.aspx" />-->
<protocols>
<add name="HttpGet" />
<add name="HttpPost" />
</protocols>
<soapExtensionTypes>
<add type="Microsoft.Web.Services2.WebServicesExtension, Microsoft.Web.Services2, Version=2.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0" />
</soapExtensionTypes>
</webServices>
<compilation defaultLanguage="cs" debug="true" targetFramework="4.5" />
<customErrors mode="RemoteOnly" />
<!-- dev only - application pool identity is configured on real environment -->
<identity impersonate="true" userName="ServiceIdentity" password="********" />
<authentication mode="Windows" />
<authorization>
<allow users="*" />
<!-- Allow all users -->
</authorization>
<trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />
<sessionState mode="InProc" cookieless="false" timeout="20" sqlConnectionString="data source=127.0.0.1;user id=someuserid;password=********;port=42424" />
<globalization requestEncoding="utf-8" responseEncoding="utf-8" />
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" />
</system.web>
<microsoft.web.services2>
<diagnostics>
<detailedErrors enabled="true" />
</diagnostics>
<policy>
<cache name="policyCache.xml" />
</policy>
<security>
<timeToleranceInSeconds>43200</timeToleranceInSeconds>
<defaultTtlInSeconds>43200</defaultTtlInSeconds>
<x509 storeLocation="LocalMachine" verifyTrust="false" />
<securityTokenManager type="OurProduct.Business.Authentication.CustomUsernameTokenManager, OurProduct.Business, Version=5.0.2.11517, Culture=neutral" qname="wsse:UsernameToken" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" />
</security>
<messaging>
<maxRequestLength>10240</maxRequestLength>
</messaging>
</microsoft.web.services2>
<startup>
<supportedRuntime version="v2.0.50727" />
</startup>
<system.serviceModel>
<diagnostics wmiProviderEnabled="true">
<messageLogging logMalformedMessages="true" logMessagesAtTransportLevel="true" />
</diagnostics>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service behaviorConfiguration="OurServiceBehavior" name="OurProduct.Service.OurService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IXXXOurService" bindingNamespace="http://localhost/XXXOurService" contract="OurProduct.ServiceContracts.XXXOurService.IXXXOurService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="OurServiceBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="OurProduct.Service.Validation.CustomUserNamePasswordValidator, OurProduct.Service" />
</serviceCredentials>
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IXXXOurService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:15:00" sendTimeout="00:15:00" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288000" maxBufferSize="524288000" transferMode="Buffered" maxReceivedMessageSize="524288000" messageEncoding="Mtom" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="524288000" maxStringContentLength="524288000" maxArrayLength="524288000" maxBytesPerRead="524288000" maxNameTableCharCount="524288000" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
<runtime>
<gcServer enabled="true" />
<gcConcurrent enabled="true" />
</runtime>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="10485761" /> <!-- 10 megabytes -->
</requestFiltering>
</security>
</system.webServer>
</configuration>

Your WCF service configuration file does not appear to have throttling values explicitly set. You may want to use performance monitor to track the WCF resources and/or adjust the default values to make sure you are not hitting the default throttle limit.
Service throttling (serviceThrottling) allows you to even out the load on your backend WCF servers and to enforce resource allocation. serviceThrottling behavior for backend WCF services is configured by modifying the values for the maxConcurrentCalls, maxConcurrentSessions, and maxConcurrentInstances parameters in the config file for the WCF service.
<serviceThrottling
maxConcurrentCalls="200"
maxConcurrentSessions="200"
maxConcurrentInstances="200" />
https://msdn.microsoft.com/en-us/library/ee377061%28v=bts.70%29.aspx

Using WCF diagnostics is great, but as far as I know you won't be able to get similar diagnostics from the Web Service so you won't have anything to compare against. However the diagnostics you are preparing in your answer will give you an indication of relative time spent in each phase of the service call.
I'll propose an alterative which should be very simple because you're using http / text in both cases. Just catch both of the responses using Fiddler or your favorite proxy tool and compare. And critically - make sure that you look at the http header, not just the body. Fiddler will tell you the round trip time and the size of the response, which should be enough.
What could this be? The obvious things:
I've experienced huge performance overhead (yes, around 3x) when using Windows Authentication with WCF. I've seen the message size blow out when using Windows Authentication due to a large encrypted blob in the header (from memory). This costs a lot of time in transmission alone.
Also on security, is the WCF request being encrypted? If you use message security then it will be packed on the server side and unpacked on the client side. This is also not free.
Multiple service instances. You should have your service set for multiple instances, which means that each operation will create its own service instance. This is the default behavior. Configured as an attribute on the service class itself, like [System.ServiceModel.ServiceBehavior(ConcurrencyMode = System.ServiceModel.ConcurrencyMode.Multiple)]
You are correct in that there are many performance counters for WCF. They are grouped by service, endpoint and operation. You probably want the service counters, as they have more information. Check the ServiceModelService 4.0 category, and look at
Calls (obviously)
Calls Per Second
Instances
Instances Created Per Second

I would suggest to debug this in the following way:
temporarily remove all authentication and security logic from both services and see if the problem remains
temporarily disable any business logic and possibly simplify the schema to a single variable
when you say performance is slower, do you mean a single user performance or a load test? when you check a single user do you make sure the server is warm?
if you time the execution duration of your logic (e.g. from start to end of the your server method implementation) - is it the same?
remember to cancel any logging / tracing while benchmarking
you can try to revert wcf to use XmlSerializer instead of DataContract

Sorry for answering in answer,I dont have enough reputation for comments.
Which specific informations (traces) you would like to see? If you have difficulties setting up tracing, I would recommend you using tool named SvcConfigEditor.exe. In it, you can open App.Config file of your WCF service and under "Diagnostics", you can enable tracing. After that, you can select whether you want to trace particular information - so called "Trace level" (more infromation about specific levels - Configuring tracing ). See screenshot of the tool:
After you trace required information, you can open the log in Microsoft Trace Viewer - in it, you can view time duration of each acitvity: For example consider this one (sorry - some labels are in Czech language):
Sorry, picture was unreadable, here is link to bigger one : Trace viewer
On the left, you can select particular activity - if you stretch the panel, you can even see start and end time. Also, you see the total duration of that activity. After you select it, in the top-left panel you can see all the calls, that belong to that activity and you can also see, which call took the most time to resolve (In "Time" column).

Related

WCF client NTLM authentication returns 500

I have a problem with WinForms application connecting to WCF service using NTLM authentication.
<LongStory-optional>
Original application was written by me in 2005 as my first C# code. With small modifications it worked well. Web service was asmx with DataSets. Recently a time has come to upgrade it because of: performance issues and Windows 10 upgrade on client (Crystal Reports 10.5.37 upgrade was required to x64 and there is no official runtime download on SAP site).
I've rewrote it using WCF, .NET 4.8, replacing Crystal with library to create Excel files. In developer environment new version works well except 500 code. Rest and .NET Core was not considered (too difficult to explain; not technical reasons).
When user launched new version first immediate problem was "Access denied". Then it was started as administrator. Error code: "The application has failed to start because its side-by-side configuration is incorrect". Then I've tried to get more info in Event Viewer without success: there was no information. sxstrace tool raised access denied. After few days I've got it: I made a comment in config file containing national non-English characters. After removing comment an error 500 during connection has occured.
<\LongStory-optional>
Application makes a call to Verify service which just returns constant value 1.
Error message: "The content type text/html of the response message does not match the content type of the binding (text/xml; charset=utf-8).
If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 75 bytes of the response were:
The page cannot be displayed because an internal server error has occurred." .
Https was not used.
Strange thing is that after opening .svc once in IE the error have disappeared until workstation reboot. This proves that client and server are working correctly. In the same time old application doesn't have such an issue. Because of that I've tried to use "Web reference" instead of "Service reference". It appears that "Web reference" works correctly. Next thing I've tried different settings on the client side. I've found that "Service reference" works after this change: client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
With fiddler tool I've found that messages exchange are almost the same except final result: before change I have statuses 401/401/500, after change 401/401/200, the other differences are time and NTLM base64 value, nothing else.
I think that it is not a solution but only a workaround. Do you know how to handle correctly NTLM authentication with WCF?
Essential bits of my code and configuration:
var client = new ServiceClient();
client.ClientCredentials.Windows.ClientCredential.UserName = Dialog1.textBox1.Text;
client.ClientCredentials.Windows.ClientCredential.Domain = Dialog1.textBox2.Text;
client.ClientCredentials.Windows.ClientCredential.Password = Dialog1.textBox3.Text;
try
{
i = client.Verify().Status;
} ...
Configuration:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicEndpoint" sendTimeout="infinite" >
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://wro67zt2/AlsbWebServices/WindService/WindService.svc" binding="basicHttpBinding" bindingConfiguration="basicEndpoint" contract="WindService.IService" name="basicEndpoint"/>
</client>
</system.serviceModel>
I regard that server side configuration is unnecessary. It works well with Web reference so I can assume that everything is ok here. I've tried "Windows" instead "Ntlm" but problem remains the same, it changes string NTLM to Negotiate in request/response messages and also number of messages from 3 to 2 (401/500 or 401/200).
Edit - server configuration:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2"/>
<globalization culture="en-GB" requestEncoding="utf-8" responseEncoding="utf-8"/>
<pages controlRenderingCompatibilityVersion="4.0" clientIDMode="AutoID"/>
<identity impersonate="false" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicBinding" >
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" realm="XXXXX"/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="WindService.Behavior" name="WindLibrary.Service">
<endpoint
address=""
binding="basicHttpBinding"
bindingConfiguration="basicBinding"
name="basicEndpoint"
bindingNamespace="http://XXXXX.com/services/prime/"
contract="WindLibrary.IService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WindService.Behavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add scheme="http" binding="basicHttpBinding" bindingConfiguration="HttpBinding" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="false"/>
</system.webServer>
</configuration>

Hosting WCF Service within WinForm Application doesn't work when running the application executable

Over the past few weeks I have developed a 64-bit WinForms application that needs to communicate with a 32-bit DLL (job specs require it).
After doing some reading around the internet and finding out that there is not going to be any fun way of doing this, I decided to go with hosting a WCF Service Application within my WinForms application for communicating to the 32-bit DLL... or so I thought I was doing.
During development (while running within Visual Studio) it has been working really well, but of course, now that I need to deploy, I am running into problems. I am having trouble getting a strong enough understanding of WCF Services to know if I am going about this in a terrible way or if I am just missing some minute detail.
I created the project as Admin. After development was finished I tried to run the WinForm executable (both debug and release), WindowsFormsApplication1.exe. The application started up, but after I tried to complete a task involving the use of the WCF service, an exception was thrown:
This has led me to believe that Visual Studio was doing the hosting of the service during development instead of the WinForm application, or my configs and/or directory structures are incorrect.
[UPDATED] WCF Service Web.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" maxRequestLength="2147483647"/>
</system.web>
<system.net>
<defaultProxy>
<proxy usesystemdefault="False"/>
</defaultProxy>
</system.net>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true" >
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="myUserTraceSource"
switchValue="Information, ActivityTracing">
<listeners>
<add name="xml"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="C:\logs\Traces.svclog" />
</sharedListeners>
</system.diagnostics>
<system.serviceModel>
<diagnostics wmiProviderEnabled="true">
<messageLogging
logEntireMessage="true"
logMalformedMessages="true"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true"
maxMessagesToLog="3000"
/>
</diagnostics>
<behaviors>
<serviceBehaviors>
<behavior name="metadadiscovery>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="ServiceReference1.Service1" behaviorConfiguration="metadadiscovery">
<endpoint address="" binding="basicHttpBinding" contract="ServiceReference1.IService1"></endpoint>
</service>
</services>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="false"/>
</system.webServer>
</configuration>
WinForm App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService2" />
<binding name="BasicHttpBinding_IService3" />
<binding name="BasicHttpBinding_IService1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:45053/Service2.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService2" contract="ServiceReference2.IService2"
name="BasicHttpBinding_IService2" />
<endpoint address="http://localhost:46351/Service3.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService3" contract="ServiceReference3.IService3"
name="BasicHttpBinding_IService3" />
<endpoint address="http://localhost:44848/Service1.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IService1"
name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
<appSettings>
<add key="ClientSettingsProvider.ServiceUri" value="" />
</appSettings>
<system.web>
<membership defaultProvider="ClientAuthenticationMembershipProvider">
<providers>
<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" />
</providers>
</membership>
<roleManager defaultProvider="ClientRoleProvider" enabled="true">
<providers>
<add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" />
</providers>
</roleManager>
</system.web>
</configuration>
Directory Where EXE resides:
The directory containing the WCF Service resides within the directory WcfService1 from the image above.
I have mostly been using the following method of instantiating the service:
ServiceReference1.Service1Client = new ServiceReference1.SErvice1Client();
Once I tried to switch to using a service host (below), but when I used that method, the service would timeout whenever it tried to communicate to the DLL.
Uri address = new Uri("http://localhost:44848/Service1.svc");
ServiceHost host = new ServiceHost(typeof(ServiceReference1.Service1Client), address);
host.Open();
And then I closed the host later. At this point, I am willing to try anything to get this working.
[EDIT] Below is the code of my WindowsFormsApplication1.exe.config file. All three contracts are giving the warning that they're "invalid according to its datatype 'clientContractType'". I think this could be the source of my problems, but I do not know why it is showing this warning:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService2" />
<binding name="BasicHttpBinding_IService3" />
<binding name="BasicHttpBinding_IService1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:45053/Service2.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService2" contract="ServiceReference2.IService2" name="BasicHttpBinding_IService2" />
<endpoint address="http://localhost:46351/Service3.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService3" contract="ServiceReference3.IService3" name="BasicHttpBinding_IService3" />
<endpoint address="http://localhost:44848/Service1.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
</configuration>
Thank you for any help and guidance you can provide.
There is no endpoint configured for your service.
<behaviors>
<serviceBehaviors>
<behavior name="metadadiscovery">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<service name="ServiceReference2.Yourimplementingservice" behaviorConfiguration="metadadiscovery">
<endpoint address="" binding="basicHttpBinding" contract="ServiceReference2.IService2">
</endpoint>
Above I have configured for Service2 ,similarly you have to configure for Service1 and Service3.
After sufficient struggling I decided to get rid of the WCF service that visual studio generates for you when you create it as a new project. I instead followed this tutorial verbatim:
Hosting Service In App
Doing this came with huge advantages:
No configuration file was necessary
Running it this way must've gotten rid of a large amount of overhead because the communication to the DLL (what I am using the service for) used to take several seconds to do large amounts of calls to the DLL, but now is able to handle 10k+ calls in the blink of an eye.
No service reference is necessary. I just needed the file for my main function, the file containing the service function implementations and the file containing the interface for the implementation.
So far, this has been the easiest and most robust way I have found for using a 32 bit DLL in a 64 bit application. Let me know if I can give any guidance for anyone else who may be struggling with this problem. I know this is not a fun thing to deal with if you've never done anything like it before.

WCF Add Service Reference - Collection type keeps trying to use System.Array

I am having a problem adding a custom WCF service reference to my WPF application. I have been working on this service and application for nearly 6 months now and have never run into this issue until today. Whenever I try and add the WCF service via "Add Service Reference," all of my methods that return List are trying to return T[] instead. When I configure the service reference and change the collection type to "System.Collection.Generics.List", It shows in the status bar that it is updating the reference code, but the methods in the WPF application are throwing errors stating that it can't implicitly convert from List to Array. It seemed to have happened after I pushed an update to the server, but the only thing that was changed was the way one of my objects is initialized. I have tried the following so far;
Cleaned the project
Cleaned the solution
Rebuild the solution
Manually deleted the obj/bin/Service Reference folders
Removed and re-published the wcf service
Restarted the server
Im at a complete loss and have no idea what to do at this point. Any help is greatly appreciated!
Update
I created a separate console project, and it hooks into the WCF service correctly once configured to return lists. Looks to be specifically an issue with the WPF project.
Update 2
I noticed the following errors showing up briefly when I try to build. They disappear after a while, but I don't know if this has anything to do with the issue. They are both in the App.config file.
The 'bindingConfiguration' attribute is invalid - The value 'BasicHttpBinding_ICustomService' is invalid according to its datatype 'serviceBindingConfigurationType' - The Enumeration constraint failed.
The 'contract' attribute is invalid - The value 'CustomServerSvc.ICustomServer' is invalid according to its datatype 'clientContractType' - The Enumeration constraint failed.
Update 3
Interestingly, this only seems to happen on the client side randomly after a build.
Adding in my web.config per request.
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="UnifyServer.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<connectionStrings>
<add name="DebugUnifyCS"
connectionString="connectionString"
providerName="System.Data.SqlClient" />
<add name="UnifyCS"
connectionString="connectionString"
providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<client />
<bindings>
<basicHttpBinding>
<binding name="myBasicBinding" maxBufferPoolSize="524288" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647" receiveTimeout="00:30:00" sendTimeout="00:30:00">
<readerQuotas maxDepth="128" maxStringContentLength="2147483647"
maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
</bindings>
<!--<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IUnifyServer" >
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>-->
<services>
<service name="UnifyServer.UnifyServer">
<endpoint address="UnifyServer" binding="basicHttpBinding" bindingConfiguration="myBasicBinding" contract="UnifyServer.IUnifyServer"></endpoint>
<host>
<baseAddresses>
<add baseAddress="http://unifysrv2012:19081/"/>
</baseAddresses>
</host>
</service>
<service name="UnifyServer.ServiceEndpoint">
<endpoint address="ServiceEndpoint" binding="basicHttpBinding" bindingConfiguration="myBasicBinding" contract="UnifyServer.IServiceEndpoint"></endpoint>
<host>
<baseAddresses>
<add baseAddress="http://unifysrv2012:19081/"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
<applicationSettings>
<UnifyServer.Properties.Settings>
<setting name="UnifyServer_some_service" serializeAs="String">
<value>https://some.url.com/some_service.asmx</value>
</setting>
</UnifyServer.Properties.Settings>
</applicationSettings>
</configuration>
This happens often so when you are adding the reference to the WCF service check this:
In the "Add service reference" screen press the "Advanced..." button (at the bottom).
In the middle part of the "Service reference settings" screen that you just opened you'll see 2 combos where you specify the collection type, select the right ones and click ok.
I doubt any service reference is updated since you are getting error while updating service reference.
Try start by these steps, each step is independent to other & might be cause of issue:
Make sure [ServiceContract] is declared for the interface of your services, because this produces the exact error.
If you have re-factored code or changed any file/namespace. make sure its applied everywhere.
Use fully qualified service name in web.config with Namespace;
Make sure System.ServiceModel & System.Runtime.Serialization reference is not missing.
Delete .SUO (solution Users Option file) file after closing VS. This will reset the cache for XMLEditor component in VS.
Update
For error The 'bindingConfiguration' attribute is invalid - The value 'BasicHttpBinding_ICustomService' is invalid according to its datatype 'serviceBindingConfigurationType' - The Enumeration constraint failed.
Make sure all service interface/contract have [ServiceContract] attribute, methods have [Operation Contract].
Also make sure all DataContract Attributes have [DataMember] Or enum have [EnumMember] attribute.
Update 2
One case I have faced was some attribute wasn't able to serialize. e.g. I was returning DataSet that can't be serialized to binary by default by wcf, that cause the error.
In worst case, you have to separate Data contracts & reuse them & have to generate proxy manually using SVCUtil. I know it sounds crazy. But sometimes when all things doesn't work it seems to be working.
Let me know it works or not.

How do I configure my WCF (svc) Service on IIS to serve on HTTPS requests only?

I have a WCF (svs) web service, that is running on a Windows 2008 IIS web server.
The IIS server already has a SSL certificate installed and is hosting Classic ASP, and PHP over both HTTP and HTTPS.
I have installed the WCF service as a application on the IIS server (on the same domain) and it can serve requests using both HTTP and HTTPS perfectly.
However, I want this WCF service to ONLY serve HTTPS requests and responses.
What do I need to change within the WCF web.config to achieve this ?
UPDATE
Following on from my post above, I've managed to research the following which appears to work using the web.config file;
<system.serviceModel>
<services>
<service behaviorConfiguration="returnFaults" name="MyService.MonitorService">
<endpoint binding="wsHttpBinding" bindingConfiguration=
"TransportSecurity" contract="MyService.IMonitorSvc" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="returnFaults">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Can anyone confirm that this is the correct approach for a WCF service, to enforce that all requests are made via HTTPS (SSL) ?
Basically using the above, would a user be able to make a HTTP request to the service or not ? Or would the service always enforce HTTPS
Thanks for the clarification.
Use the Microsoft URL Rewrite module and then add the following into your web.config file:
<system.webServer>
<rewrite>
<rules>
<clear />
<rule name="Redirect to https" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
If this isn't acceptable (as you will have to remember to add this module in other deployments), then this answer points out how to write your own https redirector.
I'm not completely sure about it, but you might be able to use System.Web.HttpContext.Current.Request.IsSecureConnection to check within your actual code as well.

maxReceivedMessageSize on Azure WCF service is too small

Whenever I connect my client to send data to my WCF Azure service, I get this error:
"The maximum message size quota for incoming messages (65536) has been exceeded. To
increase the quota, use the MaxReceivedMessageSize property on the appropriate binding
element."
I've read everywhere about setting this MaxReceivedMessageSize property on both the client and server config files. I have done this.
However, whenever I update the service reference in the client, it pulls the settings back to the default of 65536. (found via investigating the .svcinfo file)
This leads me to conclude the issue must be on the service side.
I've placed this in my web.config file:
<bindings>
<basicHttpBinding>
<!--The basicHttpBinding is used for clients which use the generated code to transmit data; the following settings make it possible to send larger amounts to the service-->
<binding maxReceivedMessageSize="10000000" receiveTimeout="01:00:00">
<readerQuotas maxStringContentLength="10000000" />
</binding>
</basicHttpBinding>
</bindings>
Now, many posts talk about naming the binding and setting it in the service endpoints on the server side as well. Something like this:
<services>
<service name="YourNamespace.YourServiceClass">
<endpoint name="endpoint1"
address="http://server:8888/YourService.svc"
binding="basicHttpBinding"
bindingConfiguration="lageMessageTransfer"
contract="IYourServiceContract" />
</service>
</services>
However, I don't have these service endpoints and my service works great for small sizes.
Where else would this need to be set?
EDIT:
More information, Tim seems to be on the right track with the default endpoints. I am using a default endpoint. It seems that you cannot just explicitly define a service for that default endpoint. or if you can, I must be doing it incorrectly.
However, it seems that you can modify the binding on a default endpoint as stated by Richard. This is done by simply not specifying a name for the binding. I have tried setting the values on my service to much lower values to see if something else was lowering them, but they are completely ignored. Its as if the default endpoint is simply ignoring the binding that I have created.
For my entire config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData="logging.e2e" />
</listeners>
</source>
</sources>
</system.diagnostics>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding maxReceivedMessageSize="100" maxBufferSize="100" receiveTimeout="00:11:00">
<readerQuotas maxStringContentLength="100" />
</binding>
</basicHttpBinding>
</bindings>
<protocolMapping>
<add scheme="http" binding="basicHttpBinding" />
</protocolMapping>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="false" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
<connectionStrings><EDITEDOUT></connectionStrings>
</configuration>
Thoughts on why the new binding settings are not being picked up?
The attribute name maxReceivedMessageSize is very explicit - it all depends on who is receiving the message - if you are sending a large amount of data then it is the service, if you are getting a large amount of data back from the service then it is the client. The service and client do not need the same value for this setting (unlike many other binding settings)
Setting an unnamed binding section should work in general as, of .NET 4, it configures the binding for anyone who doesn't explicitly specify a configuration using bindingConfiguration. However, in your example above you need to set the maxBufferSize in addition to the maxReceivedMessageSize as you are buffering rather than streaming the message. The maxBufferSize and maxReceivedMessageSize must be the same
You don't have the section in the Web.config on your service side? If you're using WCF 4.0 is it possible you're using a default endpoint?
I don't know if you can specify a binding for a default endpoint, but you might want to try specifying an endpoint via the section of the Web.config and setting bindingConfiguration to the binding specified in your section.

Categories

Resources