Silverlight 4.0 - Calling Secured WCF 4.0 Service hosted with SSL and Self-Signed Certificate

Posted by: Mahesh Sabnis , on 10/12/2010, in Category Silverlight 2, 3, 4 and 5
Views: 37641
Abstract: In this article, I have explained the procedure of creating a Web Site with SSL enabled and configuring self-signed certificate. I then explain how to create WCF Services with Custom Binding and then consume the secured WCF service using Silverlight 4
While developing Silverlight 4 (SL 4) Line-of-Business (LOB) applications, it is recommended to use WCF services while dealing with data. However what if that WCF is configured with SSL using self-signed certificates? If it is the case, then there some important configurations recommended to be followed as mentioned below:
·         Use custom binding on the WCF service.
·         Enable HttpsTransport for Transport security using SSL.
·         Enable BinaryMessageEncoding for binary communication.
In this article, I have used IIS 7.5 on Windows Server 2008 R2 where a new Web site is created using Self-Signed certificate. To help you understand the entire process, in the following steps, I have first explained the procedure of creating a Web Site with SSL enabled and configuring self-signed certificate.
Creating Web Site and Self signed certificate
 
Step 1: Open IIS and right click on ‘Application Pools’ and select ‘Add Application Pool’. Name it as ‘SSLTestPool’ and set the framework to .NET Framework 4.0 as shown below:
iimage_4
Step 2: Right click on the newly created application pool and select ‘Advanced Settings’, from the ‘Process Model’. Change the ‘Identity’ to the ‘Local System’ as shown below:
image_1
Step 3: To create a new Web Site, right click on Sites and ‘Add Web Site’ as shown below, for the newly created pool:
image_2
Step 4: Since the above site is used for SSL, we need to create a self signed certificate. Go to the root of the IIS (sites) and from the features view, select the ‘Server Certificate’ as shown below:
image_3
Then from the ‘Server Certificate’ right click and select ‘Create Self-Signed Certificate’ as shown below:
image_4
Finally, create the certificate as shown below:
image_5
Step 5: After creating the certificate, we need to configure it for HTTPS communication. To configure, right click on the new web site created and select ‘Edit Bindings’ and add the ‘https’ binding as below:
image_1
Now assign the self-signed certificate:
image_2
This completes the process of creating a web site with SSL.
Creating WCF Service with Custom Binding
 
In this series of steps, the WCF service is created and hosted in the IIS under the web site, created in the above steps.
Step 1: Open VS2010 and create a blank solution, name it as ‘SILV4_WCF_SSL’. To this solution, add a WCF service application and name it as ‘WCF_SampleService’.
Step 2: Rename IService1.cs to ‘IService.cs’ and ‘Service1.Svc’ to ‘Service.Svc’. Right-Click on ‘Service.Svc’ and select ‘View Markup’ and make the following changes.
<%@ ServiceHost Language="C#" Debug="true" Service="WCF_SampleService.Service" CodeBehind="Service.svc.cs" %>
 
Step 3: In the Web.Config file, write the following configuration:
<?xml version="1.0"?>
<configuration>
 
 <system.web>
    <compilation debug="true" targetFramework="4.0" />
 </system.web>
 <system.serviceModel>
    <services>
      <service name="WCF_SampleService.Service" behaviorConfiguration="ServBehave">
        <endpoint
           address=""
            binding="customBinding"
            bindingConfiguration="custBind"
            contract="WCF_SampleService.IService"/>
      </service>
    </services>
    <bindings>
      <customBinding>
        <binding name="custBind">
          <binaryMessageEncoding></binaryMessageEncoding>
          <httpsTransport></httpsTransport>
        </binding>
      </customBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServBehave">
          <serviceMetadata httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
 </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
 </system.webServer>
 
</configuration>
 
 
The above file uses ‘Custom Binding’ with ‘HttpsTransport’. This enables secure and encrypted communication from the client application over SSL.
Step 4: Open ‘IService1.cs’ and write following ServiceContract, OperationContract and DataContract.
C#
using System.Runtime.Serialization;
using System.ServiceModel;
 
