Tuesday, December 22, 2009

Convert Exceptions in WCF Services to Fault Exceptions a Client Can Use

This article will show you how to trap an exception that occurs within a WCF service but also inform the client application of the exception so it can be handled.  To do this we will make use of a custom faultException.

1. You need to create a fault contract for the type of fault that you want to be returned to the client via WCF.  Below I have created a ‘DBConcurrencyFault’ fault that tells the client when a database concurrency violation has occurred (e.g. 2 people tried to save the same record).

namespace Common.Services.Faults
{
    [DataContract]
    public class DBConcurrencyFault
    {
        [DataMember]
        public String Message { get; set; }

        [DataMember]
        public String ExceptionType { get; set; }
    }
}

2. Now we are going to create a new attribute that we can use to decorate our service classes with.  This attribute will trap any exception occurring in a WCF service and convert them into a specific fault exception.

namespace Common.Services
{
    public class WcfErrorHandler : Attribute, IErrorHandler, IServiceBehavior
    {
        public bool HandleError(Exception error)
        {
            return false;
        }
       
        public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
        {
            if (fault != null)
                return;

            if (error.GetType() == typeof(System.Data.DBConcurrencyException)) 
            {
                // Handle Database record being written to by different users (Conncurrency Fault)
                DBConcurrencyFault databaseConcurrencyFault = new DBConcurrencyFault();
                databaseConcurrencyFault.Message = error.Message;
                databaseConcurrencyFault.ExceptionType = error.GetType().ToString();
                String faultReason = "Someone else has already saved this record.";
                FaultException<DBConcurrencyFault> faultException = new FaultException<DBConcurrencyFault>(databaseConcurrencyFault, faultReason);
                MessageFault messageFault = faultException.CreateMessageFault();
                fault = Message.CreateMessage(version, messageFault, faultException.Action);
            }
            else
            {
                // Handle all other errors as standard FaultExceptions
                FaultException faultException = new FaultException(error.Message);
                MessageFault messageFault = faultException.CreateMessageFault();
                fault = Message.CreateMessage(version, messageFault, faultException.Action);
            }
        }

        #region IServiceBehavior Members
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {           
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher disp in serviceHostBase.ChannelDispatchers)
            {
                disp.ErrorHandlers.Add(this);
            }
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {           
        }
        #endregion
    }
}

Note: the ‘ProvideFault’ method contains code that determines if an exception of type ‘System.Data.DBConcurrencyException’ has occurred.  If one has it is converted into a ‘DBConcurrencyFault’ which is then returned to the calling client by the WCF service. 

3. Now you can either add the WcfErrorHandler attribute to all your wcf services, or you can as I have below define a base service class that all your service classes will inherit from.

namespace Common.Services
{
   [WcfErrorHandler()]
   public class BaseService
   {
       // Common service methods go here
   }
}

4. Have your service class inherit from the base service class. 

public class MileageClaimService : BaseService, IMileageClaimService
{
      // Service methods go here
}

5. Trap the fault exception from a web client and redirect the user to a tailored error page.
   5a.  For an Asp.Net web application you can add the exception handling code to the global.asax Application_Error method.

protected void Application_Error(object sender, EventArgs e) 

     Exception ex = Server.GetLastError().GetBaseException(); 

     if (ex.GetType() == typeof(System.ServiceModel.FaultException<Common.Services.Faults.DBConcurrencyFault>) ) 
     { 
        Server.ClearError(); 
        Response.Redirect("~/Errors/ErrorDbConcurrency.aspx"); 
     } 
}

  5b. From an Asp.Net MVC web application you just add a HandleError attribute to the controller with the type of DBConcurrencyFault and redirect to a specific view.

[HandleError(ExceptionType = typeof(System.ServiceModel.FaultException<Common.Services.Faults.DBConcurrencyFault>),
View = "ErrorDbConcurrency")]
[HandleError]
public class ClaimController : Controller
{
    // Controller methods go here
}

