We have a WCF service hosted in a windows service which hangs after long periods of inactivity: ie after the weekend.
This behavior happens at different locations.
The service uses WSHttpBinding which is set to use transport security a Custom serviceAuthorization authorizationPolicy which uses windows authentication.
The Spring framework is used. Spring.ServiceModel.Activation.ServiceHostFactory creates the Service hosts.
Service throttle is set to 200 sessions, instances and calls. There are at most 15 users of the system.
Tracing is enabled and set to Warning which should let me know about throttle issues.
There are no messages in the service trace log.
There are no messages in the Event log which look relevant.
There are no relevant logs in HTTPPerf logs.
We log considerably in the server side application but there is no activity being recorded when the system hangs.
It is a total black box when the system hangs.
The client fails with the following message.
08:13:32.014 [1] ERROR App - System.TimeoutException: Client is unable to finish the security negotiation within the configured timeout (00:00:59.9941374). The current negotiation leg is 1 (00:00:59.9863206). ---> System.TimeoutException: The request channel timed out while waiting for a reply after 00:00:59.9628702. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout. ---> System.TimeoutException: The HTTP request to 'http://localhost:8080/OrderManagementService.svc' has exceeded the allotted timeout of 00:00:59.9690000. The time allotted to this operation may have been a portion of a longer timeout. ---> System.Net.WebException: The operation has timed out
at System.Net.HttpWebRequest.GetResponse()
I have spent many hours searching for relevant information on this.
I do not think this is related to inactivity timeout as this should be recorded in the trace log.
Only thing that I can think of is related to Active Directory credential caching or something of that nature or that it is related to the use of the Spring framework.
Any help would be greatly, greatly appreciated.
Am thinking of moving away from WSHttpBinding or WCF altogether as this is an unacceptable situation.
Service side configuration is as follows.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646">
<readerQuotas maxDepth="2147483646" maxStringContentLength="2147483646" maxArrayLength="2147483646" maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
<security>
<transport></transport>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="Kodi.Kodiak.Security.AuthorizationPolicy, Kodi.Kodiak.Security" />
</authorizationPolicies>
</serviceAuthorization>
<serviceCredentials>
<windowsAuthentication includeWindowsGroups="true" allowAnonymousLogons="false" />
</serviceCredentials>
<serviceThrottling maxConcurrentCalls="200" maxConcurrentSessions="200" maxConcurrentInstances="200" />
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="rest">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ServiceBehavior" name="OrderManagementService">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding" contract="Kodi.Kodiak.Services.ServiceContracts.IOrderManagementService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
SPRING CONFIG
<object id="OrderManagementService"
singleton="false"
type="Kodi.Kodiak.Services.OrderManagementService, Kodi.Kodiak.Services"
scope="session">
</object>
How the clients are calling the service? If they are calling the service through the SvcUtil generated proxy; are they closing the proxy connection properly? I think the clients are not closing the connections or simply the connections are not getting closed properly.
One important thing is, you should avoid using using statement while creating proxies.
A better approach would be something like this,
ServiceClient client = null;
try
{
client = new ServiceClient();
client.CallMethod();
}
finally
{
client.CloseConnection(); // extension method
}
public static void CloseConnection(this ICommunicationObject client)
{
if (client.State != CommunicationState.Opened)
{
return;
}
try
{
client.Close();
}
catch (CommunicationException)
{
client.Abort();
throw;
}
catch (TimeoutException)
{
client.Abort();
throw;
}
catch (Exception)
{
client.Abort();
throw;
}
}
I think this can be done by maintaining the client and server Binding End Points and Behavior same, the timeout values specified in the Client and Server Configs Should be Same.
Related
I'm having a unclear CPU issue with WCF services using NetTcp binding (hosted on IIS 8 on Windows Server 2012 Datacenter)
I'm holding WCF clients (proxies) pool in one service and use it to connect the other..
Our problem is that when the client service that holds the pool is not properly disposed (which is possible scenario for us) then the server is spinning up to 100% CPU and stay there for while ( the duration is strongly depends on the number of the clients in the pool which haven’t been closed)
We are using InstanceContextMode.Single with multiple concurrency mode on the server and no reliable sessions..
server configuration:
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IRecommenderService" closeTimeout="00:00:01.5000000" openTimeout="00:00:01.5000000" receiveTimeout="00:00:01.5000000" sendTimeout="00:00:01.5000000" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxConnections="2147483647" maxReceivedMessageSize="2147483647" listenBacklog="2147483647" transactionFlow="false">
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647"/>
<reliableSession enabled="false"/>
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceThrottling maxConcurrentCalls="4000" maxConcurrentInstances="1000" maxConcurrentSessions="1000" />
</behavior>
<behavior name="Unthrottled">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceThrottling maxConcurrentCalls="6000" maxConcurrentSessions="6000" maxConcurrentInstances="6000" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="UnthrottledServiceEndpoint">
<dispatcherSynchronization maxPendingReceives="10000" asynchronousSendEnabled="true" />
</behavior>
</endpointBehaviors>
</behaviors>
Client configuration:
<client>
<endpoint address="net.tcp://this-will-be-given-at-runtime:12345/an-invalid-service-too/"
behaviorConfiguration="UnthrottledClientEndpoint" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IRecommenderService" contract="RecommenderClient.IRecommenderService"
name="IRecommenderServiceClient_nettcp" />
</client>
...
<behavior name="UnthrottledClientEndpoint">
<dispatcherSynchronization asynchronousSendEnabled="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
...
Any answer will be appreciated
Thanks,
Sagi.
//when the client service that holds the pool is not properly disposed (which is possible scenario for us) //
Are you saying you wrote your own "pool" for WCF connections?
I wouldn't do that. I would use the proxy and dispose of it after each use....to avoid the exact thing you're describing.
If you cannot "trust" your dotnet consumers to close/dispose of things, then I would suggest (as I do) to write a ClientWrapper assembly, and they must go through it...and YOU make sure you close the proxies.
I liken it to an IDataReader. If I returned IDataReaders to the client, I cannot guarantee the consumer disposes of them. Aka, it is outside of my control. No way. I consume the IDataReader, dispose of it, and give them back some (serialized?) object. The consumer would never get something back that they could forget to dispose of, and screw me me.
Below is my typical "client side" wrapper code.
private IMyService GetTheProxy()
{
string endPointName = "MyEndPointName";
ChannelFactory<IMyService> factory;
//Use default endpoint
Console.WriteLine("endPointName='{0}'", endPointName);
factory = new ChannelFactory<IMyService>(endPointName);
IMyService proxy1 = factory.CreateChannel();
return proxy1;
}
public string GetAString()
{
string returnValue = null;
IMyService proxy1 = this.GetTheProxy();
using (proxy1 as IDisposable)
{
returnValue = proxy1.GetAString();
return returnValue ;
}
}
public int GetAnInt()
{
int returnValue = null;
IMyService proxy1 = this.GetTheProxy();
using (proxy1 as IDisposable)
{
returnValue = proxy1.GetAnInt();
return returnValue ;
}
}
I setup a custom ClaimsAuthenticationManager for my wcf service. Now I found out that the method ClaimsAuthenticationManager.Authenticate is executed for each and every wcf call. Instead I want to have it executed once per session to avoid unneccessary overhead.
According to Microsoft:
The claims authentication manager is typically invoked once per session, with the following exceptions: For transport security, tokens present at the transport layer will invoke the claims authentication once per call, even if sessions are present.
Source: https://msdn.microsoft.com/en-us/library/ee748487.aspx
Since my custom binding does not use transport security I see no reason why ClaimsAuthenticationManager.Authenticate is executed per call.
Does anyone know if there are further requirements that need to be met to have this method called once per session instead? Thank you very much for any suggestions.
The wcf binding configuration:
<behaviors>
<serviceBehaviors>
<behavior name="defaultBehavior">
<serviceDebug includeExceptionDetailInFaults="True" />
<serviceThrottling maxConcurrentCalls="200" maxConcurrentSessions="200" maxConcurrentInstances="200" />
<serviceCredentials useIdentityConfiguration="true" />
<serviceAuthorization principalPermissionMode="Always" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netNamedPipeBinding>
<binding name="ServiceNamedPipeBinding" receiveTimeout="00:05:00" sendTimeout="00:05:00" maxReceivedMessageSize="134217728" maxBufferPoolSize="134217728" maxBufferSize="134217728" />
</netNamedPipeBinding>
<customBinding>
<binding name="TcpLoadBalanced" receiveTimeout="00:05:00" sendTimeout="00:05:00">
<security authenticationMode="SecureConversation" requireSecurityContextCancellation="true">
<secureConversationBootstrap authenticationMode="SspiNegotiated"/>
</security>
<binaryMessageEncoding>
<readerQuotas maxArrayLength="2147483647" />
</binaryMessageEncoding>
<tcpTransport listenBacklog="200" maxBufferPoolSize="134217728" maxReceivedMessageSize="134217728" maxBufferSize="134217728">
<connectionPoolSettings leaseTimeout="00:00:00" maxOutboundConnectionsPerEndpoint="0" />
</tcpTransport>
</binding>
</customBinding>
</bindings>
If you want to use per session call,then try like this-
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class MyService:IMyService
{
public int MyMethod()
{
int m_Counter = 0;
m_Counter++;
return m_Counter;
}
}
Default.aspx.cs
WCFService.Service1Client client = new WCFService.Service1Client();
string stream = client.JsonSerializeFromDatabase();
client.Close();
WCFService.Service1Client client2 = new WCFService.Service1Client();
foreach (WCFService.Person in client2.JsonDeserializeFromDatabase(stream))
Service1.svc.cs
public IList<Person> JsonDeserializeFromDatabase(string value)
{
MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(value));
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<Person>));
IList<Person> tableData = (IList<Person>)ser.ReadObject(ms);
ms.Close();
ms.Dispose();
return tableData;
}
IService1.cs
[OperationContract]
IList<Person> JsonDeserializeFromDatabase(string value);
Server Web.config
<httpRuntime maxRequestLength="8192"/>
</system.web>
...
<system.serviceModel>
<services>
<service name="TestWCF.Service1" behaviorConfiguration="TestWCF.Service1Behavior">
<endpoint address="" binding="wsHttpBinding" contract="TestWCF.IService1">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TestWCF.Service1Behavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</serviceBehaviors>
Client Web.config
<httpRuntime maxRequestLength="8192"/>
</system.web>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="debuggingBehaviour">
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1" closeTimeout="00:50:00" openTimeout="00:50:00" receiveTimeout="00:50:00" sendTimeout="00:50:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="64" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<reliableSession ordered="true" inactivityTimeout="00:50:00" enabled="false"/>
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="~~~~~/Service1.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1" contract="WCFService.IService1" name="WSHttpBinding_IService1" behaviorConfiguration="debuggingBehaviour">
Exception Information
- Type: System.ServiceModel.CommunicationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- Message: An error occurred while receiving the HTTP response to ~~~~~/Service1.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.
I got this exception information from Server trace viewer, so please do not advise me to put <-system.diagnostics-> tag.
As you can see, I increased all the size thing.
Like.. i don't know why I am getting an error when I call JsonDeserializeFromDatabase(stream).
"An error occurred while receiving the HTTP response to ~~~~~/Service1.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details."
I too have experienced this error message when returning records from a database in a WCF service. As well as increasing maxReceivedMessageSize in the binding in the client configuration (App.config), a separate problem seems to be that WCF has problems serializing Entity Framework objects if they have relationships that lead to circularity in their object graphs.
I solved this by returning buddy class objects (which are copies of the raw database records, but without any relationship links) rather than the raw database classes themselves.
Hope this helps -
And WHY doesn't Microsoft produce better error messages?? Here, as in many other cases, the error message gives no clue to the real problem (the serialization of the return value from the WCF call)!
re: WCF & problems serializing Entity Framework objects if they have relationships that lead to circularity in their object graphs. I was getting the same error and the answer provided by user1956642 and it did point me in the right direction, but later realized I could serialize these entities by configuring the DbContext
context.Configuration.ProxyCreationEnabled = false;
Lazy loading is still enabled, but I believe the dynamic proxies are used for change tracking and lazy loading. So yea ... just my 5c
I have a simple WCF service hosted in IIS7.5 exposed over a wsHttp binding using message security and InstanceContextMode.PerCall
I have a simple UI that spins up a configurable number of threads, each calling the service.
I have added the perfmon counter ServiceModel4.Instances. Regardless of the number of threads created and calling the service, perfmon shows that the service creates a maximum of 10 Instances.
My client config is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService3">
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/NGCInstancing/Service3.svc/~/Service3.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService3"
contract="NGCSecPerCall.IService3" name="WSHttpBinding_IService3">
<identity>
<servicePrincipalName value="host/RB-T510" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
My service config is as follows:
<?xml version="1.0"?>
<system.serviceModel>
<configuration>
<behaviors>
<serviceBehaviors>
<behavior name="SecPerCallBehaviour">
<serviceThrottling maxConcurrentCalls="30" maxConcurrentSessions="1000"
maxConcurrentInstances="30" />
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="BindingMessageSecPerCall" >
<security mode="Message">
<!-- it's by setting establishSecurityContext to false that we enable per call instancing with security -->
<message establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="ServiceInstancingDemo.Service3" behaviorConfiguration="SecPerCallBehaviour">
<endpoint address="~/Service3.svc"
binding="wsHttpBinding" bindingConfiguration="BindingMessageSecPerCall"
contract="ServiceInstancingDemo.IService3" />
</service>
</services>
</configuration>
</system.serviceModel>
The client code is as follows:
private void btnSecPerCall_Click(object sender, EventArgs e)
{
int i;
int requests;
int delay;
lblStatus.Text = "";
DateTime startTime = DateTime.Now;
this.listBox1.Items.Add("start time=" + DateTime.Now);
delay = Convert.ToInt16(txtDelay.Text);
requests = Convert.ToInt16(txtRequests.Text);
Task<string>[] result;
result = new Task<string>[requests];
for (i = 0; i < requests; i++)
{
result[i] = Task<string>.Factory.StartNew(() => _ngcSecPerCall.WaitThenReturnString(delay));
}
for (i = 0; i < requests; i++)
{
this.listBox1.Items.Add(result[i].Result);
}
DateTime endTime = DateTime.Now;
TimeSpan ts = endTime - startTime;
lblStatus.Text = "Finished! Time taken= " + ts.Seconds + " seconds";
this.listBox1.Items.Add("end time=" + DateTime.Now);
}
My service code is as follows:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service3 : IService3
{
private int m_counter;
public string WaitThenReturnString(int waitMilliSeconds)
{
System.Threading.Thread.Sleep(waitMilliSeconds);
int maxT, workCT;
System.Threading.ThreadPool.GetMaxThreads(out maxT, out workCT);
m_counter++;
return String.Format("Incrementing counter to {0}.\r\nSession Id: {1}. Threads {2}, {3}", m_counter, OperationContext.Current.SessionId, maxT, workCT);
}
}
The service returns 400,400 for the number of threads.
Does anyone know why the service refused to create more that 10 instances?
If I create a copy of the service but with a a wsHttp binding that has <security mode="None"/> then the service happily created many more instances.
Are you testing on a Windows Server or Windows 7? The reason I ask is that IIS on the client OS versions has a 10 connection limit. This is to prevent the client OS from being used in a server environment.
The MaxConcurrentSessions documentation mentions an optimization for client requests that come from the same AppDomain. Your sample code is basically hitting the same socket on the service. Since there is some throttling done per client, that may be affecting your service behavior. Also, 10 happens to be the default value for MaxConcurrentSessions so it may be that your config is not changing the WCF default value.
Enabling security affects the total threads because it establishes a "session" per client so that each request sent does not need to be authenticated on every call. Those security "sessions" count toward the MaxConcurrentSessions total.
Are you running the client and server on the same machine? Then they might be fighting for available threads.
If you are running on a different PC, please ensure you have done the following config changes on both client and server.
http://www.codeproject.com/KB/webservices/quickwins.aspx
It is possible that the client is not generating more than 10 requests to the same server. So, please try the above configs first on both client and server.
And of course, you must have a Windows Server. Otherwise it will be the IIS limit on Windows 7.
I'm new to WCF and I have issues throwing exceptions from my WCF Service to the client. I'm using code examples which I copied from the web. (I'm using VS2010 .NET Framework 4.0)
I created an ErrorHandler where the ProvideFault-method looks like this:
public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message msg)
{
FaultException<Exception> faultException = new FaultException<Exception>(error, error.Message, new FaultCode("Testing."));
MessageFault messageFault = faultException.CreateMessageFault();
msg = Message.CreateMessage(version, messageFault, Constants.FaultAction);
}
The fault contract looks like this:
[FaultContract(typeof(Exception), Action=Constants.FaultAction)]
The client side test code looks like this:
private void button1_Click(object sender, EventArgs e)
{
HistorianAccessServiceClient cli = new HistorianAccessServiceClient();
Tables.Batch bt = new Tables.Batch();
try
{
bt = cli.GetBatch(3241);
}
catch (FaultException<Exception> ex)
{
MessageBox.Show(ex.Message);
}
}
I noticed that if the error parameter to the ProvideFault method contains an inner exception then a System.ServiceModel.CommunicationException is thrown on the client side (!?), the inner exception is System.Net.WebException, the inner exception to that exception is System.IO.IOException and the inner exceptin to that exception is System.Net.Sockets.SocketException (Error Code 10054)?!?!
(Unfortunately I have a swedish operating system installed which means that the messages from the debugger is in swedish.)
The exception message (google translate) looks like this:
An error occurred while receiving the HTTP response to http://localhost:7070/Historian.WebAccess/HistorianAccessService. It may be that the service endpoint binding not using the http protocol. It may also be due to a context for the http request has been interrupted by the server (probably because the service is terminated). You can find more information in server logs.
If I throw an exception without an inner exception, the exception is handled by the client perfectly ok!?!?!
My configuration files looks like this (Service):
<system.serviceModel>
<bindings />
<client />
<services>
<service name="Historian.WebAccess.HistorianAccessService">
<host>
<baseAddresses>
<!--<add baseAddress="http://localhost:8732/Design_Time_Addresses/Historian.WebAccess/HistorianAccessService/"/>-->
<add baseAddress="http://localhost:7070/Historian.WebAccess/"/>
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<!--<endpoint address="HistorianAccessService" binding="wsHttpBinding" contract="Historian.WebAccess.IHistorianAccessService">-->
<endpoint address="HistorianAccessService" binding="wsHttpBinding" contract="Historian.WebAccess.IHistorianAccessService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="false"/>
<serviceThrottling maxConcurrentCalls="16" maxConcurrentInstances="2147483646" maxConcurrentSessions="10"/>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
<!-- 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>
Configuration file (Client):
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IHistorianAccessService" closeTimeout="00:10:00"
openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="104857600" maxReceivedMessageSize="104857600"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="104857600" maxStringContentLength="104857600" maxArrayLength="104857600"
maxBytesPerRead="104857600" maxNameTableCharCount="104857600" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:7070/Historian.WebAccess/HistorianAccessService"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IHistorianAccessService"
contract="HistorianAccessHost.IHistorianAccessService"
name="WSHttpBinding_IHistorianAccessService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Does anyone out there recognize this phenomenon and the solution to it?!
I'd be greatful for all the help I can get!
The solution is to not attempt to pass .NET Exception objects back to the client. This limits you to clients running .NET.
In fact, it limits you to running clients which know about all of the exceptions that you might throw. What if you add a new MyNewException on the server, and throw it back to the client? The client will need to have the assembly containing that exception in order for it to be deserialized at all.
I think you're being too fancy for what you're trying to do. If you're just trying to throw FaultException, just do new FaultException(error). You have to do a bit more work if you're throwing a custom fault type, but none of that message stuff is necessary. Here's a VB example I found:
Public Function DoSomething() As Data()
Try
DoSomething()
Catch ex As Exception
Throw New FaultException(ex.Message)
End Try
End Function
If you're throwing a custom type of fault (like say PermissionDenied or such), you need to create an object for that, which is a bit more work.
You also want to be careful what you're returning here. Sending back a lot of details like stack traces to the client can help an attacker trying to break into the system, and isn't a lot of use to your standard end user. You should log that on the server instead.