namespace WCF_SampleService
{
    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        clsPerson[] GetAllPerson();
    }
 
    [DataContract]
    public class clsPerson
    {
        [DataMember]
        public int PersonId { get; set; }
        [DataMember]
        public string PersonName { get; set; }
        [DataMember]
        public int Age { get; set; }
    }
}
 
VB.NET (Converted Code)
Imports System.Runtime.Serialization
Imports System.ServiceModel
 
Namespace WCF_SampleService
      <ServiceContract>
      Public Interface IService
            <OperationContract>
            Function GetAllPerson() As clsPerson()
      End Interface
 
      <DataContract>
      Public Class clsPerson
            <DataMember>
            Public Property PersonId() As Integer
            <DataMember>
            Public Property PersonName() As String
            <DataMember>
            Public Property Age() As Integer
      End Class
End Namespace
 
Step 5: Implement the ‘IService’ interface in ‘Service’ class as below:
C#
 
namespace WCF_SampleService
{
    public class Service: IService
    {
        public clsPerson[] GetAllPerson()
        {
            return new clsPerson[]
            {
                new clsPerson() {PersonId=101,PersonName="Tejas",Age=6},
                new clsPerson() {PersonId=102,PersonName="Mahesh",Age=34},
                new clsPerson() {PersonId=103,PersonName="Ramesh",Age=61},
                new clsPerson() {PersonId=104,PersonName="Ram",Age=90},
            };
        }
    }
}
 
VB.NET (Converted Code)
Namespace WCF_SampleService
      Public Class Service
            Implements IService
            Public Function GetAllPerson() As clsPerson()
                  Return New clsPerson() { New clsPerson() With {.PersonId=101, .PersonName="Tejas", .Age=6}, New clsPerson() With {.PersonId=102, .PersonName="Mahesh", .Age=34}, New clsPerson() With {.PersonId=103, .PersonName="Ramesh", .Age=61}, New clsPerson() With {.PersonId=104, .PersonName="Ram", .Age=90} }
            End Function
      End Class
End Namespace
Step 6: Now the service needs to hosted on the Web Server (IIS). Right-click on the WCF service project and select the ‘Web’ tab and specify the web server as shown below:
image_3
Make sure that, you specify the machine name instead of ‘localHost’. This is important because the certificate will generate a warning if you use localhost and your application will not be able to communicate with the service. After clicking ‘Create Virtual Directory’, the virtual directory will be created under the web site.
Step 7: Go to IIS and select the virtual directory created, browse the Service.svc file the following result will be displayed:
iiimage_1
Once you get the above result, it means that the service is successfully hosted using SSL.
One important thing to note here is that to establish a communication between Silverlight and WCF or any other web service, the root of the Web Site (on IIS) must have ‘clientaccesspolicy.xml’ for cross-domain access.
 
Consuming the Secured WCF service in Silverlight 4.0 application
 
Step 1: In the same solution, add a new SL 4.0 application, name it as ‘SILV4_Client_SSL’.
Step 2: In the Silverlight application, right click on the ‘References’ and add the reference of the WCF service using the ‘https’ url as shown below:
iimage_1
The above screen-shots shows the certification security alert while adding reference.
Once the reference is added, the Silverlight project will have the auto generated ‘ServiceReferences.ClientConfig’ with custom binding as shwb below:
Note: Makes sure the endpoint address has the machine name instead of ‘localhost’.
<configuration>
    <system.serviceModel>
        <bindings>
            <customBinding>
                <binding name="CustomBinding_IService">
                    <binaryMessageEncoding />
                    <httpsTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
                </binding>
            </customBinding>
        </bindings>
        <client>
            <endpoint address="https://mahesh-server.mithilla.com/WCF_SampleService_SSL/Service.svc"
                binding="customBinding" bindingConfiguration="CustomBinding_IService"
                contract="MyRef.IService" name="CustomBinding_IService" />
        </client>
    </system.serviceModel>
