Hosting more than 25 WCF services in Azure - wcf

We're running into Azure's limit of 25 internal endpoints with our WCF services. In keeping with SOA principles, our WCF services are fairly small, generally one per "noun" in our system. We are defining one Azure InternalEndpoint per service contract. We now want to add our 26th WCF service but can't because of the limit of 25 endpoints. We really don't want to arbitrarily start combining service contracts simply because of this Azure limitation.
Question: is there a better way to host lots of WCF services that doesn't require one endpoint per service contract?
Here's an example csdef file snippet:
<ServiceDefinition name="MyDeployment" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WorkerRole name="MyWorkerRole" vmsize="Small">
<Endpoints>
<InternalEndpoint protocol="tcp" name="IUserService" />
<InternalEndpoint protocol="tcp" name="IArticleService" />
<InternalEndpoint protocol="tcp" name="IDocumentService" />
<InternalEndpoint protocol="tcp" name="ICommentingService" />
<InternalEndpoint protocol="tcp" name="ILocationService" />
<InternalEndpoint protocol="tcp" name="IAuthorizationService" />
<InternalEndpoint protocol="tcp" name="IAuthenticationService" />
<InternalEndpoint protocol="tcp" name="ILoggingService" />
<InternalEndpoint protocol="tcp" name="IService09" />
<InternalEndpoint protocol="tcp" name="IService10" />
<!-- and so on -->
<InternalEndpoint protocol="tcp" name="IService24" />
<InternalEndpoint protocol="tcp" name="IService25" />
<InternalEndpoint protocol="tcp" name="IServiceWeWantToAddButCannot" />
</Endpoints>
</ServiceDefinition>

