Ideas and thoughts about Microsoft Identity, C# development, cabbages and kings and random flotsam on the incoming tide
Thursday, March 30, 2017
WCF : Calling an async. method
There was a legacy host that only understood SOAP and a modern back-end that only supported REST web API.
So we need a bridge between them and I had to remember everything I had ever forgotten about WCF.
I needed my WCF method to call:
string response = await my_api.CallREST(parameter);
The problem is that the compiler expects the method to be decorated with async.
Aync. WCF?
Turns out you can.
My method looks like:
public async Task<validateresponse> ValidateParameter (parameter)
... and similarly for the interface.
And it works!
The word "async" doesn't appear anywhere is the WSDL. It appears to be completely ignored.
Enjoy!
Wednesday, February 26, 2014
WCF : The page you are requesting cannot be served because of the extension configuration
Trying to access a svc URL and get:
"The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map."
The solution is:
Server Manager --> Add roles and features --> Features --> .NET Framework 4.5 Features --> WCF Services --> enable HTTP Activation.
Enjoy!
Friday, August 09, 2013
WCF : The request for security token could not be satisfied because authentication failed
In full:
System.ServiceModel.Security.SecurityNegotiationException The caller was not authenticated by the service. System.ServiceModel.FaultException: The request for security token could not be satisfied because authentication failed.
I see this when the WS call is cross domain on wsHttpBinding.
Quick and dirty is to remove the security (or move to basicHttpBinding).
Not recommended on a Production system but to get over the hump …
On the client side change:
<wsHttpBinding>
<binding name="WSHttpBinding_IService" >
<security mode="None" />
</binding>
</wsHttpBinding>
On the WS side change:
<system.serviceModel>
<services>
<service name=xxx">
<endpoint address="" binding="wsHttpBinding" contract="WcfServiceLibrary.IService" bindingConfiguration="NoSecurityConfig">
<identity>
<dns value="yyy" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="NoSecurityConfig">
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
Essentially, the changes are to add the “security mode = None” and to add the new bindingConfiguration ="NoSecurityConfig" and then specify the binding for it.
Enjoy!
Monday, April 29, 2013
WCF : Different flavours of ADFS
Playing around with the active profile in ADFS – quite a different beast to the passive one!
There are essentially two WCF flavours viz.
1) A simple WCF connection protected by ADFS with hard-coded credentials e.g.
ServiceClient sc = new ServiceClient(); if (sc.ClientCredentials != null) { sc.ClientCredentials.SupportInteractive = false; sc.ClientCredentials.UserName.UserName = "user"; sc.ClientCredentials.UserName.Password = "password"; }
In this case, the claim will always have the same information; the configured attributes for the hard coded user.
2) Using the WCF web service in a an “ActAs” scenario.
There are examples of this in the Training Kit and the WIF SDK (note we are talking WIF 1.0 here). These invariably use the CreateChannelActingAs method.
Dominick has a slightly different approach – refer Requesting Delegation (ActAs) Tokens using WSTrustChannel (as opposed to Configuration Madness).
Here the WCF claim will have the attributes of the logged-in user i.e.
The application is protected by ADFS using the passive profile. The user logins to the application in the normal manner. The application calls a WCF web service using the active profile using ActAs.
This possibly offers another level of security.
Assume the web service is:
DoSomething (string userName).
With the first flavour, you have to pass the user name since the claim is of no use. However, with the second flavour, you can simply call:
DoSomething ()
and get the userName from the claim.
Of course, that does somewhat muddy the water if you want to call the web service from something like Java but that’s another story.
Enjoy!
Friday, April 26, 2013
ADFS : WCF web service
Been playing with ADFS and WCF. There’s tons of stuff about the passive scenario but very little useful information about the active one. Actually, that’s not true . There is lots on the active profile – sadly, most of it is rubbish.
I read Dominick’s posts a few times – starting with WIF, ADFS 2 and WCF–Part 1: Overview. There’s six parts. Some of my code comes from there. There’s a link to all the code at the end of Part 2.
This is what I did in VS 2010 / WIF 1.0.
Create a WCF service in WCF – the standard IService1 / Service1.
Add a ViewClaim class:
using System.Runtime.Serialization;
namespace ADFSWcfServiceLibrary
{
[DataContract]
public class ViewClaim
{
[DataMember]
public string ClaimType { get; set; }
[DataMember]
public string Value { get; set; }
[DataMember]
public string Issuer { get; set; }
[DataMember]
public string OriginalIssuer { get; set; }
}
}
The usual contracts:
[OperationContract]
List<ViewClaim> GetClaims();
public List<ViewClaim> GetClaims()
{
var id = Thread.CurrentPrincipal.Identity as IClaimsIdentity;
return (from c in id.Claims
select new ViewClaim
{
ClaimType = c.ClaimType,
Value = c.Value,
Issuer = c.Issuer,
OriginalIssuer = c.OriginalIssuer
}).ToList();
}
Run it up with F5. It starts up the test tool – you’'ll get a null object because there aren’t any claims.
Publish this to IIS 7.5. (IIS needs SSL). Use the file option and stick it somewhere. If you look in the directory where you published it, you’ll see a .svc file. If you navigate to the .svc file via the browser you’ll get the standard:
“You have created a service.
To test this service, you will need to create a client and use it to call the service. You can do this using the svcutil.exe tool from the command line with the following syntax:”.
I use IIS 7.5 because Cassini (the internal VS web server) is rubbish with https which ADFS relies on.
Now run FedUtil. Point to the web.config in the directory where you published it and use the .svc address for the website. Use http for the address. Use your ADFS as the existing STS.
At this point, you can’t use the WCF test tool any more. You need to create a client.
What I do now is use something like WinMerge to compare my project with the directory where the project was published.
I copy all the FederationMetadata back and copy the file web.config to the project app.config.
Now I have an updated project.
Add the published web service to ADFS as an RP. You should be able just to point to the metadata using https. Configure some claims.
Now add a command line project to your solution. Make it the Startup Project.
Add the web service as a service reference.
Add something like this to Program.cs
try
{
ServiceClient sc = new ServiceClient();
if (sc.ClientCredentials != null)
{
sc.ClientCredentials.SupportInteractive = false;
sc.ClientCredentials.UserName.UserName = "user";
sc.ClientCredentials.UserName.Password = "password";
}
ViewClaim[] vc = sc.GetClaims();
foreach (var viewClaim in vc)
{
Console.WriteLine(viewClaim.ClaimType = " " + viewClaim.Value);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + " Inner = " + ex.InnerException);
}
Console.ReadKey();
The sc.ClientCredentials.SupportInteractive = false; is to get rid of CardSpace.
Look at the app.config for the command line program. You’ll see a whole lot of commented out services e.g.
<issuedTokenParameters>
<issuer address=https://xxx/adfs/services/trust/2005/usernamemixed bindingConfiguration=https://xxx/adfs/services/trust/2005/usernamemixed
binding="wsHttpBinding" />
By default, it’s set up to use services/trust/2005/certificatemixed under the WS2007FederationHttpBinding_IService binding.
Choose the binding you want and overwrite the certificatemixed entry with the one you want.
For the above code, I selected services/trust/2005/usernamemixed.
Run it – you should get the claims for the user you hard coded in sc.ClientCredentials.
Enjoy!
Wednesday, December 19, 2012
WCF : Missing WCF .svc file in project
I created a WCF project in VS 2010 in the normal manner but when I wanted to connect to it, I found that the .svc file was missing?
WTF?
So I published the project to a folder. Lo and behold, the .svc file appeared in all its glory!
I then added this folder as an application to IIS 7.5 and all was sweetness and light.
Enjoy!
Thursday, March 08, 2012
WCF : Message logging
The best developer tool is Google. 99 % of the time you can find an answer or sample code to your problem.
On the other hand, the worst developer tool is Google. At least half the links are rubbish. There should be some kind of peer review like stackoverflow has to delete crap articles from the Web.
This came about because I was looking for a way to log the actual messages being sent over WCF.
Came across loads of articles, none of which worked 100%. Some were misleading and some were absolute rubbish.
The worst aspect was that they include some small XML snippet which you cut and paste into the web.config without any context i.e. just where are you supposed to insert it?
Anyway, here’s the solution I came up with:
<configuration>
...
</system.serviceModel>
<diagnostics>
<messageLogging
logEntireMessage="true"
logMalformedMessages="false"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true"
maxMessagesToLog="3000"
maxSizeOfMessageToLog="2000"/>
</diagnostics>
</system.serviceModel>
...
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue=
"Information,ActivityTracing"
propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="messages"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\...\messages.svclog" />
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="C:\...\Trace.svclog"
type="System.Diagnostics.XmlWriterTraceListener"
name="xml" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>
...
<configuration>
Enjoy!
Monday, February 13, 2012
WCF : soapUI error "BadContextToken"
While soapUI is a really useful tool for web service unit testing, it doesn’t work with WCF.
In particular, with the default "wsHttpBinding", you get the message "BadContextToken".
Mr. Google comes back with tons of results about why soapUI doesn’t play nicely with WCF and recommends WCF Storm which looks good but it’s not free.
So a whack of investigation later:
Add the following binding into the <bindings> section of your web.config:
<!-- soapUI -->
<wsHttpBinding>
<binding name="wsHttpBindingNoSecurity">
<security mode="None">
<transport clientCredentialType="None" />
<message establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
Add the following "bindingConfiguration” parameter to your <endpoint> section:
binding="wsHttpBinding" bindingConfiguration="wsHttpBindingNoSecurity"
The WCF service has an endpoint like:
blahblah.svc
For soapUI you need to change this to blahblah.svc?wsdl when you “Add WSDL”.
Once you’ve added the service to soapUI, click the default operation and then click the “WS-A” tab at the bottom.
Click “Enable/disable WS-A addressing”.
Click “Add default wsa:Action”.
Click “Add default wsa:To”.
And (finally) success!
REMEMBER: Every time you change the web.config, you need to right-click the soapUI service and “Update Definition” or F5!
Enjoy!
Tuesday, September 27, 2011
WCF : WCF Test Client “The contract ‘IMetadataExchange’ in client configuration does not match the name in service contract”
Playing around with WCF web services in VS 2010 and .NET Framework 4.
When I run the WCF Test Client across the web service I get the above error. The service still works but there’s an error symbol (a ! in a red circle on the LHS).
Mr. Google to the rescue and you need to change the framework config file here:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config
Comment out the “endpoint” section i.e.
<client>
<!-- <endpoint address="" binding="netTcpRelayBinding" contract="IMetadataExchange" name="sb" /> -->
<metadata>
Problem solved.
Even though it still works, I hate these niggly errors in case I’ve screwed up
Enjoy!
Tuesday, March 29, 2011
WCF : Testing your web service
However, this doesn't work with WCF. It imports the WSDL no problem but doesn't show any methods to test.
You can also direct your browser to the web service e.g.
http://localhost:8000/ServiceModelSamples/Service
and you get a test page starting "You have created a service".
It shows you how to run svcutil on the command line e.g.
svcutil.exe http://localhost:8000/ServiceModelSamples/Service?wsdl
"This will generate a configuration file and a code file that contains the client class. Add the two files to your client application and use the generated client class to call the Service."
But - roll of drums and enter stage left Windows Communication Foundation (WCF) Test Client (WcfTestClient.exe)
.
"You can also invoke the WCF Test Client (WcfTestClient.exe) outside Visual Studio to test an arbitrary service on the Internet. To locate the tool, go to the following location:
C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\ "
Very neat!
Enjoy!
Thursday, January 13, 2011
WCF : Could not find default endpoint element that references contract
Built it according to the instructions (using Visual Studio 10 and .NET Framework 4), ran it up and got the following exception:
Could not find default endpoint element that references contract 'ICalculator' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.
A lot of communication with Mr. Google and then came across a comment way down in a blog entry that offered some hope.
To generate the proxies, you run:
svcutil.exe http://localhost/IISHostedCalc/service.svc?wsdl
This generates two files:
CalculatorService.cs
output.config
and you add them to your project using "Add Existing Item".
To get rid of the exception, simply rename "output.config" to "app.config" and ensure it is part of your project.
Enjoy!