-
Notifications
You must be signed in to change notification settings - Fork 11
Add WCF Faulted EventHandler for automatic recovery from communication object faulted state #217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add WCF Faulted EventHandler for automatic recovery from communication object faulted state #217
Conversation
…n faults - Added Faulted event handlers for all 19 service channels in InfoShareWcfSoapWithOpenIdConnectConnection - Added Faulted event handlers for all 19 service channels in InfoShareWcfSoapWithWsTrustConnection - Registered event handlers after client creation in both NET48 and NET60+ code paths - Event handlers call Abort() on faulted channels and set clients to null for automatic recreation - Added debug logging to track CommunicationState when recreating clients - Removed known issue about faulted communication objects from README.MD Co-authored-by: ddemeyer <19798225+ddemeyer@users.noreply.github.com>
| if ((_annotationClient == null) || (_annotationClient.InnerChannel.State == System.ServiceModel.CommunicationState.Faulted) || | ||
| (_annotationServiceReference == null) || (GetAccessToken().IsAccessTokenRefreshed)) | ||
| { | ||
| _logger.WriteDebug($"GetAnnotation25Channel recreating client - Client[{_annotationClient?.InnerChannel?.State}] ServiceRef[{(_annotationServiceReference as ICommunicationObject)?.State}] TokenRefreshed[{GetAccessToken().IsAccessTokenRefreshed}]"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove TokenRefreshed[{GetAccessToken().IsAccessTokenRefreshed}] from all WriteDebug statements as this code will always return false as the validation happened in the if clause. This across all similar log lines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit 23c0993. Removed TokenRefreshed[{GetAccessToken().IsAccessTokenRefreshed}] from all 38 debug statements in InfoShareWcfSoapWithOpenIdConnectConnection.cs.
| if ((_annotationClient == null) || (_annotationClient.InnerChannel.State == System.ServiceModel.CommunicationState.Faulted) || | ||
| (_annotationServiceReference == null) || (GetAccessToken().IsAccessTokenRefreshed)) | ||
| { | ||
| _logger.WriteDebug($"GetAnnotation25Channel recreating client - Client[{_annotationClient?.InnerChannel?.State}] ServiceRef[{(_annotationServiceReference as ICommunicationObject)?.State}] TokenRefreshed[{GetAccessToken().IsAccessTokenRefreshed}]"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename WriteDebug Client to ClientInnerChannelState. Rename ServiceRef to ServiceReferenceState. This across all similar log lines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit 23c0993. Renamed Client to ClientInnerChannelState and ServiceRef to ServiceReferenceState in all 38 debug statements in InfoShareWcfSoapWithOpenIdConnectConnection.cs.
README.MD
Outdated
| it probably means you didn't provide enough (mandatory) parameters to the WCF/SVC code so passing null parameters. Typically an `-IshPassword` is missing or using an existing username. | ||
| * ISHDeploy `Enable-ISHIntegrationSTSInternalAuthentication/Disable-ISHIntegrationSTSInternalAuthentication` adds a /ISHWS/Internal/connectionconfiguration.xml that a different issuer should be used. As ISHRemote doesn't have an app.config, all the artifacts are derived from the RelyingParty WSDL provided mex endpoint (e.g. /ISHSTS/issue/wstrust/mex). | ||
| If you get error `New-IshSession : The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.`, it probably means you initialized `-WsBaseUrl` without the `/Internal/` (or `/SDL/`) segment, meaning you are using the primary configured STS. | ||
| * ISHDeploy `Enable-ISHIntegrationSTSInternalAuthentication/Disable-ISHIntegrationSTSInternalAuthentication` adds a /ISHWS/Internal/connectionconfiguration.xml that a different issuer should be used. As ISHRemote doesn't have an app.config, all the artifacts are derived from the RelyingParty WSDL provided mex endpoint (e.g. /ISHSTS/issue/wstrust/mex). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove this bullet from the README.MD file as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit 23c0993. Removed the ISHDeploy bullet point from README.MD line 68.
| #if NET48 | ||
| if ((_annotationClient == null) || (_annotationClient.InnerChannel.State == System.ServiceModel.CommunicationState.Faulted)) | ||
| { | ||
| _logger.WriteDebug($"GetAnnotation25Channel recreating client - Client[{_annotationClient?.InnerChannel?.State}]"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename WriteDebug Client to ClientInnerChannelState. This across all similar debug lines in this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit 23c0993. Renamed Client to ClientInnerChannelState in all 38 debug statements in InfoShareWcfSoapWithWsTrustConnection.cs.
|
@copilot can you make the requested changes? |
- Remove TokenRefreshed from debug statements (always false due to if clause check) - Rename 'Client' to 'ClientInnerChannelState' in all debug logs (76 locations) - Rename 'ServiceRef' to 'ServiceReferenceState' in OpenIdConnect debug logs (38 locations) - Remove ISHDeploy bullet point from README.MD known issues section Co-authored-by: ddemeyer <19798225+ddemeyer@users.noreply.github.com>
…7/NET6+ runtime error "Object is read-only." found during Pester Tests. This is caused by assigning the EventHandler which finishes initialization before setting "CertificateValidationMode", which in turn causes "X509ServiceCertificateAuthentication.ThrowIfImmutable". Changed the order.
Corrected the copilot code after a debug session. Moamen reviewed the code.
WCF Proxy Faulted State Recovery Implementation - COMPLETE ✅
Successfully implemented automatic recovery from WCF communication object faulted state using EventHandler:
Implementation Details
Event Handlers Added
Event Handler Registrations
Debug Logging (Updated)
Client→ClientInnerChannelState(more descriptive of what's being logged)ServiceRef→ServiceReferenceState(more descriptive)TokenRefreshedparameter (always false due to if clause validation)Services Updated
All 19 WCF service channels now have automatic fault recovery:
How It Works
When a WCF channel enters a Faulted state, the registered event handler automatically:
This eliminates the need for manual
New-IshSessioncalls when encountering "The communication object cannot be used for communication because it is in the Faulted state" errors.Testing
Original prompt
This section details on the original issue you should resolve
<issue_title>Rewrite WcfSoap proxies creation using Faulted EventHandler to automatically recover from 'The communication object, ..., cannot be used for communication because it is in the Faulted state.'</issue_title>
<issue_description>Problem...
While investigating #210 a long term error came in the spotlight again
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.Workaround...
This illusive error is mentioned in the README.MD section 'Known Issues & FAQ' for years as
Analysis…
After rewrite of Refresh Token, see #210, you can still get the error, actually unrelated code. In essence it means that something in the Windows Communication Foundation (WCF) connection went wrong. This can be misbehaving server-side API code, application recycle over networking devices up to the client.
Classes like
InfoShareWcfSoapWithOpenIdConnectConnectioncontain an if clause like below for years that is checked for everyGet...Channel()call.Below analysis indicates that this considered unused code that does not trigger at the right moment in time.
Actions...
Right after every
_annotationServiceReferenceCreateChannel-creation in NET48 and NET60+ code, a specific register event needs to happen like((ICommunicationObject)_annotationClient).Faulted+= new EventHandler(AnnotationClientChannelFactoryFaulted);that hooks upSystem.ServiceModel.CommunicationStatewith an extra debug line… so print the 4 values of the if in GetDocumentObj25Channel in debug to check them when it happens againAbort(and notClose) on the Faulted object to dispose any resources cleanly.Source\ISHRemote\Trisoft.ISHRemote\Connection\InfoShareWcfSoapWithOpenIdConnectConnection.csSource\ISHRemote\Trisoft.ISHRemote\Connection\InfoShareWcfSoapWithWsTrustConnection.csReferences...
https://nahidulkibria.blogspot.com/2008/05/knowing-when-wcf-service-in-fault-state.html
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.