Note: There are 2 HandleError attributes, the first handles the DBConcurrencyFault and redirects to a custom error page.  The 2nd traps all other exceptions and redirects to the default error page.  The order of these 2 HandleError attributes is important.

Friday, December 18, 2009

Constructor Dependency Injection with a WCF Service using Unity

In a previous article I showed how to use dependency injection to specify in a config file which repository should be used by a non WCF service.

This article will show how to do the same but for a WCF service.

The previous article can be found here.

1. WCF uses interfaces so the first thing we need to do is add an interface to our service to WCF enable it.  Since the service is called MileageClaimService I will call the interface IMileageClaimService. Below is the interface definition decorated with WCF ServiceContract and OperationContract attributes.

namespace Service.Finance.Mileage.Interfaces
{
    [ServiceContract(
        Name = "MileageClaimService",
        Namespace = "http://mycompany.com/services/finance/v1.0.0.0")]
    public interface IMileageClaimService
    {
        [OperationContract(Name = "GetAllClaimsForEmployee")]
        List<DTO.Finance.Mileage.MileageClaim> GetAllClaimsForEmployee(string employeePayrollNumber);

        [OperationContract(Name = "GetClaimById")]
        DTO.Finance.Mileage.MileageClaim GetClaimById(int id);

        [OperationContract(Name = "GetClaimByReferenceNumber")]
        DTO.Finance.Mileage.MileageClaim GetClaimByReferenceNumber(string referenceNumber);

        [OperationContract(Name = "Save")]
        [FaultContract(typeof(DBConcurrencyFault))]
        void Save(ref DTO.Finance.Mileage.MileageClaim claim);

        [OperationContract(Name = "Delete")]
        void Delete(DTO.Finance.Mileage.MileageClaim claim);

        [OperationContract(Name = "SubmitClaim")]
        void SubmitClaim(DTO.Finance.Mileage.MileageClaim claim);
    }
}

Below I’ve added the interface and the ServiceBehavior attribute to the service.

namespace Service.Finance.Mileage
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class MileageClaimService : IMileageClaimService
    {
        IMileageClaimRepository _mileageClaimRepository;
       [InjectionConstructor] 
        public MileageClaimService(IMileageClaimRepository  mileageClaimRepository)
        { 
        }

        // Other service methods go here 
    }
}

2.  We need to create the Unity classes for WCF.
I’ve created a project called Common. In here I’m going to place the Unity WCF classes (there are 3 of them) in a directory called Services\Unity.  You can just copy the code to your own project as I did (thanks to dperez for helping me with this: http://blogs.southworks.net/dperez/2008/11/02/unity-friends-the-wcf-service-host-side/).

InjectionBehavior.cs

using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using Microsoft.Practices.Unity;

// WCF Unity Injection Behavior
namespace Common.Services.Unity
{
    /// <summary>
    /// Creates services instance by using Unity type resolution.
    /// </summary>
    public class InjectionBehavior : IServiceBehavior
    {
        /// <summary>
        /// Injection container.
        /// </summary>
        private IUnityContainer container;

        /// <summary>
        /// Initializes a new instance of the InjectionBehavior class.
        /// </summary>
        /// <param name="container">Injection container.</param>
        public InjectionBehavior(IUnityContainer container)
        {
            this.container = container;
        }

        /// <summary>
        /// Provides the ability to pass custom data to binding elements to support the contract implementation.
        /// </summary>
        /// <param name="serviceDescription">The service description of the service.</param>
        /// <param name="serviceHostBase">The host of the service.</param>
        /// <param name="endpoints">The service endpoints.</param>
        /// <param name="bindingParameters">Custom objects to which binding elements have access.</param>
        public void AddBindingParameters(
            ServiceDescription serviceDescription,
            ServiceHostBase serviceHostBase,
            Collection<ServiceEndpoint> endpoints,
            BindingParameterCollection bindingParameters)
        {
        }

        /// <summary>
        /// Provides the ability to change run-time property values or insert custom extension objects such as error handlers, message or parameter interceptors, security extensions, and other custom extension objects.
        /// </summary>
        /// <param name="serviceDescription">The service description.</param>
        /// <param name="serviceHostBase"> The host that is currently being built.</param>
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            foreach (var channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                var channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                if (channelDispatcher != null)
                {
                    foreach (var endpointDispatcher in channelDispatcher.Endpoints)
                    {
                        endpointDispatcher.DispatchRuntime.InstanceProvider = new InjectionInstanceProvider(this.container, serviceDescription.ServiceType);
                    }
                }
            }
        }

        /// <summary>
        /// Provides the ability to inspect the service host and the service description to confirm that the service can run successfully.
        /// </summary>
        /// <param name="serviceDescription">The service description.</param>
        /// <param name="serviceHostBase">The service host that is currently being constructed.</param>
        public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
        }
    }
}