</configuration>
 
Step 3: Open MainPage.Xaml and write the following XAML:
<Grid x:Name="LayoutRoot" Background="White">
    <TextBlock Height="48" HorizontalAlignment="Left" Margin="20,11,0,0" Name="textBlock1" Text="Personal Information" VerticalAlignment="Top" Width="356" TextAlignment="Center" FontSize="32" />
    <sdk:DataGrid AutoGenerateColumns="True"
                    Height="215" HorizontalAlignment="Left"
                    Margin="21,63,0,0" Name="dgPerson" VerticalAlignment="Top" Width="364" />
    <Button Content="Get Person Details" Height="32" HorizontalAlignment="Left" Margin="90,296,0,0" Name="brntGetPerson" VerticalAlignment="Top" Width="139" Click="brntGetPerson_Click" />
</Grid>
 
iimage_2
Step 4: In the ‘Get Person Details’ button click event,  write the following code to make a call to the WCF service. This code will be successfully executed if the ‘ClientAccessPolicy.xml’ is on the root of the Web Site and the certificate is valid.
C#
private void brntGetPerson_Click(object sender, RoutedEventArgs e)
{
    MyRef.ServiceClient proxy;
    proxy = new MyRef.ServiceClient();
    proxy.GetAllPersonCompleted += new EventHandler<MyRef.GetAllPersonCompletedEventArgs>(Proxy_GetAllPersonCompleted);
    proxy.GetAllPersonAsync();
}
 
void Proxy_GetAllPersonCompleted(object sender, MyRef.GetAllPersonCompletedEventArgs e)
{
    dgPerson.ItemsSource = e.Result; 
}
VB.NET (Converted Code)
Private Sub brntGetPerson_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
      Dim proxy As MyRef.ServiceClient
      proxy = New MyRef.ServiceClient()
      AddHandler proxy.GetAllPersonCompleted, AddressOf Proxy_GetAllPersonCompleted
      proxy.GetAllPersonAsync()
End Sub
 
Private Sub Proxy_GetAllPersonCompleted(ByVal sender As Object, ByVal e As MyRef.GetAllPersonCompletedEventArgs)
      dgPerson.ItemsSource = e.Result
End Sub
Step 5: Run the application, click on the ‘Get Person Details’ button and the following result should be displayed.
iimage_3
Conclusion: For the next-gen LOB application development, smooth secure communication over SSL can be an excellent proven mechanism.  
The entire source code of this article can be downloaded over here
Give a +1 to this article if you think it was well written. Thanks!
Recommended Articles


Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by FrustratedWithSilverlight on Friday, October 29, 2010 3:35 PM
This is exactly what we're looking to do.. when trying to hit the WCF service over SSL and using the "UserNameOverTransport" security method we're receiving the following message:

"An error occurred while trying to make a request to URI 'https://portalapps.centurion.local/Deals.svc'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details."

my crossdomain policy file looks like:

  <?xml version="1.0" encoding="utf-8" ?>
- <access-policy>
- <cross-domain-access>
- <policy>
- <allow-from http-request-headers="SOAPAction">
  <domain uri="http://*" />
  <domain uri="https://*" />
  </allow-from>
- <grant-to>
  <resource include-subpaths="false" path="/" />
  </grant-to>
  </policy>
  </cross-domain-access>
  </access-policy>

Any ideas?
Comment posted by kourosh Saleh on Tuesday, November 2, 2010 10:08 AM
Hi and thank you a lot for this amazing article.

