sixtyring design and implementation

154
SixtyRing Design and Implementation An SOA-based web system Copyright © 2007 Richard G. Todd

Upload: others

Post on 26-Feb-2022

0 views

Category:

Documents


0 download

TRANSCRIPT

SixtyRing Programmer GuideCopyright © 2007 Richard G. Todd
SixtyRing Design and Implementation
Contents at a Glance 1. Introduction ...................................................................................................................................................................................1 2. Service Contract Assemblies........................................................................................................................................................9 3. Local Service Assemblies ...........................................................................................................................................................22 4. Web Service Assemblies.............................................................................................................................................................43 5. Membership and Role Providers ..............................................................................................................................................65 6. Business Objects and Data Access...........................................................................................................................................72 7. Web Application....................................................................................................................................................................... 113 8. Data Sources ............................................................................................................................................................................. 142
Table of Contents 1. Introduction ...................................................................................................................................................................................1
Program Overview........................................................................................................................................................................4 System Implementation................................................................................................................................................................4 Data Model.....................................................................................................................................................................................7
Business Objects..........................................................................................................................................................................79 States.........................................................................................................................................................................................82 References................................................................................................................................................................................90 State Factories .........................................................................................................................................................................94 Business Objects.....................................................................................................................................................................98
Themes.................................................................................................................................................................................. 124 Skins.................................................................................................................................................................................. 125 Style Sheets ...................................................................................................................................................................... 126
Web Page Classes ..................................................................................................................................................................... 127 SixtyRing Base Page Class .................................................................................................................................................. 127 SixtyRing Master Page ........................................................................................................................................................ 128
Navigation ................................................................................................................................................................................. 130 Data Entry ................................................................................................................................................................................. 130
Data Entry Forms ............................................................................................................................................................... 130 Data Detail Forms............................................................................................................................................................... 131 Data Entry Custom Controls ............................................................................................................................................ 132
Non-Fatal Errors ................................................................................................................................................................. 138 Session Support ........................................................................................................................................................................ 139 Application Support................................................................................................................................................................. 139 Security....................................................................................................................................................................................... 140
8. Data Sources ............................................................................................................................................................................. 142 Artifacts...................................................................................................................................................................................... 142
List of Figures Figure 1 - SixtyRing Application Architecture...............................................................................................................................3 Figure 2 - SixtyRing Implementation ..............................................................................................................................................6 Figure 3 – SixtyRing Data Model.....................................................................................................................................................7 Figure 4 – SixtyRing Service Interfaces ........................................................................................................................................13 Figure 5 – Order Service .................................................................................................................................................................14 Figure 6 – Order Service Submit Method ....................................................................................................................................14 Figure 7 – OrderRequest Class ......................................................................................................................................................15 Figure 8 – OrderRequestEntry Class ............................................................................................................................................16 Figure 9 – OrderStatus Enumeration............................................................................................................................................17 Figure 10 – SixtyRing Exception Classes .....................................................................................................................................18 Figure 11 – SixtyRing Data Dictionary Classes ...........................................................................................................................20 Figure 12 – Registering Services with the Service Pool .............................................................................................................21 Figure 13 – ServicePool Register Method....................................................................................................................................21 Figure 14 – ServicePool Lookup Method ....................................................................................................................................21 Figure 15 – Retrieving Services from the Service Pool..............................................................................................................21 Figure 16 – Local OrderService Class...........................................................................................................................................23 Figure 17 – SixtyRing Permissions ................................................................................................................................................28 Figure 18 – ServicePermission Demand Method........................................................................................................................29 Figure 19 – Order Service Lookup Method.................................................................................................................................29 Figure 20 – OrderPermissionAccess Enumeration ....................................................................................................................30 Figure 21 – OrderPermission Class...............................................................................................................................................31 Figure 22 – OrderService Lookup and CreateViewPermission Methods ...............................................................................36 Figure 23 – Mapper Copy Method................................................................................................................................................37 Figure 24 – Utility HandleException Method .............................................................................................................................38 Figure 25 – ServiceInterface Class.................................................................................................................................................39 Figure 26 – IServiceContract Interface.........................................................................................................................................39 Figure 27 – WebServiceContext Class ..........................................................................................................................................40 Figure 28 – WindowsServiceContract Class ................................................................................................................................41 Figure 29 – IOperatingEnvironment Interface ...........................................................................................................................41 Figure 30 – OperatingEnvironment Class ...................................................................................................................................41 Figure 31 – Web Service Class .......................................................................................................................................................45 Figure 32 – Order Web Service Submit Method.........................................................................................................................45 Figure 33 – SixtyRingWebServiceApplication Class...................................................................................................................48 Figure 34 – Authentication SOAP Header ..................................................................................................................................49 Figure 35 – AuthenicatedService Class .........................................................................................................................................50 Figure 36 – Authenticated Service Method..................................................................................................................................50 Figure 37 – SixtyRingAuthenticationModule Class ....................................................................................................................51 Figure 38 – SixtyRingAuthenticationModule Init Method........................................................................................................51 Figure 39 – OnAuthenticate Method............................................................................................................................................52 Figure 40 – SixtyRingAuthentication Registration......................................................................................................................53
Figure 41 – Utility HandleException Method .............................................................................................................................54 Figure 42 – Utility GetSoapExceptionDetail Method................................................................................................................55 Figure 43 – Add Web Reference Dialog – Available Services ..................................................................................................57 Figure 44 – Add Web Reference Dialog – Add Reference .......................................................................................................58 Figure 45 – Order Service Proxy Class Files................................................................................................................................59 Figure 46 – Reference.cs Using Statement...................................................................................................................................59 Figure 47 – Order Web Service Proxy Implementation ............................................................................................................60 Figure 48 – WebServiceInterface Class ........................................................................................................................................61 Figure 49 – Utility HandleException Method .............................................................................................................................62 Figure 50 – SixtyRing Membership and Role Providers ............................................................................................................66 Figure 51 – UserProfileService Property ......................................................................................................................................67 Figure 52 – ResetPassword Method..............................................................................................................................................67 Figure 53 – web.config Provider Configuration..........................................................................................................................68 Figure 54 - Changing Password Question and Answer .............................................................................................................69 Figure 55 - Submit Method Implementation...............................................................................................................................70 Figure 56 - UserProfile::ChangePassword Web Service Implementation...............................................................................70 Figure 57 - Membership Provider Call Flow ...............................................................................................................................71 Figure 58 - Customer Business Object .........................................................................................................................................81 Figure 59 - ObjectManager State Components ...........................................................................................................................82 Figure 60 - SqlState Class ................................................................................................................................................................83 Figure 61 - SixtyRing State Interface Inventory ..........................................................................................................................84 Figure 62 - SixtyRing User-Defined Data Types.........................................................................................................................85 Figure 63 - SixtyRing State Interfaces ...........................................................................................................................................86 Figure 64 - SixtyRing State Implementations ..............................................................................................................................87 Figure 65 - SqlCustomer Class .......................................................................................................................................................88 Figure 66 - Customer Dataset ........................................................................................................................................................89 Figure 67 - SqlCustomer Constructor...........................................................................................................................................89 Figure 68 - SqlCustomer::UserId Property...................................................................................................................................90 Figure 69 - IReference Interface ....................................................................................................................................................90 Figure 70 - SixtyRing Reference Inventory ..................................................................................................................................91 Figure 71 - ICustomerReference Interface...................................................................................................................................91 Figure 72 - SixtyRing Reference Implementations .....................................................................................................................92 Figure 73 - SqlCustomerReference Class .....................................................................................................................................93 Figure 74 – SqlCustomerUnboundReference Class ...................................................................................................................94 Figure 75 - SqlCustomerBoundReference Class .........................................................................................................................94 Figure 76 - IStateFactory Interface................................................................................................................................................94 Figure 77 – SixtyRing State Factory Inventory............................................................................................................................95 Figure 78 - ICustomerFactory Interface.......................................................................................................................................96 Figure 79 - SixtyRing State Factory Implementations................................................................................................................96 Figure 80 - SqlCustomerFactory Class..........................................................................................................................................96 Figure 81 - State::Lookup Method.................................................................................................................................................97 Figure 82 - Object Manager Business Object Components......................................................................................................98
Figure 83 - BusinessObject Class...................................................................................................................................................99 Figure 84 - SixtyRing Business Object Inventory .......................................................................................................................99 Figure 85 - Customer Class.......................................................................................................................................................... 100 Figure 86 - Customer::Create and Customer::Load Methods ................................................................................................ 101 Figure 87 - Customer::UserId Property ..................................................................................................................................... 101 Figure 88 - Order::Customer Property....................................................................................................................................... 102 Figure 89 - Object Manager Data Source Components.......................................................................................................... 103 Figure 90 - Object Manager Session Components .................................................................................................................. 104 Figure 91 - SqlStateSession::Register Method........................................................................................................................... 105 Figure 92 - Object Manager Reader Components ................................................................................................................... 106 Figure 93 - Customer Business Object and State Reference Readers................................................................................... 107 Figure 94 - Customer::Load Method.......................................................................................................................................... 108 Figure 95 - SixtyRing Reference Reader Inventory.................................................................................................................. 108 Figure 96 - ICustomerReferenceReader Interface ................................................................................................................... 108 Figure 97 - SixtyRing Reference Reader Inventory.................................................................................................................. 109 Figure 98 – SqlCustomerReader ................................................................................................................................................. 110 Figure 99 - SixtyRing Business Object Reader Inventory....................................................................................................... 111 Figure 100 - Customer::Query Method...................................................................................................................................... 112 Figure 101 - CustomerReader Class ........................................................................................................................................... 112 Figure 102 - Customer::Load Method (overload) .................................................................................................................... 112 Figure 103 - SixtyRing Page Layout CSS Rules ........................................................................................................................ 120 Figure 104 - SixtyRing Menu Link List CSS Rules................................................................................................................... 121 Figure 105 - SixtyRing Button List CSS Rules.......................................................................................................................... 122 Figure 106 - SixtyRing Notification Lists CSS Rules............................................................................................................... 122 Figure 107 - SixtyRing Generic CSS Rules................................................................................................................................ 123 Figure 108 – SixtyRing Skin File ................................................................................................................................................. 125 Figure 109 – Generic Skin ........................................................................................................................................................... 126 Figure 110 – CSS Class Assignment Skin.................................................................................................................................. 126 Figure 111 – Attribute Assignment Skin ................................................................................................................................... 126 Figure 112 – Data Entry Web Controls..................................................................................................................................... 133 Figure 113 – Sample Data Entry Form ..................................................................................................................................... 134 Figure 114 – Configuring Data Entry Controls ....................................................................................................................... 135 Figure 115 – Data Detail Web Controls.................................................................................................................................... 136 Figure 116 – Sample Data Detail Form..................................................................................................................................... 136 Figure 117 – SixtyRingPage OnInitComplete Method ........................................................................................................... 137 Figure 118 – SixtyRingPage ErrorHandler Method ................................................................................................................ 138 Figure 119 – Callback Error Handling....................................................................................................................................... 138 Figure 120 – SixtyRingPage HandleException Method.......................................................................................................... 139 Figure 121 - web.config Security Settings.................................................................................................................................. 140 Figure 122 – CustomerDataSet ................................................................................................................................................... 143 Figure 123 – CustomerDataSource Class .................................................................................................................................. 143 Figure 124 – CustomerDataSource Lookup Method.............................................................................................................. 144
SixtyRing Design and Implementation
SixtyRing Design and Implementation Introduction
Copyright © 2006 Richard G. Todd – 1 –
1. Introduction SixtyRing is a fully-functional reference application designed to illustrate solutions to problems encountered when developing SOA-based web applications. It is implemented using the Microsoft .NET 2.0 Framework and is available for download at www.sixtyring.com.
As with most SOA-based applications, SixtyRing is partitioned into a number of distinct tiers as illustrated in Figure 1. The assets in each tier can either be used as-is or used as templates for new application-specific assets. This guide provides an in-depth overview of each tier as well as guidance for using SixtyRing as the basis for implementing similar systems.
Presentation Tier
The presentation tier of SixtyRing is an ASP.NET 2.0 web application. It highlights features introduced in ASP.NET 2.0 such as master pages, themes and custom security providers.
SixtyRing illustrates the separation of web page content from layout. Techniques employed by the application include:
• Web page layout and formatting controlled through style sheets.
• Custom theme and skins to further reduce the amount of presentation logic within individual web pages.
• Custom controls used to implement data entry and presentation. These further abstract the content of individual web pages and support alternate methods rendering using custom control adapters.
Service Tier
All SOA-based systems require a service contract to be defined. This contract defines the methods and data elements supported by the service. The SixtyRing service contract is defined by a stand-alone service contract assembly. This assembly not only encapsulates the service contract, but it also functions as programming interface that can be used by other .NET clients. Two implementations of this service contract are used by the system:
• A web service proxy implementation designed to interact with the web services exposed by the application server.
• An implementation of the service packaged as a separate .NET assembly.
SixtyRing Design and Implementation Introduction
Copyright © 2006 Richard G. Todd – 2 –
By taking this approach, the web services hosted by the application server function merely as transport mechanism.1 This allows alternate technologies to be used, such as .NET Remoting, while maintaining the same service contract programming interface.
Security is a key concern for most applications, and SixtyRing provides application security through a number features including:
• A set of service-enabled custom security providers that allow the web application to authenticate users without requiring a direct connection to the application database.
• Support for passing security credentials out-of-band using a custom SOAP header and processing them using a custom HTTP module.
• An impersonation mechanism that allows the web server to make web service calls on behalf of the signed-on user.
• A set of custom permissions that define the security policy of the application.
Business and Data Tiers
The business and data tiers are implemented using Object Manager – a generic framework for creating persistable business objects. Business objects interact with the data tier using an explicit data contract. This contract isolates database-specific details from the rest of the system and allows support for alternate database servers to be added without disrupting the rest of the application.
The data tier of many applications often consists simply of a set of data-transfer objects used by the business object layer. This approach makes business objects responsible for many data access concerns such as:
• Determining when persistent state information has been updated and needs to be saved to the database.
• Maintaining foreign-key relationships when persisting new objects to the database.
• Maintaining object-identity when retrieving state information from the database.
The data tier in the SixtyRing system maintains responsibility for these issues and allows the business tier to focus more fully on implanting the business logic required by the application.
1 There is complete fidelity between the service contract as defined by the service contract assembly and the WDSL exposed by the web services implemented by SixtyRing. This allows the service contract to be honored for non-.NET applications directly accessing the web services hosted by the application server.
SixtyRing Design and Implementation Introduction
Copyright © 2006 Richard G. Todd – 3 –
Figure 1 - SixtyRing Application Architecture
SixtyRing Design and Implementation Introduction
Copyright © 2006 Richard G. Todd – 4 –
Program Overview SixtyRing is a web-based e-commerce system. Customers are able to browse a product catalog, add items to their shopping basket and submit new orders for processing. Orders placed by customers are placed in submitted status. A customer may cancel any orders in submitted status. If an order is cancelled, it is moved to cancelled status.
Once an order has been submitted, a shipping clerk can fulfill orders by first moving all submitted orders to shipping status. The shipping clerk can then query the system for all orders in shipping status. As each order is processed, it s moved to shipped status.
SixtyRing defines four types of users:
• Customers are public users of the system. Any public user of the SixtyRing system may create a customer user ID to access the system and submit orders.
• Administrators are private users of the system. They are permitted to perform all secured functions including the creation of other administrator users.
• Shipping clerks are private users of the system. They are permitted to process orders as described above. Shipping clerks are created by administrators.
• The web user is a special user for use by the web application. It is associated with the impersonator role which allows the web application to make service calls on behalf of the user accessing the web application.
The SixtyRing system is a web-based application designed using a service-oriented architecture (SOA). It is intended to illustrate best-practices for implementing such systems.
SixtyRing is a simple order-entry entry system. It contains a product database that users may browse. Customers can add products to their shopping cart and submit orders.
System Implementation The SixtyRing system is comprised into 13 .NET assemblies, a web application and a web service application. The relationship between these items is shown in Figure 2.
Assembly Chapter
Copyright © 2006 Richard G. Todd – 5 –
SixtyRing.State
SixtyRing.Web
SixtyRing.Web.Service
Copyright © 2006 Richard G. Todd – 6 –
SixtyRIng.Service
Copyright © 2006 Richard G. Todd – 7 –
Data Model The data model used by SixtyRing is illustrated Figure 3.
Country
countryCode
name
Customer
customerId
version
name
mailingAddre. . .
mailingAddre. . .
mailingAddre. . .
mailingCity
mailingState. . .
mailingZipCode
mailingCount. . .
Copyright © 2006 Richard G. Todd – 8 –
The database contains the following tables:
• UserProfile contains information about all users of the system, including customers.
• UserProfileRole defines the roles associated with a user.
• Role is a rules table that defines the roles used by the system.
• Customer contains information about a single customer. Information includes the customer’s name, mailing address and billing address.
• CustomerOrder contains information about a single customer order. The table refers to one or more CustomerOrderEntry records that identify the products in the order.
• Product is a rules table that identifies all available products.
• State and Country are rules tables that identify all postal states and countries.
• Key is a utility table used to generate primary keys.
SixtyRing Design and Implementation Service Contract Assemblies
Copyright © 2006 Richard G. Todd – 9 –
2. Service Contract Assemblies The SixtyRing system is implemented using a service-oriented architecture (SOA). This section provides details about how services are implemented in the SixtyRing system.
The services in many SOA-based systems are implemented as web services. In fact, this is often assumed when discussing SOA-based systems. However, other technologies, such as .NET remoting, can be used to access services hosted on remote systems. Further, the services consumed by an SOA-based application can also be implemented in local libraries and accessed directly through procedure calls. Smart client applications often rely on local service implementations when running in “disconnected” mode. When the application is running in “connected” mode, these local services are disabled and the application instead uses the services hosted on a remote system.
Before a service can be implemented, the service contract must be defined. The service contract consists of the following:
• The methods implemented by the service.
• The data elements passed between the service and the client.
• The exceptions that can be raised by the service.
• The permissions required by each service method.
In the SixtyRing system, the service contract is defined by a .NET assembly known as the service contract assembly. Clients of the service refer to interfaces and classes declared in the service contract assembly. There are two concrete implementations of the service contract: a local service implementation and a web service implementation. Each of these implementations is contained in a separately assembly. The implementation to be used by an application is loaded when the application starts but is otherwise not directly referenced by client code.
This chapter details the implementation of the SixtyRing service contract assembly. For details on the local service implementation, see “Local Service ” on page 22. For details on the web service implementation, see “Web Service ” on page 43.
Artifacts The following artifacts are documented in this section. These artifacts can be used in applications based on SixtyRing as outlined below:
Use The artifact is required and will be used without modification.
Modify The artifact is required but must be modified for before use.
Optional The artifact is an optional resource that may be used if necessary.
SixtyRing Design and Implementation Service Contract Assemblies
Copyright © 2006 Richard G. Todd – 10 –
SixtyRing.Service Assembly
Copyright © 2006 Richard G. Todd – 11 –
Artifact Use Modify Optional
Copyright © 2006 Richard G. Todd – 12 –
Artifact Use Modify Optional
Service Interfaces All services interfaces inherit from a base IService interface. The SixtyRing defines the following services interfaces:
• ICustomer
• IOrder
• ILog
• IProduct
• IRules
• IUserProfile
Copyright © 2006 Richard G. Todd – 13 –
Each service has its own interface as illustrated in Figure 4.
Figure 4 – SixtyRing Service Interfaces
The methods defined by each service interface should be designed to accommodate the implementation of the service using XML web service. In particular:
• Restrict parameter types to scalar types, arrays, and data structures as described in the next section.
• All parameters should pass data by value; do not pass data by reference. Return data to the caller using the function return value.
SixtyRing Design and Implementation Service Contract Assemblies
Copyright © 2006 Richard G. Todd – 14 –
The interface used to define the Order service is shown in Figure 5.
public interface IOrderService : IService { Order Lookup( long orderId); Order [] Query( OrderSearchCriteria searchCriteria); Order [] QueryAll(); long Submit( OrderRequest order); Order PrepareToSubmit( OrderRequest order); void PrepareToShip(); void Ship( long orderId); void Cancel( long orderId); }
Figure 5 – Order Service
Service Data Data structures used by service methods should be designed to accommodate the implementation of the service using XML web services.
Consider the following service method show in Figure 6.
public interface IOrderService : IService { long Submit( OrderRequest order); }
Figure 6 – Order Service Submit Method
SixtyRing Design and Implementation Service Contract Assemblies
Copyright © 2006 Richard G. Todd – 15 –
The definition of OrderRequest is shown in Figure 7.
[ Serializable ] [ XmlType (Namespace = Xml.Namespace)] [ XmlRoot ( "OrderRequest" , Namespace = Xml.Namespace)] public class OrderRequest { #region Fields private long m_customerId = long .MinValue; private PostalAddress m_shippingAddress = null ; private PostalAddress m_billingAddress = null ; private List <OrderRequestEntry > m_entries = null ; #endregion #region Public Properties public long CustomerId { get { return m_customerId; } set { m_customerId = value ; } } public PostalAddress ShippingAddress { get { return m_shippingAddress; } set { m_shippingAddress = value ; } } public PostalAddress BillingAddress { get { return m_billingAddress; } set { m_billingAddress = value ; } } public List <OrderRequestEntry > Entries { get { return m_entries; } set { m_entries = value ; } } #endregion }
Figure 7 – OrderRequest Class
Copyright © 2006 Richard G. Todd – 16 –
The OrderRequest class makes use of the OrderRequestEntry class shown in Figure 8.
[ Serializable ] [ XmlType (Namespace = Xml.Namespace)] public class OrderRequestEntry { #region Fields private long m_productId = long .MinValue; private int m_quantity = int .MinValue; #endregion #region Public Properties public long ProductId { get { return m_productId; } set { m_productId = value ; } } public int Quantity { get { return m_quantity; } set { m_quantity = value ; } } #endregion }
Figure 8 – OrderRequestEntry Class
To permit instances of the class to be serialized using XML serialization, the following guidelines should be followed:
• Apply the Serializable attribute to all classes.
• Apply the XmlType and XmlRoot attributes as described below.
• Define collections of sub-objects using arrays or the generic List datatype. Using lists usually facilitates the construction of parameter data.
• Classes should be designed as data-transfer objects. Do not add business logic or other functionality.
XmlType
The XmlType attribute is applied to all classes and enumerations. It specifies the namespace to be associated with the elements created when the data structure is serialized.
The Xml class defines a Namespace constant that can be used to specify the namespace consistently across all classes.
XmlRoot
The XmlRoot attribute is applied to classes which are serialized as the root element in an XML document. It specifies the name of the root element. Generally speaking, these are classes which are
SixtyRing Design and Implementation Service Contract Assemblies
Copyright © 2006 Richard G. Todd – 17 –
specified as parameters in web service methods. By convention, the name of the class is used as the XML root element.
Note that the XmlRoot element has been applied to the OrderRequest class in Figure 7 but not to the OrderRequestEntry in Figure 8. In some cases, a class can be used both as a service method parameter and indirectly as parameter sub-object. When this is the class, the XmlRoot attribute will be ignored when the object is serialized as a parameter sub-object.
XmlEnum
The XmlEnum attribute is applied to enumeration element and specifies the value to be used when enumeration element is serialized.
Figure 9 shows how XmlEnum can be used.
[ Serializable ] [ XmlType (Namespace = Xml.Namespace)] public enum OrderStatus : int { [ XmlEnum( "N" )] Submitted = 0, [ XmlEnum( "P" )] Shipping = 1, [ XmlEnum( "S" )] Shipped= 2, [ XmlEnum( "C" )] Cancelled = 3 }
Figure 9 – OrderStatus Enumeration
Service Exceptions Exceptions are used to report unexpected or invalid conditions detected by an application. Each layer within an application contains exception handling logic appropriate for that layer. There are three primary exception scenarios that can occur within each layer of an application:
• An exception is received from a lower application layer and is successfully handled.
• An exception is received from a lower application layer and is allowed to percolate to a higher application layer.
• An exception is generated directly by the application layer and allowed to percolate to a higher application layer.
Exceptions that are allowed to percolate to a higher application layer are caused by forces that are either external or internal to the application layer. External forces include:
• Invalid arguments or data passed to the application layer.
• Insufficient authority to perform a requested operation.
• A request to perform an invalid operation.
• Exceptions received from external resources.
SixtyRing Design and Implementation Service Contract Assemblies
Copyright © 2006 Richard G. Todd – 18 –
Ideally, only exceptions caused by external forces should be raised by an application layer. However, exceptions can also be caused by forces internal to the application layer such as coding and deployment errors. An exception should always reflect the nature of the force that caused it to be raised.
All exceptions raised by the services defined by the service contract assembly either inherit from ServiceException or SecurityException. Two classes inherit from ServiceException:
• ClientFaultServiceException – indicates an exception caused by an external force.
• ServerFaultServiceException – indicates an exception caused by an internal force.
All the exception classes defined by the service contract assembly are shown in Figure 10 and summarized in the following table.
Figure 10 – SixtyRing Exception Classes
Exception Inherits From Definition
ServiceException The base class of all exceptions raised by the service layer.
ClientFaultServiceException ServiceException An exception caused by a client-related error.
ArgumentInvalidServiceException ClientFaultServiceException An invalid argument value was specified.
ArgumentNullServiceException ClientFaultServiceException A required argument value was omitted.
InvalidOperationServiceException ClientFaultServiceException A service operation was not permitted.
ServerFaultServiceException ServiceException An exception caused by a server-related error.
ServerUnavailableServiceException ServerFaultServiceException The server is not available at this time.
ResourceServiceException ServerFaultServiceException The server could not complete the requested operation due to an unavailable resource.
SixtyRing Design and Implementation Service Contract Assemblies
Copyright © 2006 Richard G. Todd – 19 –
All exceptions derived from ClientFaultServiceException represent errors caused the client. When appropriate, an exception derived from ClientFaultServiceException is raised. If no such class exists, a ClientFaultServiceException is raised with a message that describes the nature of the error.
All exceptions derived from ServerFaultServiceException represent errors caused by the server. If no such class exists, ServerFaultServiceException is raised. Other than the exceptions noted below, a ServerFaultServiceException should be treated as a system error requiring programmer support. In these situations, the error should be logged.
ServerUnavailableServiceException is raised when service made unavailable due to system maintenance or similar conditions. A ServerUnavailableServiceException is not considered to be a system error and is not logged.
ResourceServiceException is raised when an external resource, such as a database server, is not available. While a ResourceServiceException is not considered to be a system error, they should be logged for reference.
As noted earlier, services can also raise SecurityExceptions. The SecurityException class allows the permission associated with the exception to be passed with the exception data.
Data Dictionary The data dictionary allows the service interface to specify data type requirements. The Field class and its descendents are used by client applications to validate data before passing it the service.
Fields are obtained using the properties of domain-specific classes such as Customer and Product.
SixtyRing Design and Implementation Service Contract Assemblies
Copyright © 2006 Richard G. Todd – 20 –
Figure 11 shows the data dictionary classes used by SixtyRing:
Figure 11 – SixtyRing Data Dictionary Classes
SixtyRing Design and Implementation Service Contract Assemblies
Copyright © 2006 Richard G. Todd – 21 –
Service Pools The service pool manages the service used by an application. Services are typically added to the service pool when the application is first started. Figure 12 shows how the Customer and Order web service proxy classes are added to the service pool.
OperatingEnvironment operatingEnvironment = new OperatingEnvironment (); WebServiceContext serviceContext = new WebServiceContext (operatingEnvironment); ServicePool .Singleton.Register< ICustomerService >( new CustomerService (serviceContext , "CustomerService.asmx" ,WebUser ,WebPassword)); ServicePool .Singleton.Register< IOrderService >( new OrderService (serviceContext , "OrderService.asmx" ,WebUser ,WebPassword));
Figure 12 – Registering Services with the Service Pool
Services are added to the service pool using the Register method shown in Figure 13. The service must implement the service interface specified by the method’s type parameter.
public void Register<TService>(TService service) where TService: IService
Figure 13 – ServicePool Register Method
Services can be retrieved from the service pool using the Lookup method shown in Figure 14.
public TService Lookup<TService>() where TService : class , IService
Figure 14 – ServicePool Lookup Method
The example in Figure 15 shows how the previously registered implementation of the Customer service is retrieved.
ServicePool .Singleton.Lookup< ICustomerService >();
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 22 –
3. Local Service Assemblies The local service assembly contains implementations of all service interfaces defined by the service contract assembly. These classes can be used directly by clients. They also serve as the basis for creating web service-based implementations of the service.
Artifacts The following artifacts are documented in this section. These artifacts can be used in applications based on SixtyRing as outlined below:
Use The artifact is required and will be used without modification.
Modify The artifact is required but must be modified for before use.
Optional The artifact is an optional resource that may be used if necessary.
SixtyRing.Service.Local Assembly
Copyright © 2006 Richard G. Todd – 23 –
Artifact Use Modify Optional
SixtyRing.Service.Local.UserProfilePermission
SixtyRing.Service.Local.UserProfilePermissionAccess
SixtyRing.Service.Local.UserProfileRolePermission
SixtyRing.Service.Local.UserProfileRolePermissionAccess
SixtyRing.Service.Local.UserProfileService
SixtyRing.Service.Local.Utility
Service Classes Each service interface defined by the service contract assembly is implemented by a class in the local service assembly. The SixtyRing application contains the following service implementation classes:
• Customer
• Order
• Log
• Product
• Rules
• UserProfile
An excerpt of the local service implementation of IOrderService is shown in Figure 16. The figure contains the implementation of the IOrderService::Submit method and associated private methods.
public class OrderService : ServiceInterface , IOrderService { #region Fields private readonly IDataSource m_dataSource; #endregion #region Constructors public OrderService( IServiceContext context, IDataSource dataSource) : base (context) { m_dataSource = dataSource; } #endregion
Figure 16 – Local OrderService Class
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 24 –
#region IOrderService Members public long Submit( OrderRequest orderRequest) { try { Validate(orderRequest); BusinessObjectSession session = new BusinessObjectSession (m_dataSource); Business. Customer businessCustomer = Business. Customer .Load(session, orderRequest .CustomerId); if (!businessCustomer.Exists) throw new ArgumentInvalidServiceException ( "Customer does not exist." ); CreateSubmitPermission(businessCustomer ).Demand(); Business. Order businessOrder = Business. Order .Create(session, businessCustomer); Mapper .Copy(orderRequest, businessOrder); businessOrder.SubmitDateTime = Context.OperatingEnvironment.Now; session.Persist(); return businessOrder.OrderId; } catch ( Exception e) { Utility .HandleException(e); throw ; } } #endregion
Figure 16 – Local OrderService Class (con’t)
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 25 –
#region Private Methods private ServicePermission CreateSubmitPermission( Business. Customer businessCustomer) { if ( businessCustomer.UserId == Context.Principal.Identity.Name) { return new OrderPermission ( OrderPermissionAccess .SubmitPersonal); } else { return new OrderPermission ( OrderPermissionAccess .SubmitOther); } } private void Validate( OrderRequest orderRequest) { string context; DataDictionary. PostalAddress postalAddress = new DataDictionary. PostalAddress (); // // Shipping Address // context = "Shipping address" ; if (orderRequest.ShippingAddress == null ) { throw new ArgumentNullServiceException (context); } postalAddress.CountryCode.Validate( orderRequest.ShippingAddress.CountryCod e, context); postalAddress.AddressLine1.Validate( orderRequest.ShippingAddress.AddressLin e1, context); postalAddress.AddressLine2.Validate( orderRequest.ShippingAddress.AddressLin e2, context, true ); postalAddress.AddressLine3.Validate( orderRequest.ShippingAddress.AddressLin e3, context, true ); if (orderRequest.ShippingAddress.CountryCode == "US" ) { postalAddress.City.Validate( orderRequest.ShippingAddress.City, context); postalAddress.StateCode.Validate( orderRequest.ShippingAddress.StateC ode, context); postalAddress.ZipCode.Validate( orderRequest.ShippingAddress.ZipCod e, context); }
Figure 16 – Local OrderService Class (con’t)
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 26 –
// // Billing Address // context = "Billing address" ; if (orderRequest.BillingAddress == null ) { throw new ArgumentNullServiceException (context); } postalAddress.CountryCode.Validate( orderRequest.BillingAddress.CountryCode , context); postalAddress.AddressLine1.Validate( orderRequest.BillingAddress.AddressLine 1, context); postalAddress.AddressLine2.Validate( orderRequest.BillingAddress.AddressLine 2, context, true ); postalAddress.AddressLine3.Validate( orderRequest.BillingAddress.AddressLine 3, context, true ); if (orderRequest.BillingAddress.CountryCode == "US" ) { postalAddress.City.Validate( orderRequest.BillingAddress.City, c ontext); postalAddress.StateCode.Validate( orderRequest.BillingAddress.StateCo de, context); postalAddress.ZipCode.Validate( orderRequest.BillingAddress.ZipCode , context); }
Copyright © 2006 Richard G. Todd – 27 –
// // Order Entries // context = "Order Entries" ; if (orderRequest.Entries == null ) { throw new ArgumentNullServiceException (context); } int entryIndex = 0; foreach ( OrderRequestEntry orderRequestEntry in orderRequest.Entries) { if (orderRequestEntry.Quantity < 1) { throw new ArgumentInvalidServiceException ( "Quantity less than minimum value of 1." , String .Format( "{0:d}" , entryIndex)); } if (orderRequestEntry.Quantity > 100) { throw new ArgumentInvalidServiceException ( "Quantity greater than maximum value of 100." , String .Format( "{0:d}" , entryIndex)); } ++entryIndex; } } #endregion }
Figure 16 – Local OrderService Class (con’t)
The implementation of the Submit method has the following features common to all service method implementations:
• The input data is explicitly validated and the appropriate ClientFaultServiceException-based exceptions are raised if invalid data is passed from the client.
• Security is enforced by creating and demanding the appropriate permission.
• A method-wide exception handling block processes all exceptions and ensures the appropriate exception is thrown to the caller.
These features are described in more detail in the sections which follow.
Data Validation All data passed to a service method must be validated and the appropriate ClientFaultServiceException-based exception thrown if invalidate data exists. Most data validation is performed by a private Validate method. A Validate method exists for each parameter type used by the service. The method ensures that all require fields have been specified, maximum field lengths
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 28 –
have not been exceeded and other data formatting rules are satisfied. Many of these data validation checks can be performed using methods exposed by the data dictionary classes defined in the service contract assembly. See the Validate method in Figure 16 for an example.
Some validation cannot be performed by statically examining the data. For example, a customer ID can only be validated by ensuring the customer ID exists in the database. These checks should be performed before the data is used and the appropriate exception thrown. See the Submit method in Figure 16 for an example.
Permissions Services are required to enforce security. This function is handled through the use of permissions. All permissions used by the system inherit from a base ServicePermission class as shown in Figure 17.
Figure 17 – SixtyRing Permissions
Copyright © 2006 Richard G. Todd – 29 –
Classes that inherit from ServicePermission are required to implement the TryDemand method. This method is used by the ServicePermission::Demand method as shown in Figure 18.
public abstract class ServicePermission : IPermission { ... public virtual void Demand() { string message; if (!TryDemand( out message)) { throw new SecurityException (message, GetType()); } } public abstract bool TryDemand( out string message); }
Figure 18 – ServicePermission Demand Method
The TryDemand method can also be called directly in situations that require a permission to be checked without causing an exception to be raised. This is useful in situations where security information is being passed back to the caller as shown Figure 19.
public Order Lookup( long orderId) { ... if ( ( businessOrder.Status == SixtyRing.Business. OrderStatus .Submitted) || ( businessOrder.Status == SixtyRing.Business. OrderStatus .Shipping)) { order.Permissions.CanCancel = CreateCancelPermission(businessOrder).T ryDemand( out message); } else { order.Permissions.CanCancel = false ; } ... }
Figure 19 – Order Service Lookup Method
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 30 –
Associated with each permission is an enumeration that defines the types of access controlled by the permission. For example, associated with the OrderPermission class is the enumeration shown in Figure 20.
[ Flags ] public enum OrderPermissionAccess : uint { None = 0x0000, ViewPersonal = 0x0001, ViewOther = 0x0002, CancelPersonal = 0x0004, CancelOther = 0x0008, SubmitPersonal = 0x0010, SubmitOther = 0x0020, UpdatePersonal = 0x0040, UpdateOther = 0x0080, ShipAny = 0x0100, CancelShipping = 0x0200, AllAccess = 0x03FF }
Figure 20 – OrderPermissionAccess Enumeration
Note that the Flags attribute is used to enable access values to be combined together. When more than one access flag is specified, permission to all access values must be satistified when the permission is demanded. By convention, the access values to be used by a permission are specified by the class constructor.
The implementation of the OrderPermission class is shown in Figure 21. Most of the logic unique to the OrderPermission class is in the TryDemand method as described above. The class is also required to implement the following methods defined by the IPermission and ISecurityEncodable interfaces:
• Copy
• Intersect
• IsSubsetOf
• Union
• FromXml
• ToXml
Implementation of these methods by other permission classes can be made based on the code shown below.
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 31 –
public class OrderPermission : ServicePermission , ICloneable { #region Fields private OrderPermissionAccess m_access; #endregion #region Constructors public OrderPermission( OrderPermissionAccess access) { m_access = access; } #endregion #region Public Members public override IPermission Copy() { return ( IPermission )Clone(); }
Figure 21 – OrderPermission Class
Copyright © 2006 Richard G. Todd – 32 –
public override bool TryDemand( out string message) { if ((m_access & OrderPermissionAccess .SubmitPersonal) != 0) { if (! Thread .CurrentPrincipal.IsInRole( SixtyRingRoles .Customer)) { message = "User not authorized to submit new order." ; return false ; } } if ((m_access & OrderPermissionAccess .ViewPersonal) != 0) { if (! Thread .CurrentPrincipal.IsInRole( SixtyRingRoles .Customer)) { message = "User not authorized to order." ; return false ; } } if (((m_access & OrderPermissionAccess .CancelPersonal) != 0) || ((m_access & OrderPermissionAccess .UpdatePersonal) != 0)) { if (! Thread .CurrentPrincipal.IsInRole( SixtyRingRoles .Customer)) { message = "User not authorized to order." ; return false ; } } if ((m_access & OrderPermissionAccess .SubmitOther) != 0) { if (! Thread .CurrentPrincipal.IsInRole( SixtyRingRoles .Administrator)) { message = "User not authorized to submit new order." ; return false ; } } if (((m_access & OrderPermissionAccess .ViewOther) != 0)) { if ( ! Thread .CurrentPrincipal.IsInRole( SixtyRingRoles .Shipper) && ! Thread .CurrentPrincipal.IsInRole( SixtyRingRoles .Administrator)) { message = "User not authorized to order." ; return false ; } }
Figure 21 – OrderPermission Class (con’t)
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 33 –
if (((m_access & OrderPermissionAccess .CancelOther) != 0) || ((m_access & OrderPermissionAccess .CancelShipping) != 0) || ((m_access & OrderPermissionAccess .UpdateOther) != 0)) { if (! Thread .CurrentPrincipal.IsInRole( SixtyRingRoles .Administrator)) { message = "User not authorized to order." ; return false ; } } if ((m_access & OrderPermissionAccess .ShipAny) != 0) { if ( ! Thread .CurrentPrincipal.IsInRole( SixtyRingRoles .Shipper) && ! Thread .CurrentPrincipal.IsInRole( SixtyRingRoles .Administrator)) { message = "User not authorized to order." ; return false ; } } message = string .Empty; return true ; } public override IPermission Intersect( IPermission target) { if (target == null ) return null ; OrderPermission targetOrderPermission = target as OrderPermission ; if (targetOrderPermission == null ) throw new ArgumentException ( "target" , string .Format( "Type {0:s} expected." , typeof ( OrderPermission ).FullName)); OrderPermissionAccess intersectAccess = m_access & targetOrderPermission.m_access; return new OrderPermission (intersectAccess); }
Figure 21 – OrderPermission Class (con’t)
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 34 –
public override bool IsSubsetOf( IPermission target) { if (target == null ) return false ; OrderPermission targetOrderPermission = target as OrderPermission ; if (targetOrderPermission == null ) throw new ArgumentException ( "target" , string .Format( "Type {0:s} expected." , typeof ( OrderPermission ).FullName)); OrderPermissionAccess access = m_access & (~targetOrderPermission.m_access); return (access == 0); } public override IPermission Union( IPermission target) { if (target == null ) return null ; OrderPermission targetOrderPermission = target as OrderPermission ; if (targetOrderPermission == null ) throw new ArgumentException ( "target" , string .Format( "Type {0:s} expected." , typeof ( OrderPermission ).FullName)); OrderPermissionAccess unionAccess = m_access | targetOrderPermission.m_access; return new OrderPermission (unionAccess); }
Figure 21 – OrderPermission Class (con’t)
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 35 –
public override void FromXml( SecurityElement e) { m_access = OrderPermissionAccess .None; // If XML indicates an unrestricted permission, mak e this // permission unrestricted. // String s = ( String )e.Attributes[ATTRIBUTE_UNRESTRICTED]; if (s != null ) { m_access = OrderPermissionAccess .AllAccess; } else { // Retrieve the order permission flags. // s = ( String )e.Attributes[ATTRIBUTE_FLAGS]; if (s != null ) { m_access = ( OrderPermissionAccess ) Convert .ToInt32( Enum .Parse( typeof ( OrderPermissionAccess ) ,s , true )); } } } public override SecurityElement ToXml() { // Create a new security element. Replace the doub le quotation // marks (") with single quotation marks (') to rem ain XML // compliant when the culture is not neutral. // SecurityElement e = new SecurityElement ( "IPermission" ); e.AddAttribute( "class" , GetType().AssemblyQualifiedName.Replace( '\"' , '\'' )); e.AddAttribute( "version" , "1" ); // Set the appropriate security element attribute. // if (m_access == OrderPermissionAccess .AllAccess) e.AddAttribute(ATTRIBUTE_UNRESTRICTED, VALUE_TRUE); else e.AddAttribute( ATTRIBUTE_FLAGS, Enum.Format( typeof ( OrderPermissionAccess ) ,m_access , "G" )); return e; } #endregion
Figure 21 – OrderPermission Class (con’t)
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 36 –
#region ICloneable Members public object Clone() { return MemberwiseClone(); } #endregion }
Figure 21 – OrderPermission Class (con’t)
Because the access permission can often vary based on the data passed to the service method, construction of the appropriate permission is made by a private method and called when the permission is required. For example, when an order is retrieved, the service ensures the caller has the proper “view” permission as shown in Figure 22
public class OrderService : ServiceInterface , IOrderService { public Order Lookup( long orderId) { ... Business. Order businessOrder = Business. Order .Load(session ,orderId); if (!businessOrder.Exists) return null ; CreateViewPermission(businessOrder).Demand(); ... } private ServicePermission CreateViewPermission( Order businessOrder) { if ( businessOrder.Customer.UserId == Thread .CurrentPrincipal.Identity.Name) { return new OrderPermission ( OrderPermissionAccess .ViewPersonal); } else { return new OrderPermission ( OrderPermissionAccess .ViewOther); } } }
Figure 22 – OrderService Lookup and CreateViewPermission Methods
Data Mapping The local service assembly must transform data defined by the service interface assembly and data defined by the business and data access layers of the application. This logic is handled by a mapper
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 37 –
class. This is a static class that defines a number of overloaded Copy methods as illustrated in Figure 23.
public static void Copy(Service. OrderRequest from, Business. Order to) { if (from.ShippingAddress == null ) { to.ShippingAddress.Clear(); } else { Mapper .Copy(from.ShippingAddress, to.ShippingAddress); } if (from.BillingAddress == null ) { to.BillingAddress.Clear(); } else { Mapper .Copy(from.BillingAddress, to.BillingAddress); } to.OrderEntries.Clear(); if (from.Entries != null ) { foreach ( OrderRequestEntry orderEntry in from.Entries) { Business. Product product = Business. Product .Load(to.Session ,orderEntry.Pr oductId); if (!product.Exists) { throw new ArgumentException ( String .Format( "Product {0:d} does not exist." , orderEntry.ProductId)); } to.OrderEntries.Add(product, orderEntry .Quantity); } } }
Figure 23 – Mapper Copy Method
Exception Handling As shown in Figure 16, service methods declare a method-wide exception handler and process any exceptions throw using the Utility::HandleException method shown in Figure 24.
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 38 –
public static void HandleException( Exception e) { // Allow all ServiceException's to be rethrown by t he caller. // if (e is ServiceException ) return ; // and rethrow exception. // Convert State.ResourceStateException's to // Service.ResourceStateException's. // State. ResourceStateException resourceStateException = e as State. ResourceStateException ; if (resourceStateException != null ) { throw new ResourceServiceException ( resourceStateException.Message, resourceStateException.ResourceName); } // If a SecurityException was caused by a StatePerm ission, allow it // to be rethrown by the caller. // SecurityException securityException = e as SecurityException ; if ( securityException != null && securityException.PermissionType != null ) { if ( typeof ( ServicePermission ).IsAssignableFrom( securityException.PermissionType)) { return ; // and rethrow exception } } throw new ServerFaultServiceException ( "Internal exception occurred." , e); }
Figure 24 – Utility HandleException Method
If the exception originates from the service layer, the function returns to the caller which then rethrows the exception. Specifically, the function checks for these conditions:
• The exception is a ServiceException or inherits from ServiceException.
• The exception is a SecurityException and the associated permission is a ServicePermission or inherits from ServicePermission.
The function also handles ResourceStateExceptions thrown from the data access layer and throws a corresponding ResourceServiceException.
If the exception does not satisfy these conditions, it is considered to be an unexpected service error and a ServerFaultServiceException is thrown.
Note that this function assumes that the service layer does not throw ArgumentNullException, InvalidArgumentException, InvalidOperationException or similar exceptions. If these exceptions
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 39 –
are thrown, they are assumed to originate from the business or data access layers of the application and therefore are considered to be service-based errors rather than client-based errors.
Service Interfaces All classes that provide access to a service, either local or remote, inherit from ServiceInterface, or a ServiceInterface-derived class, as shown in Figure 25.
public class ServiceInterface { public ServiceInterface( IServiceContext context) { ... } public IServiceContext Context { get { ... } } }
Figure 25 – ServiceInterface Class
When a ServiceInterface object is created, an object that implements IServiceContext must be provided. This is described in the next section.
IServiceContext The IServiceContext interface shown in Figure 26 allows a service interface to gather information about the calling environment. Among other things, it allows the IPrincipal associated with the current user to be retrieved.
public interface IServiceContext { IPrincipal Principal { get ; } IOperatingEnvironment OperatingEnvironment { get ; } }
Figure 26 – IServiceContract Interface
• WebServiceContext – used when accessing a service from a web application.
• WindowsServiceContext – used when accessing a service from a windows application.
These classes are shown in Figure 27 and Figure 28 below. Note the implementations of the Principal method.
SixtyRing Design and Implementation Local Service Assemblies
Copyright © 2006 Richard G. Todd – 40 –
public class WebServiceContext : IServiceContext { private IOperatingEnvironment m_operatingEnvironment; public WebServiceContext( IOperatingEnvironment operatingEnvironment) { m_operatingEnvironment = operatingEnvironme nt; } #region IServiceContext Members public IPrincipal Principal { if ( Thread.CurrentPrincipal.Identity.Name != HttpContext.Current.User.Identity.Name) { throw new InvalidOperationException( "HttpContext and Thread principals do not match."); } return Thread.CurrentPrincipal; } public IOperatingEnvironment OperatingEnvironment { get { return m_operatingEnvironment; } } #endregion }
Figure 27 – WebServiceContext Class
Copyright © 2006 Richard G. Todd – 41 –
public class WindowsServiceContext : IServiceContext { private IOperatingEnvironment m_operatingEnvironment; public WindowsServiceContext( IOperatingEnvironment operatingEnvironment) { m_operatingEnvironment = operatingEnvironme nt; } #region IServiceContext Members public IPrincipal Principal { get { return Thread.CurrentPrincipal; } } public IOperatingEnvironment OperatingEnvironment { get { return m_operatingEnvironment; } } #endregion }
Figure 28 – WindowsServiceContract Class
public interface IOperatingEnvironment { DateTime Now { get ; } }
Figure 29 – IOperatingEnvironment Interface
The definition of this interface in the SixtyRing system contains a single method used to retrieve the current time. An implementation of this interface is shown in Figure 30.
public class OperatingEnvironment : IOperatingEnvironment { #region IOperatingEnvironment Members public DateTime Now { get { return DateTime .Now; } } #endregion }
Figure 30 – OperatingEnvironment Class
Copyright © 2006 Richard G. Todd – 42 –
Alternate implementations of this interface that allow a value other than the current system time to be returned might be used during development.
SixtyRing Design and Implementation Web Service Assemblies
Copyright © 2006 Richard G. Todd – 43 –
4. Web Service Assemblies When a service is implemented as web service, two key components are required:
• A web service that implements the service. To minimize the amount of dynamically compiled code, classes required by the web service are contained in web service application assembly.
• A web service proxy which is callable by client code. The proxy implements the service interface and invokes the appropriate web service methods. This code is contained in the web service proxy assembly.
Artifacts The following artifacts are documented in this section. These artifacts can be used in applications based on SixtyRing as outlined below:
Use The artifact is required and will be used without modification.
Modify The artifact is required but must be modified for before use.
Optional The artifact is an optional resource that may be used if necessary.
SixtyRing.Service.Web Assembly
Copyright © 2006 Richard G. Todd – 44 –
Artifact Use Modify Optional
CustomerService.asmx
Global.asax
LogService.asmx
OrderService.asmx
ProductService.asmx
RulesService.asmx
UserProfileService.asmx
web.config
Web Service Site A web service site contains a number of web services, each defined by an asmx file and associated code-behind file. The SixtyRing application contains the following web services:
• CustomerService.asmx
• OrderService.asmx
• LogService.asmx
• ProductService.asmx
• RulesService.asmx
• UserProfileService.asmx
The structure of each web service class is shown in Figure 31.
SixtyRing Design and Implementation Web Service Assemblies
Copyright © 2006 Richard G. Todd – 45 –
[ WebService (Namespace = Xml.Namespace)] [ WebServiceBinding (ConformsTo = WsiProfiles .BasicProfile1_1)] public class OrderService : AuthenticatedService { [ WebMethod] [ SoapHeader ( AuthenticatedService .SoapHeader)] public long Submit( OrderRequest orderRequest) { ... } }
Figure 31 – Web Service Class
The web service class is marked with the WebService attribute that defines the namespace associated with the service. The class inherits from AuthenticatedService which, in turn, inherits from System.Web.Services.WebService. The AuthenticatedService class is described below.
Web Service Methods Each method defined by the service interface has a corresponding web service method. The method associated with the IOrder::Submit method is shown in Figure 32
[ WebService (Namespace = Xml.Namespace)] [ WebServiceBinding (ConformsTo = WsiProfiles .BasicProfile1_1)] public class OrderService : AuthenticatedService { [ WebMethod] [ SoapHeader ( AuthenticatedService .SoapHeader)] public long Submit( OrderRequest orderRequest) { try { return SixtyRingWebServiceApplication .OrderService.Submit( orderRequest); } catch ( Exception e) { Utility .HandleException(e, Context); throw ; } } }
Figure 32 – Order Web Service Submit Method
The implementation of the Submit method has the following features common to all web service method implementations:
• The implementation of the method is delegated to corresponding local service assembly method. The SixtyRingWebServiceApplication.OrderService property returns the interface associated with the local service implementation of the IOrder service.
SixtyRing Design and Implementation Web Service Assemblies
Copyright © 2006 Richard G. Todd – 46 –
• It is marked with the SoapHeader attribute to indicate a application-defined SOAP header is used. In this case, a SOAP header is used to pass out-of-band authentication information to the web service.
• A method-wide exception handling block processes all exceptions and ensures the appropriate exception is thrown to the caller.
These features are described in more detail in the sections which follow.
All web services methods are implemented in terms of their corresponding local service assembly methods. These services are registered and managed by the SixtyRingWebServiceApplication class – a singleton contained in the web service application assembly. This class is shown in Figure 33.
When the object is initialized, it creates an instance of each service defined by the local service assembly and registers it with the service pool. It exposes a number of convenience properties that allow these services to be retrieved.
SixtyRing Design and Implementation Web Service Assemblies
Copyright © 2006 Richard G. Todd – 47 –
public class SixtyRingWebServiceApplication { private static SixtyRingWebServiceApplication m_singleton = new SixtyRingWebServiceApplication (); private IDataSource m_dataSource; private SixtyRingWebServiceApplication() { m_dataSource = new SqlDataSource ( "..." ); string logFileName = ConfigurationManager .AppSettings[ "logFile" ]; OperatingEnvironment operatingEnvironment = new OperatingEnvironment (); SixtyRing.Service. WebServiceContext serviceContext = new SixtyRing.Service. WebServiceContext (operatingEnvironment); ServicePool .Singleton.Register< ICustomerService >( new SixtyRing.Service.Local. CustomerService (serviceContext ,m_dataSource)); ServicePool .Singleton.Register< IOrderService >( new SixtyRing.Service.Local. OrderService (serviceContext ,m_dataSource)); ServicePool .Singleton.Register< IProductService >( new SixtyRing.Service.Local. ProductService (serviceContext ,m_dataSource)); ServicePool .Singleton.Register< IRulesService >( new SixtyRing.Service.Local. RulesService (serviceContext ,m_dataSource)); ServicePool .Singleton.Register< IUserProfileService >( new SixtyRing.Service.Local. UserProfileService (serviceContext ,m_dataSource)); ServicePool .Singleton.Register< ILogService >( new SixtyRing.Service.Local. FileLogServiceLocal (serviceContext ,logFileName)); } public static SixtyRingWebServiceApplication Singleton { get { return m_singleton; } } public IDataSource DataSource { get { return m_dataSource; }
SixtyRing Design and Implementation Web Service Assemblies
Copyright © 2006 Richard G. Todd – 48 –
}
Figure 33 – SixtyRingWebServiceApplication Class (con’t)
SixtyRing Design and Implementation Web Service Assemblies
Copyright © 2006 Richard G. Todd – 49 –
Web Service Authentication Web services must authenticate users of the service and ensure they have the necessary permissions when calling web service methods.
There are several authentication mechanisms available to web services.
• Challenge/Response
• WS-Security
The SixtyRing application uses custom SOAP headers to authenticate callers.
• Define a new Authentication custom SOAP header.
• Define a HTTP module to read and process the SOAP header.
• Response to events raised by the custom HTTP handler to authenticate the caller.
Authentication Custom SOAP Header
Authentication is managed using a custom SOAP header. The header defines User, Password and ImpersonateUser properties as shown in Figure .
[ Serializable ] [ XmlType (Namespace = Xml.Namespace)] [ XmlRoot (Namespace = Xml.Namespace, IsNullable = false )] public class Authentication : SoapHeader { private string m_user; private string m_password; private string m_impersonateUser; public string User { get { return m_user; } set { m_user = value ; } } public string Password { get { return m_password; } set { m_password = value ; } } public string ImpersonateUser { get { return m_impersonateUser; } set { m_impersonateUser = value ; } } }
Figure 34 – Authentication SOAP Header
SixtyRing Design and Implementation Web Service Assemblies
Copyright © 2006 Richard G. Todd – 50 –
A web service classes inherit from the AuthenticatedService as shown in Figure 35.
public class AuthenticatedService : System.Web.Services. WebService { private Authentication m_authentication; public Authentication Authentication { get { return m_authentication; } set { m_authentication = value ; } } public const string SoapHeader = "Authentication" ; }
Figure 35 – AuthenicatedService Class
Web services methods are marked with the SoapHeader attribute to indicate the Authentication SOAP header is expected to be received with the method is called. An example is shown in Figure 36.
[ WebMethod] [ SoapHeader ( AuthenticatedService .SoapHeader)] public Order Lookup( long orderId) { try { return SixtyRingWebServiceApplication .OrderService.Lookup(orderId); } catch ( Exception e) { Utility .HandleException(e, Context); throw ; } }
Figure 36 – Authenticated Service Method
When the web service method marked with this SoapHeader attribute is called, the ASP.NET framework sets the associated property with the contents of the SOAP header. In this case, the Authenticated property defined by the base AuthenticatedService class is set. However, as we will see in the next section, this SOAP header is processed by a custom HTTP module prior to method invocation.
SixtyRing Design and Implementation Web Service Assemblies
Copyright © 2006 Richard G. Todd – 51 –
Authentication Custom HTTP Handler
The SixtyRing system uses SixtyRingAuthenticationModule, a HTTP module, to read and processes the authentication SOAP header passed to web service methods. The class is shown in Figure 37.
DemoAuthenticationModule Class
IHttpModule
Figure 37 – SixtyRingAuthenticationModule Class
With the web service application starts, the ASP.NET framework calls the module’s Init method (as defined by the IHttpModule interface) shown in Figure 38.
public void Init( HttpApplication context) { context.AuthenticateRequest += new EventHandler ( this .OnEnter); }
Figure 38 – SixtyRingAuthenticationModule Init Method
SixtyRing Design and Implementation Web Service Assemblies
Copyright © 2006 Richard G. Todd – 52 –
The module adds an event handler – OnEnter – to the application’s AuthenticateRequest event. This event is raised when the ASP.NET framework as part of the web service request authentication process. The OnEnter event handler reads and processes the Authenticate custom SOAP header. It then processes the authentication data using the private OnAuthenticate method as shown in Figure 39.
private void OnAuthenticate( HttpContext context, string user, string password, string impersonateUser) { if ( Membership .ValidateUser(user, password)) { if (impersonateUser != null ) { string [] roleNames = Roles .GetRolesForUser(user); if ( Array .IndexOf(roleNames ,SixtyRing.Service. SixtyRingRoles .Impersonator) != -1) { GenericIdentity identity = new GenericIdentity (impersonateUser); roleNames = Roles .GetRolesForUser(impersonateUser); context.User = new GenericPrincipal (identity ,roleNames); } } else { GenericIdentity identity = new GenericIdentity (user); string [] roleNames = Roles .GetRolesForUser(user); context.User = new GenericPrincipal (identity, roleNames); } } }
Figure 39 – OnAuthenticate Method
If the specified user and password are valid, the handler authenticates the web service call using either the caller’s identity or the impersonated identity. In either case, the sets the User property of the HttpContext associated with the web service call to the identity of the authenticated user.
SixtyRing Design and Implementation Web Service Assemblies
Copyright © 2006 Richard G. Todd – 53 –
Registering the SixtyRingAuthentication HTTP Module
The SixtyRingAuthentication HTTP module is registered in the web.config file as shown in Figure 40.
<configuration > < system.web > < httpModules > < add name=" SixtyRingAuthentication " type = " SixtyRing.WebService.SixtyRingAuthenticationModule, SixtyRing.WebService " /> </