I have a .Net 3.5 WCF service that functions as a SOAP API. A Client has a requirement to now send SOAP 1.2 envelopes (soap:Envelope instead of soapenv:Envelope), but they still use text/xml as the content type of the request instead of application/soap+xml
Is it possible to adjust the service through configuration to accept this behavior, or would i need to create something like an HttpHandler to intercept the request and modify the content type? I am already using a custom Message Filter registered in the Dispatcher to cater for modifications to the Action, as a custom header is provided that i am reading and routing.
The current configuration of the web services looks like this:
<services>
<service behaviorConfiguration="Service1Behavior"
name="BusinessService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="myBindingForBigArrays"
contract="IMasterService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="/12" binding="customBinding" bindingConfiguration="https12Binding"
contract="IMasterService" behaviorConfiguration="crsBehavior">
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
And the binding configuration is
<customBinding>
<binding name="https12Binding">
<transactionFlow />
<textMessageEncoding messageVersion="Soap12">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
</textMessageEncoding>
<httpsTransport maxReceivedMessageSize="2147483647" />
</binding>
</customBinding>
<basicHttpBinding>
<binding name="myBindingForBigArrays" maxReceivedMessageSize="2147483647">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
<readerQuotas maxDepth="64" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
I've solved my issue, and i am going to update this question for future reference and for anyone else who might come across this problem.
The trick to this is to register a new Text Encoding element to identify the type of messages this binding may accept.
Since the <textMessageEncoding /> element can only really take SOAP11 (text/xml) and SOAP12 (application/soap+xml), registering a new custom element that can be configured even further is the most robust way to do this.
Microsoft has some sample code to perform this, which can easily be imported into a solution (i created a separate library to house this code for reference). This reference data can be found here here, and the sample code here.
Once this code is implemented you can define a new textMessageEncoding element customTextMessageEncoding combination such as <customTextMessageEncoding encoding="utf-8" mediaType="text/xml" messageVersion="Soap12" />. Note that the reference link has incorrectly labelled the line above with contentType instead of mediaType. The combination above allowed me to register the binding with a SOAP 1.2 envelope, and a SOAP 1.1 content type.
Another thing to do is to use the mediaType instead to change the response type, and override the IsContentTypeSupported on the MessageEncoder to allow the service to respond on a different content type. this is also a requirement from the client, as unusual as it is. The service can now accept both text/xml and application/soap+xml (through the overrided method) and respond on the provided mediaType
In a nutshell the solution requires:
implement a custom encoder and encoder factory
Implement a binding element for a custom encoder
Use the custom binding configuration to integrate custom binding elements
Develop a custom configuration handler to allow file configuration (app.config or web.config) of the custom binding element
Register the new binding element in the web.config
Use the new binding element to configure the binding
I need to create a WCF service that gets some data out of a database. This service should only be accessible at night, for some reason. I have been told this should be possible by some code in web.config, but I have no idea how.
Not sure if there's a way to define in web.config, but it seems like you can use PowerShell to schedule and terminate the service.
MSDN blog post on scheduling background jobs
It's not possible in web.config. This is a highly unusual requirement. Certainly not built in.
Just go like this:
if (DateTime.Now.Hour >= 22)
throw new FaultException("ServiceUnavailable");
For a client, you would want to adjust the sendTimeout attribute of a binding element. For a service, you would want to adjust the receiveTimeout attribute of a binding elemnent.
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="longTimeoutBinding"
receiveTimeout="00:10:00" sendTimeout="00:10:00">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="longTimeoutService"
behaviorConfiguration="longTimeoutBehavior">
<endpoint address="net.tcp://localhost/longtimeout/"
binding="netTcpBinding" bindingConfiguration="longTimeoutBinding" />
</service>
Let me know if this answers your question.
I have a BizTalk app up and running that is currently using the WCF-BasicHttp Adapter. It's currently using only Message security using the UserName credential type and that is all working fine.
Things have since changed, we are now required to accept Client Certificates at the Transport (IIS) level for authorization of the service and still continue to use Message security for authentication into the service.
After much pain and searching, I was able to get this to work in a NON-BizTalk WCF environment basing my config of bits of this this post and ended up with the following customBinding configuration:
<customBinding>
<binding name="CustomCDARequestEndpointBinding">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="UserNameOverTransport" />
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
This resulted in a WCF client config like so:
<customBinding>
<binding name="CDARequestEndpoint">
<security defaultAlgorithmSuite="Default" authenticationMode="UserNameOverTransport"
requireDerivedKeys="true" includeTimestamp="true" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<localClientSettings detectReplays="false" />
<localServiceSettings detectReplays="false" />
</security>
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ohBehave">
<clientCredentials useIdentityConfiguration="false">
<clientCertificate findValue="6D0DBF387484B25A16D0E3E53DBB178A366DA954" storeLocation="CurrentUser"
x509FindType="FindByThumbprint" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
This works perfectly fine in a NON-BizTalk environment and it seems to be the critical piece of configuration is the <httpsTransport requireClientCertificate="true" /> config element because of the requreClientCertificate attribute. The problem is, no matter what I try, I cannot find a similar setting in the BizTalk WCF-Custom/customBinding configuration anywhere. I can't add the <httpsTransport> binding element extension because it doesnt' exist as on option in BizTalk
Does anyone know what my options are here?
Can I edit the web.config directly?
Is there another extension I can add to achieve the same effect in the BizTalk GUI?
Can I code something in the orchestration to manually setup this receive location the way I'm proposing?
Because the WCF-BasicHttp Adapter only surfaces certain properties, you can't use it for your purpose.
Instead:
Start with the WCF-Custom Adapter
BindingType = customBinding
Delete httpTransport
Add httpsTransport (you will then see requireClientCertificate)
Add the clientCredentials Behavior and set your options and credentials in the Credentials tab.
I'm currently working on an integration with a leasing service provider, which runs (I assume) a Java service.
When I add the service reference in Visual Studio 2012, the reference is created correctly and I can call the methods specified in the service.
The problem arises when I get a response from the service.
Let's say I call the service with wrong parameters getCalculation and I get the JSON response JSONException. The problem is, that Visual Studio throws an exception There was an error reflecting 'JSONException'. and as InnerException: {"Namespace='http://service.ecommerce.cetelem.hu/' is not supported with rpc\\literal SOAP. The wrapper element has to be unqualified."}
This is the web.config code:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="EcommerceServiceImplPortBinding">
<security mode="Transport" />
</binding>
<binding name="EcommerceServiceImplPortBinding1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://ecomdemo.cetelem.hu:443/ecommerce/EcommerceService"
binding="basicHttpBinding" bindingConfiguration="EcommerceServiceImplPortBinding"
contract="CetelemInstallmentsService.EcommerceService" name="EcommerceServiceImplPort" />
</client>
</system.serviceModel>
If this is of any help, I'm using WebAPI for the user "front-end".
Thank you for all the answers!
I figured this thing out eventually, but with the help of another post on SO: SOAP Requests in .net
All I needed to change in the service refence file was:
[System.ServiceModel.XmlSerializerFormatAttribute(Style = System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults = true)]
To:
[System.ServiceModel.XmlSerializerFormatAttribute(Style = System.ServiceModel.OperationFormatStyle.Document, SupportFaults = true)]
I am trying to make a WCF service over basicHttpBinding to be used over https. Here's my web.config:
<!-- language: xml -->
<service behaviorConfiguration="MyServices.PingResultServiceBehavior"
name="MyServices.PingResultService">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="defaultBasicHttpBinding"
contract="MyServices.IPingResultService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
...
<bindings>
<basicHttpBinding>
<binding name="defaultBasicHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
...
<behaviors>
<serviceBehaviors>
<behavior name="MyServices.UpdateServiceBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
I am connecting using WCFStorm which is able to retrieve all the meta data properly, but when I call the actual method I get:
The provided URI scheme 'https' is invalid; expected 'http'. Parameter
name: via
Try adding message credentials on your app.config like:
<bindings>
<basicHttpBinding>
<binding name="defaultBasicHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
Adding this as an answer, just since you can't do much fancy formatting in comments.
I had the same issue, except I was creating and binding my web service client entirely in code.
Reason is the DLL was being uploaded into a system, which prohibited the use of config files.
Here is the code as it needed to be updated to communicate over SSL...
Public Function GetWebserviceClient() As WebWorker.workerSoapClient
Dim binding = New BasicHttpBinding()
binding.Name = "WebWorkerSoap"
binding.CloseTimeout = TimeSpan.FromMinutes(1)
binding.OpenTimeout = TimeSpan.FromMinutes(1)
binding.ReceiveTimeout = TimeSpan.FromMinutes(10)
binding.SendTimeout = TimeSpan.FromMinutes(1)
'// HERE'S THE IMPORTANT BIT FOR SSL
binding.Security.Mode = BasicHttpSecurityMode.Transport
Dim endpoint = New EndpointAddress("https://myurl/worker.asmx")
Return New WebWorker.workerSoapClient(binding, endpoint)
End Function
Change
from
<security mode="None">
to
<security mode="Transport">
in your web.config file. This change will allow you to use https instead of http
Are you running this on the Cassini (vs dev server) or on IIS with a cert installed? I have had issues in the past trying to hook up secure endpoints on the dev web server.
Here is the binding configuration that has worked for me in the past. Instead of basicHttpBinding, it uses wsHttpBinding. I don't know if that is a problem for you.
<!-- Binding settings for HTTPS endpoint -->
<binding name="WsSecured">
<security mode="Transport">
<transport clientCredentialType="None" />
<message clientCredentialType="None"
negotiateServiceCredential="false"
establishSecurityContext="false" />
</security>
</binding>
and the endpoint
<endpoint address="..." binding="wsHttpBinding"
bindingConfiguration="WsSecured" contract="IYourContract" />
Also, make sure you change the client configuration to enable Transport security.
I had same exception in a custom binding scenario. Anybody using this approach, can check this too.
I was actually adding the service reference from a local WSDL file. It got added successfully and required custom binding was added to config file. However, the actual service was https; not http. So I changed the httpTransport elemet as httpsTransport. This fixed the problem
<system.serviceModel>
<bindings>
<customBinding>
<binding name="MyBindingConfig">
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap11" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<!--Manually changed httpTransport to httpsTransport-->
<httpsTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false"
decompressionEnabled="true" hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="65536"
proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://mainservices-certint.mycompany.com/Services/HRTest"
binding="customBinding" bindingConfiguration="MyBindingConfig"
contract="HRTest.TestWebserviceManagerImpl" name="TestWebserviceManagerImpl" />
</client>
</system.serviceModel>
References
WCF with custombinding on both http and https
I had the EXACT same issue as the OP. My configuration and situation were identical. I finally narrowed it down to being an issue in WCFStorm after creating a service reference in a test project in Visual Studio and confirming that the service was working. In Storm you need to click on the "Config" settings option (NOT THE "Client Config"). After clicking on that, click on the "Security" tab on the dialog that pops up. Make sure "Authentication Type" is set to "None" (The default is "Windows Authentication"). Presto, it works! I always test out my methods in WCFStorm as I'm building them out, but have never tried using it to connect to one that has already been set up on SSL. Hope this helps someone!
Ran into the same issue, this is how my solution turned out at the end:
<basicHttpsBinding>
<binding name="VerificationServicesPasswordBinding">
<security mode="Transport">
</security>
</binding>
<binding name="VerificationServicesPasswordBinding1" />
</basicHttpsBinding>
I basically replaced every occurrence of Http with Https. You can try adding both of them if you prefer.
If you do this programatically and not in web.config its:
new WebHttpBinding(WebHttpSecurityMode.Transport)
Its a good to remember that config files can be split across secondary files to make config changes easier on different servers (dev/demo/production etc), without having to recompile code/app etc.
For example we use them to allow onsite engineers to make endpoint changes without actually touching the 'real' files.
First step is to move the bindings section out of the WPF App.Config into it's own separate file.
The behaviours section is set to allow both http and https (doesn't seem to have an affect on the app if both are allowed)
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true" />
And we move the bindings section out to its own file;
<bindings configSource="Bindings.config" />
In the bindings.config file we switch the security based on protocol
<!-- None = http:// -->
<!-- Transport = https:// -->
<security mode="None" >
Now the on site engineers only need to change the Bindings.Config file and the Client.Config where we store the actual URL for each endpoint.
This way we can change the endpoint from http to https and back again to test the app without having to change any code.
Hope this helps.
To re-cap the question in the OP:
I am connecting [to a WCF service] using WCFStorm which is able to retrieve all the meta data properly, but when I call the actual method I get:
The provided URI scheme 'https' is invalid; expected 'http'. Parameter name: via
The WCFStorm tutorials addresses this issue in Working with IIS and SSL.
Their solution worked for me:
To fix the error, generate a client config that matches the wcf service configuration. The easiest way to do this is with Visual Studio.
Open Visual Studio and add a service reference to the service. VS will generate an app.config file that matches the service
Edit the app.config file so that it can be read by WCFStorm. Please see Loading Client App.config files. Ensure that the endpoint/#name and endpoint/#contract attributes match the values in wcfstorm.
Load the modified app.config to WCFStorm [using the Client Config toobar button].
Invoke the method. This time the method invocation will no longer fail
Item (1) last bullet in effect means to remove the namespace prefix that VS prepends to the endpoint contract attribute, by default "ServiceReference1"
<endpoint ... contract="ServiceReference1.ListsService" ... />
so in the app.config that you load into WCFStorm you want for ListsService:
<endpoint ... contract="ListsService" ... />
I needed the following bindings to get mine to work:
<binding name="SI_PurchaseRequisition_ISBindingSSL">
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType="None" realm="" />
</security>
</binding>
wsHttpBinding is a problem because silverlight doesn't support it!
I've added a "Connected Service" to our project by Visual Studio which generated a default method to create Client.
var client = new MyWebService.Client(MyWebService.Client.EndpointConfiguration.MyPort, _endpointUrl);
This constructor inherits ClientBase and behind the scene is creating Binding by using its own method Client.GetBindingForEndpoint(endpointConfiguration):
public Client(EndpointConfiguration endpointConfiguration, string remoteAddress) :
base(Client.GetBindingForEndpoint(endpointConfiguration),
new System.ServiceModel.EndpointAddress(remoteAddress))
This method has different settings for https service and http service.
When you want get data from http, you should use TransportCredentialOnly:
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.TransportCredentialOnly;
For https you should use Transport:
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport;
In my case in web.config I had to change binding="basicHttpsBinding" to binding="basicHttpBinding" in the endpoint definition and copy the relative bindingConfiguration to basicHttpBinding section
<!-- Binding settings for HTTPS endpoint -->
<binding name="yourServiceName">
<security mode="Transport">
<transport clientCredentialType="None" />
<!-- Don't use message -->
</security>
</binding>
My solution, having encountered the same error message, was even simpler than the ones above, I just updated the to basicHttpsBinding>
<bindings>
<basicHttpsBinding>
<binding name="ShipServiceSoap" maxBufferPoolSize="512000" maxReceivedMessageSize="512000" />
</basicHttpsBinding>
</bindings>
And the same in the section below:
<client>
<endpoint address="https://s.asmx" binding="basicHttpsBinding" bindingConfiguration="ShipServiceSoap" contract="..ServiceSoap" name="ShipServiceSoap" />
</client>