I have downloaded the code but when I open it in VS 2010 it says
the local IIS url https://mahes-server/wcf_sampleservice_ssl specified for web project wcf_sampleService has not been configured.In order to open this project the virtual directory needs to be configured. would you like to create the virtual directory now?
I click on Yes and then says creation of virtual directory https://mah..... failed with the error: could not find the server "https://mahes-server" on the local machine. make sure the local iis server has been configured to support secure communication.
what must i do now? please help thank you again.
Comment posted by Greg Farquhar on Monday, November 15, 2010 4:50 PM
I am having the same issue here. My webservice is hosted with SSL and self signed certificate. My website only works with SSL. If I do not access my website via https I get the same error. Attempting to use a crossdomain policy file is not helping.
Comment posted by JR on Friday, November 19, 2010 12:08 PM
Great article. Thank you so much for posting. This was a life saver.

Everything works for me except the last step when talking from the client to the server.
I get the same error message as @FrustratedWithSilverlight.

It all works but the proxy throws an error. I will keep trying and post here if I figure out.

Thanks again.
Comment posted by Mahesh Sabnis on Tuesday, November 23, 2010 2:01 AM
Hi, kourosh Saleh, sorry for the delayed reply,
mahesh-server is my machine name, you need to use your machine name there. Make sure that you have an application pool targetting to ASP.NET 4.0. Make sure that clientassesspolicy.xml file shold be there on the root of this web site. Update the Service reference in the silverlight client application. If the ServiceReference.config file use http://localhost then replace it with your machine name. It will work.

Thanks
Mahesh Sabnis
Comment posted by Mahesh Sabnis on Tuesday, November 23, 2010 2:05 AM
Hi,
FrustratedWithSilverligh, Greg Farquhar,
Can you please try the file below
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="http://*"/>
        <domain uri="https://*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>
Thanks
Comment posted by Viral Panchal on Wednesday, December 1, 2010 11:01 PM
Hi,
I get error of cross domain. I have implemented as per the post.
Can u help me for the same.
Is there any settings required in iis or os?
Thanks
Comment posted by Mahesh Sabnis on Saturday, December 18, 2010 12:38 AM
Hi,
  Can ypu please check proxy settings on the Web Browser from Tools-Internet Options->Comectivity->LAN Settings. If you have them, just deactivate it. The call should work.

Thanks
Mahesh Sabnis
Comment posted by Umair on Thursday, January 13, 2011 11:07 AM
Thanks man, it was very much needed for me. i was working for around 20Hrs to find solution for this and your solution worked.
Comment posted by Jonathan Verwilghen on Thursday, January 20, 2011 5:45 AM
I Had the cross domain error aswell and I had it because the .xml files were in the wrong place.
My service was hosted on:
https://be-czc9453797.be.deloitte.com/WCF_SampleService_SSL/Service.svc
And i placed the xml's in the physical path of: https://be-czc9453797.contoso.com/WCF_SampleService_SSL/
Which was wrong! it should be the physical path of: https://be-czc9453797.contoso.com/
basically the root of where your website is hosted in the IIS.
Hope this solves something for someone with the same issue
Comment posted by webchetan on Monday, January 31, 2011 11:48 AM
Thank you all. I will try this at home. I was getting the same proxy and cross domain error. I hope the answers above solve the issues. Thank you all!
Comment posted by david choi on Tuesday, February 1, 2011 3:22 PM
Great article. One question you have no endpoint on your config. How are you setting up the proxy on the client?
Comment posted by Chandresh Makwana on Sunday, June 19, 2011 3:18 PM
Hello,

I appreciate this article. However, my problem is about invoking the Silverlight application in Out of browser mode, with elevated permissions. This is required, as my Silverlight application accesses the local hardware resource (Serial port, particularly). Hence, it needs to be an OOB with elevated trusts applied. However, in OOB mode, I am unable to access the WCF service that is exposed over HTTPS channel. If you enhance the above solution to have Silverlight application with OOB mode checked with elevated permissions applied, then the call to the WCF method always throws an exception - NotFound. Just let me know if that is true in your case. If it successfully executes, then can you please send me the same code ? Also note that there are no cross domain calls, as the hosting web site is on the same machine.

Thanks in advance.

Chandresh.
Comment posted by Dubisek on Wednesday, August 10, 2011 8:26 AM
For all who have problem with clientaccesspolicy.xml!!
Correct version for this project is:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="http://*"/>
        <domain uri="https://*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

