Saturday, October 04, 2008

Securing .NET Config Files

As you know, Web.Config and App.Config files are like plain readable XML files. However, it contains sensitive information such as Connection Strings, Impersonation, App Setting Keys and their values. At some point you may need to secure these sections. .NET Framework allows to make your life simple, by just executing few commands on Command Prompt or few clicks using a Enterprise Library Configuration tool, you can achieve the desired result. There is only one basic requirement you should be able to at least remotely login to the Server where you would like to make these thing. Following are few simple steps to secure web.config or app.config.

File: Web.Config using Command Prompt

1. Go to Command Prompt

2. Change Directory to C:\Windows\Microsoft.NET\Framework\v2.0.50727

3. To Encrypt a Section in Web.Cofig -  type following - 

         aspnet_regiis -pef "<CONFIG_SECTION" "<PHYSICAL_PATH>"

        i.e. aspnet_regiis -pef "connectionStrings" “C:\Inetpub\wwwroot\TestWebSite"

        i.e. aspnet_regiis -pef "system.web/identity" “C:\Inetpub\wwwroot\TestWebSite"

4. Go to your website root directory, and create a File AppUser.Aspx and type the following line save it.                

        a. <%@ Page Language="VB" %>

            <% Response.Write( System.Security.Principal.WindowsIdentity.GetCurrent().Name ) %>

        b. Now, open your browser and call this page, this will show you a DOMAIN/UserName under which you website is running. Take a note of it. Now go back to command prompt.

5. Run the following command on command prompt to allow Permission to Users e.g. "NT Authority\Network Service", and the User Your Web Site is using it. run following command

              aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT Authority\Network Service"       

              aspnet_regiis -pa "NetFrameworkConfigurationKey" "DOMAIN/USERNAME"

6. After successful completion of command, remove the AppUser.Aspx file.

7. If you ever want to decrypt the section you encrypted, use following command

              aspnet_regiis -pdf  "<CONFIG_SECTION" "<PHYSICAL_PATH>"

You do not need to make any code change in your application for encryption or decryption, .NET automatically does it for you. 

For more details you can visit http://msdn.microsoft.com/en-us/library/ms998283.aspx

File: App.Config using Command Prompt

So what would you do to encrypt the same in case of App.Config, above command only work for Web.Config. Here is a trick – Copy the contents of App.Config into Web.Config file, or you can rename as web.config. Follow the same instructions as above, and after encryption, copy the file contents or rename it back to App.Config.

Easy Way To Encrypt/Decrypt - Web.Config/App.Config

If you have downloaded and Installed Microsoft Enterprise Library Configuration Tool, just open Web.Config or App.Config and select the section you want to encrypt, Go into Protection à Protection Provider and choose a provider you want (default is none) and save the file, you are done.  BUT,  you may have to follow #4 - #6, if .NET is not able to read encrypted section.

Tuesday, August 12, 2008

Communication with the underlying transaction

If you are using .NET 2.0 or higher Framework and System.Transactions Namespace to handle your transactions, chances are you may come across this error. In my application, I was using ADO.NET transaction, in stored procedure SQL Server transaction and now we decided to use a powerful transaction handler using .NET framework. If you are writing everything fresh, most likely you won’t like to mix different type of transaction handling mechanism. But what if you already have existing code and do not want to change, what to do. I tried to mix all the three kind of transactions, but it resulted in errors. Sometime, they timeout, sometime it just hanged and sometime it produced Microsoft Transaction Coordinator (MSDTC) error. So, how to resolve this problem? After spending several hours I found that one must follow following basic steps.


 

1. Import System.Transactions namespace in the class where you want to use distributed transaction

2. Make sure that this transaction mode is the root or mothers for all other type of transactions

3. Now you can add different type of transactions, it can be ADO.Net transaction, SQL Transaction or another child transaction using System.Transaction Namespace

4. After doing the first 3 steps, make sure you configure your machines with following options, otherwise you will come across the above error.

To fully enable MS DTC:

1. In Control Panel, open Administrative Tools, and then double-click Component Services.