InjectionElement.cs
using System;
using System.Configuration;
using System.ServiceModel.Configuration;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

// WCF Unity Injection Element
namespace Common.Services.Unity
{
    /// <summary>
    /// Injection element class representing a behavior extension configuration tag.
    /// </summary>
    public class InjectionElement : BehaviorExtensionElement
    {
        /// <summary>
        /// Default Unity configuration section path.
        /// </summary>
        private const string DefaultUnityConfigurationSectionPath = "unity";

        /// <summary>
        /// Initializes a new instance of the InjectionElement class.
        /// </summary>
        public InjectionElement()
        {
            this.UnityConfigurationSectionPath = DefaultUnityConfigurationSectionPath;
        }

        /// <summary>
        /// Gets the type of behavior.
        /// </summary>
        /// <value>Behavior type.</value>
        public override Type BehaviorType
        {
            get
            {
                return typeof(InjectionBehavior);
            }
        }

        /// <summary>
        /// Gets or sets the injection container name.
        /// </summary>
        /// <value>Container name.</value>
        [ConfigurationProperty("containerName")]
        public string ContainerName
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the Unity configuration section path to read configuration from.
        /// </summary>
        /// <value>Configuration path.</value>
        [ConfigurationProperty("unityConfigurationSectionPath", DefaultValue = DefaultUnityConfigurationSectionPath)]
        public string UnityConfigurationSectionPath
        {
            get;
            set;
        }

        /// <summary>
        /// Creates a behavior extension based on the current configuration settings.
        /// </summary>
        /// <returns>The behavior extension.</returns>
        protected override object CreateBehavior()
        {
            var unitySection = ConfigurationManager.GetSection(this.UnityConfigurationSectionPath) as UnityConfigurationSection;
            IUnityContainer container = new UnityContainer();
            if (this.ContainerName == null)
            {
                unitySection.Containers.Default.Configure(container);
            }
            else
            {
                unitySection.Containers[this.ContainerName].Configure(container);
            }
            return new InjectionBehavior(container);
        }
    }
}

InjectionInstanceProvider.cs
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using Microsoft.Practices.Unity;

// WCF Unity Injection Provider
namespace Common.Services.Unity
{
    /// <summary>
    /// Injection instance provider for new service instances.
    /// </summary>
    internal sealed class InjectionInstanceProvider : IInstanceProvider
    {
        /// <summary>
        /// Injection container.
        /// </summary>
        private IUnityContainer container;

        /// <summary>
        /// Type of the service implementation.
        /// </summary>
        private Type instanceType;

        /// <summary>
        /// Initializes a new instance of the InjectionInstanceProvider class.
        /// </summary>
        /// <param name="container">Injection container.</param>
        /// <param name="instanceType">Type of the service implementation.</param>
        public InjectionInstanceProvider(IUnityContainer container, Type instanceType)
        {
            this.container = container;
            this.instanceType = instanceType;
        }

