So got an older WCF service / client I'm working on. Added a new (static) logging system to it, actually and now doing some load testing.
Getting some really annoying sporadic issues now - claiming "Secure channel cannot be opened because security negotiation with the remote endpoint has failed". I noticed I get a CommunicationException with a fault name of Sender and subcode of BadContextToken.
Weird thing is, I'll get 2-4 correct responses, then a flurry of these exceptions, then start getting good responses again.
This is my first real foray into WCF, and not loving it so far :)
Service web.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="MyNamespace.MyService">
<endpoint address="" binding="wsHttpBinding" contract="MyNamespace.IMyService" bindingConfiguration="wsMessage">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceCredentials>
<serviceCertificate findValue="MyValue" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyNamespace.UserNamePassValidator, MyNamespace" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
And on the client side, the client is instantiated as such:
var binding = new WSHttpBinding();
binding.Name = "WSHttpBinding_IMyService";
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
var client = new MyService(binding, "http://myserver:8080/myapp/service.svc");
var endpointIdentity = new DnsEndpointIdentity("MyValue"); // Match the certificate name used by the server
client.Endpoint.Address = new EndpointAddress(new Uri("http://myserver:8080/myapp/service.svc"), endpointIdentity, client.Endpoint.Address.Headers);
var creds = client.ClientCredentials;
creds.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
creds.UserName.UserName = "myuser";
creds.UserName.Password = "mypassword";
string retVal = client.SendRequest(); // SendRequest == one of the methods on my IMyService, returns a string. This is also where I sporadically see my error when load testing.
I would appreciate any pointers to help me out with this WCF setup!
These might be useful additions to your web.config:
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="False" />
<serviceMetadata httpGetEnabled="True"/>
<serviceThrottling maxConcurrentCalls="20" maxConcurrentInstances="100"/>
</behavior>
</serviceBehaviors>
</behaviors>
<binding name="basicHttp" allowCookies="true" maxReceivedMessageSize="1048576" maxBufferSize="1048576" maxBufferPoolSize="1048576">
<readerQuotas maxDepth="32" maxArrayLength="1048576" maxStringContentLength="1048576"/>
</binding>
Usually this kind of "random" behaviour might depend on:
Timeouts (probably not your case, since you'd get a different exception)
Too many connections: if you client opens too many connections (and "forgets" to close them), you'll exceed the default allowed maximum (depending on context, it might be 10 connections).
You can act on this if you alter your web.config, editing maxConcurrentCalls and maxConcurrentInstances
Perhaps those errors are not random, but specific to some message; if so, that might be due to its size (i.e. it's too large): again, alter your web.config setting maxReceivedMessageSize, maxBufferSize, maxBufferPoolSize and readerQuotas
Of course you will get more info if you turn on WCF tracing.
Related
I have written a WCF Service which is being called by a Winforms application.
I have tested calling the WCF Service from the WinForms application locally and it all works fine
I have moved both the WinForms application and the WCF Service to a Remote Server, on the Remote Server I can use IE to browse to the Service but when I try to use the Winforms application I get a 400 Bad Response error.
My local machine and the Remote Server has been configured exactly the same, Windows Firewall, User accounts etc and the codebase/config files of both the Service and Winforms app are the same.
The config file for the WCF Service is as follows (i've had to remove the base address)
<bindings>
<webHttpBinding>
<binding name="webBinding">
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="CodeLocksAPIServiceBehavior" name="CodeLocksAPI.WCF.CodeLocksAPIService">
<host>
<baseAddresses>
</baseAddresses>
</host>
<endpoint address="" behaviorConfiguration="webHttpBehavior" binding="webHttpBinding" bindingConfiguration="webBinding" contract="CodeLocksAPI.WCF.ICodeLocksAPIService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CodeLocksAPIServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
In the Winforms app config I have tried adding the DefaultProxy tabs which do not help
WCF Service is called from Code Using the following
string serviceUserName = ConfigurationManager.AppSettings["ServiceUserName"];
string servicePassword = ConfigurationManager.AppSettings["ServicePassword"];
HttpClientHandler handler = new HttpClientHandler
{
Credentials = new
System.Net.NetworkCredential(serviceUserName, servicePassword)
};
this.Client = new HttpClient(handler);
this.Client.BaseAddress = new Uri(this.GetBaseAddressFromConfig());
processInitializeLockRequestArgs.AssetRef = assetRef;
string contentMessage = Newtonsoft.Json.JsonConvert.SerializeObject(processInitializeLockRequestArgs);
byte[] contentBytes = System.Text.Encoding.UTF8.GetBytes(contentMessage);
ByteArrayContent content = new ByteArrayContent(contentBytes);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
httpResponse = this.Client.PostAsync(methodUri, content).Result;
As already stated - this code is working locally but not on the remote server - the WCF Service can be browsed to locally and on the remote service
I've been informed that the issue is most likely down to Proxy settings on the WinForms application and that the issue is not down to a Firewall or anything like that
You could try adding
<configuration>
<system.net>
<defaultProxy useDefaultCredentials="true"/>
</system.net>
....
to the beginning of your WinForms config file.
I've a problem with BizTalk Server 2013 and a WCF Service. BizTalk needs to consume the WCF Service. BizTalk needs to sign the message with a X509 certificate and I receive the following error message:
There was a failure executing the send pipeline: "BizTalkUtilities.SignPipeline,
BizTalkUtilities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d749e81ab815db56" Source:
"MIME/SMIME encoder" Send Port: "SndPort_Sign_V2" URI: "http://XXXX/DemoServiceSigned
/DemoService.svc" Reason: The message has a bad message signature.
First I've created the service without security, everything works. Once I've setup my security (message security, Sign) it didn't work anymore. To be sure my service was fine, I've created a test WCF client which consumes the service with the security - no problem.
The message needs to be signed using a X509 certificate. All the certificates are in the correct place. I followed the info stated on MSDN.
Service config:
<bindings>
<wsHttpBinding>
<binding name="clientSignConfig">
<security mode="Message">
<message clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="SignServiceBL.DemoService" behaviorConfiguration="DemoServiceBehavior">
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="clientSignConfig"
contract="SignServiceBL.IDemoService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DemoServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine"/>
</clientCertificate>
<serviceCertificate findValue="CN=DemoServiceServerCertificate"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
Client config (this works for a WCF Client, but doesn't work in BizTalk)
<bindings>
<customBinding>
<binding name="demoService_CustomBinding">
<transactionFlow />
<security authenticationMode="SecureConversation" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<secureConversationBootstrap authenticationMode="MutualSslNegotiated" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" />
</security>
<textMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="signingBehavior">
<clientCredentials>
<clientCertificate findValue="CN=DemoServiceSigning"
storeLocation="CurrentUser" storeName="My"/>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://XXXX/DemoServiceSigned/DemoService.svc"
binding="customBinding" bindingConfiguration="demoService_CustomBinding" behaviorConfiguration="signingBehavior"
contract="DemoService.IDemoService" name="WSHttpBinding_IDemoService">
<identity>
<dns value="DemoServiceServerCertificate"/>
</identity>
</endpoint>
</client>
I've setup tracing, but BizTalk isn't even sending a message to my service. It's like the sendpipeline is blocking my request.
Any ideas?
EDIT
You don't need the pipeline with a MIME/SMIME encoder to sign WCF messages. You should use this pipeline if you need to sign emails... See the first sentence of MSDN
BizTalk Server supports signing outbound messages and signature verification for inbound Secure Multipurpose Internet Mail Extensions (S/MIME) messages
Once I remove the pipeline, BizTalk sends a message to the service. The problem now is that it's signed and encrypted. I am figuring out how to tell BizTalk to only sign the message. If you have any ideas, feel free to post them. If I find it, I will post it ;-)
It wasn't easy, but I was able to solve my issue :-)
I wrote a blogpost about it, because it's a bit to complicated to create an answer here.
So check it out!
i have created a wcf service with Message security mode enabled this is my
service
[ServiceContract]
public interface IMessagingServices
{
[OperationContract]
string SendMessage(string from, string to, string message);
[OperationContract]
List<Message> GetMessages(string from, string to);
[OperationContract]
int DeleteMessages(int[] idList);
}
}
and this is it's config
<bindings>
<wsHttpBinding>
<binding name="wsBinding1">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="MessagingServices" behaviorConfiguration="SecureServiceBehavior" >
<endpoint address="" binding="wsHttpBinding" contract="IMessagingServices" bindingConfiguration="wsBinding1" />
<!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetaDataExchange"/>-->
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="httpBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="SecureServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="KServic.local" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="AuthenticationHandler, mynamespace" />
</serviceCredentials>
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
everything seems to be fine , i can add service in add service reference in VS 2010 and the proxy is created successively but in client when try to call a service operation i get a error this is the client code
ServiceReference1.MessagingServicesClient mscClient = new MessagingServicesClient();
// mscClient.Open();
mscClient.ClientCredentials.UserName.UserName = "test";
mscClient.ClientCredentials.UserName.Password = "test";
mscClient.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByIssuerName, "KService.local");
// error is here
var msg = mscClient.SendMessage("rnd.test", "rnd.test", "Hello brother!");
mscClient.Close();
and this is error
The identity check failed for the outgoing message. The expected identity is 'identity(http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/thumbprint)' for the 'http://192.168.100.24:16027/MessagingServices.svc' target endpoint.
what's wrong here ? and how can i fix this problem ?
You should set endpoint identity at client side when using message security.
The code you provided sets client credentials, not an endpoint identity.
See <identity> and <certificateReference> elements in WCF configuration schema, if you want to set up identity via .config file, or X509CertificateEndpointIdentity class, if you want to set up identity in code:
var certificate = ...; // load X509Certificate2 instance from the X509Store
var address = new EndpointAddress(uri, new X509CertificateEndpointIdentity(certificate));
Note, that service certificate must be validated before use at client side. For more information, see <authentication> of <serviceCertificate> element page.
I have a WCF service being hosted over https with a self-signed certificate. I'm having trouble programatically creating the binding: specifically the portion of the endpoint behavior.
My Service config looks like this:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="DisableServiceCertificateValidation">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="None"
revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="ContactEmail.Web.EmailService.customBinding0">
<binaryMessageEncoding />
<httpsTransport/>
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<services>
<service name="ContactEmail.Web.EmailService">
<endpoint address="https://xxxxxxxxxxxxxx/EmailService/EmailService.svc" binding="customBinding" bindingConfiguration="ContactEmail.Web.EmailService.customBinding0" contract="ContactEmail.Web.EmailService" behaviorConfiguration="DisableServiceCertificateValidation" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
And when I use the "Add Service Reference" feature, the generated client works as expected. Given that I call set up a Cert Validation Callback like this:
System.Net.ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
However, rather than feed the service configuration through a config file on the client, I need to set it programmatically, because the call will be part of a commonly shared library. So, I'm trying to do this by providing my own parameters to the client constructor like:
var myClient = new EmailServiceClient(GetBinding(), new EndpointAddress(Strings.EmailServiceEndpointAddress));
In GetBinding(), I create CustomBinding with BindingElements like HttpsTransportBindingElement, BinaryMessageEncodingBindingElement and SecurityBindingElement.CreateSecureConversationBindingElement(SecurityBindingElement.CreateUserNameOverTransportBindingElement()).
Do you know how I can specify things like certificateValidationMode="None" and revocationMode="NoCheck" or if I'm doing anything wrong?
SecureConversation is implementation of WS-SecureConversation => advanced message level security where special security token is created during first call to the service (authenticated by the message security mode passed as parameter to the binding element creation) and this token is used to secure subsequent messages. This security also forms something know as security context or security session.
Your current binding in config file is not using SecureConversation so your binding defined in code is not compatible with your service.
You should have a Credentials property (of type ClientCredentials) (http://msdn.microsoft.com/en-us/library/ms733836.aspx) on your ClientBase (EmailServiceClient)...and that should have a ServiceCertificate property:
http://msdn.microsoft.com/en-us/library/system.servicemodel.description.clientcredentials.servicecertificate.aspx
this if my first attempt at using streaming for WCF, and I am struggling with the dreadful "The remote server returned an unexpected response: (400) Bad Request" response.
The trace viewer says that this is a System.ServiceModel.ProtocolException with message "There is a problem with the XML that was received from the network. See inner exception for more details." The inner exception type says "The body of the message cannot be read because it is empty."
Leaving everything else equal, if I switch to buffered mode on the client side, I am able to debug into the server code!
For some reason, I have to configure my service programmatically, as follows:
public IUniverseFileService OpenProxy(string serviceUrl)
{
Debug.Assert(!string.IsNullOrEmpty(serviceUrl));
var binding = new BasicHttpBinding();
binding.Name = "basicHttpStream";
binding.MaxReceivedMessageSize = 1000000;
binding.TransferMode = TransferMode.Streamed;
var channelFactory =
new ChannelFactory<localhost.IUniverseFileService>(
binding,
new EndpointAddress(serviceUrl));
return channelFactory.CreateChannel();
}
While the server is configured as follows:
<system.serviceModel>
<!-- BEHAVIORS -->
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true" httpHelpPageEnabled="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
</behaviors>
<!-- SERVICES -->
<services>
<service behaviorConfiguration="serviceBehavior" name="Org.Acme.UniverseFileService">
<endpoint address=""
binding="basicHttpBinding"
name="basicHttpStream"
bindingConfiguration="httpLargeMessageStream"
contract="Org.Acme.RemoteCommand.Service.IUniverseFileService" />
<endpoint address="mex"
binding="mexHttpBinding"
bindingConfiguration="" name="mexStream"
contract="IMetadataExchange"/>
</service>
</services>
<!-- BINDINGS -->
<bindings>
<basicHttpBinding>
<binding name="httpLargeMessageStream"
maxReceivedMessageSize="2147483647"
maxBufferPoolSize="2147483647"
maxBufferSize="2147483647"
transferMode="Streamed"/>
</basicHttpBinding>
</bindings>
I appreciate your help!
Stefano
Everything started to work when I changed the transfer mode from Streamed to StreamedResponse as follows:
binding.TransferMode = TransferMode.StreamedResponse;
Still I don't understand why this works and Streamed does not, and why I am able to both send and receive a file stream from the server.
Streaming mode is not supported by ASP.NET development server. You need to deploy the service to IIS (or a WCF Service Application) to use Streaming mode.
Try to add messageEncoding="Mtom" in bining tag.