As I mentioned in my comment to your question, I don't think you really need all of those InternalEndpoints that you have. You are pairing those one-to-one with your WCF Endpoints. This is probably wrong. Instead, pair them up with your WCF Bindings/Behaviors (i.e. one per port, really). In our case, we have ~250 different WCF Services all going through this one endpoint. Here is 100% of our endpoints from our csdef file:
<Endpoints>
<InputEndpoint name="WcfConnections" protocol="tcp" port="8080" localPort="8080" />
</Endpoints>
(While we use InputEndpoint instead of InternalEndpoint, there should be no difference from this question's perspective.)
That single endpoint is utilized by three different netTcpBindings in our Self-Hosted TCP service application. We also have a Web App version of our TCP services (for easy local dev hosting/testing in IIS) and the bindings we use are:
<bindings>
<netTcpBinding>
<binding name="A" maxBufferPoolSize="5242880" maxBufferSize="5242880" maxReceivedMessageSize="5242880" listenBacklog="100" maxConnections="1000">
<readerQuotas maxDepth="256" maxStringContentLength="16384" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
<binding name="B" maxBufferPoolSize="15728640" maxBufferSize="15728640" maxReceivedMessageSize="15728640" listenBacklog="100" maxConnections="1000">
<!-- 15MB max size -->
<readerQuotas maxDepth="256" maxStringContentLength="15728640" maxArrayLength="15728640" maxBytesPerRead="204800" maxNameTableCharCount="15728640" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
<binding name="C" maxBufferPoolSize="524288" maxBufferSize="524288" maxReceivedMessageSize="524288" listenBacklog="100" maxConnections="1000">
<!-- 0.5MB max size -->
<readerQuotas maxDepth="256" maxStringContentLength="524288" maxArrayLength="524288" maxBytesPerRead="204800" maxNameTableCharCount="524288" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</netTcpBinding>
</bindings>
In the end, as long as you're willing to share multiple services per port (except for some very high-load situations, this should be fine with a proper self-hosting app), then what you're doing is unnecessary.
Perhaps your larger problem and the question you need to learn to ask is, "How can I host multiple services on a single port in a self-hosted WCF app?" If that's the case, check out this code (note, the endpoint object we use in the loop is simply a struct that holds a few key pieces of each WCF endpoint):
// Build up Services
var hosts = new List<ServiceHost>();
foreach (var endpoint in endpoints)
{
var host = new ServiceHost(endpoint.ServiceType, new Uri(string.Format("net.tcp://{0}:{1}", FullyQualifiedHostName, SharedTcpPortNumber)));
hosts.Add(host);
foreach (var behavior in MyBehaviorSettings)
{
if (behavior is ServiceDebugBehavior)
host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = (behavior as ServiceDebugBehavior).IncludeExceptionDetailInFaults;
else
host.Description.Behaviors.Add(behavior);
}
if (endpoint.ServiceContract == null)
throw new Exception();
if (endpoint.ServiceBinding == null)
throw new Exception();
if (endpoint.EndpointUrl == null)
throw new Exception();
if (endpoint.ListenUrl == null)
throw new Exception();
// Add the endpoint for MyService
host.AddServiceEndpoint(endpoint.ServiceContract, endpoint.ServiceBinding, endpoint.EndpointUrl, new Uri(endpoint.ListenUrl));
host.Open();
}

Well I would say that you pushed the SOA "principles" a bit too far, if the end result is something like 25 services. Document service?! ILoggingService?!
There are a few good services that should not really exist as individual entities, because they are something that supports your system but they are not services per se. I would say that you need to changes a few of your services, combine then something like 10 would even be a very big number.
Something like this:
Support
Logging
Document
Localization
Articles
Products
Customers
Authentication
Authorization
Something like that, with 4 services only. I think you're missing the composition aspect.

WCF can host several services on same physycal port.
For example if you register your services to endpoints like:
http:// 145.12.12.23:1000/
Then you will not be able to use same port.
But if you will add to the end for example contract name - you able to register services to such endpoints:
http:// 145.12.12.23:1000/AContract
http:// 145.12.12.23:1000/BContract
http:// 145.12.12.23:1000/CContract
WCF will create proxy that will map each URL to specific host.

Related

Multiple identical HTTP requests in single service call

I have WCF service hosted on IIS 7.5 communicating via HTTP protocol. It is confugured as customBinding, see below. It requires session and it has no protection level yet.
<customBinding>
<binding name="customHttpBinding" openTimeout="00:15:00" sendTimeout="00:15:00" receiveTimeout="00:15:00" closeTimeout="00:15:00">
<reliableSession ordered="false" />
<security requireSignatureConfirmation="false" enableUnsecuredResponse="true" />
<textMessageEncoding messageVersion="Soap12WSAddressingAugust2004" />
<httpTransport maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" />
</binding>
</customBinding>
Client is MS Excel AddIn that on user's purpose call asynchronously 6 different operation contracts. Everything works and looking good until I open Fiddler. There I see multiple identical HTTP requests:
I browsed the content of these identical responses and it really holds identical data. In debug mode I made myself sure that the client calls every operation contract one time only and the service method runs one time only as well.
The question is how to reduce multiple requests?
In the past I have that configured as wsHttpBinding and the data was not requested multiple times but we need a little more control over configuration as it will be deployed on multiple servers.
I don't want to transfer the same data multiple times on the network, in other cases I need to transfer larger data (about hundreds of MB).
UPDATE
According to spodger question, here is client configuration:
<customBinding>
<binding name="customHttpBinding" openTimeout="00:15:00" sendTimeout="00:15:00" receiveTimeout="00:15:00" closeTimeout="00:15:00">
<reliableSession ordered="false" acknowledgementInterval="00:00:30" inactivityTimeout="00:15:00" flowControlEnabled="true" />
<security requireSignatureConfirmation="false" enableUnsecuredResponse="true" />
<textMessageEncoding messageVersion="Soap12WSAddressingAugust2004" />
<httpTransport maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" requestInitializationTimeout="00:10:00" />
</binding>
</customBinding>

How to create a .NET client for a wso2 Secure Token Service

I need to create a .NET client for a wso2 Secure Token Service.
Normally I would create a simple console or WinForm project adding a Service Reference to it. The exposed WSDL would be turned in a set of classes that I can use to query the service and to properly manage its response.
Unfortunately, the generated request and response classes are empty: just the class declaration without any property or method. This is similar to the behaviour described in this other (unanswered) Stack Overflow question https://stackoverflow.com/q/22049080/2131913
I have found a sample request for the service in this forum post: http://cxf.547215.n5.nabble.com/Sample-STS-Client-tp4643980p4664175.html and I made it to work with SOAP UI.
Is there a proper, and possibly automated, way to recreate the complex data structure needed to query the Secure Token Service?
EDIT
OK, after many tries I have reduced the SOAP request from the above forum post to the minimal structure needed to still get a RequestSecurityTokenResponse from the STS service.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-6D35592DCDDA26FFF3141578725699577">
<wsse:Username>USERNAME HERE</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">PASSWORD HERE</wsse:Password>
</wsse:UsernameToken>
<wsu:Timestamp wsu:Id="TS-6D35592DCDDA26FFF3141578725699576">
<wsu:Created>2014-11-12T10:14:16.995Z</wsu:Created>
<wsu:Expires>2014-11-12T10:16:16.995Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
<wsa:Action soap:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT</wsa:Action>
<wsa:MessageID soap:mustUnderstand="1">uuid:6d4eab69-77f9-42b7-8d6b-1f710020fb0b</wsa:MessageID>
<wsa:To soap:mustUnderstand="1">STS ENDPOINT ADDRESS HERE</wsa:To>
</soap:Header>
<soap:Body>
<wst:RequestSecurityToken xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust">
<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType>
<wst:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</wst:TokenType>
<wst:Claims>
<wsid:ClaimType Uri="http://wso2.org/claims/userid" xmlns:wsid="http://schemas.xmlsoap.org/ws/2005/05/identity"/>
</wst:Claims>
</wst:RequestSecurityToken>
</soap:Body>
</soap:Envelope>
I have obtained a partial success defining in the app.config of my project either a single wsHttpBinding like the following:
<wsHttpBinding>
<binding name="SendUsername" messageEncoding="Text">
<security mode ="TransportWithMessageCredential">
<message clientCredentialType ="UserName"/>
<transport clientCredentialType ="Basic" />
</security>
</binding>
</wsHttpBinding>
with or without adding a CustomBinding like the following:
<customBinding>
<binding name="wso2carbon-stsSoap12Binding">
<security defaultAlgorithmSuite="Default" authenticationMode="IssuedToken"
requireDerivedKeys="true" securityHeaderLayout="Lax" includeTimestamp="true">
<localClientSettings detectReplays="false" />
<localServiceSettings detectReplays="false" />
<issuedTokenParameters keyType ="SymmetricKey" tokenType ="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<issuer address =STS ENDPOINT ADDRESS HERE binding ="wsHttpBinding" bindingConfiguration ="SendUsername"/>
<claimTypeRequirements>
<add claimType ="http://wso2.org/claims/userid"/>
</claimTypeRequirements>
</issuedTokenParameters>
</security>
<textMessageEncoding messageVersion="Soap12" />
<httpsTransport />
</binding>
</customBinding>
In both cases however the request throws a timeout exception, and inspecting with WCF tracing the issued request I can see that it is missing the Claims element. Any hints?
Please refer this article
Security Token Service with WSO2 Identity Server 2.0
For more insight on this please refer:
http://wso2.com/library/3190/
Configuring WSO2 Identity Server Passive STS with an ASP.NET
Client
After many days struggling with WCF configuration option I have obtained a partial success.
The key that allows me to obtain a response from the Security Token Service is that I realized that, in the long term, I will need to operate in a federated security scenario. I don't need the token per se, but I need it to obtain a mean to authenticate to other services.
With this option in mind I started to explore what WCF has to offer for this kind of scenario and I built the following configuration options:
<wsFederationHttpBinding>
<binding name="fs">
<security mode="TransportWithMessageCredential">
<message issuedKeyType="SymmetricKey" issuedTokenType ="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<issuer address = <!-- STS address here --> binding ="customBinding" bindingConfiguration ="StsBinding"/>
<claimTypeRequirements>
<add claimType="http://wso2.org/claims/userid" />
</claimTypeRequirements>
</message>
</security>
</binding>
</wsFederationHttpBinding>
The above binding is used to contact the service that needs token authentication while the following adds further instructions about how to contact the security token issuer:
<customBinding>
<binding name="StsBinding">
<textMessageEncoding messageVersion="Soap12WSAddressingAugust2004"/>
<useManagedPresentation/>
<security authenticationMode="UserNameOverTransport" includeTimestamp ="true" keyEntropyMode ="ServerEntropy" securityHeaderLayout ="Lax"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" >
</security>
<httpsTransport authenticationScheme ="Basic"/>
</binding>
</customBinding>
With this configuration, and with the help of Fiddler and WCF trace I can see I get a Security Token Response from the STS issuer.
Howevere as I said, in the beginnig, this was only a partial success because WCF infrastructure, when processing the token, says that it has a wrong action... but this can be the subjet of another question ;-)
I hope this can be considered a valid answer although my quest for token authentication is not yet concluded