        /// <summary>
        /// Returns a service object given the specified System.ServiceModel.InstanceContext object.
        /// </summary>
        /// <param name="instanceContext">The current System.ServiceModel.InstanceContext object.</param>
        /// <param name="message">The message that triggered the creation of a service object.</param>
        /// <returns>The service object.</returns>
        public object GetInstance(InstanceContext instanceContext, Message message)
        {
            return this.container.Resolve(this.instanceType);
        }

        /// <summary>
        /// Returns a service object given the specified System.ServiceModel.InstanceContext object.
        /// </summary>
        /// <param name="instanceContext">The current System.ServiceModel.InstanceContext object.</param>
        /// <returns>The service object.</returns>
        public object GetInstance(InstanceContext instanceContext)
        {
            return this.GetInstance(instanceContext, null);
        }

        /// <summary>
        /// Called when an System.ServiceModel.InstanceContext object recycles a service object.
        /// </summary>
        /// <param name="instanceContext">The service's instance context.</param>
        /// <param name="instance">The service object to be recycled.</param>
        public void ReleaseInstance(InstanceContext instanceContext, object instance)
        {
            this.container.Teardown(instance);
        }
    }
}

3. Now we need to update the app.config file for the service project.  Below shows the configuration to enable the service for Unity dependency injection (it’s exactly the same as in the previous post).

<configSections>
  <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>

<unity>
    <containers>
      <container>
        <types>
           <type type="DataAccess.Finance.Mileage.Interfaces.IMileageClaimRepository,
                            DataAccess.Finance.Mileage.Interfaces"
                    mapTo="EF.DataAccess.Finance.Mileage.Repositories.MileageClaimRepository,
                            EF.DataAccess.Finance.Mileage"/>
        </types>
      </container>
    </containers> 
</unity>

And below is the new configuration to enable the service for WCF using the Unity behavior.

<system.serviceModel> 
    <extensions>
      <behaviorExtensions>
        <add name="unity" type="Common.Services.Unity.InjectionElement, Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
      </behaviorExtensions>
    </extensions>
    <bindings>
      <netTcpContextBinding>
        <binding name="netTcpContextBindingConfig" transactionFlow="true" />
      </netTcpContextBinding>
    </bindings>

    <services>
      <service behaviorConfiguration="Service.ServiceBehavior" name="Service.Finance.Mileage.MileageClaimService">
        <endpoint address="" binding="netTcpContextBinding" bindingConfiguration="netTcpContextBindingConfig"
          name="TcpBinding_MileageClaimService" contract="Service.Finance.Mileage.Interfaces.IMileageClaimService" />
        <endpoint address="mex" binding="mexTcpBinding" name="MexTcpBinding_MileageClaimService"
          contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:8734/Services.Finance/MileageClaimService/v1.0.0.0" />
          </baseAddresses>
        </host>
      </service>
    </services>

     <behaviors>
      <serviceBehaviors>
        <behavior name="Service.ServiceBehavior">
          <serviceMetadata httpGetEnabled="false"/>
          <serviceDebug includeExceptionDetailInFaults="false" />
          <unity />
        </behavior>
      </serviceBehaviors>
    </behaviors> 
</system.serviceModel>

Note the behaviorExtensions section contains a Unity entry.  This points to the Unity InjectionElement class you added in the last section. 

Also note the <unity /> line in the serviceBehaviors. 

Both of these are critical to enabling the WCF service to use Unity dependency injection.

Thats it, you can use the wcf service as you would do any wcf service by adding a service reference to your client project and calling the methods on it.  The repository will be injected automatically into the constructor on the service because of the behavior extensions defined in the wcf configuration.

Thursday, December 17, 2009

Constructor Dependency Injection using Unity (Enterprise Library)

In the previous article I discussed using the repository design pattern.  I also showed how to use a service layer which can then call the repository data access layer.  This was done by specifying in code which repository to use in the constructor of the service.

This article will show how to use dependency injection to specify in the web.config / app.config which repository should be used by the service.

The previous article can be found here and you should understand this before continuing.

1. You need to download Enterprise Library 4.1 or higher which contains the dependency injection block called ‘Unity’.

