TexasJetter
.NET Development Examined

Creating a Service Layer


Friday, October 3, 2014

WCF services are an excellent way to expose information to applications. They provide service endpoints that can be called synchronously or asynchronously from a variety of client applications, ranging from web to iOS based. WCF Services can be hosted by IIS, as a Windows Service, or from a standalone application. This loosely coupled relationship allows for reuse of data and business logic from multiple applications.

The CODE Framework Service offering assists in the creation WCF Services, in many cases removing the burden of complex configuration. Additionally the CODE Framework has features that assist programmers during the development process.

The home for the CODE Framework is http://codeframework.codeplex.com/ and multiple documents, articles, and quick tips can be found there.

Services by their nature are responsible for returning information required by the UI. Because they are a supporting service it is common that the UI is developed first. This allows the developer to better define the methods required. However there is no technical reason that requires the UI to exist before services are created. This lab will build on the solution created in the Lab “Creating a WPF Application”, but it can be performed as a standalone exercise.

In this exercise you will create two CODE Framework projects, one to define the Service Contracts, and one to implement the service.

Task 1 – Create the Service Contract Project

The Service Contract project will define the methods, objects, and properties that are exposed to the client. These objects are called “Service Contracts” because they outline what the client may ask for, what the client must provide, and what the client can expect in return. When a client adds a reference to the service contracts project a copy of the contracts are made local to the client. This copy is called the Client Proxy.

  1. Start Visual Studio “As Administrator”.
  2. Determine the methods to expose on the Service. Our sample application deals with a list of customers, and editing a single customer’s information. From this we can determine that we will need at least three methods, one to retrieve a list of customer, one to retrieve a single customer’s information, and one to save a single customer’s information
  3. Add a new Contract Project. Right click on the solution and select Add/New Project
  4. Expand the templates listing and click on CODE.Framework
  5. Select the CODE Framework Service Contract Project and give it a name of <your project>.Services.Contracts and click OK
  6. Open the ICustomerService.cs file. This file provides an example of how service contracts are defined, and illustrates the recommended request and response pattern. On a real project this file can be removed. For our lab we will use this contract as a starting point
  7. Examine the ICustomerService Interface. The template generated two sample methods, GetCustomerList and GetCustomer. It is recommended that methods that returns information be prefixed with Get. Methods responsible for committing information should be prefixed with Save. ALL methods should receive a single parameter, the request object. ALL methods should return a single result, the response object. These objects should be named the same as the method and appended with their respective use (i.e. the request object for GetCustomer is GetCustomerRequest. The response for GetCustomer would be GetCustomerResponse)
  8. Examine the request and response objects. The request objects contain the information required by the method to perform its function. You can see that even though we are not providing any information in the GetCustomerListRequest that we still generate one. This will keep us from breaking this contract if we decide we need a parameter later. The GetCustomerRequest contains a single property, the unique identifier of the customer. The response objects properties will vary based on the actions performed in the method, but at minimum will return two properties, a Boolean property called Success, and a string property called FailureInformation.
  9. Examine the information objects. At the bottom of the file we see two Information objects. These classes define the information returned by a method. They can be a direct representation of the data container, but more commonly the represent a unique set of information assembled by the service implementation. Also note that there is a “Quick” information definition. This is a small subset of the customer information intended for use on a list display. The basic tenant observed here is that the service should only return what the UI needs.
  10. Organize the project. The sample generated contains all the interface, request and response, and information objects are located in the same file. While good for quick examples this is not the recommended method of organization.
  11. Right Click on the contracts project and select Add/New Folder. Name the folder Information. Repeat the process and create a second folder called RequestAndResponse.
  12. Move the Information class. Right Click on the Information folder and select Add/New Item.
  13. Select the CODE Framework Information Service Contract template and give it a name of CustomerInformation and click OK.
  14. If not already open, open the CustomerInformation.cs file. Remove the .Information from the name space.
    namespace CFBootCamp.Services.Contracts.Information
  15. Return to the ICustomerService file and cut the CustomerInformation class and paste it into the CustomerInformation class we just created. Be sure to replace everything inside the namespace brackets {}
  16. Change the property FirstName to Name (both for the property declaration and the default value in the constructor
  17. Remove the properties LastName and CreditLimit (both the property declarations and the default values in the constructor).
  18. Repeat the process of adding a new Information file for CustomerQuickInformation (remember to remove the .Information from the name space).
  19. After cut/pasting into the new file add two properties, Address and Phone, both as string types.
    [DataContract]
    public class CustomerQuickInformation
    {
        public CustomerQuickInformation()
        {
            Id = Guid.Empty;
            FullName = string.Empty;
            Address = string.Empty;
            Phone = string.Empty;
        }
        [DataMember(IsRequired = true)]
        public Guid Id { get; set; }
        [DataMember(IsRequired = true)]
        public string FullName { get; set; }
        [DataMember(IsRequired = true)]
        public string Address { get; set; }
        [DataMember(IsRequired = true)]
        public string Phone { get; set; }
    }
    
  20. Move the Request and Response classes. Right Click on the RequestAndResponse folder and select Add/New Item.
  21. Select the template CODE Framework Response Service Contract and give it a name of GetCustomerRnR and click OK.
  22. Remove the .RequestAndResponse part of the name space.
    namespace CFBootCamp.Services.Contracts.RequestAndResponse
  23. Return to the ICustomerService file and cut both the GetCustomerRequest and GetCustomerResponse classes and paste into the new GetCustomerRnR file. When pasting, replace everything inside the name space brackets {}.
  24. Repeat the process to create a GetCustomerListRnR file. (Remember to remove the .RequestAndResponse from the name space).
  25. Add a new service contract method. In the ICustomerService file add a new operation contract for the saving the customer. This contract will utilize the same request and response pattern as our other methods (Note Visual Studio will complain that the request and response objects do not exist, we will create those next).
    [OperationContract]
    SaveCustomerResponse SaveCustomer(SaveCustomerRequest request);
    
  26. Create request and response objects for saving. Right Click on the RequestAndResponse folder and select Add/New Item.
  27. Select the template CODE Framework Response Service Contract and give it a name of SaveCustomerRnR.
  28. Open the SaveCustomerRnR file. Remove the .RequestAndResponse from the name space.
    Note: We are removing the .Information and .RequestAndResponse from the namespace so that IntelliSense will find all of our contracts in the same place. This just makes programming a bit easier.
  29. Rename the SaveCustomerRnR class to SaveCustomerResponse (ensure that you rename both the class name and the default constructor). You can remove the comments if desired.
  30. Add a new request object. At the top of the SaveCustomerRnR file add a new public class called SaveCustomerRequest. Ensure that you have decorated the class with the [DataContract] attribute.
  31. Add a property called Customer that is of the type CustomerInformation. Decorate the property with the [DataMember(IsRequired=true)] attribute.
  32. Add a default constructor and initialize the Customer property to a new CustomerInformation object.
    namespace CFBootCamp.Services.Contracts
    {
        [DataContract]
        public class SaveCustomerRequest
        {
            public SaveCustomerRequest()
            {
                Customer = new CustomerInformation();
            }
    
            [DataMember(IsRequired = true)]
            public CustomerInformation Customer { get; set; }
        }
    
        [DataContract]
        public class SaveCustomerResponse
        {
            public SaveCustomerResponse()
            {
                Success = false;
                FailureInformation = string.Empty;
            }
    
            [DataMember(IsRequired = true)]
            public bool Success { get; set; }
    
            [DataMember(IsRequired = true)]
            public string FailureInformation { get; set; }
        }
    }
    
  33. Build the solution to ensure there are no compile errors. If the build is successful you have complete the Service Contract project. !

Task 2 – Create the Service Implementation Project

Thus far, we have only defined what our service calls will look like to the UI project. The Implementation Project will contain the code responsible for fulfilling the service methods defined in the contract.

  1. Add a new Implementation Project. Right click on the solution (not a project) and select Add/New Project.
  2. Expand the templates listing and click on CODE.Framework.
  3. Select the CODE Framework Service Implementation Project and give it a name of <your project>.Services.Implementation and click OK.
  4. Select the contract interface. The implementation project wizard will examine your solution an present you with the option to implement any service contract found. In this case the only contract interface available is the ICustomerService exposed on the Service Contract project. Leave this item selected and click OK.
  5. Open the CustomerService.cs file. This class implements all methods defined in the contract interface. Typically these methods will interact with your Object Relational Mapping (ORM will be define later) and your business logic. Your business logic may be contained in the method, or housed in a separate class/project if desired. You will see that a method stub utilizing the recommended request/response objects has been generated for you. This stub also follows the recommended pattern of using a try/catch block around the method code. It is important to implement your code such that the service always returns the proper response object defined in the contract even if the call fails.
    public GetxxxResponse Getxxx(GetxxxRequest request)
    {
        try
        {
            var response = new GetxxxResponse();
            // TODO: Add service-specific code here
            response.Success = true;
            return response;
        }
        catch (Exception ex)
        {
            LoggingMediator.Log(ex);
            return new GetxxxResponse {Success = false, FailureInformation = "Generic fault in..." };
        }
    }
    
    The LoggingMediator object called in the catch is an optional CODE Framework logging utility. It can be configured to write logs to disk, email, a database or the System Event Logs. It is recommended that you log all Service exception details, but you should never return these to the user.
  6. Add testing code to the GetCustomerList method. Just below the //TODO add the following code to create sample records.
    for (var x = 1; x < 10; x++)
    {
        response.Customers.Add(new CustomerQuickInformation
            {
                Id = Guid.NewGuid(),
                FullName = "Test Customer #" + x,
                Address = x + " Street, Somewhere, TX",
                Phone = "222-222-123" + x
            });
    }
    
  7. Add testing code to the GetCustomer method. Just below the //TODO add the following code to create a sample record.
    response.Customer = new CustomerInformation
        {
            Id = Guid.NewGuid(),
            Name="Bill Gates",
            Address = "123 Street, Somewhere, TX",
            Phone = "222-222-1234",
            CustomerSince = DateTime.Now.AddYears(-23)
         };
    	 
  8. Build the solution to ensure there are no build errors. If successful you now have a functional service.

Now lets look at how we can access these service in Part 2 of this series.


Comments

Add Comment