WSDL Generation for WCF Service Behind Load Balancer

The Background:
I have a Service hosted on IIS 7.0 behind a Load Balancer which decrypts SSL as traffic passes through it.
The security mode required of the Service is Mixed-Mode ie TransportWithMessageSecurity
To enable the Service to accept HTTP traffic whilst allowing clients to communicate to the Load Balancer over SSL, I have created a User Defined Binding, which adds a custom HttpTransportBindingElement to its Channel Stack.
The custom HttpTransportBindingElement in turn asserts to the framework that it is capable of Encrypting and Signing messages...therefore the Framework won't complain when traffic comes in through it via HTTP because the Transport is claiming that it is signing/encrypting the messages...even though its not.
(For all those concerned, this has been determined to be acceptable security wise because the message orginally should have arrived over SSL to the Load Balancer...)
The Problem:
When we use svcutil.exe to generate the client proxy, the resulting auto-generated app.config file contains an endpoint to the service which is addressed over HTTP. This should be over HTTPS.
Additionally the <transport> element within the <customBinding> node is defined as a <httpTransport> element when it needs to be a <httpsTransport> element.
I suspect this is because the WSDL which is generated by the framework on the server, is being built with HTTP addresses instead of HTTPS > in turn, as a result of using the custom HttpTransportBindingElement (as explained above).
The auto-generated app.config for the client:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="myBindingEndpoint">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'http://tempuri.org/': -->
<!-- <wsdl:binding name='myBindingEndpoint'> -->
<!-- <sp:HttpToken xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">..</sp:HttpToken> -->
<security defaultAlgorithmSuite="Default" authenticationMode="CertificateOverTransport"
requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true"
keyEntropyMode="CombinedEntropy" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<localClientSettings cacheCookies="true" detectReplays="false"
replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"
replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true"
timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="false" issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"
negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="true" maxPendingSessions="128"
maxCachedCookies="1000" timestampValidityDuration="00:05:00" />
<secureConversationBootstrap />
</security>
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Default" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpTransport 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="http://myserver/GAEASSLWcfService/ServiceOverSSL.svc"
binding="customBinding" bindingConfiguration="myBindingEndpoint"
contract="IServiceOverSSL" name="myBindingEndpoint" />
</client>
</system.serviceModel>
</configuration>
The Work-around:
Simply changing the <httpTransport /> to <httpsTransport /> and re-addressing the endpoints to use HTTPS fixes the issue.
But we'd prefer to not have to instruct our service consumers to change their .config files...the use of our service should be as seemless as possible...
The Question:
How can i ensure the client proxies will generate automatically with the correct Addresses and Transport elements???
References:
For those who want to learn about the solution to the 'service behind a load-balancer/ssl decrypter' and the custom HttpTransportBindingElement, see this post XXX by ZZZ regarding building the user defined binding and also this post XXX by ZZZ regarding some of the other issues with exposing Services behind a Load Balancing/SSL accelerator.
I was having the same problem, my WSDL was generated with the http scheme instead of https behind my load balancer.
I've reflected the WCF code and I found a solution that worked, for me though.
In addition to useRequestHeadersForMetadataAddress, you need to turn httpGetEnabled off and httpsGetEnabled on in the serviceMetadata.
Also, if you're using .net 4 like I think you are, instead of adding a custom HttpTransportBindingElement, just use the standard HttpTransportBindingElement and set AllowInsecureTransport on your TransportSecurityBindingElement.
Check out this question. Try to configure:
<serviceBehaviors>
<behavior name="<name>">
<!-- Other options would go here -->
<useRequestHeadersForMetadataAddress>
<defaultPorts> <!-- Use your own port numbers -->
<add scheme="http" port="81" />
<add scheme="https" port="444" />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>
</serviceBehaviors>