2. You need to add references for Microsoft.Practices.Unity.Configuration.dll and Microsoft.Practices.Unity.dll to the service project.

3. The only change you need to make to the service is to specify which constructor is the one that should be enabled for dependency injection.  You do this by using the [InjectionConstructor] attribute.

namespace Service.Finance.Mileage
{
    public class MileageClaimService
    {
        IMileageClaimRepository _mileageClaimRepository;

         [InjectionConstructor] 
        public MileageClaimService(IMileageClaimRepository  mileageClaimRepository)
        { 
        }

        // Other service methods go here 
    }
}

4. For ease of use, its useful to create a helper class to hide the Unity code that is needed to work out the repository to use for the service.  I’ve called the class ‘UnityDependencyInjectionHelper’ and its best to place it in a common project as it will be reused so I have a project called Common.Service.  You can just copy the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;

namespace Service.Common
{
    public static class UnityDependencyInjectionHelper
    {
        private static IUnityContainer container;

        private static void Init()
        {
            container = new UnityContainer();
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers.Default.Configure(container);
        }

        public static T Resolve<T>()
        {
            Init();
            return container.Resolve<T>();
        }

        public static T Resolve<T>(string name)
        {
            Init();
            return container.Resolve<T>(name);
        }
    }
}

5. To call the service from the client you used to do this:

    // Get the mileage claim repository we want to use Entity Framework or ADO.Net.  
    IMileageClaimRepository repository = new EF.DataAccess.Finance.Mileage.Repositories.MileageClaimRepository(); 
   
    // Initialise the service passing in the data access repository it should use 
    MileageClaimService mileageClaimService = new MileageClaimService( repository ); 
   
    // Call a method on the service  
    DTO.Finance.Mileage.MileageClaim mileageClaimService.GetClaimById( 10 );

but now you would do this:

mileageClaimService = Service.Common.UnityDependencyInjectionHelper.Resolve<Service.Finance.Mileage.MileageClaimService>();

// Call a method on the service   
DTO.Finance.Mileage.MileageClaim mileageClaimService.GetClaimById( 10 );

Notice the difference here is we are not specifying the repository to use, it will be automatically injected into the constructor on the service.

6. Lastly you need to add a few lines to the web.config file so the Unity Helper can find the repository.
  6a. First you need to add the Enterprise Library Unity section to the configSections.

<configSections>
  <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>

  6b. Next you need to add the mapping to the repository.  You do this by adding a Unity block with containers as shown below. You can add this straight after the </configSections>

<unity>
    <containers>
      <container>
        <types>
           <type type="DataAccess.Finance.Mileage.Interfaces.IMileageClaimRepository,
                            DataAccess.Finance.Mileage.Interfaces"

                    mapTo="EF.DataAccess.Finance.Mileage.Repositories.MileageClaimRepository,
                            EF.DataAccess.Finance.Mileage"/>
        </types>
      </container>
    </containers>
  </unity>

The ‘type’ effectively says replace any occurrence of the IMileageClaimRepository interface.  And the mapTo effectively says with this MileageClaimRepository.

If you ever needed to change the MileageClaimRepository that is being used all you need to do is change the mapTo line e.g.

To change the above which is using the Entity Framework repository (EF.DataAccess…..) to use ADO.Net repository (ADO.DataAccess…..) you would end up with:

<unity>
    <containers>
      <container>
        <types>
           <type type="DataAccess.Finance.Mileage.Interfaces.IMileageClaimRepository,
                            DataAccess.Finance.Mileage.Interfaces"

                    mapTo="ADO.DataAccess.Finance.Mileage.Repositories.MileageClaimRepository, 
                            ADO.DataAccess.Finance.Mileage"/>
        </types>
      </container>
    </containers>
  </unity>

Wednesday, December 16, 2009

Using The Repository Design Pattern For Data Access Code

In this article we will create a repository for our data base access code. The repository pattern is useful when:
• Some of your clients use Oracle and others use SQL Server you can create a repository for each.
• Your company decides to upgrade to a newer way of doing data base access. 