2. In the left pane of Console Root, click Component Services, and then expand Computers.

3. Right-click My Computer, and then click Properties.

4. On the MSDTC tab, click Security Configuration.

5. Under Security Settings, select all of the check boxes.

6. Verify that the DTC Logon Account name is set to NT AUTHORITY\NetworkService.

 

 

 

If MSDTC still does not work then

1. Install MSDTC by going on command prompt and run following command: msdtc –install

2. After that you'll need to actually start the service

3. Make sure to go back in component services and follow the above step to enable MS DTC.

4. Windows Firewall –Make sure C:\Windows\System32\MSDTC.exe is added in Exceptions list of Windows Firewall

 

 

 

       If MSDTC still does not work, reboot the machine.

If you MSDTC still does not work, download the following tool and you can see where it is failing

                  http://www.microsoft.com/downloads/details.aspx?familyid=5E325025-4DCD-4658-A549-1D549AC17644&displaylang=en 

                  You need to make sure that these options are enabled on all participating machines (Web Server, App Server, SQL Server etc)


Example:
 
                 Public Sub MainMethod()
                       Dim tranOptions As New TransactionOptions()
                       tranOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted
                       tranOptions.Timeout = New TimeSpan(0, 2, 0)
                       Using topMostScope As New TransactionScope(TransactionScopeOption.Required, tranOptions)
 
                            Call Method1UsingAdo_Net_Transaction()
                            Call Method2UsingSql_Server_Transaction()
                            Call Method3UsingChildTranScope()
 
                            topMostScope.Complete()
                       End Using
                End Sub
 
 

 

 

Thursday, May 29, 2008

Secure Query String using Symmetric Cryptography

It is important to secure information on the web specially when transferring data from one page to another. Some information you may not want to make it readable by end user. Microsoft .NET provides Cryptography namespace which can be easily utilized for this purpose. The following example contains a simple class containing Encryption and Decryption method. It supports 2 types – DESC and Rijndael. Symmetric type and encryption key can be configured easily through .config file.


Imports System
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography
Imports System.Configuration
 
