Creating a WCF service and Silverlight client that work together seems like a fairly common requirement. You would probably also require username/password and HTTPS. And it would be best if your development bindings were similar to deployment bindings. Here is what I used:
- Visual Studio 2010, .NET 4.0
- Windows 7
- IIS 7
- Make sure you have IIS and the "IIS Metabase and IIS6 configuration compatibility" installed.
- Run Visual Studio as an Administrator so that you can access IIS configuration features from within Visual Studio.
- Create a new WCF Service Application.
- Change the debug options on the Project Properties, Web tab to Use Local IIS Web Server.
- Press the Create a Virtual Directory button.
- Test that your service provides metadata. (http://localhost/WcfService1/Service1.svc?wsdl)
- Optional: Enable directory browsing on your virtual directory.
- Setup IIS, IE, and Visual Studio for HTTPS.
- In Internet Information Server (IIS) Manager, select the local computer and the "Server Certificates."
- Create a Self-Signed Certificate.
- On the web site (not the virtual directory), add a binding for HTTPS and test that it works. (https://localhost/WcfService1/Service1.svc)
- In Internet Explorer, install the self-signed certificate, placing the certificate in the Trusted Root Certification Authorities.
- Change the WCF project's Project URL to use https and the machine name, instead of http and the localhost. (https://mishael/WcfService1)
- Test that Visual Studio can launch the web service view in Internet Explorer without a certificate error.
- Create a new Silverlight Application.
- Add a Service Reference to the WCF service.
- Add a button that calls the WCF service.
int counter = 0; private void button1_Click(object sender, RoutedEventArgs e) { var c = new Service1Client(); c.GetDataCompleted += c_GetDataCompleted; c.GetDataAsync(++counter); } void c_GetDataCompleted(object sender, GetDataCompletedEventArgs e) { if (e.Error != null) textBlock1.Text = e.Error.Message; else textBlock1.Text = e.Result; } - Edit the generated ServiceReferences.ClientConfig to use https instead of http.
- Edit the generated ServiceReferences.ClientConfig to use security mode of Transport.
security mode="Transport"
- Using the WCF Service Configuration Tool, update the WCF service as follows:
- Create a new service, with the endpoint address pointing to the services.
- Create a New Binding Configuration for basicHttpBinding. On the Security tab, change the mode to Transport.
- Use the new binding configuration for the service endpoint. It will be something like this:
- Testing the service endpoint with Internet Explorer (https://mishael/WcfService1/Service1.svc) reveals that there is an issue with multipleSiteBindingsEnabled. Comment out the multipleSiteBindingsEnabled attribute in the web.config.
- Test that the Silverlight app can successfully communicate with the WCF service using HTTPS, including stopping at breakpoints in both the Silverlight client and WCF service.
- Enable client username and password authentication as follows:
- In the Web.config, switch the security from "Transport" to "TransportWithMessageCredential". and a client message credential type of "UserName".
- In the ServiceReferences.ClientConfig, switch the security from "Transport" to "TransportWithMessageCredential".
- Define a UserNamePasswordValidator class to do the username and password validation. (The base class UserNamePasswordValidator is in System.IdentifyModel.dll.)
namespace WcfService1 { public class MyUserNamePasswordValidator: UserNamePasswordValidator { public override void Validate(string userName, string password) { if (userName == "Wally" && password == "password") return; throw new SecurityTokenValidationException("Unrecognized user."); } } } - Update the service behavior to use the new UserNamePasswordValidator class.
- Update the Silverlight client code set a username and password.
var c = new Service1Client(); c.ClientCredentials.UserName.UserName = "Wally"; c.ClientCredentials.UserName.Password = "password";
- Using breakpoints, verify that the UserNamePasswordValidator class is being called.
- In your WCF operation, throw a FaultException. Testing will reveal that on the client, all you get is a CommunicationException. Improve the availability of exception messages sent to the client as follows:
- Update the Web.config to includeExceptionDetailInFaults.
serviceDebug includeExceptionDetailInFaults="true"
- Create a BehaviorExtensionElement class using the code here.
- Update the Web.config to include this behavior extension.
- Update the Web.config to add the extension to the endpoint behavior.
- Update the Web.config to use this behavior for your endpoint.
behaviorConfiguration="SilverlightFaultBehavior"