This XML file must be placed to root folder of ISS web site. If your website is located in C:\MyPath as in this example, the secure policy file must be placed there --> C:\MyPath\clientaccesspolicy.xml. It is very important.

Dont forget set "Require SSL" and Client certificates -> Accept in SSL Setting of your WebSite!!

Hope that it will be useful for you, have a nice day :-)
Comment posted by Bijayece on Monday, June 25, 2012 6:27 AM
Hi Mahesh,
I have created the WCF service as per your instruction and it is working fine when i am accessing the Service with HTTPS.

Getting the below exception if i checked "Require SSL" checkbox in IIS and then sccess the WCF service with HTTPS. Will you please help on this

"Could not find a base address that matches scheme http for the endpoint with binding CustomBinding. Registered base address schemes are [https]"

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: Could not find a base address that matches scheme http for the endpoint with binding CustomBinding. Registered base address schemes are [https].

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.  

Stack Trace:


[InvalidOperationException: Could not find a base address that matches scheme http for the endpoint with binding CustomBinding. Registered base address schemes are [https].]
   System.ServiceModel.ServiceHostBase.MakeAbsoluteUri(Uri relativeOrAbsoluteUri, Binding binding, UriSchemeKeyedCollection baseAddresses) +12349612
   System.ServiceModel.Description.ConfigLoader.LoadServiceDescription(ServiceHostBase host, ServiceDescription description, ServiceElement serviceElement, Action`1 addBaseAddress) +12346965
   System.ServiceModel.ServiceHostBase.LoadConfigurationSectionInternal(ConfigLoader configLoader, ServiceDescription description, ServiceElement serviceSection) +67
   System.ServiceModel.ServiceHostBase.ApplyConfiguration() +108
   System.ServiceModel.ServiceHostBase.InitializeDescription(UriSchemeKeyedCollection baseAddresses) +192
   System.ServiceModel.ServiceHost.InitializeDescription(Type serviceType, UriSchemeKeyedCollection baseAddresses) +49
   System.ServiceModel.ServiceHost..ctor(Type serviceType, Uri[] baseAddresses) +151
   System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(Type serviceType, Uri[] baseAddresses) +30
   System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(String constructorString, Uri[] baseAddresses) +422
   System.ServiceModel.HostingManager.CreateService(String normalizedVirtualPath) +1461
   System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +44
   System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +651

[ServiceActivationException: The service '/HTTPS_Exp.Web/MathService.svc' cannot be activated due to an exception during compilation.  The exception message is: Could not find a base address that matches scheme http for the endpoint with binding CustomBinding. Registered base address schemes are [https]..]
   System.Runtime.AsyncResult.End(IAsyncResult result) +688590
   System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +190
   System.ServiceModel.Activation.ServiceHttpHandler.EndProcessRequest(IAsyncResult result) +6
   System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +96

If possible please provide a sample WCF service with HTTPS and "Require SSL" ON

Thanking you adv

Thanks,
Bijay.
Comment posted by Praveen Kumar on Friday, May 31, 2013 4:27 AM
I agree with Bijay.
If possible please provide a sample wcf service with HTTPS and SSL on.

Thanks,
Praveen Kumar
Comment posted by Thomas Hagström on Friday, November 22, 2013 4:25 AM
Ran in to some gotchas setting this up (Win8). Mostly because of WCF services not being enabled in IIS. Fixed using this article:
http://stackoverflow.com/questions/15688930/could-not-load-type-system-servicemodel-activation-httpmodule-from-assembly-s

I prefere putting up the acutal service codeless in my ASP.NET site, using the WcfService project's reference. This is in my ASP.NET site, where WCFService is my WCF project:
<%@ ServiceHost Language="C#" Debug="true" Service="HLI.IntraNodes.WcfService.Service1, HLI.IntraNodes.WcfService, version=1.0.0.0, culturePublicKeyToken=e70043076d86709c" %>

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel