5

I would like to call an external WCF Service from within SharePoint 2010. Using normal WCF calls immediately causes a SocketException (An existing connection was forcibly closed by the remote host), which can be circumvented with SPSecurity.RunWithElevatePrivileges.

[SocketException (0x2746): An existing connection was forcibly closed by the remote host]
System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags) +85
System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing) +204

[CommunicationException: The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:58.7210000'.]
System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing) +15307563
System.ServiceModel.Channels.SocketConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout) +90
System.ServiceModel.Channels.DelegatingConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout) +34
System.ServiceModel.Channels.ConnectionStream.Read(Byte[] buffer, Int32 offset, Int32 count, TimeSpan timeout) +34
System.ServiceModel.Channels.ConnectionStream.Read(Byte[] buffer, Int32 offset, Int32 count) +88
System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count) +58
System.Net.Security.NegotiateStream.StartFrameHeader(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) +62
System.Net.Security.NegotiateStream.StartReading(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) +54
System.Net.Security.NegotiateStream.ProcessRead(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) +402

[IOException: The read operation failed, see inner exception.]
System.Net.Security.NegotiateStream.ProcessRead(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) +704
System.Net.Security.NegotiateStream.Read(Byte[] buffer, Int32 offset, Int32 count) +154
System.ServiceModel.Channels.StreamConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout) +87

[CommunicationException: The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:58.7210000'.]
System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +10257978
System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +539
MyApp.FunctionThatCallsService()

That got me thinking: SharePoint does it, and they do it in a nice way where they have individual service configurations in 14\WebClients.

I reflected and cloned a lot of it (The Extension Methods on the ChannelFactory are used internally all over the place - SPChannelFactoryOperations), but I wonder: Are the "proper" APIs that SharePoint uses to call it's own WCF Services exposed to external code, so that I can call my non-SharePoint WCF Services from custom SharePoint code?

(This is a farm solution deployed to the GAC, so neither CAS nor Sandboxing applies)

Edit: Added some clarification and callstacks

3 Answers 3

2

Check this reference implementation from SharePoint Patterns and Practices Group: http://msdn.microsoft.com/en-us/library/ff798482.aspx

They have downloadable sample solution too.

2
  • That's for sandboxed solutions and requires excessive plumbing. Do you know if there is a more straight-forward solution for non-Sandboxed solutions?
    – Michael Stum
    Jul 11, 2011 at 20:23
  • Michael, check the code that makes the WCF-call. That can help you
    – Bas Lijten
    Jul 15, 2011 at 14:41
1

Ended up keeping the SPSecurity.RunWithElevatedPrivileges section. Microsoft's SPChannelFactoryOperations at some point hit a NullReferenceException, most likely due to Claims required to be setup within the service even when not using it (SPServiceAuthenticationMode only has SPServiceAuthenticationMode.Claims as a member. The fact that CreateChannelActingAsLoggedOnUser() immediately throws an ArgumentException is a signal that the SPChannelFactoryOperations aren't meant to be used by non-Microsoft code.

3
  • The SPChannelFactoryOperations are only used for claims aware services. aobut the security exception: are you sure that you current identity (logged on user) has sufficient rights to call the wcf-service? And took care of the double hop issue? Calling SPSecurity.RunWithElevatedPrivileges gets rid of the "double-hop" and calls your wcf-service as the app-Pool account
    – Bas Lijten
    Jul 18, 2011 at 8:49
  • @Bas yes, the user does have permission. I've run Wireshark on the target server, and the call doesn't even make it to that server. Is ASP.net impersonation enforcing any other security constraints on the call?
    – Michael Stum
    Jul 18, 2011 at 17:45
  • I ran into the same thing on 2013! And thanks to my zero knowledge of wcf, spent almost a day on this before finding this answer! Thanks! (Going to try braving SPchannelfactoryoperations though) Apr 18, 2016 at 3:56
1

You should have a look at Eric White's article around calling WCF External Web Services from SharePoint 2010 which use Claims based authentication. The process is absolutelly the same whether you consume or not the services via BCS.

See here the series link http://blogs.msdn.com/b/ericwhite/archive/2010/06/18/consuming-a-claims-enabled-wcf-web-service-as-an-sharepoint-2010-external-content-type.aspx

Hope it helps, C:\Marius

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.