''' <summary>
''' Custom Encryption Class
''' Author: Vishwa
''' Date :05/28/08
''' Purpose: To Encrypt and Decrypt the Data
''' Design Pattern : Singleton
''' </summary>
''' <remarks>
''' This class implements a Base 64 encryption and decryption Using Symetric
''' IMPT: Config File will contain 2 keys and its value - SymmetricType and SymmetricKey
''' </remarks>
 
Public NotInheritable Class RegCryptographer
    Private Shared _instance As New RegCryptographer
 
#Region "Constructor"
    Private Sub New()
 
    End Sub
#End Region
 
#Region "Public Methods"
 
    Public Shared Function DecryptQueryString(ByVal stringToDecrypt As String) As String
        Return DecryptSymmetric(stringToDecrypt.Replace(" ", "+"))
    End Function
 
    Public Shared Function EncryptQueryString(ByVal stringToEncrypt As String) As String
        Return EncryptSymmetric(stringToEncrypt)
    End Function
 
#End Region
 
#Region "Custom Cryptography"
    Private Shared _key() As Byte = {}
    Private Shared _IV() As Byte = {}
    Private Shared _symmetricKey As String = String.Empty
 
#Region "Rijndael Encryption/Decryption"
    Public Shared Function DecryptSymmetric(ByVal stringToDecrypt As String) As String
        If SymmetricType = "Rijndael" Then
            Return DecryptSymmetricRijndael(stringToDecrypt)
        Else
            Return DecryptSymmetricDESC(stringToDecrypt)
        End If
    End Function
 
    Public Shared Function EncryptSymmetric(ByVal stringToEncrypt As String) As String
        If SymmetricType = "Rijndael" Then
            Return EncryptSymmetricRijndael(stringToEncrypt)
        Else
            Return EncryptSymmetricDESC(stringToEncrypt)
        End If
    End Function
 
    Private Shared Function DecryptSymmetricRijndael(ByVal stringToDecrypt As String) As String
        Try
            Dim inputByteArray(stringToDecrypt.Length) As Byte
            Dim rijndael As New RijndaelManaged()
            rijndael.GenerateIV()
            'rijndael.GenerateKey()
            '_key = rijndael.Key
            _IV = rijndael.IV
 
            rijndael.KeySize = 128
            rijndael.BlockSize = 128
            rijndael.Mode = CipherMode.ECB
            rijndael.Padding = PaddingMode.PKCS7
            _key = System.Text.Encoding.UTF32.GetBytes(SymmetricKey)
            inputByteArray = Convert.FromBase64String(stringToDecrypt)
 
            Dim decryptor As ICryptoTransform = rijndael.CreateDecryptor(_key, _IV)
            Dim msDecrypt As New MemoryStream()
            Dim csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write)
            csDecrypt.Write(inputByteArray, 0, inputByteArray.Length)
            csDecrypt.FlushFinalBlock()
            Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8
            Return encoding.GetString(msDecrypt.ToArray())
        Catch e As Exception
            Return e.Message
        End Try
    End Function
 
    Private Shared Function EncryptSymmetricRijndael(ByVal stringToEncrypt As String) As String
        Try
            Dim rijndael As New RijndaelManaged()
            rijndael.GenerateIV()
            'rijndael.GenerateKey()
            '_key = rijndael.Key
            _IV = rijndael.IV
            _key = System.Text.Encoding.UTF32.GetBytes(SymmetricKey)
 
            rijndael.KeySize = 128
            rijndael.BlockSize = 128
            rijndael.Mode = CipherMode.ECB
            rijndael.Padding = PaddingMode.PKCS7
            Dim encryptor As ICryptoTransform = rijndael.CreateEncryptor(_key, _IV)
            Dim inputByteArray() As Byte = Encoding.UTF8.GetBytes(stringToEncrypt)
            Dim msEncrypt As New MemoryStream()
            Dim csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
            csEncrypt.Write(inputByteArray, 0, inputByteArray.Length)
            csEncrypt.FlushFinalBlock()
            Return Convert.ToBase64String(msEncrypt.ToArray())
        Catch e As Exception
            Return e.Message
        End Try
    End Function
 
#End Region
 
#Region "DESC Encryption/DeCryption"
    Private Shared _symmetricType As String = String.Empty
    Private Shared Function DecryptSymmetricDESC(ByVal stringToDecrypt As String) As String
        Dim inputByteArray(stringToDecrypt.Length) As Byte
        Try
            inputByteArray = Convert.FromBase64String(stringToDecrypt)
            Dim des As New DESCryptoServiceProvider()
            des.GenerateIV()
            _IV = des.IV
            _key = System.Text.Encoding.UTF8.GetBytes(SymmetricKey)
 
            Dim ms As New MemoryStream()
            Dim cs As New CryptoStream(ms, des.CreateDecryptor(_key, _IV), CryptoStreamMode.Write)
            cs.Write(inputByteArray, 0, inputByteArray.Length)
            cs.FlushFinalBlock()
            Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8
            Return encoding.GetString(ms.ToArray())
        Catch e As Exception
            Return e.Message
        End Try
    End Function
 
    Private Shared Function EncryptSymmetricDESC(ByVal stringToEncrypt As String) As String
        Try
            Dim des As New DESCryptoServiceProvider()
            des.GenerateIV()
            _IV = des.IV
            _key = System.Text.Encoding.UTF8.GetBytes(SymmetricKey)
 
            Dim inputByteArray() As Byte = Encoding.UTF8.GetBytes(stringToEncrypt)
            Dim ms As New MemoryStream()
            Dim cs As New CryptoStream(ms, des.CreateEncryptor(_key, _IV), CryptoStreamMode.Write)
            cs.Write(inputByteArray, 0, inputByteArray.Length)
            cs.FlushFinalBlock()
            Return Convert.ToBase64String(ms.ToArray())
        Catch e As Exception
            Return e.Message
        End Try
    End Function
 
 
#End Region
 
#Region "Properties"
   
    Private Shared ReadOnly Property SymmetricType() As String
        Get
            If String.IsNullOrEmpty(_symmetricType) Then
                Try
                   _symmetricType = ConfigurationManager.AppSettings.Item("SymmetricType")
                Catch ex As Exception
                    _symmetricType = "Rijndael"
                End Try
                If String.IsNullOrEmpty(_symmetricType) Then _symmetricType = "Rijndael"
            End If
            Return _symmetricType
        End Get
    End Property
 
 
    Private Shared ReadOnly Property SymmetricKey() As String
        Get
            If String.IsNullOrEmpty(_symmetricKey) Then
                Try
                    _symmetricKey = ConfigurationManager.AppSettings.Item("SymmetricKey")
                Catch ex As Exception
                    _symmetricKey = "DIffTkey"
                End Try
                If String.IsNullOrEmpty(_symmetricKey) Then _symmetricKey = "DIffTkey"
            End If
            Return Left(_symmetricKey, 8)
        End Get
    End Property
 
#End Region
 
#End Region
 
End Class

Friday, April 18, 2008

Error: System.ServiceModel.Channels

Recently I came across interesting error messages while calling a WCF Service Hosted in IIS 6.0 on Windows 2003 Server. From the error message, I could not figure out the real cause. But after doing some research and changing few configuration information and changing the code, it appears that these solutions fixed these errors.

 Errors

System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)     at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)     at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway,  ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)     at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)  at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService( IMethodCallMessage methodCall, ProxyOperationRuntime operation)     at System.ServiceModel.Channels.ServiceChannelProxy.Invoke (IMessage message)    Exception rethrown at [0]:   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage( IMessage reqMsg, IMessage retMsg)     at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) 
 Or
System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)     at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)      at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)     at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)     at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)     at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)    Exception rethrown at [0]:      at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)     at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
Solutions
1.       Increase the default value of maxConcurrentCalls from 16 to 50 and maxConcurrentSessions from 10 to 50. You can increase even higher based on your need.
<serviceBehaviors>
    <behavior name=" ServiceBehavior1">
     <serviceMetadata httpGetEnabled="true" />
     <serviceDebug includeExceptionDetailInFaults="true" />
      <serviceThrottling maxConcurrentCalls="50" maxConcurrentSessions="50"/>     
     <serviceTimeouts />
    </behavior>  
   </serviceBehaviors>
 
2.       Use “Using Block” in Service Client to gracefully dispose the object. Also, explicitly close ChannelFactory and Client.
          Using svcClient As ServiceReference1.Service1Client = New ServiceReference1.Service1Client()
           ' Or  Using svcClient As ServiceReference1.Service1Client = New ServiceReference1.Service1Client("EndPointConfigName", "ServiceRemoteAddress")
            'Do the Service related stuff here
            'Before you end the process explicitly Close Client's ChannelFactory and Client
            'Note: Closing the ChannelFactory Closes Client as well but Closing Client does not close the ChannelFactory
            svcClient.ChannelFactory.Close()
            svcClient.Close()
        End Using

Thursday, April 17, 2008

Error: Could not establish trust relationship for the SSL/TLS secure channel with authority

I got this error when calling a WCF Service over HTTPS. A Similar error can also occurs when you try calling a web service programmatically over SSL (HTTPS) and certificate is either not valid or Certificate is attached to a domain and you are not using the domain name but the machine name or IP address. So, what to do in that case if you don’t care about certificate and would like to accept all certificates. I found that it can be done using one of two ways. 

Main Class – Where you are calling the Web Service, add following Import Statements
Imports System.Security.Cryptography.X509Certificates
Imports System.Net.Security
Imports System.Net
 
Public Class MyWebServiceCall
 
    Public Sub CallServiceUsingFunction()
        'Instanciate the Service here
        'Set all paramaters which you need to pass
        'Before You call the Service
        ServicePointManager.ServerCertificateValidationCallback = AddressOf TrustAllCertificatesCallback
        'Call your service Now.......
    End Sub
 
 
    Public Shared Function TrustAllCertificatesCallback(ByVal sender As Object, ByVal cert As X509Certificate, _
                                                 ByVal chain As X509Chain, ByVal errors As SslPolicyErrors) As Boolean
        Return True
    End Function
    Public Sub CallServiceUsingClass()
        'Instanciate the Service here
        'Set all paramaters which you need to pass
        'Before You call the Service
        Dim CertOverride As New CertificateOverride
        ServicePointManager.ServerCertificateValidationCallback = AddressOf CertOverride.RemoteCertificateValidationCallback
        'Call your service Now.......
    End Sub
End Class
 CertificateOverride Class - An Alternate Option
Public Class CertificateOverride
    Public Function RemoteCertificateValidationCallback(ByVal sender As Object, ByVal certificate As X509Certificate, ByVal chain As X509Chain, _
            ByVal sslPolicyErrors As SslPolicyErrors) As Boolean
        Return True
    End Function
End Class

 

Saturday, April 05, 2008

Make a .NET Component accessible in Classic ASP or VB6

I came across a situation again to use exactly same .NET component as COM component in classic ASP page. I had totally forgotten these steps but finally managed to make it work. Later, I thought to put these steps together on my blog, so that if anyone else also don’t know or forget these steps, this will help.


 

1.       In AssemblyInfo.vb -- Add Following NameSpaces, you will have to add their corresponding references
Imports System.Runtime.InteropServices
Imports System.EnterpriseServices
 
2.       Add Following Assembly Attributes
<Assembly: ApplicationName("AppName")>
<Assembly: ApplicationActivation(ActivationOption.Server)>
<Assembly: ApplicationAccessControl(False, AccessChecksLevel:=AccessChecksLevelOption.ApplicationComponent)>
<Assembly: ComVisible(True)>
 
3.       Make sure AssembyVersionAttribute is set to a static value (i.e. 1.0.0.0 not 1.0.0.*)
<Assembly: AssemblyVersion("1.0.0.0")>
 
4.       Make Sure you class has a Public Default Constructor, thus no singleton design pattern or shared Methods.
 
5.       In Signing tab Check Sign the assembly and give a name for strong name key.
 
6.       Compile your project and create the dll.
 
7.       Go to C:\Windows\Microsoft.NET\Framework\v2.0.50727 folder and then run following command to create and register type library,  on command prompt type appropriate path and dll name
 
>RegAsm <PathName>\ProjectName.dll /tlb /codebase
 
Note: You will get a message that Types Registered Successfully. It will create a .tlb (type library file) in the same folder where your dll exist.
8.       Now you can refer the type library file into your Classic ASP Page.
 
9.     If you change and recompile first unregister by adding a switch /unregister of Command Line Param in #7, If you deploy this component on a different machine, perform the step #7 again on that machine.
 
10.   You are ready to use the .NET component in ASP Page now.
 
If Component reads Web.Config file, then you have to do some extra steps
1. In "bin" folder - Create 2 files
              a. Create "application.manifest" file with following content
                          <?xmlversion="1.0"encoding="UTF-8"standalone="yes"?>
                         <assemblyxmlns="urn:schemas-microsoft-com:asm.v1"manifestVersion="1.0"/>

 

 

                       b. Create "application.config" with needed section(s) from Web.Config

       2.  Go to COM+ package through Component Services

                     a. Add your type library file (.tlb ) in your package

                     b. In Properties of the Package go to "Activation" tab  and  change Application Root Directory to <APP_PATH>\bin


     Working Example:  For example let’s create a Class Library Project – Vishwa.Example.ComTest

File: AssemblyInfo.vb
 Class Name : TestProcess.vb
   1:  Imports System
   2:  Imports System.Reflection
   3:  Imports System.Runtime.InteropServices
   4:  Imports System.EnterpriseServices
   5:   
   6:  #Region "Assembly Attributes"
   7:  <Assembly: AssemblyTitle("Vishwa.Example.ComTest")> 
   8:  <Assembly: AssemblyDescription("")> 
   9:  <Assembly: AssemblyCompany("")> 
  10:  <Assembly: AssemblyProduct("Vishwa.Example.ComTest")> 
  11:  <Assembly: AssemblyCopyright("Copyright © 2008")> 
  12:  <Assembly: AssemblyTrademark("")> 
  13:  <Assembly: ApplicationName("ComTest")> 
  14:  <Assembly: ApplicationActivation(ActivationOption.Server)> 
  15:  <Assembly: ApplicationAccessControl(False, AccessChecksLevel:=AccessChecksLevelOption.ApplicationComponent)> 
  16:  <Assembly: ComVisible(True)> 
  17:  <Assembly: Guid("1e411fb7-d23f-4246-99da-4200e999e030")> 
  18:  <Assembly: AssemblyVersion("1.0.0.0")> 
  19:  <Assembly: AssemblyFileVersion("1.0.0.0")> 
  20:  #End Region
   1:  Public Class TestProcess
   2:   
   3:  #Region "Default Public Constructor"
   4:      Public Sub New()
   5:      End Sub
   6:  #End Region
   7:   
   8:  #Region "Public Methods"
   9:   
  10:      Public Function Add(ByVal value1 As Integer, ByVal value2 As Integer) As Integer
  11:          Return value1 + value2
  12:      End Function
  13:   
  14:  #End Region
  15:   
  16:  End Class

In Order to Test in Classic ASP page
Dim obj: Set obj = Server.CreateObject("Vishwa.Example.ComTest.TestProcess")
Dim returnValue
returnValue = obj.Add(2, 3)
Note: I was not able to see the method name Add in intellicense  but it works.

Tuesday, March 25, 2008

Implementing WCF Service Part 5 - Fault Contract

In WCF, there are five major contracts – Service Contract, Operation Contract, Data Contract, Fault Contract and Message Contract. In my previous examples I used first three. In this example, I will implement the Fault Contract. I am not very fond of using Message Contract as some guidelines suggest using the least or based on requirement, however you cannot get away from the first four contracts. In the event of Fault (exception), WCF throws a fault containing detail error message which you may not like to be passed back to the caller. In other words, this example focuses on how to hide full error details and provide a custom error code, message and details. You can use multiple Fault Contracts on one Operation Contract in similar way. This example provides a simple and generic way to handle Faults.

In order to show this example, I will add or modify following classes.

1.       ErrorResponse Class - New 
<DataContract(Name:="ErrorResponse", Namespace:="http://http://schemas.vishwamohan.net/2008/03/ErrorResponse")> _   
    Public Class ErrorResponse   
 #Region "Public Fields"   
    <DataMember(Name:="Code", Order:=0)> _   
  Public Code As String = "Error"   
  <DataMember(Name:="Message", Order:=1)> _   
   Public Message As String = "Sorry! An exception occured."   
  <DataMember(Name:="Details", Order:=2)> _   
  Public Details As String = "Please contact support."  
 
 #End Region  
#Region "Constructors"  
     Public Sub New()  
    End Sub  
 
  Public Sub New(ByVal code As String, ByVal message As String, ByVal details As String)  
         Me.Code = code  
         Me.Message = message  
         Me.Details = details  
  End Sub  
#End Region  
 
End Class
 
2.       ICustomerService.vb Class – Modifying Existing Operation Contract, by adding Fault Contract
<FaultContract(GetType(ErrorResponse))> _   
<OperationContract(Name:="GetCustomer")> _     
Function GetCustomer(ByVal ID As Integer) As Customer
 
3.       CustomerService.svc – Modifying Existing Service Contract, by Handling the Exception and Throwing Fault
 
Public Function GetCustomer(ByVal ID As Integer) As Customer Implements ICustomerService.GetCustomer   
              Try   
                  Return ServiceHelper.GetCustomerData(ID)   
              Catch ex As Exception   
                 Throw New FaultException(Of ErrorResponse)(New ErrorResponse, ex.Message)   
                  'or  
         'Throw New FaultException(Of ErrorResponse)(New ErrorResponse("ErrorCode", "ErrorMessage", "ErrorDetails"), ex.Message) 
               End Try   
End Function
 
Note: The value of for reason which is provided by ex.Message is optional, but if you will not provide, WCF Service will generate a message that creator of this fault did not specify the reason. So it will be advisable to pass a proper message in reason.