Custom WCF Binding equivalent to WSHttpBinding with WS-Addressing turned off

I am trying to create a WCF service that needs to be consumed by a Java client. Requirements from the Java client is to disable WS-Addressing. I must have to use WSHttpBinding. First of all I am bit new to this. I did some quick search online but was not able to figure out if that is the correct solution. Can somebody please point me to right direction ?
Thanks
Use http://webservices20.cloudapp.net/ for such issues. You did not specify which security you need. One option is
<!-- generated via Yaron Naveh's http://webservices20.blogspot.com/ -->
<customBinding>
<binding name="NewBinding0">
<transactionFlow />
<security authenticationMode="UserNameOverTransport" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" />
<textMessageEncoding messageVersion="Soap12" />
<httpsTransport />
</binding>
</customBinding>
<!-- generated via Yaron Naveh's http://webservices20.blogspot.com/ -->

Silverlight - WCF Enable Binary Encoding

I have a WCF service that is returning a lot of data. I want to compress that information so I thought that using BinaryEncoding would be appropriate.
Currently, I have a binding setup in my web.config as follows:
<binding name="myCustomBinding" closeTimeout="00:05:00" openTimeout="00:05:00"
receiveTimeout="00:05:00" sendTimeout="00:05:00">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="8388608" maxBufferSize="8388608">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpTransport>
</binding>
In my ServiceReferences.clientconfig file, I have the following binding settings:
<binding name="CustomBinding_MyService">
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpTransport>
</binding>
Oddly, this configuration will not work. As soon as I remove the <binaryMessageEncoding /> line from the web.config, everything works fine.
My question is, how do I use binary message encoding? Is there something I need to configure in my ServiceReferences.clientconfig?
Thank you
Can you define "will not work"?
Note that the client and server must agree; Silverlight has only a limited subset of extension points, but it seems that <binaryMessageEncoding/> is supported (source and more info) - so perhaps add it to the client?