You only need to create a new repository class to do it. E.g. you might have one repository for ADO.Net and one for Entity Framework data access code.

To get started what we are going to do here is create a repository that will contain data base access code to retrieve MileageClaim information.

1. First we need a Data Transfer Object (DTO). This is where the mileage claim data will be placed that we retrieve from the database.

namespace DTO.Finance.Mileage
{
    public class MileageClaim
    {  
        public int MileageClaimId { get; set; }       
        public string PayrollNumber { get; set; }
        public string ReferenceNumber { get; set; }
        public int? VehicleId { get; set; }
        public int CreatedByPersonId { get; set; }
        public DateTime DateCreated { get; set; }
        public int? UpdatedByPersonId { get; set; }
        public DateTime? DateUpdated { get; set; }
    }
}

You should place the DTO class in a separate class library project as you will reference these classes from many places. I’ve called the project DTO.Finance.Mileage.

2. Define an interface for the repository. Since its going to handle mileage claim data an appropriate name is IMileageClaimRepository.

namespace DataAccess.Finance.Mileage.Interfaces
{
    public interface IMileageClaimRepository
    { 
        List<DTO.Finance.Mileage.MileageClaim> GetAllClaimsForEmployee(String employeePayrollNumber);
        DTO.Finance.Mileage.MileageClaim GetClaimByReferenceNumber(String referenceNumber);
        DTO.Finance.Mileage.MileageClaim GetClaimById(Int32 id);
        void ChangeMileageClaimStatus(DTO.Finance.Mileage.MileageClaim claim, DTO.Common.Status status, String userIdentity);
        void Save(ref DTO.Finance.Mileage.MileageClaim claim, String userIdentity);
        void Delete(DTO.Finance.Mileage.MileageClaim claim);
    }
}

Again you should place these interfaces in a separate project as it makes it easier later if/when you create additional mileage claim repositories.

This interface defines the methods that the repository will provide. Because it’s going to contain data base access code it will handle the standard CRUD (create, read, update, delete) methods.

3. Next we need to create the actual repository.

3.1. You should place these data base access classes in a separate project; I’ve called it EF.DataAccess.Finance.Mileage because this repository is going to access the database using Entity Framework. If I had another repository for ADO.Net I’d call it ADO.DataAccess.Finance.Mileage. Inside this project I place all the data base access code including the model diagrams for Entity Framework.

3.2. Inside this project I place the repository class for accessing mileage claim data from the database, so I’ll call it MileageClaimRepository and place it in a Repositories folder. It will implement the IMileageClaimRepository interface.

namespace EF.DataAccess.Finance.Mileage.Repositories
{
    public class MileageClaimRepository : IMileageClaimRepository
    {
        public MileageClaimRepository()
        {
        }

        public List<DTO.Finance.Mileage.MileageClaim> GetAllClaimsForEmployee(String employeePayrollNumber)
        {
            // Data base access code goes here
        }

        public DTO.Finance.Mileage.MileageClaim GetClaimByReferenceNumber(String referenceNumber)
        {
            // Data base access code goes here
        }

        public DTO.Finance.Mileage.MileageClaim GetClaimById(Int32 id)
        {
            // Data base access code goes here
        }

        public void ChangeMileageClaimStatus(DTO.Finance.Mileage.MileageClaim claim, DTO.Common.Status status, String userIdentity)
        {
            // Data base access code goes here
        }

        public void Save(ref DTO.Finance.Mileage.MileageClaim dtoClaim, String userIdentity)
        {
            // Data base access code goes here
        }

        public void Delete(DTO.Finance.Mileage.MileageClaim claim)
        {
            // Data base access code goes here
        }
    }
}

4. We now have our data access layer. To use this layer and to use the separation of concerns principle I’m going to add 1 more layer, a service layer.  Note the service contains more methods than the repository (a service layer does not have to map 1 to 1 to the repository layer).

