WCF Concurrency? - c#

I have a WCF service deployed to IIS 7 and the client. I thought the service is configured to handle concurrency. When I tested with two client, it took double the amount of time. I have spent hours and not yet able to figure out where I missed it. Any help/suggestions would be appreciated. Service1.svc.cs looks like this:
[ServiceBehavior( ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
[CallbackBehavior(UseSynchronizationContext=false)]
public class Service1 : IService1
{
public byte[] DownloadFile()
{
byte[] byt = File.ReadAllBytes(#"C:\Temp\TestFile.pdf");
System.Threading.Thread.Sleep(1000);
return byt;
}
}
Configuration:
<system.net>
<connectionManagement>
<add address="*" maxconnection="100"/>
</connectionManagement>
</system.net>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<processModel autoConfig="false" maxWorkerThreads="1400" maxIoThreads="1400" minWorkerThreads="2"/>
<httpRuntime minFreeThreads="1000" minLocalRequestFreeThreads="1000"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="Service1Binding" maxBufferSize="2147483647" maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647" transferMode="Streamed">
<readerQuotas maxDepth="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="DocService.Service1">
<endpoint address="http://localhost/DocService/Service1.svc" binding="basicHttpBinding"
bindingConfiguration="" name="Service1Binding" bindingName="Service1Binding"
contract="DocService.IService1" />
<endpoint address="http://localhost/DocService/mex" binding="mexHttpBinding"
name="mexpoint" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceThrottling maxConcurrentCalls="100" maxConcurrentInstances="100" maxConcurrentSessions="100"/>
</behavior>
</serviceBehaviors>
</behaviors>

The requests are taking much longer than 1s sleep time and the read time of, say, 10mb file. They should complete in maybe 1.1-2s There is something fishy here.
Comment out the read and return a new byte[0]. Does it take 1.0s now? Do you have concurrency now?
Edit: What client are you using?
Edit 2: Responding to your comment, the file transfer is not limiting concurrency in some way. WCF does not care what you do inside your service method. It knows nothing about files. The problem is that your disk is too slow and that serializing 36mb is probably slow too! You server is just too slow! You can find out, if the disk or the serializing is the problem by replacing the IO with new byte[1024*1024*36].

Related

Set WCF Service endpoints at server side web config for https

I am stuck in very odd situation and do not know how to solve this issue.
I have very simple WCF service working very fine with http BUT now I want to move it to https.
The issue is Server where it needs to be hosted. Server IIS have an alias name "server-test.local" (not "localhost") with http. Its is accessible locally with this alias name. And its mapped to a Domain name with https (example, https://rmt.XXXXXXX.com).
When I deploy my WCF to that server and check WSDL file, it has mapping of the local alias name instead of public domain name.
it is showing http://server-test.local/WCFService/Service.svc (WRONG)
I want mapping like https://rmt.XXXXXXXX.com/WCFService/Service.svc (CORRECT)
Service web.config
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<pages controlRenderingCompatibilityVersion="4.0"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="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>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer> <modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
When I add service reference to app. It adds following endpoint which is not conrrect.
Client App.config (endpoint)
<endpoint address="http://server-test.local/WCFService/Service.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IProcessing"
contract="WCFService.IService" name="BasicHttpBinding_IProcessing" />
I am able to access the url and WSDL file through browser but not able to consume any Service methods. I am getting error "There is no endpoint which can accept the message."
I think I am missing something obvious here. Please suggest me changes.
You can try to change some simple steps in the web.config file, you can refer to this post for details.
1.Enable transport level security in the web.config file of the service:
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
2.Use the bindingConfiguration tag to specify the binding name and the behaviorConfiguration tag to configure the behavior, and then specify the address of the managed service. The code is as follows:
<service name="***" behaviorConfiguration="***">
<endpoint address= https://rmt.XXXXXXXX.com/WCFService/Service.svc
binding="basicHttpBinding"
bindingConfiguration="???"
contract="WCFService.IService"/>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>

Error 400 on WCF Rest Service Get Request

I recently developed a WCF rest service where its sole purpose is to handle Get requests and return data.
I have (mostly) successfully done this however I run into an issue when I want to send more than about 200-300 characters in the request. Whenever I try this I end up getting an error 400 on the webpage. Initially I thought I was running into some sort of character limitation but after reading many webpages and other questions I'm stumped as to what is truly failing.
I have tried to change bindings like maxReceivedMessageSize, maxStringContentLength, maxBufferSize, and maxBufferPoolSize hoping one of those was the culprit but alas I was wrong. I also tried to add tracing to see if I could read any errors in the log but when I make a long request nothing gets added to the log. I'm unable to use a different browser than edge currently so I made an app that uses HttpClient to communicate with my server and I am still getting an error 400 when I make a "long" request.
An example of a request that works perfectly fine is http://IP:PORT/POINTINFO/DBNAME/{"User":"testuser","Pc":"testpc","Data":["Point01","Point02"]}
An example of a request that will get an error 400 is http://IP:PORT/POINTINFO/DBNAME/{"User":"testuser","Pc":"testpc","Data":["U1R0011AS","U1R0012AS","U1R0012BS","U1R0041AS","U1R0041BS","U1R0041CS","U1R0044AS","U1R0044BS","U1R0046AS","U1R0046BS","U1R0046CS","U1R0046DS","U1R11A-AV","U1R12A-AV","U1R12B-AV","U1R41A-AV","U1R41B-AV","U1R41C-AV","U1R44A-AV","U1R44B-AV","U1R46A-AV","U1R46B-AV","U1R46C-AV","U1R46D-AV","U1R46E-AV","U1RCSCOLDEST","U1RCSPRESS","U1RXPCNTBE"]}
As you can see, the request is long (at least to type) but it shouldn't be hitting any limitations. This is also perfectly valid JSON so that can't be why it's dying. I've also tried to put a breakpoint on my GetPointList function to see if there's something wrong with my code, but that never even gets called. This is my only exposure to WCF rest services so I'm sure there's a beginners mistake I'm making but I can't see what I'm doing wrong. Any help will be appreciated.
Here is my main:
static void Main(string[] args)
{
WebServiceHost hostWeb = new WebServiceHost(typeof(ConsoleApp1.Service));
ServiceEndpoint ep = hostWeb.AddServiceEndpoint(typeof(ConsoleApp1.IService), new WebHttpBinding(), "");
ServiceDebugBehavior stp = hostWeb.Description.Behaviors.Find<ServiceDebugBehavior>();
stp.HttpHelpPageEnabled = false;
hostWeb.Open();
Console.WriteLine("Service Host started # " + DateTime.Now.ToString());
Console.Read();
}
This is the interface I have:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "POINTINFO/{database}/{pointlist}")]
[return: MessageParameter(Name = "Data")]
List<PointData> GetPointList(string pointlist, string database);
}
Here is my config that is scarred with prior attempts at fixing my issue:
<!--tracing for error detection-->
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging" switchValue="Information, ActivityTracing">
<listeners>
<add name="log"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="C:\Users\Administrator\Documents\messages.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
<bindings>
<!--<wsHttpBinding>-->
<basicHttpBinding>
<binding name="basicHttp" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="01:00:00" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647">
<security mode="None">
<!--<transport clientCredentialType="None" />-->
</security>
<readerQuotas maxStringContentLength="2147483647"/>
<!--<reliableSession enabled="true" />-->
</binding>
</basicHttpBinding>
<!--</wsHttpBinding>-->
<webHttpBinding>
<binding name="webHttp" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="01:00:00" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647">
<security mode="None">
<!--<transport clientCredentialType="None" />-->
</security>
<readerQuotas maxStringContentLength="2147483647"/>
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="ConsoleApp1.Service">
<endpoint address="rest" binding="webHttpBinding" bindingConfiguration="webHttp" contract="ConsoleApp1.IService" behaviorConfiguration="web"></endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:12345" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="mexBehaviour">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<!-- rest api-->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<diagnostics>
<messageLogging
logEntireMessage="true"
logMalformedMessages="true"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true"
maxMessagesToLog="300"
maxSizeOfMessageToLog="20000"/>
</diagnostics>
</system.serviceModel>
I figured it out, thanks to this website: https://www.codeproject.com/Questions/847265/WCF-How-to-overcome-urllength-restriction
It turns out that the default character limit of each parameter in a REST url is 260. So you have to go in the registry and change the value of
UrlSegmentMaxLength in HEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters to a REG_DWORD of whatever value you need.

Self Hosted WCF Service throws Error Message "405 Method not allowed"

I have a Self Hosted WCF Service, which looks like this:
[ServiceContract]
public interface IService {
[OperationContract]
[WebGet]
List<Data> GetData();
//...and much more Methods
}
My App.config looks like this:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<behaviors>
<serviceBehaviors>
<behavior name="MetaInformation">
<serviceMetadata httpGetEnabled="true"
httpGetUrl="http://localhost:8500/MetaInfo"
httpsGetBinding="" />
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="EndpointBehavior">
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MetaInformation" name="Library.WcfService.ServiceModel">
<endpoint address="http://localhost:8500/Service"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBindingSettings"
contract="Library.WcfService.IService"
bindingName="BasicHttpBindingSettings"
behaviorConfiguration="EndpointBehavior"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBindingSettings"
closeTimeout="00:50:00"
openTimeout="00:50:00"
sendTimeout="00:50:00"
maxBufferSize="524288"
transferMode="Streamed"
maxReceivedMessageSize="2147483647"
maxBufferPoolSize="2147483647"
messageEncoding="Text">
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
<system.web>
<httpRuntime maxRequestLength="102400"/>
</system.web>
When I run this Server and the Client Applications on my local machine, it's working fine.
But when i try to run the Server Application on another PC, I cannot add a Service Reference at the Client because I get this:
405 Method not allowed Metadata contains a reference that can not be resolved : "http://192.168.178.54:8500/MetaInfo". It was not a
listening to http://192.168.178.54:8500/MetaInfo endpoint present who
could accept the message. This is often caused by an incorrect
address or SOAP action
I tried almost everything I found at the internet but nothing worked.
Switching to IIS or using an other Protocol should be a plan B, i want to keep it self hosted with http.
Please can somebody help me I'm desperate with this Problem.
your operation contract is decorated with [WebGet] attribute, which means you're trying to expose your service as a REST. But your service is using basicHttpBinding as means of building the communication channel which isn't supported because the content type for this binding is soap+xml. You'll need to use WebHttpBinding in this case which is the only binding that supports restful implementation of WCF Services and supports both Xml and Json data types.

WCF service reaching high memory usage on first call

We have a WCF service as a BL service.
The service is in Mixed Transport mode, have more than 10 different endpoint, binded by BasicHttpBinding, with different contracts and the same address for all of them.
The service runs on its on application pool on IIS-7.
The problem is, the service works fine, but after the first call, even the get the WSDL, the memory usage of the w3wp.exe goes straight to 300 mega, the service memory usage keeps to increase constantly, taking over all the physical memory of the server (98 - 100 %). We didn't get out of memory exception, but this situation slows down other applications and the service so we need to manually refresh the application pool once every couples of days.
I already tried to use memory profiling tool and didn't find any leads to the cause of the problem.
Did anyone encounter this issues? and if yes, what did you do?
Additional information:
The BL service is located above a DAL framework based on NHibernate,
we've already ruled out the memory leak is originating from there.
Config file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime maxRequestLength="20000" requestLengthDiskThreshold="20000" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="DefaultServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="AnonymousBehavior">
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="SecureBinding"
closeTimeout="00:10:00"
openTimeout="00:10:00" receiveTimeout="00:10:00"
sendTimeout="00:10:00" allowCookies="true"
hostNameComparisonMode="StrongWildcard" maxBufferSize="65536000"
maxBufferPoolSize="524288000" maxReceivedMessageSize="65536000"
transferMode="Buffered">
<readerQuotas maxDepth="20000000"
maxStringContentLength="8192000"
maxArrayLength="16384000"
maxBytesPerRead="4096000"
maxNameTableCharCount="16384000" />
<security mode="None">
<transport clientCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="BL.Services.MyService"
behaviorConfiguration="DefaultServiceBehavior">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="SecureBinding"
bindingNamespace="Security/Anonymous"
behaviorConfiguration="WithSecurityContextInspector"
contract="BL.Services.Contracts.IAnonymousClaimsService" />
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="SecureBinding"
bindingNamespace="Domain/App"
behaviorConfiguration="WithSecurityContextInspector"
contract="BL.Services.Contracts.IAppService" />
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="SecureBinding"
bindingNamespace="Domain/App"
behaviorConfiguration="WithSecurityContextInspector"
contract="BL.Services.Contracts.IAttachmentService" />
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="SecureBinding"
bindingNamespace="Domain/Site"
behaviorConfiguration="WithSecurityContextInspector"
contract="BL.Services.Contracts.ISecurityService" />
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="SecureBinding"
bindingNamespace="Domain/Transaction"
behaviorConfiguration="WithSecurityContextInspector"
contract="BL.Services.Contracts.ITransactionService" />
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="SecureBinding"
bindingNamespace="Domain/ActiveDirectory"
behaviorConfiguration="WithSecurityContextInspector"
contract="BL.Services.Contracts.IActiveDirectoryService" />
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="SecureBinding"
bindingNamespace="Domain/Report"
behaviorConfiguration="WithSecurityContextInspector"
contract="BL.Services.Contracts.IReportService" />
<host>
<baseAddresses>
<add baseAddress="//MyService.svc" />
</baseAddresses>
</host>
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<defaultDocument>
<files>
<add value="MyService.svc" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
The 300MB is not unusual as AnkMannen notes. Heavily used service can easily plateau out around 700MB or more. Your second observation of the service consuming most available server memory but not triggering an out of memory exception is likely due to the non-default config values:
binding:
maxBufferSize="65536000"
maxBufferPoolSize="524288000"
maxReceivedMessageSize="65536000"
transferMode="Buffered"
readerQuotas:
maxDepth="20000000"
maxStringContentLength="8192000"
maxArrayLength="16384000"
maxBytesPerRead="4096000"
maxNameTableCharCount="16384000"
You are actually configuring WCF to consume excessive memory with the values you have chosen. Unless you have encountered a specific condition that required changing the default value for any of those attributes, don't change them. The only value I routinely change is maxReceivedMessageSize from a default of 64K to around 1 to 2 MB, if unavoidable. If you're routinely slinging around messages that are bigger than 3 MB, you should reconsider your data contract design. A lot of the performance issues WCF is accused of are actually misconfigurations not performance problems in WCF itself.
After a long search we found the problem.
Our service used a lot of logic units in a unit of work pattern.
Each logic unit inherited from a BaseLogic class. In the the BaseLogic unit there is an Enterprise Library UnityContainer property which created a factory. Each call created many instances of this factory, changing this property to a static property fixed the problem.
The first initial jump to 300MB is consistent with what I've seen in our applications. Haven't really found a way to decrease that number but it stays at that figure over time.
For the increasing part of memory it sounds like a standard memory leak or at least a GC issue. Are you using entity framework and did you profile with a tool like Red Gates Memory Profiler, not the built in VS profiler?
It's hard to give any more specific answer based on the information in the question.
In the mean time, try to use the IIS auto refresh of the application pool. Set it to a threshold of your choice and let it automatically handle the refresh.

WCF - Error Trying to Receiving Large List of Data (~5000 objects)

I am attempting to transfer around 7000-8000 objects that are not large (only 9 properties per object instance). Does anyone know why when I begin to retrieve more than 5000 or so objects that I get connection errors? It works perfectly until I hit some threshold for data size.
I am exposing the retrieval of these objects via WCF's TCP service binding. I have the following sample configuration:
<bindings>
<netTcpBinding>
<binding name="NetTcpBindingConfig"
openTimeout="00:01:00"
sendTimeout="00:05:00"
closeTimeout="00:01:00"
maxBufferPoolSize="2147483647"
maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
<security>
<transport/>
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior"
name="TestService">
<endpoint address=""
binding="netTcpBinding"
bindingConfiguration="NetTcpBindingConfig"
contract="ServiceInterfaces.ITestService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex"
binding="mexTcpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8526/TestService" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Services.ServiceBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
From my .NET code I am calling the service using a ChannelFactory with the following sample code:
using (ChannelFactory<ITestervice> channel = new ChannelFactory<ITestService>(BindingConfig, "net.tcp://localhost:8526/TestService"))
{
ITestService testService = channel.CreateChannel();
toReturn = testService.LoadAll();
channel.Close();
}
BindingConfig object is a NetTcpBinding property in my code that is populated as 'new NetTcpBinding("NetTcpBindingConfig")'. My client binding is the exact same as my WCF TCP service binding.
Can anyone offer any insight as to how I can retrieve all of the data (it seems my maximum limit is ~5000 objects with my current setup)? Any help is much appreciated. Thanks.
EDIT:
In case anyone runs into this, see the accepted solution about the MaxItemsInObjectGraph. If, however, you are using ChannelFactory from the Client to consume your services, see the following code to make it work:
foreach (OperationDescription operation in channel.Endpoint.Contract.Operations)
{
DataContractSerializerOperationBehavior dataContractBehavior = operation.Behaviors[typeof(DataContractSerializerOperationBehavior)] as DataContractSerializerOperationBehavior;
if (dataContractBehavior != null)
dataContractBehavior.MaxItemsInObjectGraph = int.MaxValue;
}
Consider increasing MaxItemsInObjectGraph quota as well (its default value is 64k). It should be on both the server and the client side. See the sample configuration:

Categories