namespace Service.Finance.Mileage
{
    public class MileageClaimService
    { 
        IMileageClaimRepository _mileageClaimRepository;

        public MileageClaimService(IMileageClaimRepository mileageClaimRepository)
        {
            _mileageClaimRepository = mileageClaimRepository;
        }

        public List<DTO.Finance.Mileage.MileageClaim> GetAllClaimsForEmployee(String employeePayrollNumber)
        {
            return _mileageClaimRepository.GetAllClaimsForEmployee(employeePayrollNumber);
        }

        public DTO.Finance.Mileage.MileageClaim GetClaimByReferenceNumber(String referenceNumber)
        {
            return _mileageClaimRepository.GetClaimByReferenceNumber(referenceNumber);
        }

        public DTO.Finance.Mileage.MileageClaim GetClaimById(Int32 id)
        {
            return _mileageClaimRepository.GetClaimById(id);
        } 

        public void Save(ref DTO.Finance.Mileage.MileageClaim claim)
        {
            String userIdentity = User.Identity.Name;

            if (claim.MileageClaimId == 0)
            {
                // It's a new claim so do some new claim stuff here
                // You could do stuff like automatically set the reference number here 
                // Get the status object so we can set the new claim with an initial status of draft
                StatusService statusService = new StatusService();
                DTO.Common.Status status = statusService.GetStatus(
                           (Int32)MileageClaimStatusTypeKeys.MileageClaim,
                           (Int32) Service.Finance.Mileage.Enums.MileageClaimStatusKeys.Draft);

                // We want to make sure that if one of the 2 service calls fail then
                // neither will write any data into the db so lets create a transaction.
                using (TransactionScope scope = new
                         TransactionScope(TransactionScopeOption.Required))
                {
                    // Save any changes to the claim
                    _mileageClaimRepository.Save(ref claim, userIdentity);

                    // Change the claim status to draft
                    ChangeMileageClaimStatus(claim, status);

                    // If no exceptions have been thrown so far then commit the transaction
                    // so everything is saved to the db
                    scope.Complete();
                }
            }
            else
            {
                // It’s an existing claim being edited so save any changes to the claim
                _mileageClaimRepository.Save(ref claim, userIdentity);
            }
        }

        public void Delete(DTO.Finance.Mileage.MileageClaim claim)
        {
            _mileageClaimRepository.Delete(claim);
        }

        public void SubmitClaim(DTO.Finance.Mileage.MileageClaim claim)
        {           
            // Save any changes to the claim
            Save(ref claim); 

            // Change the claim status to submitted
            StatusService statusService = new StatusService();
            DTO.Common.Status status = statusService.GetStatus(
                        (Int32)MileageClaimStatusTypeKeys.MileageClaim,
                        (Int32)Service.Finance.Mileage.Enums.MileageClaimStatusKeys.Submitted);

            ChangeMileageClaimStatus(claim, status);
        }
    }
}

This service accepts as a parameter on the constructor an interface for an IMileageClaimRepository. When we use the service in our code we tell the service what repository it should use e.g. Entity Framework or ADO.Net repositories.

Because all the repositories use the same interface they will all have the same method names that the service can call so we don’t need to change the service code at all to use different repositories.

5. From a client you just need to reference the service, DTO and the repository you want to use projects.  Then to call a method from the client you just:

// Get the mileage claim repository we want to use Entity Framework or ADO.Net.   
IMileageClaimRepository repository = new EF.DataAccess.Finance.Mileage.Repositories.MileageClaimRepository(); 
    
// Initialise the service passing in the data access repository it should use  
MileageClaimService mileageClaimService = new MileageClaimService( repository );  
    
// Call a method on the service   
DTO.Finance.Mileage.MileageClaim mileageClaimService.GetClaimById( 10 );

Note: You could use dependency injection (e.g Unity) to work out automatically which repository to use based on settings in a config file and in a future article we will look at doing just that.

Note: You can also use wcf on the service layer with minimal code changes if you wanted to move to a 3-tier architecture, this will be covered in a future article.