P. 1
Domain Driven Design in Action

Domain Driven Design in Action

|Views: 29|Likes:
Published by Arun Nair
ddd
ddd

More info:

Published by: Arun Nair on Jun 13, 2013
Copyright:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

08/07/2014

pdf

text

original

Master's thesis, Department of Computer Science University of Copenhagen, spring 2009 Supervisor: Jyrki Katajainen

Domain-driven design in action

Designing an identity provider
Klaus Byskov Homann

iii

Abstract.

In many scientic disciplines complexity is one of the most exciting

current topics, as researchers attempt to tackle the messiness of the real world. a software developer has that same prospect when facing a complicated domain that has never been formalized. In this thesis the principles of domain-driven design are used to model a realworld business problem, namely a framework for an extensible identity provider. A specication for the software is presented and based on this specication a complete model is created, using the principles of domain-driven design which are also presented. The thesis also includes an implementation of a generic domain-driven design framework that leverages object-relational mappers. It is then showed how this framework can be used to implement the designed model. Finally, the quality and completeness of the model is validated through a series of reviews and interviews. The work shows that applying the principles of domain-driven design is a good approach to modelling a complex business domain.

Resumé.

I mange videnskabelige discipliner er kompleksitet et af mest spændende

aktuelle emner, idet forskere forsøger at takle den virkelige verdens rod. En software udvikler har den samme udsigt når han står overfor et kompliceret domæne der aldrig er blevet formaliseret. I dette speciale bruges principperne fra domænedrevet design til at modellere et forretningsproblem fra den virkelige verden, nemlig et rammeværk for en udvidbar identity provider. En specikation for softwaren præsenteres, og baseret på denne specikation udvikles en komplet model ved brug af principperne fra domænedrevet design, der ligeledes præsenteres. Specialet indeholder også en implementering af et generisk domænedrevet design rammeværk der gør brug af objeckt-relationelle oversættere. Herefter bliver det vist hvordan dette rammeværk kan bruges til at implementere den designede model. Slutteligt valideres modellens kvalitet og komplethed igennem en række reviews og interviews. Arbejdet viser at det at benytte principperne fra domænedrevet design er en god tilgang til at modellere komplekse forretningsdomæner.

.............................................................................................................Contents Abstract Resumé Contents Preface .................................... iii iii iv 1 4 5 8 21 44 88 103 118 133 136 139 147 151 ...... .................. ........................ ..... .................................................................... ........................ ....................................... 5 Object relational mappers 7 Implementation 9 Conclusion B Interviews Bibliography 6 A domain-neutral component 8 Design validation ..................................... Acknowledgements 1 Identity provider 2 Specication .......................................................... ............ 3 Domain-driven design 4 Dening the model ......................... ......... ....................................................... ...................... ....................................................................................................... A C# language elements .......................................... iv ...

1 . and everyone involved in the programming solves their tasks from a varying understanding of the problem domain. If the design is not thought through from the beginning. is not how many programmers you hire to code it but how well you design it. I alone am responsible for the development of the software. design patterns and best practices in order to achieve faster development of software dealing with a complex business domain. Domain driven design is not a technology or a method. The project does of course have other stakeholders. scient degree in Computer Science at the University of Copenhagen. and extend. it is important to me that the discussion is based on a real life problem. which makes the project well suited for this one-man thesis. Therefore. On this project. In order to discuss how domain-driven design can be used to design complex software. this thesis is based on a project that I am working on with my current employer. thus breaking down the language barriers that often exist between them. When focusing on the model it is easier to achieve a shared terminology between the domain experts and the programmers. The thesis was written in the period from September 1st 2008 to May 29th 2009. then chances are that you will end up with a cluttered code base which is both hard to understand. The premises for domain driven design are that each software project should be based on a model and that focus should be on the domain and the domain logic instead of on the technology that is being used. such as the technical director and the CEO of Safewhere. and not just on ctitious examples.Preface This master's thesis concludes my cand. but a mind set and a set of priorities. maintain. a company called Safewhere. Domain-driven designdeals with choosing a set of design principles. while at the same time achieving a code base that is maintainable and extensible. Introduction The thing that determines how complex a problem that can be solved by a piece of software.

Chapter overview The rst three chapters contain a general introduction to the problem domain and to domain-driven design. Thus. but does include a complete design and implementation of the core functionality. what an Iden- tity Provider (IdP) is. Implementation: In this chapter I will showcase the source code for some of the most interesting parts of the implementation of the system. as described in Chapter 2. I have interviewed each person and had them assess the quality of the design and the benets of using domain-driven design in general. Domain-driven design: This chapter contains an introduction to domaindriven design and the concepts it uses. in general terms. The thesis does not include a fully functional version of the product. The last six chapters contain my main contribution. these chapters mainly contain material from books and papers and my contribution to the contents found herein is merely that of passing on knowledge in a suitable and more compact format. To make sure that I have achieved making an easily maintainable and extendible model I have asked a few of my peers to review the model. Identity provider: This chapter explains. and its purpose is to let me assess the quality of the model and the software presented herein. . where I take the theory from the rst chapters and put it into practical use.2 The project at hand concerns the development of a framework needed to implement a multi-protocol identity provider. Design validation: This chapter is based on interviews with some of my peers. A domain neutral component: In this chapter I will present the implementation of a domain neutral component that implements a lot of basis functionality that is useful for implementing a system based on domain-driven design. Specication: This chapter contains the feature specication of the software that is going to be developed. Model: This chapter contains the design model of the software using domaindriven design. Object-relational mappers: In this chapter I discuss how object-relational mappers can be leveraged in domain-driven design.

Tips for the reader This thesis is written in British English. The reader should be familiar with object oriented programming and design. . int j) { //Do nothing with the input data and return return. since most of the chapters build on theory explained in previous chapters. } If you are not familiar with C# you may refer to the Appendix A. The thesis is intended to be read from beginning to end. however each code le can be inspected in any text editor. The developed code can be found on the enclosed disk.NET TM family. Having Microsoft Visual Studio 2008 installed is a prerequisite for opening the solution le.3 Conclusion: This chapter contains a conclusion on what has been learned from working with domain driven design. All code samples in this report are in C#. a language of the Microsoft . A code sample may look like this: 1 2 3 4 5 A code sample public void DoNothing(int i. which contains a short introduction to the language.

4 . professor Jyrki Katajainen for his support and thorough dedication to the project. Peter Haastrup. Finally I wish to thank my beautiful wife Gitte Byskov Homann for bearing with me on the late nights and weekends where a substantial part of my time has been spent studying for and writing on this thesis. for letting me write my thesis in collaboration with the company. Mikkel Christensen and Peter Haastrup for taking time to review the model and participate in interviews. I also wish to thank the CEO at Safewhere. and Mark Seemann. for shielding me from things I did not need to bothered with. for his sincere interest in the project. and for keeping encouraging me throughout the entire process. Niels Flensted-Jensen. I also want to thank the technical director at Safewhere.Acknowledgements First of all I wish to thank my supervisor.

The IdP identies the user based on some credentials and the statements that it makes about the user are known as claims. In general terms it can be said that an IdP performs the function f( ) = ζ : ζ ∈ φ where is a given set of credentials and ζ is a set of claims from the complete set this thesis I will refer to token. Ajax. An identity provider. will be as identity provider claims φ of claims that can be issued by the IdP. ζ will be referred to as referred to as user credentials and nally I will refer to φ 1. Figure 1 shows the primary work of an identity Figure 1. Throughout f ( ) as token issuance. provider. such as the users name. according to [Daarbak 2008].1. email or CPR number. new browser capabilities and higher internet bandwidth has made it feasible for ISV's to provide software that is hosted in the cloud.Identity provider 1 An identity provider (IdP) is a centralized identity service whose primary responsibility is identifying a user and stating something about that user. the analyst company Gartner predicts that 30 percent of all CRM systems will be running on the software as a service model in the year 2012. Software as a service solutions are hosted in large data centers and provide the ability 5 . IdP use case example The advent of a range of new technologies such as SOAP web services. Buying software as a service is becoming a more and more popular for a number of reasons. In fact. self-hosted software tends to be lower. Primarily because the total cost of ownership for software as a service vs. This type of software is referred to as software as a service.

Since this is the claim required by the bookkeeping application. since the identity provider will remember him. The bookkeeping application uses the SAML2. When user 1 wants to log in to the bookkeeping application.0 identity protocol and the shipping application uses the OpenId protocol. Secondly. the same thing happens.6 to quickly scale the application for a given customer should the need arise. This setup has several benets. namely OpenId. Figure 2 below shows a ctitious company that uses two SaaS applications in the cloud. When user 1 later wants to go and use the shipping application. the shoe sales company has one single . Figure 2. user 1 only has to log in once within a session. he is asked to go and get a security token from an identity provider that is trusted by the bookkeeping application. The shoe sales company uses a shipping application and a bookkeeping application in the cloud. User 1 is now allowed to use its features. The only dierence is that the shipping application uses another identity protocol. IdP use case. ISV's that sell software as a service solutions may choose to use claims based access control in their applications. The identity provider now issues a security token containing a claim that the holder is a SalesPerson. First of all. This extra exibility is another selling point for software as a service solutions.

Please note that the IdP shown here is actually a software as a service product itself. the IdP allows the shoe sales company to easily integrate with software as a service products that use dierent identity protocols. This means that it would be possible to revoke user 1's access to both the shipping and bookkeeping application by revoking his SalesPerson claim in the IdP. Last. .7 place where it can manage it's users and the claims that are issued about them. although conceptually it could just as well be a stand-alone application in the shoe sales company. It is the design and implementation of an identity provider such as the one in Figure 2 that is the goal of this thesis.

The chapter will contain requirements to both the software and the platform on which the software runs. from a business perspective. and therefore they are included here for completeness. thus allowing for seamless leverage of your existing investments in user directories. 8 . Before we go into the specic details. the software. to give you an idea of what the project is about. a term that I will throughout the remainder of the thesis. In the following text the product is referred to as Safewhere*Identify.509 as well as various identity federation mechanisms. For external users not ready for federated authentication Safewhere*identify provides integration to local user databases. User identities are seamlessly and securely transferred from their origin  the place where the user rst logged in  to your infrastructure. not use Safewhere*identify is a new kind of user identication solution providing for seamless and heterogeneous authentication across the supply chain of web applications and web services. Safewhere*identify supports any kind of authentication including traditional methods such as username/password and X. however. Applications and services move all authentication to the Safewhere*identify identity broker. The main focus of this thesis is. Selected benets and advantages include: Externalization of authentication. considerations about the platform are important for a complete understanding of the system. taken from a marketing brochure made by Safewhere. I want to present the following text. of course. thereby removing the need for operation and administration of a local extranet user database Traditional user authentication.Specication 2 This chapter includes the feature specication of the identity provider software that is going to be designed and implemented. With Safe- where*identify an organization may handle user identication centrally and outside of all web applications and web services. which in turn integrates with any and all authentication mechanisms Federated identities.

Safewhere*identify provides a rich set of features with the aim to remove entirely all need for local administration and authentication . Safewhere*identify automatically provisions a user database per organization for authentication purposes and maintenance of other user attributes. Whichever is chosen has no eect on feature set or security.9 Figure 3. one organization. Due to the unique and standards compliant architecture and communication patterns. and is administered by. Logical identity ow from users to web applications Delegated user administration. Safewhere*identify provides identity conversion/mapping to successfully transfer identities between applications Provided both as a service and as traditional on premise software. Service provider integration. Each database belongs to. As more and more of your applications leverage the new identity solution. Safewhere*identify may equally well be leveraged as an external service (Software as a Service) or as software installed in your own infrastructure.

The key capabilities include: Browser based federation. 2. Designing a multitenant system requires extra considerations regarding data storage layout and data security. each of your extranet partners) providing for full separation of data. Systems that host multiple instances of the same software for dierent customers are often called multitenant systems. (E. "active" federation  through WS-Trust and possibly WS-Federation One Identity Provider instance per organization (e.1.g.10 of users. IdP The main dierence between this IdP and standard IdP implementations is that it must support more than one instance. Self registration of organizations and users. Safewhere*identify implements a number of federation protocols including SAML 2. and often with slightly dierent names and formatting. Safewhere*identify provides delegated administration of attribute mappings to transparently and correctly transfer identity between applications. a role to one application is a group to another).g. Workows support the signing of new organizations  e.g. The rst requires review and approval of you whereas the latter leverages the distributed nature of user administration and leaves it up to the user's home organization. An instance is an iso- lated IdP that runs side by side on the same server as other instances. Another key feature of the IdP is that it must be extensible in a way that it can support more than one identity exchange protocol and more than one authentication mechanism. . new business partners  as well new uses of each organization. but without being coupled to the other instances in any way other than sharing storage. Applications leveraging Safewhere*identify potentially all need dierent kinds of user attributes. or claims.0 and WS-Federation for browser based authentication Federated authentication for Web services  aka. Separate IIS Application Pools under dierent service accounts for each instance ensure very tight security around each organizations data all the way to the le system and database level Claims mapping.

The IdP will be running on Windows Server 2003/2008 on IIS 7. Technical requirements The IdP must be developed in C# and Asp. 2. User: An end user who uses an IdP instance to identify himself to a service provider.NET. Personal data store: All changes made to IdP congurations through the admin website are written to the personal data store. There is no implementation dierence between the system IdP instance and the customer's IdP instances. and relies on a set of claims issued by the system IdP to determine which IdP instance the administrator belongs to. Each IdP instance belongs to a customer. The gure shows the following concepts: IdP instances: The SaaS IdP contains a number of IdP instances. the system instance. 2. Administrator: A person who administrates a single IdP instance.11 2. The system IdP instance is used to authenticate administrators when they log in to administrate their own IdP instance through the Admin web. Registration website: The registration website is where new customers can sign up for the services provided by the SaaS IdP. On the admin website an administrator must be able to congure his IdP instance in a number of ways which will be discussed in further detail below. Admin website: The admin website acts as a service provider against the system IdP. except for one instance. Conguration data will be stored in SqlServer 2008.4. Terms This chapter makes use of the following terms: Customer: An organization that has bought an IdP instance. Overview Figure 4 shows an overview of the SaaS IdP. Each IdP instance .2.3.

retrieve claims. 2. Protocols: Which protocols does the IdP support. . An IdP instance is driven by its conguration.12 Figure 4. IdP overview. The conguration mainly species the following ve things: Credentials: Which types of credentials are accepted.5. authenticate users etc. The personal data store is either a separate database or a separate database schema. IdP instance This section contains the specication of which features a single IdP instance contains. uses the personal data store to read it's conguration.

The IdP instance may be congured to accept a large range of dierent credentials. The same requirement for being pluggable applies to the protocols that the IdP supports. but it is important that checking credentials is done in way such that further types of credentials can be added later. however this must be done in a way that does not impede future support for other protocols such as OpenId or WSFederation. In windows. Initially. Figure 5. Most identity protocols use certicates for encryption and signing of messages. Figure 5 shows a single IdP instance. the only require- ment is to support username/password and SAML2. the IdP may also be congured to issue a set of dierent claims. All the dierent conguration options are saved in the personal data store. a certicate store is tied to a system account. so in order to achieve having a personal certicate store for each IdP instance. Therefore the conguration must contain information on which certicates are to be used for this purpose. The only initial requirement is to support the SAML2.0 credentials. As Figure 2 shows. Service Providers: Which service providers is the IdP connected to. every instance must run under a separate user account. The certicates themselves must be stored in a personal certicate store on the Windows server. IdP instance.0 protocol. Certicates: Which certicates does the IdP use for signing and decryption. and which SP certicates are trusted. .13 Claims (attributes): Which claims does the IdP issue.

To make SOAP requests over SSL to an IdP instance running in a virtual directory would require trusting the SSL certicate belonging to www. This would imply explicitly trusting every SSL certicate for each individual IdP instance. e.com. The IdP instance runs in its own IIS website.com. Figure 6 shows how an IdP instance should be deployed in IIS (Internet Information Services).14 2. and accessing it through www. by doing so. each IdP instance must run in its own IIS website and have a unique domain name and therefore also a unique SSL certicate. Hosting Figure 6.saasidp. all instances would be using the same SSL certicate. a trust relationship would be implicitly made to all IdP instances on the server. If each IdP instance runs under a dierent system account. in order to be able to con- gure dierent SSL certicates for each IdP instance it is important that the IdP instance has its own unique domain name. However. However.saasidp. Running in its own website means that it can have its own unique domain name.g. somecustomeridp.saasidp.com.com/somecustomeridp.6. namely that pertaining to www. IdP instance hosting. The alternative would be to have each IdP instance run in an IIS virtual directory.saasidp. Another benet of separate IIS websites is the ability to tie a website to an application pool. we can achieve having personal certicate stores . An SSL certicate is always tied directly to a domain name. So if the instances were running in a virtual directory. To avoid this. An application pool lets us dene the system account under which the website runs.

7. personal certicate stores provide a way of conguring dierent trusted certicates. the password should be entered and the remember password feature should be used. a clear separation of the IdP instances is achieved when it comes to certicates and certicate trust. Having personal certicate stores requires creating a new system account for each IdP instance. in which all administrators of . and the account will be hard to compromise. no one will ever be able to use that account for anything other than running the IdP instance. something that is important when importing certicates from federation partners. The administration website acts as a service provider to the system IdP instance. When conguring the IIS application pool. IdP instance administration. By doing this. Figure 7 shows how an administrator can administrate his IdP instance through the administration website.15 for each IdP instance. 2. By using the deployment structure shown in Figure 3. This account should be created as part of the installation of each IdP instance. This is deemed very important since most identity protocols rely on mutual certicate trust. By having personal certicate stores the operating system ensures that certicates in the personal store can only be accessed by the user to which the store belongs. Furthermore. IdP instance administration Figure 7. The password for the specic system account should be randomly generated and forgotten.

UserEditable This property species whether or not the user will be able to edit the value of this claim.8. The IdP should specify a set of predened rules. . For example: dk:gov:saml:attribute:CvrNumberIdentier ClaimValue This property contains a specic value for the claim. The denition of a claim contains the following properties: Property ClaimType Description The type of the claim. the most important claim being an OrgId. Claim denition An administrator must be able to dene a set of claims for his IdP. and claim types are typically on URI form. There exists a set of predened claim types. the administration website knows which data to get from the data store. and when only one specic value for the claim makes sense. ValidationRule The administrator must be able to add some kind of validation rule for the value of a claim. but it would probably also be useful if the administrator was able to type in a regular expression do meet specic validation needs. It is used when users are not allowed to override the value. The customer's running IdP instance uses the data from the personal data store to fetch it's conguration. 2. DefaultValue Some claims may have a default value. When changes are made. This property lets the administrator specify a default value for the claim. This is especially useful when claim values are typed in by users.16 all customer IdP instances have an account. Based on the OrgId. and lets the administrator edit them. these are saved back to the shared data store. The system IdP issues a set of claims about the specic administrator. for example Email.

and is presented with a list of his claims.17 Figure 8. and the value for the claims dened for the IdP instance. An organization may have several hundreds or thousands of users. 2. The gure mainly focuses on the username/password case. User and attribute administration Figure 8 shows an overview of user and attribute management. which leads to the need for an update page. must be possible for the administrator to dene which claims can be edited . but this is considered a special case. This fact calls for some import functionality. When the user has lled out the claim values. User and attribute management. The Email claim will be lled out on beforehand because it is already known.9. where users are created in the data store. shown in the gure as the user attribute update page. so many that it would be infeasible for a single administrator to create them all. It should of course also be possible for the administrator to create users manually. a password. each user needs to be approved by the administrator. To access the page. in this case FirstName and LastName. If we assume that a company has dened the claims FirstName. asking the recipient to go to a self registration page where he or she can enter a desired username. and the IdP should automatically send an email to each address. LastName and Email. The administrator must be able to import a list of email addresses. the It user presents his credentials. It must be possible for a user to change the value of his/her claims.

Figure 9 shows the order in which this claims mapping is performed. This property must be dened when the claim is dened. Let us assume that the SalesPerson claim was a group claim with the value SalesPerson. However the IdP must make it easy to add and remove users from groups. As the gure shows. group claim with value Managers. 2. however the administration pages for an IdP instance must provide the ability to work with groups in a familiar manner. Figure 2 showed two service providers that both required a SalesPerson claim. This is important to note. The IdP should allow a simple mapping of claims such that when a user that has the SalesManager claim is connecting to the service provider which requires the SalesPerson claim. the service provider may specify that it requires some specically named claim. this claim is just another claim in the user's security token. 2. . groups are not hierarchical either.10. and claims have no hierarchical structure. In some specic customer organization they may have a group claim called SalesManager. Since group claims are merely expressed as claims. This involves listing all groups. listing all users in a group and an easy way to add and remove users from groups. Consider a Behind the scenes. which is conceptually identical to the SalesPerson claim. since in some systems groups have a hierarchical structure where a group can be a member of another group. Groups Group claims are no dierent from any other type of claims. both the self registration page and the attribute update page must be customizable with regards to look and feel such that it is possible for the customer to make it look like other of their corporate websites. This is not the case in this system.18 by the users and which cannot. the SalesManager claim is automatically mapped to the SalesPerson claim.11. Claims mapping When a connection to a service provider is created.

Customer registration The IdP must contain a customer registration page which is the entry point for the workow shown in gure 7.13. the customer goes to the registration page and enters his data. Thus. Conclusion The support for multi-tenancy is an important commercial concern for this system. the multi-tenancy aspect can be solved by the platform alone. 2.  Creating certicates for encryption and signing.  Conguring website and application pool in IIS. A contract is then sent to the customer. address etc. However. and when the contact is returned the order is conrmed and the customer's IdP instance is created automatically. This automatic process includes:  Creating the administrator in system IdP instance. such as a contact name. as we have seen in this chapter. 2. Claims mapping pipeline.  Creating SSL certicate and conguring SSL in IIS. saved.  Sending log in details to administrator. This data is The sales representative then contacts the user to conrm his identity and his intent to buy. the IdP must support automatic creation of new IdP instances. and a sales representative is alerted.12. When a customer wants to buy the services provided by the IdP. email. Having a per- tenant system account allows database isolation through either separate . Tenant isolation is achieved through a per-tenant system account running each tenants instance.19 Figure 9.

which. . Claims mapping pipeline. the software design presented in this thesis will be totally multi-tenancy agnostic. The same goes for the certicate store. as mentioned. Therefore. to which only that system account has access. is also isolated on a per user basis. without compromising the commercial demand for multi-tenancy. databases or separate database schemas.20 Figure 10.

no. The business people are talking to technical people in requirements gathering." The business person says. That means you can never have a conversation about how the system really works. Translation is never a perfect The way estimates work is that the technical person says. that's a totally dierent thing and will take an enormous amount of time. no. The material discussed herein is largely based on the book Domain-driven design: tackling complexity in the heart of software by Evans [2004]. Some will know the language the business people use. and then it's written up and handed o in this other sort of language for implementation. On most projects. "No. Before we dive into the details of domain-driven design. They will have words for the functional entities that are dierent from the words used by the business people. 2009. They will describe the actual functioning of the system in the same way. for the 21 . so it seems to me that feature C is a natural extension of A and B. What are the primary aspects of domain-driven design? I could boil it down into two or three basic things. let us start with an excerpt from an interview with Eric Evans. The software on the inside is actually nothing like what the business people are imagining it to be. The chapter is however not just a summary of the book. so they act as interpreters for the technical people who don't know that language.Domain-driven design 3 This chapter serves as an introduction to domain-driven design. It also hurts estimates. You have a process broken into parts. but will also contain my own perspectives and the explanatory examples provided here will be based on the problem at hand whenever possible. the author of the book DomainDriven Design (Evans [2004]). The interview was brought in the Software Development Times (Handy [2009]) on March 12. thing. "I have feature A and feature B." When in fact. Your technical people will discuss the system with a certain language. This leads to usability problems. The rst is the ubiquitous language. you'd have dierent people talking in dierent languages.

You'd have to start with an intention to do it. and the results are much worse. it's not totally dierent from an implementation point of view. It's one of those cases where the cure is worse than the disease. Some people are good at it and some are not. we use that consistent language. When we build the system. that's ne. This we cannot eliminate. We share this. I don't mean this thing where people say we take the business language and the conception. There's no way for a non-technical person to anticipate what might be easy or what might be hard. Instead. we try to understand them and map them out. Also. Projects that succeed have usually accomplished this. it's naming things the way they would expect. Does that mean that something as simple as naming your libraries and classes after the business tables they represent? At the most basic level. it's a system of names and relationships among things. . It's very closely related and so much easier said than done.22 technical people. business people never propose ideas that might have been easy because it's not evident to them that they would be easy. If the system isn't built that way. There's no communication there. and when we talk about it. One of the keys to this is in recruitment. Here is one of the areas where I kind of had to invent a system because no one had really systematized this. Within any given project there are multiple models in play. What are the boundaries that dene where each one applies? If you say potay-to and I say pot-ah-to. You have to hire the kind of people who are good at this. People have tried. we stay true to this. What are the other two important aspects of domaindriven design? The second element is that you have to bring about a creative collaboration between the domain experts and the technical experts. and in [that] subsystem we talk about it that way. we're just talking about some ction. With the application model itself. as long as we know where pot-ay-to is used and where pot-ah-to is used. and just make software that reects it. In this subsystem we talk about it this way. I'm not talking about the kind of models I've already spoken of. who are good at getting in a fruitful conversation with a domain expert. The third aspect is what I call an awareness of context. There are more subtle aspects.

1. or drawing on a whiteboard. The developer's view is often not as complete as that of the domain expert and thus the model produced by the developer is not as rich and communicative as that of the domain expert. or as the book puts it. The domain model is an abstraction of all the knowledge about the domain. This does not mean that the such diagrams. the design models produced are cluttered with unimportant aspects that draw attention away from. the core domain logic. The main philosophy of domain-driven design is that the primary focus of any software project should be on the domain and the domain logic. software users. the model is also the backbone of the language spoken by all team members: developers. documents.23 Having a language to describe this and a terminology and a system serves to make it more reproducible. Domain-driven design is not a development method per se. The book refers to this discipline as knowledge crunching. It is however oriented toward agile development as we shall see further on. nor is it tied to any particular methodology. It is therefore of utmost importance that developers and domain experts collaborate intensely on the creation and maintenance of the model. The domain model is not a particular diagram. The domain model represents a large amount of knowledge contributed by everyone involved in the project and it reects deep insight into the domain at hand. carefully organized in a way that it conveys this knowledge in the most expressive way possible. put in practice. the business logic. or drawings could not exist. The domain model is the idea that the combination of these diagrams and documents intend to convey. or document. and therefore the business. but they are not the domain model as such. successful and protable. the book argues. address a specic problem. 3. The philosophy of domain-driven design Most software projects. if not all. and they probably should. ie. or completely hide. and it is denitely not just a data schema. many software projects are too focused on technology when designing their software. domain experts. Therefore. and testers. Therefore. and it also draws on well established software design patterns. . Developers and domain experts can have a dierent view of the problem domain. This may sound like common sense. Solving this problem well is important to making the software. One of the primary concepts of domain-driven design is the so-called domain model. the model is distilled knowledge.

perhaps more technical jargon. This eectively means that any change to the language is also a change to the model and viceversa. not to mention the risk of misunderstanding makes the use of dierent jargons dangerous. the method lacks feedback.24 Knowledge crunching is achieved through brainstorming and experimenting. But when a deep and expressive model exists. and the model and language are very tightly coupled. In the waterfall method. Ubiquitous language A model should be based on a ubiquitous (universally present) language. The ubiquitous language must be used in both oral and written communication within the team. First of all. current users. Evans states that he has met many developers who initially do not like the idea of a common language because they think that domain experts will nd their terms too abstract or will not understand objects. and knowledge is potentially lost through the chain of information. This model based language should not only describe artifacts but also tasks and functionality. Using this method of modelling also has various benets over methods such as the waterfall method. a widespread practice when modeling. the principles of domain-driven design state that a conscious eort should be made to encourage a common language and that the model should be based on the ubiquitous language. and teams are often rearranged. Knowledge crunching is therefore an extensive exploration of the domain and a continuous learning experience. But the waterfall method has various shortcomings. Skilled and knowledgeable programmers get promoted. and when such things happen knowledge is essentially lost. Distilling as much knowledge as possible in the model is important because of the natural leaking of knowledge from most software projects. Having a common language resolves the confusion that often occurs when domain experts and developers use dierent terms to describe the same thing. continuous talking. and as such it goes far beyond nding the nouns. knowledge is usually passed on from domain experts to analysts. 3. as argued in [Evans 2004]. This is important because deep and expres- sive models seldom lie on the surface. etc. and from analysts to programmers. involving experiences from current systems or legacy systems and drawing on knowledge from domain experts.2. but he argues: . Thus. most of this knowledge is to a large extent preserved on the project. But the overhead cost of translation. Usually. In [Evans 2004]. domain experts use the business jargon and technical team members use another. diagramming and sketching.

developers will improve their modelling skills and domain specic knowledge. then the model is by denition not right.25 If sophisticated domain experts don't understand the model. but they should represent skeletons of ideas and not be overly detailed. The code should be written to reect the domain model in a very literal way and it should use the same terminology as in the ubiquitous language.3. a layered architecture as that shown in Figure 11 should be used. Doing this will uncover any infeasible facets of the model early on and it is also an important part of getting the developers involved in the design process. Thus. The vital details of the model lie in the code. If they do not realize this. By taking part in the modelling process with domain experts. 3. database and network access and other things that are not related in any way to the domain. and to avoid cluttering the code. but one thing is for sure. but most importantly the will feel responsible for the model. then the code is denitely another representation of that same model. the code is always the most detailed representation of the model. So if a domain expert does not recognize his own business in what is supposed to be a model of that same business. Figure 11 shows the layers that make up the layered architecture. there is probably something wrong with the model. Domaindriven design focuses exclusively on the domain layer. It is important to notice that the components of each layer only interact with other components in the same . I really agree on this point. Diagrams and documents can be used to clarify design intent or decisions. Relationship between model and code If the ubiquitous language is one representation of the domain model. Especially because the focus of the model should be on the business domain and not on technical details. And that is very important. in order to achieve the tight coupling between model and code. because developers must realize that by changing the code they also change the model. and this is the layer which should contain all domain logic. any future refactoring of the code will weaken the model instead of strengthening it. something that the code does particularly well. Being detailed is Coupling the model and the implementation from an early start through prototyping is very important. It is obvious that every application has a lot of plumbing concerned with graphical user interfaces. It is arguable that the code is the most correct representation of the model.

it becomes very hard to see the domain logic and reason about it. infrastructure layer. etc.4. such as managing long running transactions or workows. network access. it renders itself well to object-oriented programming languages. To change a business rule may require code changes in many dierent parts of the code and this can be very error prone. When domain related code is scattered throughout the UI. Since domain-driven design deals heavily with assigning responsibilities to the right places in code. etc. Building blocks of the model Domain-driven design species a set of conceptual objects that should be used in code to create the domain model. A layered architecture. and nally the infrastructure layer contains code related to data access. the application layer contains application specic code. layer or in layers below them. . logging. The user interface (UI) layer contains code for interaction with the user. Evans refers to the act of designing the code components that make up the model as model-driven design. So the value of using a layered architecture is that each layer can be specialized to manage dierent aspects of the computer program. 3.26 Figure 11.

1 2 3 4 5 6 7 8 public class User{ private private private private Guid _userId.4. which will be discussed in detail next. CreatedDate. . DateTime _createdDate. and UserAttributes as shown below. User object with properties UserId. The lifespan of entity objects is usually long. Consider a An example of an entity object could be a User object.27 Figure 12 shows an overview of these concepts. public User(Guid userId. The building blocks of domain-driven design.1 Entities Entities are objects that are dened by their identity rather than by the values of their properties. string _lastName. Figure 12. IEnumerable<Attribute> _userAttributes. 3. and the values of its properties can change often over time whereas the identity does not change. UserName.

_userId = userId. } } Even though two identical if the User objects have the same LastName. change over time. The identity eld of an entity object is often automatically generated such as it would be the case in the example of the User object. this.28 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 string lastName.UserId. they are only LastName are not identical as long as the UserId is UserId is the same._lastName = lastName. since these can. } public Guid UserId{ get{return userId. if the user changed his or her last name.UserId == other. for example if the id was a social security number.} } public string LastName{ get{return _lastName._createdDate = createdDate. and most likely will.} set{_lastName = value. The Equals method above is an example of such an implementation. DateTime createdDate){ this. when implementing entity objects. this. The identity eld (UserId) is not always important to the user of the system. Thus. Two objects could even represent the same user regardless that the same. it is important to implement equality functions in such a way that the equality of two objects is based on comparing identity rather than comparing the individual properties of the object. or package tracking number.} } public DateTime CreatedDate{ get{return _createdDate. but it could be. for example.} } public IEnumerable<Attribute> UserAttributes{ get{return _userAttributes. .} } public overrides bool Equals(User other){ return this.} set{_userAttributes = value.

} } public Currency Currency{ get{return currency. We usually do not care about the identity of the ten dollars (unless of course we are looking for stolen money) but only the value they represent. After all. When adding Money objects. Currency currency){ this. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Money{ private int amount. 3.4. unique id.currency = currency. This maintains the immutability of the objects..29 3.} } public Money Add(Money other){ // Make sure currency is the same // Add amounts // return new money object . not who they are. this. private Currency currency. contrarily to entity objects. meaning that after creation the properties of the object cannot be changed. ten dollars are ten dollars no matter what.. are by denition immutable.2 Value objects Value objects. } public int Amount{ get{return amount. A service's interface should be dened in . are objects that do not have a Value objects are often used to describe entities. such as the Money class. new objects are created instead of changing any of the objects being added.amount = amount.3 Services Services are classes that implement domain logic that does not naturally belong to an entity or a value object. } } Note that the value objects. public Money(int amount. and we care about them only for what they are. A good example of a value object could be a Money object as the one below.4.

a web-service could be created in the application and the only responsibility of that web-service would be to digest the XML input and delegate the call to the CertificateService in the domain layer. In terms of the CertificateService mentioned above. This does not mean that a system built using domain-driven design should not expose web-services. stateless classes are often comprised of static methods that do not require an instance of the class in order to be invoked. Since the concept of a service is used widely in computer science in general I feel it is important to clarify that a service in terms of domain-driven design should not be confused with a service such as in web-service. An aggregate. Figure 13.4. Classes that implement services should be stateless. . when using domain-driven design and a layered architecture.30 terms of other elements of the domain model and its operation names should be part of the ubiquitous language. In practice. however.4 Aggregates Aggregates are clusters of associated objects which are worked on as one unit when it comes to data changes. An example of a service in our problem domain could be a with operations such as CertificateService CreateCertificate and RevokeCertificate. 3. a web-service would be part of the application layer and not part of the domain layer.

The following is the skeleton of a repository: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class UserRepository : IUserRepository { public User this[Guid userId] {get{ . }} public IEnumerable<User> FindByLastName(string lastName) .. public IEnumerable<User> FindRecentlyCreated() . But this SQL select firstname.. All these methods actually implement some kind of domain logic with regards to users. 3. public IEnumerable<User> FindAllUsers() . that SQL statement could potentially be duplicated many places in the code. making it harder to change the logic of nding recently created users. if for some reason the denition of recently created would change. public void AddUser(User newUser) .. } The above repository lets us fetch a User object by a unique id.. but the aggregate itself can be much more complex than the one shown here. meaning that this example.. nding all users with some last name. Attribute objects are only interesting to modify in the context of a User and do not make sense outside the context of a User.. The FindRecentlyCreated method could be using a SQL statement such as :createdDateThreshold would be a bound parameter).. The repository should hide all database code and give the illusion that all objects are in RAM..4. the it is the primary entry point when accessing the objects that make up the aggregate.5 Repositories The purpose of a repository is to fetch and save entities and value objects from a data store.. By implementing the IUserRepository and referencing the con- crete instance only by means of its interface. Aggregates can only have one aggregate root...31 Figure 13 shows an aggregate made up of a User object with various Attribute objects. Another benet of using repositories is that they can be made interchangeable. In User object is said to be the aggregate root.. and it also allows us to add new users. separate specic implementa- . . lastname from users where createdDate > :createdDateThreshold (where statement expresses domain logic so if we did not have a central place to put this function.

it is important that developers understand the implementation of the repository being used. By specifying the concrete class that implements the repository in some external conguration le can make it easy to switch between the live environment and a developer or testing environment . thus facilitat- could be used for fetching dummy instances of the ing a means of testing various aspects of the code without having to access the production database. that User class. we could imagine the need to User class was created recently. A live system typically fetches its data from large databases. This is especially useful for testing. In our current example we could imagine an alternative implementation of the 1 IUserRepository. and replicating these databases to a development server can be both time consuming and sometimes even impossible. A specication is a class with only one method called |IsSatisedBy|. The method has a Boolean return type and the argument of the method depends on the type of object it is a specication for. 1995] . The term determine if a given instance of the recently is chosen on purpose because it is unspecic and denitely contains 1 This concept is actually a well established design pattern. 3. if someone was to write a method for counting all users in the system the function the FindAllUsers could be used and the Count method of IEnumerable<User> could be used to return the number of users. thus stressing why it is important that developers understand the implementation of repository functions.4. often referred to as strategy or policy. However. If we continue our User class example from above. That would most likely perform badly. In Chapter 5 I will discuss how OR-mappers can be leveraged to create repositories quite easily even for complex database schemas. when using a real repository implementation that accesses the production database the eect of performing the count this way would be that all users in the database would be loaded into memory just for the sake of counting them. called InMemoryUserRepository. However.6 Specications Specifications provide a means of encapsulating and more importantly naming those small Boolean expressions that tend to appear in most programs but whose purpose and or meaning with regards to business logic can be hard to gure out. This would probably perform quite well with a dummy repository implementation returning only a limited number of users. when using this approach. See [Gamma et al. For instance.32 tions of the repository can be seamlessly interchanged.

} } The above code snippet is a class that implements the recently created business logic. However it suers from two serious drawbacks.. } The above code snippet shows one way of determining if a User was created recently. This observation is probably right for this very simple example..AddDays(−10)){ .. Now if we were to use this specication in code it could look something like the following: 1 2 3 4 User u = .IsSatisfiedBy(u)){ .. and furthermore we have created a single placeholder for the business logic. the code would have to be duplicated. leading to extra maintenance if the criterion ever changed. meaning that without code comments it does not convey to the reader which business rule it is checking. a class with a lot of predicate functions like large. one could easily imagine cases where the object itself does not contain all the necessary information to check the condition. 1 2 3 4 5 6 7 8 //Specification class that determines if a user has //been created recently public class RecentlyCreatedSpecification{ public static bool IsSatisfiedBy(User u){ return u. First of all it is not very expressive. It could be argued that what is achieved by the specication in this example could just as well have been placed in a function on the User class.CreatedDate > DateTime. Furthermore.AddDays(−10). making it easy to maintain.CreatedDate > DateTime. 1 2 3 4 User u = . IsRecentlyCreated easily becomes very Furthermore.... Let us assume that the denition for a recently created is that it is was created within the last 10 days. .33 business logic with regards to our current example. However. if(u. } The above code example shows how the resulting code is much more expressive in terms of what business rule is checked. if the same check was needed somewhere else..Now. if(RecentlyCreatedSpecification.Now.

Most importantly factories should not automatically assign new ids to entity objects when they are reconstituted.7 Factories The factory design pattern is widely used in object-oriented design. module names should make sense in 2 Or . This means that everything needed to construct the object should be passed to the factory such that the construction can take place in one single interaction with the factory. . modules is used to group related concepts from the model. the continuity of that particular object would be broken.g. but it does mean that the factory should make sure to invoke this logic before returning the instance of the object in question.4. As with everything else in the domain model. A 2 module could be either a dll or merely a namespace within a dll. The most important property of factory methods is that they should be atomic. One important benet of using factories as opposed to con- structors is that the methods of the factories can have abstract return types or return some implementation of an interface.lib or whatever equivalent is oered by the technology used. because if they did. 3. in conceptual packages. Factories used for construction of entity objects should behave dierently when creating new instances of an object as opposed to creating a reconstituted instance of the object. This way. Furthermore.4. . I have seen examples of open source software packages (such as OpenSAML [OpenSAML 2009]) where even the simplest of objects had to be created through a factory. The analogy of the factory object is that sometimes the construction of an object is too complex for the object itself to perform. which makes changing or substituting these objects completely transparent to the caller. and it needs to be created in a factory. the user of the factory method does not need to reference the concrete type of the object that is returned. Simple objects that do not implement a common interface or use polymorphism should probably not use factories for their construction. The overuse of factories can actually obscure simple objects and make the user think that the object is more complex than it actually is. it is important that the factory ensures that all invariants for the object being created are met.34 3.jar. Factories should of course not be used for everything.8 Modules The concept of e. all classes containing User related logic. This does not mean that the logic that checks these invariants should be moved outside the object being created.

In domain-driven design a design that renders itself well to refactoring and iterative renement is called a supple design.5. By being explicit about . operations.35 terms of the ubiquitous language. thus leading to duplicate code. In fact. the lack of a good design may completely stop refactoring and iterative renement since developers will dread to even look at the existing code and they will be afraid to make changes. be obvious that the naming of this method and parameter is more intention revealing than for example Create(User u). Likewise. The It should method name reveals that the method adds a user. Therefore. monolithic design elements also impede code reuse.5. An example of an intention revealing method could be the function from the AddUser(User newUser) UserRepository discussed in Section 3. Determining whether to use individual dll's or just namespaces within that dll should probably be based on the number of classes involved although no details are oered in [Evans 2004]. since a change to the existing mess may break some unforeseen dependency or just aggravate the mess. and argument names should be named in a way that reveals the eect and purpose.5 on page 31.1 Intention-revealing interfaces The word interface in with the keyword intention-revealing interfaces should not be confused interface as known from many programming language. Evans argues. classes. There are no exact formulas to achieving a supple design. just as design elements with confusing or misleading names may lead them to used inconsistently by dierent developers. The names should however not contain any information on how the eect is achieved. and that the argument should be a new user (as opposed to an already existing one). In this context. It is therefore important to make the design open to refactoring and change such that new knowledge can easily be incorporated into the design when it is discovered. the word interface refers to the naming of all public elements of a software artifact. Refactoring When we set out to write software we never know everything about the domain. 3. 3. These patterns are shown in Figure 14.4. but Evans oers a set of patterns that could lead to it. A system that lacks a good design does not encourage developers to leverage existing code when refactoring. and will be discussed in detail in this section.

but the conceptual basis of the design will have been corrupted. and the two developers will be working at cross-purpose.5. 3. a side eect means a change in the state of a system. If someone other than the original developer must infer the purpose of an object or operation based on its implementation. but in the context of computer science in general and domain-driven design specically. the code may work for the moment. In [Evans 2004]. the risk of some developer unintentionally using the method for something else than its intent is minimized. Evans argues that generally there are two dierent types of functions in a system. that new developer may infer a purpose that the operation or class fullls only by chance. and what its parameters are.36 Figure 14. Patterns that contribute to a supple design.2 Side-eect-free functions A side eect normally means some unintended consequence. . Evans gives the following example of why intention-revealing interfaces are important: If a developer must consider the implementation of a component in order to use it. Functions that query system data and functions that alter system state. Evidently. what the method does. If that was not the intent. the value of encapsulation is lost.

Evans states that the add() function should not be split add() and subtract() There is of course no simple up into two separate functions. 3. It does not always make sense to code the pre and post-conditions as part of the program because of performance overhead or missing support in the programming language.37 changes to system state neither can nor should be avoided per se. each function should perform something meaningful in its own right. according to the conceptual contours pattern. recipe for achieving conceptual contours.and post-conditions that should always be satised before and after invoking a function. nothing more and nothing less. side eects cannot be avoided.5. the assertions should be included in automated unit tests and in the documentation of the program. and therefore the decomposition of design elements into cohesive units is something that must be based on intuition and which must be expected to undergo many changes over time until a good granularity has been achieved. This is achieved through a set of pre. functions that alter system state should not return data. Evans argues that no single granularity will t everything in our domain model. Thus.4 Conceptual contours The conceptual contours pattern strives to achieve a meaningful granularity of functions. so instead of using a naive approach where every function or class is limited to a xed number of lines of code or the like. but it should not span several conceptual operations. so if that is the case. This means that functions that return data should not alter the system state in any observable way. classes and interfaces in the model.5. The assertions pattern in conjunction with intention revealing interfaces makes it even more explicit what the side eect of a function is. according to the side-effect-free functions pattern. the granularity should be based on what the function or object conceptually achieves. In the same way the functions should not be combined into one. 3. . In the same way. these two types of be- haviors should not be mixed.3 Assertions As we have just discussed in the preceding section. However. As an example of the latter. each object should be a whole concept. In the same way.

6 Closure of operations The name closure of operations comes from mathematics. especially those that are not essential to the concept. In general. 1 + 2 = 3. The addition of two integers yields another integer.38 3. the closure of operations pattern is Because of the mostly used for value types. the addition operation is closed under the set of integers. It is of paramount importance that these teams have a shared understanding of the model such that the meaning of each concept in the model is the same for all teams. thus leading to misuse of that class . However.5 Standalone classes The pattern called standalone classes revolves around reducing coupling between objects. The goal of this pattern is to achieve low coupling where ever possible because it makes the model easier to understand. Its function Money class presented in add is closed under instances of the Money class. and it is easier to understand. and not so often for entities. 3. life cycle of an entity it is not natural that a function on an entity would return another instance of that entity. Evans argues that every dependency that a class has makes the class more complex and the relationship between the class and its dependencies have to be understood in order to fully understand the class. If this is not the case. Therefore. classes that represent one concept to one team could potentially represent a dierent concept to another team.5. classes with low coupling are easier to understand. Model integrity Building large systems often involves several teams of developers who develop each their part of the system.5. In mathematics.6. since it does not introduce new concepts. e. value types can often have functions that oer closure of operations. However. it is important to reduce the number of interdependencies between classes.2 on page 29. It is obvious that taking the standalone classes pattern to the extreme leaves us with a (useless) model where everything is reduced to a primitive.g. 3.4. An example of a value type that has a function with closure of operations is the Section 3. This property can be used when designing a good model.

but also because some of these patterns are useful for modelling in general. The teams may have an intention to work on the same model and share code.6. Figure 15. as outlined by domain-driven design are shown in Figure 15. The patterns used for maintaining model integrity. But sometimes systems are too big for a single unied model to exist. especially when communication between teams is not as good as it could be.1 Bounded context On large projects with several teams working on the same system it can become unclear whether or not the teams are working on the same model. nevertheless. the system being developed is developed only by this author. Model integrity patterns. not least because the future maintenance of the system being designed may have to be undertaken by more than one person or team. Having one large unied model requires good communication and processes to detect conicting interpretations of the model. Within the scope of this thesis. 3.39 and in the end maybe faulty behavior in the system. In order to overcome this . the patterns of domain-driven design that address model integrity are still interesting to describe.

3. the boundaries of these contexts can be explicitly dened in terms of usage within the application. continuous integration of the model is something that must be achieved by continually discussing the model and relentlessly exercising the ubiquitous language in order to strengthen the shared view of the model and to avoid that concepts evolve dierently in developers' heads.3 Context map When working with a number of bounded contexts. A good set of automated tests should make it more comfortable for developers to refactor existing code. 3. Domain-driven design takes the concept of continuous integration a step further.. As opposed to the continuous integration of code. This should happen through automated builds and automated tests.6. they will know instantly whether or not something is broken by the change they made. and hereby eliminates the risk that dierent teams will think that they are working on a unied model when in actual fact they are working on conceptually divergent models. The context map can be a diagram or a . but also on the continuous integration of model changes. Once a number of bounded contexts have been dened. thus being able to achieve a pure model within the bounded context. The relationship be- tween bounded contexts often involves some kind of mechanism to translate data between bounded contexts. Continuous integration of code is of course something that must take place in parallel with continuous integration of the model. Evans argues that it may sometimes be benecial to split the code and model into several bounded contexts. namely by not only focusing on the continuous integration of code. because by running the automated tests. the continuous integration of a model is not something for which a set of automated processes exist. code base etc.2 Continuous integration Continuous integration is a well-known practice that is aimed at speeding up delivery times and decreasing integration times in software development. A bounded context is an explicit denition of a context in which a given model applies.40 problem. a context map serves the purpose of creating a global view of the entire system and dening the relationship between the dierent bounded contexts.6. Therefore. Using bounded contexts makes it explicit to developers that they are working on dierent models.

The rationale behind this is that if there is a real need for an external component. Evans argues that a pattern called the conformist pattern should be used. . The conformist patterns says that to conform to the model represented by the bounded context represented by the o-shelf component. 3.6 Conformist Sometimes one of the bounded contexts in a system is an o-shelf component with a large interface.5 Customer/supplier development teams The customer/supplier development teams pattern suggests that when there exist a relationship between two teams where one team delivers code that the other team is dependent on. but it can be any part of the model that is needed by all or some teams. and that the names of every bound context described in the context map enter the ubiquitous language.6.6. The shared kernel often represents the core domain of the system and/or a set of generic subdomains. The obvious benet of having a shared kernel is that code reuse between teams can be maximized. When this is the case. 3. then each team should work within their own bounded context. then that component probably represents valuable knowledge and probably has a well thought through model .41 text document or both. Making changes to the shared kernel requires consultation with all its users such that the model integrity of the shared kernel is not broken. and it is important that everyone involved in the development of the system know and understand the context map. 3. Doing so makes it easier to dene responsi- bilities and deliverables and the joint development of acceptance tests will validate whether these have been met.4 Shared kernel A shared kernel is essentially a part of the model that is used in more than one bounded context. Therefore.6. conforming to the model of the component is usually a good idea 3 3 Evans also argues that if this is not the case the use of that component should be seriously questioned.

3. The legacy system may have weak model or a model that does not t the current project. The facade is an interface that simplies access for the client. and therefore may not be worthwhile. and that can be used uniformly by all bounded contexts using the subsystem. the open host service pattern can be used. When this is case.6.6. thus making the subsystem easier to use. An anticorruption layer is often made up of a number services that have responsibilities in terms of the current model and internally use the facade and adapter patterns as described in [Gamma et al. The conformist pattern is most important when the interface with the component is big.8 Separate ways Sometimes the benet of integrating bounded contexts is small. 3. thus allowing developers to nd simple and specialized solutions within a small scope. the be used. and because the possibility of being dragged into a better design exists. . and making customized translators between all the subsystems and all the bounded contexts can be time consuming and hard to maintain over time.7 Anticorruption layer Interfacing with legacy systems is often a necessity for one reason or another. and an adapter is a wrapper that is used to transform messages from one protocol to another. The open host ser- vice pattern is about dening a protocol that gives access to the subsystem.6.9 Open host service Sometimes a subsystem has to be used by many bounded contexts. 1995]. The separate ways patterns can be used when that is the case. So instead of doing so. 3.42 because less translation between concepts is necessary. anticorruption layer pattern may An anticorruption layer is a technique where legacy systems are isolated through classes and functions that honor the current model and hides any conversion and translation logic from the current model to the model of the legacy system.

10 Published language Finally.6.43 3. . the published language takes the open host service pattern to the next level by dening a formal common language for the service. An example of a published language in this context could be SQL or XML.

6 and 7). 4. Therefore some sections may include a refactoring sub-section. In the following I will refer to the software as a whole as the IdP. the aim of the following sections is also to illustrate the iterative process involved in domain-driven design. administrating a single IdP instance. the aim of this chapter is to present the model from a point of view that is not overly implementation specic. but the implementation details will be left for the following chapters (5. however. In domain-driven design the model is comprised of both the code and all the documents that describe what the system does and which parts of the system are responsible for doing what.1. and the person who administrates the IdP the administrator (or an administrator since there may be several). Therefore. You may argue that instead of having a refactoring sub-section I could have just performed the refactoring right away. However. Figure notation Any model is tightly coupled to the data that it represents. Therefore. and therefore I have chosen the sub-section approach. Figure 16 shows an imaginary model concept called SomeConcept which 44 . interfaces and functions. domain-driven design also emphasizes that the model must be understood by (typically) non-technical domain experts. It is important to notice that in this context the administrator is a customer of the software. it seems natural to present the data schema together with the model.Dening the model 4 In this chapter I will dene a model of the software that was specied in Chapter (2). Apart from presenting the model. I will use terms such as classes. and for most applications and this one in particular. This does. that data is stored in a database. the entity objects) the same. not illustrate the iterative process that is one of the cornerstones of domain-driven designas well. Since I have great focus on the ubiquitous language I will name my database tables and the classes that encapsulate each row in a given table (ie.

The schema view shows shows all the data properties of each of these two concepts. Apart from being naming convention that is easy to remember and easy to recognize. I use tity objects. It also shows the primary key. the SomeConceptId is a reference to the OID of some instance of SomeConcept. the arrow in the gure denotes that a For example. In fact. SomeConceptAttribute is coupled to a SomeConcept. OID OID (short for object id) as a primary key for all en- such that is should always be easy to infer which property references the of the other class.45 Figure 16. using this naming convention is useful in the imple- . Schema view also shows relationships between the classes. which is denoted by a small key symbol next to the property. Figure explanation has attributes called SomeConceptAttribute. I use a strict naming convention for these references.

Figure 17 shows the convention for interfaces. As a matter of fact. these properties will denote some computed property that is not a part of the data schema. This nature of the relationship is explained with some text above or under the arrow. I will explain all methods and their parameters where I deem it necessary for understanding its purpose. are references to instances). which are: . You may also assume that the relationships denoted by arrows in schema view still exist in class view. and the class. An abstract class. I have now introduced the gure notation that is going to be used throughout this chapter. but they are not shown in order to keep the gure simpler. For example. There may sometimes be properties on the classes in class view. and it is time to take a look at the core concepts of the model.46 mentation as we shall see in Chapter 5. of the classes. and that each has an instance (reference to an instance) of a there may be blue arrows between the classes in class view denoting some kind of relationship between the classes. color). you may assume that all the properties that were there in schema view are still there. In class view. Also note that some classes are not part of the data schema at all. and abstract classes in class view. ISomeInterface represents an interface (note the green SomeClass is a class that implements that interface. when introducing new concepts that expand something that has already been shown. denoted by the circle and interface name above the class. I will not show relationships that have already been explained. when introducing a new concept I will not show relationships to things that have not yet been introduced. Class view also shows what type of class each class is in terms of domain-driven design. SomeOtherClass that inherits SomeAbstractClass has an arrow to class and a small arrow with the name of the base class next to it. Finally. and therefore they may have non-computed properties. if any. Likewise. For example. I will generally explain the type and meaning of all the properties unless they are self-explanatory are identical to previously explained properties. This is denoted in italics above each class. such as SomeAbstractClass has dotted line around it. Please note that I may chose not to show all relationships of a given table in schema view. as exemplied in the gure. but if there is. while. for Figure 16 you may assume that each a (possibly empty) list of SomeConcept class has SomeConceptAttribute instances (technically these SomeConceptAttribute instance SomeConcept class. The class view on the other hand shows additional functions.

Events in this context is logging of errors and other activities in the system.47 Figure 17. I will refer to logging and tracing before actually introducing the part of the model that describes them. Figure explanation  Plug-ins  Users  Conguration  Certicates  Credential providers  Protocols  Connections  Claims  The runtime  Events Please note that I have chosen to introduce reporting of events as one of the last things.12. since as a concept it is not as central as the others. which you can nd in Section 4. .

without the need of recompilation. Figure 18 shows two important interfaces used for creating plug-ins. This technique is commonly used. Figure 18. however. 1995] with the motto "Program to an interface. letting the system be extensible in this way would denitely allow for this in the future. An extensible system One of the most important properties of the system is that it must be extensible in two areas. and thus the IdP will not have to care about the how the plug-in is implemented.2.1 Plug-ins A plug-in is an extension to the IdP. but only that it satises the contract dened by the interface. not an implementation". Current development visions for the IdP do not include any third-party plug-ins. These properties are just descriptive strings. A plug-in is created by coding a class that implements the IPlugin interface.48 4. Class view: IPlugin and IEndpoint interfaces Both the IPlugin and IEndpoint interfaces specify that properties called Name and Description. This will be dealt with through the concept of plug-ins. The core IdP framework itself does not implement any plug-ins. it only denes how such a plug-in should behave. Another important benet of using a plug-in structure is that extensions to the system can easily be deployed to existing installations. namely in the way a user presents his credentials and in the protocols supported by the system.2. and endorsed by [Gamma et al. 4. The .

The should return an instance of a class that can handle web requests. Figure 19 shows the properties of a User.49 ProvidedLoggingSources property of the IPlugin interface returns a list of logging source names that the given plug-in uses when (or if ) it creates log entries. The Password is a computed hash of the user's plain text password. Lastly. an endpoint denes a (web-site absolute) path and some class that knows how to handle any requests for that path.3.Net framework it would simply be an implementation of the IHttpHandler interface. 4. Handler property Every Conceptually. and comparing the result with the value . These a quite self-explanatory. However. a DateCreated and a LastLogin property. by denition. and that. it knows something about. The plug-in concept of our model is actually a general abstraction that will be specialized by the more specic credential plug-in and protocol plug-in as we shall see later on. using the original salt value. A user represents some person which is known by the IdP. all that needs to be done is to compute the hash of the password entered by the user. and in the . so that needs to be added. by the GetEndpoints function dened IPlugin interface must return a list of IEndpoint implementations. the hashing function will only return the same computed hash as the one stored in the User object if the same salt value is used. So to verify a user's password. the system must therefore create the logging sources by using the LoggingSourceRepository. and the PasswordSalt is some random value used by the hash- ing function as entropy. a PasswordSalt property. The bounded context comprised by each plug-in will have a conformist relationship to the IdP since the plug-in must adhere to the model dened in the IdP. modern web development framework has extensibility points for such classes. the Add The logging source repository denition that we saw earlier did not have an function. Given the user's plain text password. During installation of a plug-in. Each plug-in implementation will be a bounded context in domain-driven design terms. the user contains a UserName. Users One of the core concepts of the IdP is the user. Apart from a unique id (the User has a Password and a OID).

50 Figure 19. the userName and clearTextPassword. you may think that this is silly. Now.3.1 User creation The administrator must be able to manually create users. a The UserFactory class has CreateNew method that takes two arguments. Schema view: User stored in the User object. by passing it as a parameter to the Note that the UserRepository also has a ExistsByName function. Comparing usernames is just a matter string comparison right? The answer is no. Using this approach disallows anyone with access User class VerifyPassword function. The ExistsByName function in turn uses a specication (the ExactUserName specication) to compare the given username with that of existing users. the classes shown in Figure 20 are needed. Note that the shown in Figure 20 has a 4. and false other otherwise. sets the creation date and other relevant User instance. To achieve this. that does just that. The IdP has a rule that says that usernames are case insensitive. and the ExactUserName specication im- plements logic that compares usernames case insensitively. and it is therefore important to use the ExistsByName function to check that no user with that name already exists. . namely a When called. elds and returns a CreateNew method computes the hashed password and password salt. user to have the same username. to the database to see any of the users' passwords. The User instance can then be persisted Add function of the UserRepository class. This funcThe IdP does not allow for more than tion takes a username and returns true if a user with the given name already exists.

will discuss how this can be achieved in a generic way.3. You can think of this as an easy way for the administrator to create users in the IdP. Until then.51 Figure 20. 4. It may also need to have a all users whose UserName starts with some specic letter.3. the UserRepository will need to have a FindAll funcFindByFirstLetter function to easily fetch In Chapter 6 I tion. you may assume that all repositories have at least a FindAll function. In fact. because instead of having to type in all the information about each . To cater to this need. Class view: User creation 4.2 Displaying existing users The administrator will need to be able to display a list of all existing users.3 Inviting users As you may remember from Chapter 2 an important feature of the system is that it must be possible to invite users to register at the the IdP. search functions will probably be needed in all the repositories.

52

user, the invitation mechanism delegates this work to each user. The act of inviting a user merely entails sending an email to some email address with a verication code in it. The verication code is simply an automatically

generated code that the IdP links the email address to which it was sent. By presenting his email address and the correct verication code, the user can prove that he was indeed invited. The user then chooses a user name and types in any additional information (for example values for his claims as we shall see in section 4.10) and he is then enabled in the system without further involvement of the administrator.

Figure 21. Schema view: User invitation

Figure 21 shows the schema involved in class holds the each

user invitations.

The

UserInvitation

Email and VerficationKey as just explained. Furthermore, UserInvitationStatus. The UserInvitationStatus

UserInvitation has a number of UserInvitationStatusHistory refer-

ences, each of which reference a

is used to dene statuses, such as email sent, code veried and user created. The history table merely links a status to an invitation using the

StatusDateTime property to record the date and time of the given status.
When the user is created as an actual

User in the system, an InvitationToUser

object is created in order to be able to track which invitations correspond to which users. Figure 22 shows the entities from Figure 21 in class view, together with all the other classes needed for user invitations. trates most things related to user invitations is the The class that orches-

UserInvitationService

53

Figure 22. Class view: User invitation

class.

The

IniviteUser method takes a single parameter, an email adCreateNew method UserInvitation

dress, and performs the following steps; First it calls the of the

UserInvitationFactory, passing the email address as the only paVerificationKey for the

rameter to the method, to create a new instance of the class. The factory method internally generates the

UserInvitation instance, and it also generates an instance of UserInvitationStatusHistory
which it couples to the

UserInvitation instance. Next, the UserInvitation Add method of the UserInvitationRepository.

instance is persisted by calling the

Finally, a mail message, including the verication key is composed, and the

SendEmail method of the EmailService is called to send the email message.
The

InviteUsers method of the UserInvitationService takes a comma sepInviteUser method once for each CreateUserFromInvitation method takes an email ad-

arated list of email addresses and calls the email address. The

dress, a verication key, a user name and a password as parameters. It then nds the

UserInvitation instance corresponding to the email address and VerifyKey method VerifyKey method takes the verication key provided

veries that the verication key is correct by calling the on that instance. The

by the would-be user and compares it to the one it holds internally. If everything is ok, the invitation history is updated by creating the proper objects and calling the proper repositories. Finally a new persisted, and nally an

User object is created and

InvitationToUser instance is created and persisted.

54

And that concludes the user invitation, and the user is now ready to login with the IdP.

4.3.4 Self registration

Another way of user creation is through

self registration.

Self registration

has many similarities with user invitations, but diers in that the would-be user and not the administrator initiates the creation process. Furthermore, any self registration must be approved by an administrator.

Figure 23. Schema view: Self-registration

Figure 23 shows the schema view of the classes needed for the support of self registration. You can probably recognize most of the concepts from user invitations. The main dierence here is that the

SelfRegisteredUser User object, such

class contains all the properties needed for creating a as

Password, PasswordSalt, etc.

The

SelfRegisteredUser class contains

a property called

RequestedUserName. The reason for this is that at the time

of self registration a given user name may be available, but at the time of actual user creation, the name may have been taken by someone else. Figure 24 shows the classes for self registration in class view. The classes are similar to those of user invitation, and therefore I will not explain them in detail. It is important though, to note that there are many more statuses involved in self registration than there are for user invitations. Registered

conrming his registration. Lets see how the model could benet from having these concepts made more explicit. The administrator may also choose to deny registration. Finally the administrator may choose to ignore the registration. Class view: Self-registration is the status for newly registered users. instance of a 4. First of all. such as UserInvitationService. Subject. as described earlier. When the The address is veried an administrator must take some kind of action. the status is changed to Veried. which results in a status of Ignored. which may have changed from what the user wanted. The UserRegistrationService is the class that provides all these Also notice that the status changes.55 Figure 24. but no email is sent. and returns an User.5 Refactoring The model thus far contains some implicit concepts regarding sending emails to users. . This email will contain the actual user name. UserService and UserRegistrationService compose mail messages internally and sending them through the EmailService. UserFactory has been extended to include a method called of a CreateFromRegistration which takes an instance SelfRegisteredUser and an optional new user name. and an email being sent to the user. which results in the status changing to User created and an email being sent to the user. these dierent email messages should be made explicit concepts in the model. administrator can either approve the registration. After registration an email is sent to the provided email address in order to verify the address. Instead of having the services.3. When the user conrms the email address. which results in a status of Denied. Figure 25 shows the classes involved in sending these email messages. the interface IEmailMessage denes three properties.

including the verication key (available through the property of the UserInvitation instance passed to the constructor) and a Email property is also read from link to the verication page. Message and Recipient BaseEmailMessage.11. For example.56 Figure 25. Furthermore. The Subject is simply a static string saying something like You have been invited to join an identity provider. Now. A last concern is if the 4 EmailService has been made obsolete. Class view: Emails Message and Recipient. passing itself as the parameter. Finally. the 4 BaseEmailMessage implements the IEmailMessage interface. but has all the properties from the interface as abstract members . You may wonder how the correct address to the verication page is obtained. This address. the UserInvitation instance. So the signature of this method is changed to take an instance of an IEmailMessage as a parameter. and takes an instance of an UserInvitation in its constructor. These are the properties that are needed by the SendEmail method of the EmailService class. This method calls the EmailService's SendEmail method. gure. implements a (non abstract) method called BaseEmailMessage This Send. allows us to dene explicit email messages such as the ones shown in the InvitationEmailMessage is a class that inherits the Subject. The Message property contains the message VerificationKey body. It implements the abstract properties from the base class (and which originate from IEmailMessage). Could the Meaning that they must be implemented by any inheriting classes . and a lot of other parameters about the the IdP will be made available to all components in a way explained in Section 4.

each plug-in will rely on the ability to be congured in order to function correctly. but which are logically grouped in lists (or tables).4. text configuration element which hold string data. the namespace is just used to group conguration elements belonging to some part of the system. if at a later point I wished to implement a method called CheckServerConnection. This does not make the model implementation specic. certificate configuration elements which hold references to certicates. than on a BaseEmailMessage class. Conguration Conguration of the IdP is essential in many ways. First of all. Figure 26 shows the schema view of the conguration elements. Common for all the conguration elements is that they are identied by a and an NameSpace ElementName. or protocol. and indicate thereby indicate that only the values true and false would be valid. but the the type of data in the string. This is also the case for connections. EmailService is to know about which SMTP server to use and which credentials (if any) to present to that SMTP server. Therefore a conguration framework is called for. The value is always stored as a string. which are described later in this chapter.saml2.core conguration element. for all elements belonging to the IdP itself. The information contained in the is to some extent specic for the way certicates are stored on machines running Windows.57 logic implemented by the well have been put in the SendEmail method of the EmailService just as Send method of BaseEmailMessage? It denitely The main purpose of the could have. The Type eld is used to indicate Type could. conguration of the IdP itself must be possible. for example. Furthermore. Generally speaking. Furthermore. The CertificateConfigurationElement contains references to certiCertificateConfigurationElement cates. the The namespace used by any given part of the system must be unique. but I do not think it is good idea. TextConfigurationElement has a Value eld which contains the actual value. it EmailService would denitely be more logical to have such a method on an class. but .connection1 for some connection.saml2 for a some protocol implementation and nally protocol. and list configuration values which also hold string data. Therefore. The NameSpace is a string identier of the owner of the The namespace could be something like idp. The conguration framework denes three basic types of data. 4. be Boolean.

The most important features of conguration elements are that they must be presentable to the administrator such that they can be read and edited. and where zero or more rows of data may be called for. there must be a mechanism for validating the values typed in by the administrator. So a as shown in the gure. ListValue is tied to both a row and a column. or part of the system. . acts as a conformist to the environment where it is ultimately going to run. the meaning of which is dened by a column. Furthermore. a single row of data contains several values. if such a list exists. Schema view: Conguration elements merely indicates that the bounded context that the model comprises. that relies on a given conguration element must be able to provide a list of valid values for a given element.58 Figure 26. The ListConfigurationElement is used to dene conguration elements ListConfigurationElement could be presented. The plug-in. Figure 27 shows how a Generally. only certain values make sense for a given conguration element. that have a tabular nature. Another important concern is that in some cases.

denes that a single property called Namespace. Class view: Conguration elements Figure 28 shows the conguration elements and their repositories in class view. The important thing to notice here is the INamespaceElement interThe interface merely Since all three entities face. . that is implemented by all the three entities.59 Figure 27. Conguration lists Figure 28.

in class view. all three repositories can use the same specication to nd the elements of the respective type that matches a given namespace. It can validate the values of all conguration elements as a whole. we will call a configurable com- ponent. of course). This way. they can implement the interface without further ado. This is useful. be it the core IdP itself or any plug-in or connection. To provide this functionality a number of classes and interfaces are called for. It can provide a structure that logically groups its conguration values such that they can be displayed to an administrator in a way that makes sense in the context of the meaning of the conguration elements. A congurable component is represented by the IConfigurableComponent interface. thus making it straightforward to nd all conguration elements belonging to a given component (identied by its namespace. and the value of a single conguration element individually. because we can now dene a specication called NamespaceMatchesSpecification. whose IsSatisfiedBy method takes an instance of a INamespaceElement. Any part of the system that depends on conguration values.60 have such a property already. A congurable component provides the following functionality: It can provide a set of default values for all its conguration elements. Figure 29. Class view: Congurable component Figure 29 shows some of the concepts needed to support congurable components. This is useful because the itself only contains information about where the certicate is stored. Also notice that the method called CertificateConfigurationElement denes a CertificateConfigurationElement The LoadCertificate that loads the actual certicate from the cer- ticate store. The interface denes which namespace . method returns an instance of the framework class called X509Certificate2.

and validates its value (or values. GetDefaultValues is a Furthermore. Figure 30. or null if the validation succeeds. Finally. or heading if you like. is an overloaded method that takes one of the three conguration element types as a parameter. function that returns an instance of a ConfigurationSet. Visual conceptualization of conguration Figure 31 shows the classes involved in conguration element display. if it is a ListConfigurationElement). which is a string containing a caption. The main purpose of the DisplayConfigurationSet is to display a cong- uration set in some UI. containing an error message if the value is not valid. The DisplayConfigurationSet is the aggregate root of all the classes.61 the elements of the component has. This function is called during installation of a congurable component and its main purpose is to return all conguration elements such that they can be created in the database. the interface denes a set of functions. and as you may have noticed a few extra properties have been added since the class was introduced in Figure 29. a class that presents ements of the dierent types explained earlier. It returns a string. A ConfigurationSet is merely a container for the conguration elGetDisplayConfigurationSet DisplayConfigurationSet. The returns an instance of a the conguration elements in a way suitable for showing in a user interface. through the ElementNamespace property. such as that shown in gure 30. the method. The ConfigurationSet as a parameter and returns an instance of a DisplayConfigurationSet (which will contain information about potential errors). of the en- . The DisplayConfigurationSet class will be explained in greater deValidateConfigurationSet is a method that an instance of a ValidateElement tails later. These properties are the Caption property.

DisplayTextConfigurationElement has the following properties. yet another grouping container.0 protocol conguration. and most Groups property. This is useful for the order of which the elements are displayed. A tab control is a common user interface control found in most applications. The DisplayConfigurationTab class also has a Caption property. The base class contains a single property. intended to be displayed as a single tab in a tab control. The last property of this class is the of Tabs property. it has a of DisplayConfigurationGroup instances. Class view: Display conguration elements tire display conguration set. used to logically and visually group conguration elements. ConfigurationElement is of type TextConfigurationElement and represent the conguration ele- . which returns a list of instances of the abstract The BaseDisplayConfigurationElement class serves the single purpose of being a common base class for the three display conguration elements. Apart from the erty. A caption value could for example be Identity provider conguration or SAML 2. A DisplayConfigurationGroup is Caption property it has an Elements propBaseDisplayConfigurationElement.62 Figure 31. DisplayConfigurationTab is a grouping container. ReadOnly property indicates whether a given display conguration element is editable. namely ReadOnly which is the only property The the three display conguration elements have in common. A This property returns a list DisplayConfigurationTab instances. The Groups property returns a list importantly.

Those certicates that are not issued by another certicate are said to be self-issued.5. you know that most certicates are issued by other certicates. but a list of X509Certificate2 instances. The other two display conguration elements are similar. 4. and are often referred to as root certificates. I have chosen to extend the BaseDisplayConfigurationElement with a Description property. Now. amongst other things. it must. and they use a very well guarded root certicate to issue certicates that .4. correspond- ListValue inside the ListConfigurationElement returned by the PossibleValues property of the other two display elements. from where a value can be chosen. the PossibleColumnValues is similar to the ever it contains a list of lists. The PossibleValues may be null. ConfigurationElement property. if the ministrator can type in any value.63 ment that is being displayed.1 Refactoring There needs to be some way of communicating the meaning of a conguration element to the administrator. Finally. Such companies are called certicate authorities (CA's). null. ConfigurationElement. DisplayCertificateConfigurationElement diers in that its DisplayListConfigurationElement PossibleValues does not return a list of string values. where each list corresponds to the possible values for a column in 4. Therefore a Description property is called for. Finally. trust the root certicate that issued Quite a few companies world-wide make their living by issuing certicates. should the Description property be on the conguration element. in which case the adHowever. Sometimes the name of a conguration element may not be enough do explain what a conguration element is. Certicates If you know a little about X.509 certicates. howListConfigurationElement. or on its display counterpart? Since it is primarily a display related thing. from which the administrator can choose. They dier in the type returned by the Furthermore. the of possible values. that certicate. The diers in that its ing each Errors property is a matrix of error messages. the string values it contains will be rendered as a drop-down list. In order for an application to deem some certicate to be valid. The Error property is a string containing a PossibleValues is a list PossibleValues is not possible error message for the element.

64 other companies or people can buy. the certicate conguration elements were only references to certicates in the certicate store. you can create your own root certicate. Figure 32. or if you can persuade your business partners to trust your root certicate. because they ship with the operating system. The most important class is the CertificateService class. However. creating new certicates. The CreateCertificate . The administrator needs some means of inspecting (searching for) the certicates in the certicate store. and use this to issue other certicates. when you do not wish to pay for a certicate that you are going to use for test purposes. because you can choose to trust that root certicate. only parameter to the method is a so-called distinguished name. This will work ne on your own systems. deleting existing certicates and so on. However other systems will not trust your root certicate. a string value that is used to identify the certicate later. Class view: Certicates Figure 32 shows the classes involved in maintaining certicates. but that does not really matter as long as you are only using it for test purposes. We have already seen how certicates can be used in conguration of the system. The CreateRootCertificate The method can be used to create a root certicate as explained above. The root certicates of these CA's are per default trusted by all computers world wide. Sometimes.

5 A common format is the canonical encoding rules (CER) format which is supported on most platforms. and nally. only it searches in trusted root certicates store instead of in the standard location. and 12 is a version number. is an overloaded method. the cate to another. 6 A common format for exporting certicates with private key is the PKCS12 format. together with a It also returns a byte array. The DeleteCertificate is X509Certificate2 ExportCertificate method takes as its only X509Certificate2 class. All the certicate specications in the gure take an instance of the X509Certificate2 in their respective IsSatisfiedBy methods. This method takes an instance of an X509Certificate2 class. The FindCertificates method takes a list of certicate specica- tion instances. it would be useful to have a feature that could check if the certicate is being used by a CertificateConfigurationElement. The specications are.65 is used to create a certicate. ExportCertificateWithPK exports a certicate including its private key. password to use to protect the certicate. takes a byte array (in PKCS12 format) and a password. and not expired. The FindRootCertificates does exactly the same as the FindCertificates method. The other overload. eg. but furthermore. and imports the certicate private and public key into the certicate store. it takes a root certicate that is used to issue the certicate. and warning the administrator if this was the case. and returns a byte 5 The used to delete a certicate. The does the opposite. PKCS stands for Public-Key Cryptography Standards. and also in a common format . issued CertificateIsInvalid CertificateMatches compares one certi- to the distinguished name string parameter given in the specication's constructor. .1 Refactoring When deleting a certicate. CertificateByDistinguishedName which compares a certicate CertificateIsValid checks if a certicate is valid. The parameter an instance of the array representing the certicate's public key in a common format . The root certicate parameter is passed to the method as an instance of the X509Certificate2 framework class.5. As a parameter it also takes a distinguished name. 4. The by a trusted root certicate. 6 The ImportCertificate method The rst overload only takes a byte array (in CER format) and imports a certicate public key into the certicate store. and it takes an instance of an class its only parameter. and returns all the certicates that match those specications. this time corresponding to both the public and private key of the certicate.

it is safe to delete the certicate. Class view: Refactoring the certicate conguration element repository Figure 33 shows that the CertificateConfigurationElementRepository FindByCertificate. If the list is not empty. 4. but it is the administrator who chooses which credential providers are enabled for his IdP. such that the administrator can enable it. A concrete credential provider plug-in implementation is contained within a module (dll) on the IdP server.6. Schema view: Credential providers . and possibly change those conguration elements to reference another certicate before deleting it. Figure 34.66 Figure 33. If the list is empty. The IdP will oer several dierent credential providers. It takes has been extended to include a method called an instance of an X509Certificate2 and returns a list of CertificateConfigurationElements that are currently the depending on that given certicate. the administrator can be told which certicate conguration elements depend on that certicate. Credential providers Credential providers are specialized plug-ins that facilitate user logins. and registered in the database.

The ICredentialProvider interface extends the IPlugIn interface. Here. As mentioned in Chapter 2. explained in Section 4. while the SAML variant uses federation with another identity provider to collect the user's credentials. as there is only one local user database anyway. But what about the SAML federation scenario. and CredentialProviderType. This works well for the username/password scenario. that can be used to create an instance of the given credential provider using reection. . The model only allows for one instance of each credential provider to be congured. The credential mechanisms are actually quite dierent. in that the username/password variant validates users through the local database. SupportsConnections is a boolean that indicates whether or not the credential provider supports connections. must represent a type that implements a specic interface. it must be possible to setup several federations with several other IdPs.8. A credential provider may have more endpoints for various purposes. such that it can initiate the login sequence properly. The default endpoint is the endpoint that initiates the login for a given user. and indicates that the given CredentialProviderDefinition has been congured (is in use). however not by conguring more than one instance of the credential provider. and adds two new properties.67 Figure 34 shows the who main concepts involved in setting up credential providers. A CredentialProviderDefinition denes a credential provider It has a that can be used to log users in. pointer to a The ConfiguredCredentialProvider is merely a CredentialProviderDefinition. The instance of an DefaultEndpoint is a property that returns an IEndpoint (see Figure 18 on page 48). Figure 35 shows the interface that must be implemented by plug-ins that are credential providers. but by the concept of connections. so it is important that the IdP knows which is the default endpoint. This is useful for displaying a user interface to the administrator where he can congure the connections for a given credential provider that supports connections. which I will explain in detail below. And this is indeed going to be possible. which is a string that The type name contains a fully qualied type name. most importantly it has a Name and a Description.0 federation. the IdP must be able to accommodate credentials both in the form of username/password and via SAML 2.

so I will not get into a lengthy explanation here. Such protocols include SAML. that there are repositories for both concepts (ProtocolDefinition and shown here.7. ConfiguredProtocol) even though they are not . Class view: Credential provider interface 4. Notice however.68 Figure 35. WS-Federation. OpenID and many more. Figure 36 shows the schema view of the classes for dening and conguring protocols in the IdP. There is no real dierence from the way credential providers where dened and congured. Protocols Protocol plug-ins are specialized plug-ins that provide the implementation of some protocol for exchanging security related information.

69

Figure 36. Schema view: Protocols

Figure 37. Class view: Protocol plug-in interfaces

70

Many, but not necessarily all, protocols rely on the exchange of metadata in order to establish a trust relationship between an identity provider and a service provider .

7

Our IdP has no way of knowing the metadata

format used in dierent protocols, therefore the responsibility of creating the metadata must be delegated to the protocol plug-in implementation itself. Therefore, the

HasMetadata property of the IPotocolPlugIn can be

used by the implementor of a specic protocol to indicate whether or not the implementation provides (or has) metadata. When that is the case, the implementation of

GetMetadata is supposed to return a string representing
If

metadata for the given implementation.

HasMetadata returns false, the

GetMetadata method will not be called. It does however still need to implemented, because otherwise the interface will not be implemented. Throwing an exception in the method implementation will be acceptable. The

SupportsConnections property is identical to that of credential providers.
This indicates that the property could be moved to the common interface

IPlugIn, something that I will address below. The IProtocolEndpoint interface is an extension of the property,

IEndpoint interface, which adds one important

RequiresAuthentication. This property indicates whether a given
This is the case for all protocol endpoints that

protocol endpoint requires the user to be authenticated before delegating control to the endpoint.

send user's identity to a service provider. The IdPwill check any protocol endpoint for this property, and make sure to authenticate the user (through one of the congured credential providers) before delegating control to that endpoint. I will explain this in greater detail in Section 4.11.

4.7.1 Refactoring

As mentioned before, the

SupportsConnections property exists in both the

ICredentialProviderPlugIn and IProtocolPlugIn interfaces. Therefore it
can be moved to the

IPlugIn interface. Furthermore, some credential providers HasMetadata property

also need to export metadata. This means that the and the

GetMetadata method could also be moved. This leaves the question

of whether the two interfaces should be there at all. However I like the idea of having them both. They are good to have for the sake of of the possibility that the two may diverge in the future. Having them both also make them more explicit as concepts, which is important in terms of domain-driven design.
7

Service provider is also sometimes referred to as relying party.

71

4.8. Connections

As already mentioned, it is normal for an identity provider to require a congured connection before it wants to communicate with a service provider. A connection is merely some information about the other party. This in-

formation usually includes certicates, and a set of string values describing various aspects of the way communication between the two parties is carried out. In other words, a connection is a specialized conguration set. Given the fact that the data (the conguration set) that describes a connection is specic to a given protocol (the language the two parties speak), it must be responsibility of the protocol implementation to provide the default conguration set values, and the display conguration set. A credential provider may also need to congure connections, for example in the case of federated SAML2.0 login. In this case the credential provider acts as a service provider to some other IdP.

Figure 38. Schema view: Connections

Figure 38 shows the schema view of some of the classes needed to model connections. nection. A

ConfiguredConnection

represents some congured con-

Besides having an object identier, a congured connection has

a name, a description, and a namespace, represented by the properties

a congured connection belongs to either a protocol or a credential provider. in class view in Figure 39. Finally. in order to support working with the data classes shown in Figure 38 a set of services and repositories are called for. The ConnectionNamespace. SaveConnection has two parameters. Class view: Connections Now. namely the parameters required to create a new instance of the and ConfiguredConnection class. Figure 39. updating and fetching of congured connections. OwnerId refers to the id of either a ConfiguredProtocol or a ConfiguredCredentialProvider. and the second is an instance of a ConfigurationSet. ConnectionDescription. Please note that the are not shown in the gure. These are ConnectionName. This mapping is achieved through the and ProtocolConnection CredentialProviderConnection classes. The CreateConnection method has three parameters.72 ConnectionName. the rst is an instance of IConnectionService interface. ConnectionDescription and ConnectionNamespace. The GetConnection method has a single paramOwnerId and it returns an instance of ConfiguredConnection. that map a congured connecConfiguredProtocol and ConfiguredCredentialProvider classes tion to either a congured connection or a congured protocol. eter. A These are shown connection service is a service that faThe cilitates creating. IConnectionService denes these functions. As the gure also shows. ConfiguredConnection. There are two classes that implement the namely ProtocolConnectionService and CredentialProviderConnectionService. . The ConnectionNamespace is used to map a congured connection to a ConfigurationSet.

It has also been necessary to expand the called ConnectionConfigurator. not shown in the gure for brevity).9. is an abstract class that contains the implementation for since this method must do the same thing in the context of protocol connections and credential provider connections. This property is of type IConfigurableComponent. one for in- . it is the responsibility OwnerId parameter to fetch the cor- of the concrete implementation to use the rect instance of either ProtocolConnection or CredentialProviderConnection IPlugIn interface with a property (using the appropriate repository. The implementation of ent for the classes. Plug-in installation Since the system is plug-in based. and is used to validate the values in the conguration set for either a protocol connection or credential provider connection. and that there are no endpoints within the plug-in that handle the same path. again. for the GetConnection method. The dates (saves) the instance of SaveConnection method upConfigurationSet ConfiguredConnection through the ConfiguredConnectionRepository (not shown in the gure). 4. the installation of a new plug-in must not lead to multiple endpoints that handle the same path. In the case of the CreateConnection method. because only these implementations can know what the valid values are in their specic case. The concrete implementation of the IConfigurableComponent must of course be provided by the implementation of a protocol or credential provider. Figure 40 shows the classes needed for plug-in installation. Most importantly. and likewise it saves the instance of through its corresponding service (ConfigurationService shown in the gure). GetConnection and CreateConnection is dier- ProtocolConnectionService and CredentialProviderConnectionService This is due to the fact that they interact with instances of the ProtocolConnection and CredentialProviderConnection respectively (shown in Figure 38). The central class is the PluginInstallationService that has two methods. It is also important to test that the new plug-in implements the correct interface. The BaseConnectionService SaveConnection.73 Both classes inherit the BaseConnectionService. Likewise. it is important that installation of new plug-ins is supported by the system. it is the respon- sibility of the respective service implementation to create an instance of the correct connection class (either ProtocolConnection or CredentialProviderConnection) in order to associate the connection with either a protocol or a credential provider.

Step 2 Test that the instance implements the correct interface (ICredentialProviderPlugin or 8 IProtocolPlugin). Step 4 Create an instance of the NoEndpointAlreadyExistsForPathSpecification class. namely the type string . Class view: Plug-in installation stalling protocol plug-ins and one for installing credential provider plug-ins. and the assembly containing the plug-in. and the paths of their handlers are appended to the list. In order to make this list. The constructor of this class takes a list of paths that are registered for those plug-ins that are already installed. which are then instantiated. The IsSatisfiedBy Step 3 Create an instance of the and make sure that its method has an argument of type returned by the GetEndpoints method and tests that no two endpoints have identical path properties. Finally. the two repositories shown are used get all installed plug-ins. and it iterates all endpoints IsSatisfiedBy method returns true.74 Figure 40. AllEndpointPathsAreUniqueSpecification IPlugIn. the 8 IsSatisfiedBy method is called for each endpoint Corresponding to the CredentialProviderType or ProtocolType properties of the CredentialProviderDefinition or ProtocolDefinition classes respectively. as a byte array. . Each method has two parameters. The two methods perform similar actions: Step 1 Load the assembly and instantiate the class given in the type string through reection.

or in the case where all users must get a predened value for . The provider claim. mainly used in UI. that a name must comply to. This type of claim is called a CredentialClaim. The DefaultValue is used to dene a default value for the claim. and represents a claim that is issued by the IdP. Finally. the only claim that originates from the credential provider is a username claim. in the sense that it does not provide a concrete value for the claim. type is called an called IdentityProviderClaim. Since this instance implements the IPlugin interface (both Verb|ICredentialProviderPlugin| and IProtocolPlugin are extensions of instance. The IdentityProviderClaimDefinition class is used to dene an identity It does however dene every other aspect of the claim. In the simple case of username/password credentials. The name and description properties of the denition object are taken from the concrete instance instantiated in step 1. Claims The ability to dene and work with claims is one of the core features of the IdP. The is acceptable for the claim.75 in the plug-in that is going to be installed. However. The IdPdenes three conceptually dierent types of claims. for example. a number of claims may be returned by the federation partner. The This claim next type of claim is a claim that is dened in the IdP itself. Figure 41 shows some of the classes related to claims. in schema view. The ValueType denes the type of value that etc. The NameFormat is used to describe the format of the Name. in the case of federated login. An instance of either CredentialProviderDefinition or ProtocolDefinition is created and added to the corresponding repository. IPlugin) these properties are available on the concrete 4. A name format could. The rst type of claim is a claim that originates from some credential provider. such as xs:string or xs:int Description is merely a textual description. It is normal for dierent protocols to dene name formats. Step 5 If we have come this far. the last type of claim is IssuedClaim. The value type is normally expressed as an xml type. in the case where a user has no explicit value for the given claim. the plug-in is ready to be installed. DisplayName property is a reader friendly name used for display in UI. specify that the name must be a well-formed URI.10. The Name is the actual name of the claim used when sending the claim some security token.

but having the DefaultValue and IsGroup properties allows the IdP to display a user interface where the administrator can work with groups. When the claim is issued by the IdP it looks like any other claim. used for dening groups.76 Figure 41. Adding a user to a group simply results in a claim that states that the user is part of some group. Name. in the case of groups. The DefaultValue is. whereas for other claims it could be set to true. Schema view: Claims the claim. the IsUserUpdateable boolean propIsUserUpdateable property The erty is used to specify whether or not the value of a claim can be changed by a user. and that its value can be used to nd a . Finally. By creating an IdentityProviderClaimDefinition with a and default value of for example Administrator. This property is used to dene that a given credential claim bears the identity of the user. The CredentialClaimDefinition class does not have a DefaultValue property. the will be set to false. for example. As specied in Chapter 2. ClaimName idp:Group. a conceptual group can be created. it must be possible to assign users to groups. It does however have an IsIdentityBearer property. Again. ValueType and Description properties. NameFormat. The CredentialClaimDefinition class is similar to the IdentityProviderClaimDefinition class in that it also has DisplayName. IdentityProviderClaim couples an IdentityProviderClaimDefinition to a User. and (optionally) assigns a ClaimValue for the given claim denition to the given user. since its value is not asIsGroup and signed by the IdP. For the same reason it does not have the IsUserUpdateable properties.

it is probably not very practical. Figure 42.77 corresponding User instance. this mechanism is a clear candidate for future refactoring. The IdentityProviderClaim CredentialClaim class) has. When an administrator or a user assigns a value to the claim. as we shall see in Section 4. The IssuedClaim class is a simple data class that holds the values that are needed in the response of a given protocol implementation.11 . A given protocol implementation can query the IdP for a list of instances of on page 79. but The Verb|ClaimValidation| class is used If. This solution denitely works theoretically. the validator is instantiated and evaluated against the value. Class view: Claims Figure 42 shows the three dierent claim types. The class is the same as we have already seen in Figure 41. The a class whose main purpose is to tie a value. and therefore. IssuedClaim for the current user. for example. or have a specic length or format. and are CredentialProvider implementation. Instances of the created by a given CredentialClaim is CredentialClaimDefinition with a CredentialClaim class are never persisted. a the ClaimValidation can be coupled to IdentityProviderClaimDefinition. some claim dictates that its value must be an integer. to dene validation classes for the value of identity provider claims. the credential claim that is identity bearer must have a value that corresponds to a username of some given User instance. It is shown here again to emphasize the two methods it (and the ToIssuedClaim method takes no parameters and returns an instance of the IssuedClaim class. The mechanism is very similar to that of plug-ins in that a ClaimValidation refers to a type string that can be used to create instances of the validator through reection. For this to work.

that de- claim mapping denition has a scribe the claim mapping. A claim mapping denition is made up of zero or more CredentialClaimMappings and/or IdentityProviderClaimMappings. and ValueType. The service which has three parameters.1 Claim mapping As mentioned in the specication. Name. Schema view: Claim mapping Figure 43 shows the entity classes used to model claim mapping. As with every other aspect of the model. a protocol id.78 4. and ProtocolClaimMapping and ConnectionClaimMapping. or These two classes dene a number of Boolean values. The actual mapping of claims is done by the has one method. and OverrideValueType. By definition. NameFormat. OverrideNameFormat. NewNameFormat. A Name and a Description property. a GetMappedClaimsForUser. Figure 43. The ClaimMappingDefinition is used to dene a claim mapping. In chapter 7 I will show the implementation of this method. there are services and repositories to handle reading and writing claim mapping data. but only the descriptive properties. and a connection id. user name. a claim mapping belongs to either a this fact is modelled in the classes which hold references to a and Protocol or a Connection. . This concept is called claim mapping. The semantics of these values are that if they have the value true. ClaimMappingDefinition and a ConfiguredProtocol ConfiguredConnection respectively.10. OverrideName. ClaimMappingService. the corresponding New value (NewName. NewValueType) will be used to override the original value of the claim. in schema view. It is important to note that it is not the value of a claim that is changed. shown in Figure 44. it must be possible to change various properties of a claim depending on who the receiver of that claim is.

the IdP lets the handling protocol perform validation on. all the components of the model are orchestrated in a way that makes the system work.79 Figure 44. Figure 45 shows the sequence of events that happen when the IdP receives a request for a protocol endpoint. the wellformedness of the request. If the requested URI does not match any of the URIs exposed by the congured protocols an error is reported and a trace entry is created. BeginRequest In this phase the IdP initializes the IdPContext (explained in Section 4. All request parameters will be saved in the IdPContext. Figure 45. DetermineProtocol In this phase. This protocol will be referred to as the "handling protocol".11. The runtime system During runtime.11. for example (but not limited to). the IdP uses the requested URI to determine which specic protocol implementation to reroute the request to. ValidateRequest During this phase.1) and establishes a session. Class view: Claim mapping 4. Runtime request sequence Each of the steps is described below. If validation fails an error is reported and a trace .

If necessary. the next phase will be performed. Authentication (optional) In this phase the handling credential provider will collect the user's credentials and create the set of credential claims. The singleton instance .11.80 entry is created. all credential claims that must be reissued are promoted to IdPClaims SendResponse During this phase the response it sent and the sequence ends. and that one is chosen. the IdP will ask the handling protocol if the requested endpoint is one that requires an authenticated user. 4. DetermineCredentialProvider (optional) During this phase the IdP will determine which credential providers have been congured. If the user is already authenticated. Figure 46 shows the IdPContext class in class view. but it also serves as a placeholder for state information between http requests. and instead it is implemented using the singleton pattern (as explained in [Gamma et al. Furthermore. MapUser During this phase. The credential provider that ultimately collects the user's credentials will be referred to as the "handling credential provider". The class does not have a public constructor. each claim is mapped as dened in the IdP conguration. If more than one provider has been congured. the identity bearing credential claim will be mapped to a userid in the user store ProcessRequest During this phase the handling protocol will process the request as specied by its implementation. the user will be presented with a list of possible providers to choose from. If this is the case.1 IdPContext The IdPContext is the IdP's main interface for plug-ins. 1995]). AuthenticationCheck During this phase. The credential claims will stored in the IdPContext. It exists to make it easier for any plug-in to access the IdP's core functionality without having to know too many details about services and repositories. Otherwise there will be only one. First a protocol mapping is performed (if it exists) and then a service provider mapping is performed. otherwise it will skip to the ProcessRequest phase. the current user will be extracted. Optionally the claims for ExtractIdPClaims (optional) During this phase the user's IdPClaims are extracted. the IdP will skip to the ProcessRequest phase.

This is done though the EndpointService. because a plug-in can be only a single le. no physical les are requested. such as the last part of the URI. Class view: IdPContext of the class is accessed through the Current property of the class. given a protocol id and a connection id. if the person that makes the request is currently logged in (indicated by the tion). Therefore. when you request a URI. . This method returns the mapped claims for the current user. UserName property holds the username of the user. upon successful authentication of the user. index. namely the dll containing its implementation. The method has an argument whose type is a list of CredentialClaim instances. corresponds to a le on the web server. the IsLoggedIn utility func- ShouldTrace and Trace functions from the TraceService.11. On the IdP.html. and their log counterparts are being exposed here.2 EndpointService In general. The AuthenticationDone method must be called by a credential provider. Finally. however.example. the authenAuthenticationFailed method must be called by the creGetClaimsForUser method is the only method that a The tication fails. it must be able to nd out which plug-in should handle the request. in this case http://www. This makes it easier to upload new plug-ins. Instead. for some reason.html.81 Figure 46. when the IdP receives a request. the dential provider. If. The given protocol implementation must call. 4. what is requested are virtual endpoints that map to some implementation that knows how to respond.com/index.

Class view: EndpointService Figure 47 shows the EndpointService class and related classes. Reporting of events During runtime. Both log entries and . logging and tracing. The EndpointService denes a single method. conguration errors. Reporting of these events will be split into two dierent concepts. but also in terms of actions taken by the users and the administrator or administrators themselves. 4. a path. It then uses the to determine which endpoint can handle the path. GetEndpointForPath which has a single argument.12. and which returns an instance of knows how to respond to requests for that path. the IdP must report events in a way that administrators of the system can see what is going on in terms of unexpected errors.82 Figure 47. The method internally uses the IEndpoint that GetEndpointForPath ConfiguredProtocolRepository and ConfiguredCredentialProviderReposi EndpointHandlesPathSpecification to nd all endpoints.

and it can also be used to turn logging on and o for dierent parts of the IdP. for example. The LogEntry and LoggingSource classes contains the following elds shown in Figure 48. Figure 48. This is.1 Logging As mentioned above. A single unit of logging data will be called a and its corresponding class will be called coupled to a log entry LogEntry.12. In such an application.83 trace entries must be saved in the database because of the nature of the IdP being a software-as-a-service application. and therefore writing these entries to a le on the disk is not as good an option as writing them to a table in a database. A log entry is always logging source. the administrator will not have access to les on the machine where the application runs. A logging source is used to dene parts of the system that write log entries. but logging sources can also be dened for plug-ins as we shall see below in Section 4. useful for corporations who need to comply to the Danish standard for information security (DS-484).1. logging has to do with events that happen in the system as part of normal use. the IdP will itself dene a set of logging sources.2. Logging such events will allow administrators of the system who has made changes to the system and when. Having this information in a database enables rich query capabilities that are not oered by simple text les. something that will come in handy when needing to display the data in a graphical web user-interface. This is useful for grouping log entries. Furthermore it allows him to see information about user activity. 4. Schema view: LogEntry and LoggingSource .

A session is a well-known concept when working with web applications. It also contains the id of the logging source it belongs to. that is used to determine if logging for a given source is turned on or o. We have now dened what kind of data a log entry contains. We denitely need some way of facilitating logging. the . In fact. Note that the relationship between the two is denoted by an arrow. incurred by the UserId property.84 As the Figure 48 shows. a name and a description. but it is by no means obvious how it is to be used. and returns true if logging is enabled for that logging source. a log entry also contains a SessionId. That arrow represents the Finally. each log entry contains a timestamp of when the log entry was created (EntryDateTime) and some message (EntryText). LoggingService Figure 49. and since the IdP is a web application it makes sense to log the session id. Finally. the caller might decide not to build the message at all. User class. So what if logging has been turned o for the current logging source? In this case. But logging often entails building large text messages. which takes both memory and time. or even what the unique id of the logging source is. and ll in the missing parameters. namely the name of a LoggingService needs to interact logging source. A logging source also has a unique id. Figure 49 shows the class. In order to perform the correct logic. Therefore our logging service needs to have a function to help the caller determine if logging is turned on for a given logging source. such that all log entries for a given session can be found. it also has an Enabled ag. how would a user of the class know what unique id to assign to the log entry. Class view: Logging service class The ShouldLog function takes a single parameter. the name of a logging source and some text. The LoggingService class would then have the responsibility of creating a new instance of a LogEntry. what the id of the current user is. You may have noticed another arrow pointing to the relationship to the LogEntry class. What we probably want is some kind of service class with a function that takes two parameters.

. do not have to call the ShouldLog function. namely a logging First of all. Figure 50. The source name and a message. IdPContext class will be explained later. which returns the LoggingSource class. and the current LoggingSourceRepository to get the correct instance of SessionId. the function calls corresponding instance of the check the it should return. if they wish. As mentioned this function takes a single parameter. but for now just accept that Add function on the LogEntryRepository which takes an instance of a Finally it reads the The it knows the current user's id and the session id.85 with other components of the system. Note that the bold italic text over or below each component denotes what type of object it is in terms of domain-driven design. not the case. the LogEntry class and lls in the LogEntryText. If the function determines that logging is enabled. It calls the LoggingSource class from where it can retrieve the LoggingSourceId. When called. Figure 50 shows which other components the LoggingService class interacts with. and UserId properties the IdPContext class. Finally. the name of the logging source. the function can return. namely the ShouldLog function. the function calls the LogEntry as a parameter. This also means that callers. The function can now Enabled property of the LoggingSource instance to determine what Log function takes two parameters. Class view: Logging service interactions Lets start by considering the most simple of the two functions. but that they may do so. ShouldLog to If this is determine if logging is turned on for the current logging source. starts by creating a new instance of the time. the the ShouldLog function calls FindByName function on the LoggingSourceRepository.

and have a corresponding class called TraceEntry.12. especially for warning and information level trace entries. It must be possible to turn tracing on and o. critical. However. This is because a tracing prole does not have an identity. Since tracing is used to report errors. It will also be possible to turn o errors.2 Tracing Tracing has to with recording events that are related to errors and debugging the system. but it will however not be possible to turn o tracing of critical errors. the TraceEntryFileWriter . error. Data regarding whether or not tracing is turned on for dierent levels is encapsulated in a concept called a trace prole. there is a small dierence here. warning and information. but the le would of course only be accessible to maintainers of the entire software-as-aservice solution. As before we create a service to facilitate adding trace entries.86 4. We dene 4 levels of error tracing. A single unit of tracing data will be called a trace entry. and any two instances of the class can be considered to be the same if their values are identical. This is especially helpful when dealing with errors that have to do with missing database connectivity. any trace entries with trace level critical will also be written to a le on disk. Secondly. Class view: Tracing service interactions Figure 51 shows that adding trace entries is in many ways similar to adding log entries. The it interacts with are shown in Figure 51. The most important things to notice is that the TraceProfile is a value object and not an entity objects. Trace entries need to be written to the database for much the same reason that log entries needed to be written to the database. TracingService and the classes Figure 51.

There credential provider plug-ins and protocol plugCredential claims. Every aspect of the IdP can be congured through configuration sets. A claim mapping sends information about a user to a service provider. Users. and invokes the Add function on the TraceEntryRepository everytime. and can be summarized as follows: that binds The IdP is an application Claims to are two kinds of plug-ins. and the Add TraceEntryFileWriter whenever the trace level is set to function on the critical. When a protocol issued claims. namely and protocol claim mappings connection claim mappings. When something in the IdP fails. which is a claim dened in the IdP. Users are created in the IdP through self registration. The two are conceptually identical but the protocol claim mapping is always performed rst. An issued claim originates from either a credential claim. The Trace function of the TracingService takes as parameters a message and a trace level. There are two dierent types of claim mappings. The IdP is extensible through plug-ins. import. and the result of an authentication is a set of information about a user and his claims to some other party. and when an important event occurs.13. The set of issued claims that are sent may have undergone a claim mapping. except their value.87 is used to write trace entries to a le on disk. or invitation. or an identity provider claim. it sends a set of is a mechanism that alters any aspect of a set claim. Both protocols and credential providers may rely on service connections to describe how they communicate with other systems. 4. A credential provider plug-in can authenticate a user. . which contain dierent configuration elements. a trace entry is created. A protocol plug-in sends ins. a log entry is created. called a provider. Ubiquitous language The model described in this chapter has left us with a broad ubiquitous language.

Object relational mappers 5 Most modern IT systems rely on databases to store application data. string userName. when using a traditional data access layer.1) NOT NULL. } 88 .} public User(int oid. set.} public string UserName { get. } public string PasswordSalt { get. a UserRepository UserFactory factory class. a User domain class. the denition of a supple model is a model that can easily be changed. set. set.[User]( OID INT IDENTITY(1. changing the database schema would potentially require many changes in the data access classes and domain objects. } public DateTime DateCreated { get. [Password] NVARCHAR(128) NOT NULL. } public string Password { get. namespace IdP { public class User { public int OID { get. PasswordSalt = passwordSalt. PasswordSalt NVARCHAR(128) NOT NULL. The table denition might look something like this: 1 2 3 4 5 6 7 8 9 User table −− User table CREATE TABLE [idp]. Password = password. CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([OID]) ) A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 User domain class could look like this: User domain class using System. set. As we saw in Chapter 3. string passwordSalt) { OID = oid. DateCreated = dateCreated. DateTime dateCreated. However. string password. example. and the database schema used is indeed an important part of the domain model. UserName = userName. DateCreated DateTime NOT NULL DEFAULT GetDate(). where we have a repository class and a Let consider the following simple User table. UserName NVARCHAR(128) NOT NULL. set.

SqlCommand cmd = new SqlCommand(sql.ExecuteReader().Data. DateCreated from User where UserName = @UserName". return UserFactory. return UserFactory. conn).Parameters.Data. SqlCommand cmd = new SqlCommand(sql. userName).Open(). either by name or by id. namespace IdP { public class UserFactory . using (SqlConnection conn = new SqlConnection("a valid connection string")) { conn. } } public User GetUserByName(string userName) { string sql = "select OID. } } } } And nally a factory which that is able to translate a record of a to an instance of our SqlDataReader User domain class. PasswordSalt.Parameters. conn).AddWithValue("UserName".FromReader(reader). UserName. could look like this: User factory class 1 2 3 4 5 6 using System. cmd. Password. PasswordSalt. Password.FromReader(reader).SqlClient.ExecuteReader(). could look like the following: User repository class 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 using System.89 21 22 } } A repository with methods to nd a given user. oid). cmd.AddWithValue("oid". DateCreated from User where OID = @oid". using (SqlConnection conn = new SqlConnection("a valid connection string")) { conn. namespace IdP { public class UserRepository { public User GetUserById(int oid) { string sql = "select OID. SqlDataReader reader = cmd.SqlClient. using System. UserName. SqlDataReader reader = cmd.Open().

complete with queries and update and delete methods. In this chapter we shall see how we can leverage the power of object relation mappers to create a more supple and maintainable design. For .Net. Since the specication requires me to use a SQL Server database. passwordSalt). adding another eld to the However. updating the two select statements and adding another line of code to the factory method.ToString(). userName. password. .ToString(). DateTime dateCreated = (DateTime) reader["DateCreated"]. using this approach would not yield an especially supple design. and I'm already using .Net 3.Read()) { int oid = (int) reader["OID"]. since even small logical model changes would require quite a few changes to the code. LINQ to SQL is part of the .5. return new User(oid.Net framework 3. the two most feature complete being NHibernate and LINQ to SQL. Needless to say. several alternatives exist. string userName = reader["UserName"].ToString(). dateCreated. string passwordSalt = reader["PasswordSalt"]. string password = reader["Password"]. } return null.90 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 { public static User FromReader(SqlDataReader reader) { if(reader. what if we were to add another eld to the require updating the table. } } } The preceding classes show how we could implement data access for a the User table using the building blocks of domain-driven design. Object relational mappers are software tools that automatically map the tables of a database schema to classes in a programming language. User table? Doing so would User domain class. using LINQ to SQL seems like a natural choice. if we had a large database schema.5 framework and has been developed in close cooperation with the SQL Server team for high performance when used with a SQL Server database.

IEnumerable<string> query = from s in names where s. however.Net language.WriteLine(item). The most important thing to notice. First of all.91 5. Extension methods are static methods that are declared outside of a the class they work on. 9 The standard query operators apply to IEnumerable<T> which is the interface implemented by every enumerator (array and specialized collections) in .ToUpper(). "Frank". " David" }. "Everett". foreach (string item in query) Console. T. is that the SQL like syntax in the example is merely syntactic sugar on top of a concept called extension methods. LINQ LINQ stands for language-integrated query and provides a set of standard query operators that can be used directly in any . "Albert". 1 2 3 4 5 6 7 8 9 10 User extension namespace IdP { public static class UserExtensions { public static int UserNameLength(this User u) { return u. method for the The following example shows how an extension User class could be implemented.Net over a generic type shows the syntax for a standard LINQ query. having the from keyword in the beginning of the expression.1. and brought into scope by importing the namespace where they are declared. Query expressions in LINQ benet from compile time syntax checking. "George". static typing and intellisense . There are several interesting things to note about the above code.Length == 5 orderby s select s. The following code sample 1 2 3 4 5 6 7 8 9 10 LINQ example string[] names = { "Burke". the reverse syntax of the query. "Connor". This has been necessary to make intellisense work.Length. } } } 9 Intellisense is the auto-completion feature in the Visual Studio IDE .UserName. "Harris".

The full applying extension methods as the example shows. This means that the above query could be rewritten to this: 1 2 3 4 5 6 7 8 LINQ example 2 string[] names = { "Burke".OrderBy(s => s). "Connor". Console. "Everett".Select(s => s.GetByName("Klaus"). LINQ to SQL is an extension of what we have seen so far. As a matter of fact. ToUpper()). "Harris". Note that the result of applying a LINQ extension method to an IEnumerable<T> is itself an IEnumerable<T>.UserNameLength(). the syntax of the above example is merely syntactic sugar. bool> predicate). LINQ to XML provides language integrated query for XML documents.Length == 5).Length == 5 in the example. Figure 52 shows the dierent avours of LINQ that are oered by the framework.1.WriteLine(item). such as list of query operators dened by LINQ can be seen in Table 5. as mentioned.Net.Where(s => s. So how does this apply to the LINQ query shown above? Well. however they have nothing to do with LINQ to SQL. LINQ to XML and the LINQ enabled ADO. int len = u. Figure 52 shows that there are three dierent LINQ enabled data sources. and actually translates to a set of extension methods on IEnumerable<T>. which is written as a lambda expression.ReadLine().92 Note the special this keyword. "Albert". foreach (string item in query) Console. and LINQ enables ADO. User u = UserRepository. By importing the namespace where the extension UserNameLength function directly on applies to the type method is dened. Func<T.Net provides language integrated queries for relational . IEnumerable<string> query = names. The example shows how extension methods on IEnumerable<T> are used to express the query. "Frank". The signature of the extension methods used is The Func type is an expression from type T to bool. " David" }. s => s. The LINQ examples we have seen thus far have been good for illustratory purposes. We have already seen how LINQ to objects works in the preceding examples. thus allowing us to keep this IEnumerable<T> source. that tells the compiler that the method User. LINQ to objects. "George". which is called LINQ to objects. I can now call the the 1 2 User class.

LINQ. Except First. and LINQ enabled ADO.93 Restriction Projection Ordering Grouping Quantiers Partitioning Sets Elements Aggregation Where Select. ElementAt. LastOrDefault. ToDictionary. ADO. ElementAtOrDefault. TakeWhile. Average. Min. Max. namely . ToList.Net consists of three dierent technologies. Skip. data stores. Union. Cast Element First. Sum. ElementAt Count. SkipWhile Distinct. AsEnumerable. DefaultIfEmpty Figure 52. SelectMany OrderBy. ToLookup. Contains Take. ThenBy. LongCount. Aggregate Conversion ToArray. Intersect.Net is the framework for manipulating relational data. SingleOrDefault. OfType. Single. FirstOrDefault. Reverse GroupBy Any. All. Last. FirstOrDefault.

LINQ to SQL data context (designer view). but it is said that it will become the predecessor of LINQ to SQL. A data context is a class that has several responsibilities. a framework for dening conceptual data schemas. LINQ to SQL and LINQ to entities. called entity data models. Furthermore. and nally it tracks in memory changes made to the instances of those classes. and drag the onto the design surface. mainly because it lacks tool support in the IDE. LINQ to datasets is an extension to the in memory dataset classes of the .2.94 Figure 53. LINQ to SQL also supports compile time type checking. User table . the data context contains information about which database to connect to. as shown in Figure 53. LINQ to datasets.Net Entity framework. Using the IDE we can create a new data context. LINQ to entities has still not proven to be mature. and LINQ to entities is the LINQ extension of the . This is achieved through the what is called a data context. First of all. LINQ to SQL As with LINQ to objects.Net framework. 5. it contains denitions for the classes that represent the tables in the database.

instance). System.Linq. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 LINQ data context #pragma warning disable 1591 // − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − // <auto−generated> // This code was generated by a tool. instance). // Runtime Version:2.1433 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated.MappingSource mappingSource = new AttributeMappingSource().Data.Linq. System. } public IdPDataClassesDataContext(string connection) : base(connection. // </auto−generated> // − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − − namespace IdP { using using using using using using using using using System.Linq.Linq. partial void InsertUser(User partial void UpdateUser(User partial void DeleteUser(User #endregion Definitions instance). System. System.Settings.Data.Mapping.Data. mappingSource) { OnCreated().0.IDbConnection connection) : .DatabaseAttribute(Name="IdPDatabase")] public partial class IdPDataClassesDataContext : System. System. public IdPDataClassesDataContext() : base(global::IdPTestApp.Data.Mapping. System. System. System.Data.Expressions. [System.Linq.Mapping. #region Extensibility Method partial void OnCreated().Default. } public IdPDataClassesDataContext(System.Data.Reflection. SafewhereConnectionString.DataContext { private static System. Now lets see what kind of code is generated behind the scenes. mappingSource) { OnCreated().95 We have now seen that we can easily drag tables onto our data context to generate the corresponding class.Collections.50727.Data.Generic.Linq.Properties.ComponentModel.Linq.

96

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

base(connection, mappingSource) { OnCreated(); } public IdPDataClassesDataContext(string connection, System.Data.Linq.Mapping. MappingSource mappingSource) : base(connection, mappingSource) { OnCreated(); } public IdPDataClassesDataContext(System.Data.IDbConnection connection, System .Data.Linq.Mapping.MappingSource mappingSource) : base(connection, mappingSource) { OnCreated(); } public System.Data.Linq.Table<User> Users { get { return this.GetTable<User>(); } } } [Table(Name="idp.[User]")] public partial class User : INotifyPropertyChanging, INotifyPropertyChanged { private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); private int _OID; private string _UserName; private System.DateTime _DateCreated; private System.Nullable<System.DateTime> _LastLogin; private string _Password; private string _PasswordSalt; #region partial partial partial partial partial partial partial partial partial Extensibility Method Definitions void OnLoaded(); void OnValidate(System.Data.Linq.ChangeAction action); void OnCreated(); void OnOIDChanging(int value); void OnOIDChanged(); void OnUserNameChanging(string value); void OnUserNameChanged(); void OnDateCreatedChanging(System.DateTime value); void OnDateCreatedChanged();

97

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138

partial void partial void partial void partial void partial void partial void #endregion

OnLastLoginChanging(System.Nullable<System.DateTime> value); OnLastLoginChanged(); OnPasswordChanging(string value); OnPasswordChanged(); OnPasswordSaltChanging(string value); OnPasswordSaltChanged();

public User() { OnCreated(); } [Column(Storage="_OID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] public int OID { get { return this._OID; } set { if ((this._OID != value)) { this.OnOIDChanging(value); this.SendPropertyChanging(); this._OID = value; this.SendPropertyChanged("OID"); this.OnOIDChanged(); } } } [Column(Storage="_UserName", DbType="NVarChar(128) NOT NULL", CanBeNull=false )] public string UserName { get { return this._UserName; } set { if ((this._UserName != value)) { this.OnUserNameChanging(value); this.SendPropertyChanging(); this._UserName = value; this.SendPropertyChanged("UserName"); this.OnUserNameChanged(); } } } [Column(Storage="_DateCreated", DbType="DateTime NOT NULL")] public System.DateTime DateCreated

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

98

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198

{ get { return this._DateCreated; } set { if ((this._DateCreated != value)) { this.OnDateCreatedChanging(value); this.SendPropertyChanging(); this._DateCreated = value; this.SendPropertyChanged("DateCreated"); this.OnDateCreatedChanged(); } } } [Column(Storage="_LastLogin", DbType="DateTime")] public System.Nullable<System.DateTime> LastLogin { get { return this._LastLogin; } set { if ((this._LastLogin != value)) { this.OnLastLoginChanging(value); this.SendPropertyChanging(); this._LastLogin = value; this.SendPropertyChanged("LastLogin"); this.OnLastLoginChanged(); } } } [Column(Storage="_Password", DbType="NVarChar(128) NOT NULL", CanBeNull=false )] public string Password { get { return this._Password; } set { if ((this._Password != value)) { this.OnPasswordChanging(value); this.SendPropertyChanging(); this._Password = value; this.SendPropertyChanged("Password"); this.OnPasswordChanged(); }

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214

} set { if ((this.SendPropertyChanged("PasswordSalt"). It is decorated with a DatabaseAttribute which denes the name of the database it connects to.PropertyChanged(this. DbType="NVarChar(128) NOT NULL". Also note that it is declared as partial. public event PropertyChangedEventHandler PropertyChanged. Partial classes are especially useful when one part of the partial class is autogenerated by a tool._PasswordSalt != value)) { this.99 215 216 217 218 } } [Column(Storage="_PasswordSalt".OnPasswordSaltChanged()._PasswordSalt.PropertyChanging(this. new PropertyChangedEventArgs( propertyName)).OnPasswordSaltChanging(value)._PasswordSalt = value.SendPropertyChanging(). emptyChangingEventArgs). CanBeNull= false)] public string PasswordSalt { get { return this. this. protected virtual void SendPropertyChanging() { if ((this. because it means that we can dene other meth- .PropertyChanging != null)) { this. } } protected virtual void SendPropertyChanged(String propertyName) { if ((this.PropertyChanged != null)) { this. } } } } #pragma warning restore 1591 LINQ data context 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 The main data context class begins on line 25. this. } } } public event PropertyChangingEventHandler PropertyChanging. which means that it can extended. this. this.

This is the eld that we can use to The return perform LINQ queries. If you remember the example from page 92.Linq. type of the property is Table<User>. which allow LINQ to SQL to track . In LINQ to SQL. On lines 32-35 we nd a set of extensibility methods. When we start iterating over the result. as we shall see in an example shortly. any query on a Table<T> is not executed until you iterate over the result. a SQL query is automatically generated behind the scenes and executed against the database. On line 68 we can see a public property called Users.DataContext class. again declared partial. even though they can be used. is that the Table<T> class implements another interface. The way it has been done. connecting to the database. the and User class implements the INotifyPropertyChanging INotifyPropertyChanged interfaces. but with another internal implementation. The generic Table<T> type is an integral Table class implements the part of the LINQ to SQL framework and implements the translation from LINQ expressions to actual SQL statements. The User class has a Table attribute that includes information about the actual table name in the database. This problem has of course been overcome by the designers of LINQ to SQL.Data. updated or deleted. for which all the same extension methods have been dened. which will not be overwritten if we run the code generation tool again. and in general it would be a complete misuse of the rdbms's capabilities. we applied three extension methods to an array. This would potentially cripple the application's performance. However. we would eectively fetch all rows into memory and do the selection logic on the in memory data representation. which contains most of the logic for tracking object changes. committing changes etc. The IEnumerable<T> interface and can thus make use of the extension methods mentioned earlier.100 ods and elds of that same class in an other le. Furthermore. The class inherits the System. of course. On line 77 we have the denition for the User class. These methods allow us to implement extra logic whenever User objects are inserted. This behaviour allows us to compose a complex query of several less complex parts without executing the actual query before we iterate over the result. If we were to do this with the data from a SQL database table. Lines 38-66 contain various overloaded constructors. called IQueryable<T>. This is because the LINQ to objects extension methods are executed immediately on the underlying IEnumerable<T> instance. the LINQ to objects extension methods should not be used with Table<T> classes.

101 in-memory data-changes. In Chapter 3 we saw an example of a specication called RecentlyCreated.OID). The example below shows how we can use the data context to query the user table.UserName).UserName. which contained the denition for a recently created user. database column type etc. such as Apart from that. A very nice feature of LINQ to SQL is its ability to translate generic expressions to SQL statements. namespace IdPTestApp . thus enabling us to have specications that can be used both in code and in the database.. //The query is not performed against the database before we iterate over the result foreach(var user in result3) { Console.Select(u => u). all three variables declared using the actually of type IQueryable<User>.Select(u => u).Where(u => u. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 LINQ to SQL example using(var ctx = new IdPDataClassesDataContext()) { //Find users with a UserName of length 5 var result = from u in ctx. } } Note that the var keyword is a shorthand that can be used where the var keyword are compiler can infer the type by looking at the type of what is assigned to variable.WriteLine(user. pected properties. We could extend the User class generated by the data context to contain a method that could tell us if a user was recently created: Extending the User class 1 2 3 using System. the User class has all the ex- OID.OrderBy(u => u.Users. and all these properties are decorated with attributes that tell something about the database column name.OID > 100).Length == 5 orderby u. We can leverage this ability to declare our domain-driven designspecications as LINQ expressions.Users where u.Where(u => u.UserName.OID select u.Length == 5). UserName etc. In this case. //or var result2 = ctx. //we can further refine the result by adding an extra where clause specifying that OID must be higher than 100 var result3 = result2.

Invoke(this). } } } Note the static variable called to SQL query too.102 4 5 6 7 8 9 10 11 12 13 14 { public partial class User { public static Func<User. we can reuse that same LINQ expression. public bool IsRecentlyCreated() { return spec. This variable can be used in a LINQ So if we want to nd all recently created users in the database. .Where(User. AddDays(−10)). } } In this elegant way. bool> spec = (user => user. as shown in the following example. thus making maintenance a lot easier.WriteLine(user.Now. spec.Users. 1 2 3 4 5 6 7 8 9 10 11 Using specification to query the database using (var ctx = new IdPDataClassesDataContext()) { //Find recently created users var result = ctx.Select(u => u). foreach (var user in result) { Console.DateCreated > DateTime.UserName). we can ensure that our domain logic is only dened in one single place.spec).

this identity usually translates to a primary key. In Chapter 3 we saw that repositories should be used to store and retrieve entity objects. when in reality they are being retrieved from some external storage. the result of any of the operations should not be stored.Core. The rameter. We can dene an interface for entity objects as shown below. OID (acronym for object id). IEntity. and in [McCarthy 2008] and [Harding 2008] in particular. and in this chapter we shall explore how we can leverage the capabilities of LINQ to SQL to create a domain-neutral component that can support development using the domaindriven design concepts. meaning that if one of the operations fail. interface species that every object that implements the interface must have a readonly property called We will sometimes need to manipulate several dierent entity objects from dierent repositories within a transaction. an entity object always has an identity. A transaction is an encapsulation of a series of operations that are co-dependent. such as a relational database. In the domain-driven design community.Domain { public interface IEntity<TPrimaryKey> { TPrimaryKey OID { get. It is. and in a relational database. I presume that this term has been chosen instead of transaction because of the fact that the word transaction is so tightly coupled to a specic storage technology.A domain-neutral component 6 In Chapter 5 we saw how LINQ to SQL works. of course. The word transaction is well-known from the world of relational databases. which species the type of the primary key. thus creating the illusion that these objects are all in memory. namely relational databases.cs 1 2 3 4 5 6 7 namespace Safewhere. not the responsibility of a repository to know when it is used within a unit 103 . } } } The IEntity interface shown above is a generic interface with a type paTPrimaryKey. this transaction concept is referred to as a unit of work. Given its long life-span.

Core. an equivalent to committing when working with Create function is a generic function that will IUnitOfWorkElement a constructor that takes no create an instance of any class that implements the interface and has a default constructor (eg.Domain { public interface IUnitOfWorkElement { IUnitOfWork UnitOfWork { set. Create and Complete. IUnitOfWorkElement interface has the following denition: 1 2 3 4 5 6 7 IUnitOfWorkElement.Domain { public interface IUnitOfWork : IDisposable { T Create<T>() where T : IUnitOfWorkElement. new().Net. The interface for an abstract unit of work could be dened as follows: IUnitOfWork. but should we wish to use some other data storage in the future. LINQ to SQL resources are not unmanaged . void Complete().Core.cs 1 2 3 4 5 6 7 8 9 10 11 using System. relational databases. using System.Data. } } } The IUnitOfWorkElement interface denes a write-only property called IUnitOfWork in- UnitOfWork of type IUnitOfWork.cs 1 2 3 4 using System. } } The IUnitOfWork interface denes two functions. The The Complete method is used to complete the unit of work. arguments.104 of work. using System.Linq. and will be used by the IUnitOfWork's Create method. IDisposable interface. Any implementor of the IUnitOfWorkElement interface will thus expose a way of setting the associated stance.Transactions. as we shall see in the following concrete implementation of a unit of work: LinqToSqlUnitOfWork. including the IDisposable interface is a safe choice. But a repository must have the ability to be enrolled in a unit of work. This is denoted by the The new() restriction on the generic type T). . namespace Safewhere. an interface that can The interface also inherits the be implemented to release unmanaged resources during garbage collection when working in .cs namespace Safewhere.

105 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 namespace Safewhere. } public void Dispose() { _dataContext = null. A . } #endregion } } The LinqToSqlUnitOfWork class has two constructors.Domain { public class LinqToSqlUnitOfWork : IUnitOfWork. _txScope = transactionToUse == null ? new TransactionScope() : new TransactionScope(transactionToUse). _txScope.GetEntityContainer<T>() { return new LinqToSqlEntityContainer<T>(_dataContext). } public T Create<T>() where T : IUnitOfWorkElement. Transaction transactionToUse) { if (dataContext == null) throw new ArgumentNullException("dataContext"). TransactionScope _txScope. new() { return new T {UnitOfWork = this}. and calls the null value for the transactionToUse parameter. The rst one takes DataContext as discussed in the previous chapter.Core. public LinqToSqlUnitOfWork(DataContext dataContext) : this(dataContext. } public void Complete() { _dataContext.SubmitChanges(). null){} public LinqToSqlUnitOfWork(DataContext dataContext. _dataContext = dataContext. } #region IRepositoryImplementationHelper Members IEntityContainer<T> IRepositoryImplementationHelper. IRepositoryImplementationHelper { DataContext _dataContext.Dispose().Complete(). _txScope. DataContext in a private variable and sets a LINQ other constructor with a The second constructor saves the the private _txScope variable based on wether or not the transactionToUse TransactionScope is used to implicitly enlist a block of parameter is null.

cs namespace Safewhere.106 code in a transactions in . and allows you to assign values to public properties during the call to the constructor. The persist the changes made in memory to the database.5.Linq. } } The IRepositoryImplementationHelper interface is going to be used by GetEntityContainer. The IRepositoryImplementationHelper interface is dened as follows: 1 2 3 4 5 6 7 IRepositoryImplementationHelper.cs 1 2 3 4 5 6 7 8 9 10 using System. which should be used to add an remove entity objects from a Note the use of the object initializer syntax that is new in . See [Microsoft 2009] for an in-depth explanation. as described in [Microsoft 2007]. . The Verb|IEntityContainer| our repository implementation.Domain { public interface IEntityContainer<T> : IQueryable<T> { void Add(T element). the class implements the terface by implementing the IRepositoryImplementationHelper in- GetEntityContainer method. void Remove(T element).Domain { public interface IRepositoryImplementationHelper { IEntityContainer<T> GetEntityContainer<T>() where T : class. namespace Safewhere.Core. } } The IEntityContainer interface is a generic interface that inherits from IQueryable interface.Net 3. The Create method is implemented by calling the default constructor10 of T and setting the unit of work instance to the current LinqToSqlUnitOfWork the type instance. The vate Complete method is implemented by calling SubmitChanges on the priSubmitChanges method on a DataContext will make the DataContext _dataContext object.Core. and denes a single method called which returns an has the following denition: IEntityContainer. Finally. It denes the two methods Add the generic built-in and 10 Remove.Net. IEntityContainer of a given class T. and then calling Complete on the TransactionScope instance.

Linq. System. } #region IEntityContainer<T> Members public void Add(T element) { _table.IEnumerator System. System.Data. } public void Remove(T element) { _table. System. } #endregion #region IEnumerable<T> Members public IEnumerator<T> GetEnumerator() { return _table.Linq. internal LinqToSqlEntityContainer(DataContext dataContext) { _table = dataContext.Collections.cs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 using using using using System.GetEnumerator() { return _table.Core. namespace Safewhere.Generic.IEnumerable. } #endregion #region IEnumerable Members System.InsertOnSubmit(element).Collections.107 container. The following class is an implementation of the interface. } #endregion #region IQueryable Members public Type ElementType { get .GetEnumerator().Domain { internal class LinqToSqlEntityContainer<T> : IEntityContainer<T> where T : class { Table<T> _table.GetTable<T>().Collections. IEntityContainer LinqToSqlEntityContainer.GetEnumerator().DeleteOnSubmit(element).

108 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 { var q = _table as IQueryable<T>. using System. Since this entity container uses LINQ to SQL. but only as an internal datastorage-specic container for entities.Linq. return q.cs The rst thing to notice about the is marked LinqToSqlEntityContainer is that it internal is that internal.ElementType.Expressions. return q. The constructor takes a LINQ DataContext which is uses for retrieving the correct Table for the generic type T. TPrimaryKey> . It implements all the interface methods from IEntityContainer by Table instance _table.Expressions. using System.Expression. for the generic type Table. T.cs 1 2 3 4 5 6 7 using System. return q. This means that it can only be used from within the assembly where it resides. its internal implementation is based on an instance of a as described earlier. The reason that this class is made it is not supposed to be used directly by any client.Domain { public interface IRepository<TEntity.Linq.Provider. calling the suitable methods on the We have now seen the denition of most of the classes needed for our generic repository implementation.Core. } } #endregion } } LinqToSqlEntityContainer. namespace Safewhere. } } public System.Linq. and we can now dene the interface for the repository as follows: IRepository. } } public IQueryProvider Provider { get { var q = _table as IQueryable<T>.Expression Expression { get { var q = _table as IQueryable<T>.

The rst function takes a parameter of type Expression<Func<TEntity. repository. } IQueryable<TEntity> Find(Expression<Func<TEntity. bool>> expr). Lines 16-22 dene dierent nder functions. TEntity this[TPrimaryKey primaryKey] { get. bool>> expr). IUnitOfWorkElement where TEntity : IEntity<TPrimaryKey> { void Add(TEntity element). bool>>. the The two Find functions. IQueryable in- TPrimaryKey. The IBooleanExpressionHolder interface is dened as follows: . IRepository interface denes Add and Remove functions for adding and removing entity objects. but only return the rst result instead of returning The a collection. an inFindFirst functions take the same parameters as terface that we will use to encapsulate our specications. bool>> expr). which is the lambda expression that was described earlier in this chapter. as we shall see further down. It also denes an indexer function (in line 14) that allows nding a single instance of an entity object based on its unique identier. void Remove(TEntity element). the interface imposes the restriction that the type must implement the as a primary key. and the IUnitOfWork interface. The second Find function takes an IBooleanExpressionHolder. the interface denes two mines if one or more entity objects exist for a given lambda expression or IBooleanExpressionHolder. and type. TEntity FindFirst(Expression<Func<TEntity. IQueryable<TEntity> FindAll().109 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 : IQueryable<TEntity>. TEntity FindFirst(IBooleanExpressionHolder<TEntity> spec). Furthermore. IQueryable<TEntity> Find(IBooleanExpressionHolder<TEntity> spec). where TEntity is the type of the entity object that the repository serves. The repository must also implement the terface for type The TEntity. TPrimaryKey. bool Exists(Expression<Func<TEntity. bool Exists(IBooleanExpressionHolder<TEntity> spec). } } The IRepository interface is a generic interface of type TEntity and TPrimaryKey is the type of the primary key of that entity TEntity IEntity interface with using the same type. The two Find func- tions return a collection of entity objects based on some search criterion. FindAll function returns all the entity objects in the Exists functions that deter- Finally.

. using System. namespace Safewhere. } public Expression<Func<T.Core. bool>>. The purpose of this interface is to hold an expression that will evaluate to a Boolean value for an instance of a given generic type junction with a repository. IBooleanExpressionHolder<T> { Expression<Func<T. } } } The IBooleanExpressionHolder is a generic interface for a generic type T and contains a single property of type Expression<Func<T. namespace Safewhere. bool>> Expression { get.Domain { public interface IBooleanExpressionHolder<T> { Expression<Func<T. } return _compiledExpr. bool>> specExpression) { _expr = specExpression.110 IBooleanExpressionHolder.Domain { public abstract class LambdaSpecification<T> : ISpecification<T>.Expressions. bool>> _expr. that is dened as follows: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 using System.Linq. When used in conFind.cs 1 2 3 4 5 6 7 8 9 10 using System. The most important class in the component that implements the IBooleanExpressionHolder interface is the LambdaSpecification ISpecification.Expressions.Core.Linq. FindFirst or IBooleanExpressionHolder can be used to express a search criterion for use with the Exists functions. bool> CompiledExpression { get { if (_compiledExpr == null) { _compiledExpr = _expr. an implementation of T. protected LambdaSpecification(Expression<Func<T.cs class. bool>> Expression { get { return _expr.Compile(). } } public Func<T. bool> _compiledExpr. using System. Func<T.

} } The ISpecification interface is a generic interface that has a single function.Linq.cs 1 2 3 4 5 6 7 8 9 using using using using System. just like the example presented earlier. This is because in domain-driven design a specication should be explicitly named and be a concept of it's own. TPrimaryKey> : IRepository<TEntity. we do not want anyone to use instances of the class directly.Collections. The LambdaSpecification class does however implement Expression and CompiledExpression.cs namespace Safewhere.111 30 31 32 33 34 35 36 37 38 } } public bool IsSatiesfiedBy(T element) { return CompiledExpression. and invokes the compiled expression on this instance. the implementation of the interface is implemented by the an argument of an instance of the class' generic type. only compiled internally ISpecification IsSatisfiedBy function. even though it could be possible.cs The both LambdaSpecification class is a generic abstract class that implements ISpecification (described further down) and the IBooleanExpressionHolder interface. CompiledExpression is that same expression. } } } ISpecification. The class contains two properties.Invoke(element). Lastly. The class is abstract since.Expressions. the The Expression property is the same that the class gets in the constructor.Core. The method takes ISpecification interface is dened for better performance.Domain { public class Repository<TEntity.Core.Generic. The as follows: 1 2 3 4 5 6 7 ISpecification.Domain { public interface ISpecification<T> { bool IsSatiesfiedBy(T element). System.Linq. System. namespace Safewhere. The value of most of the logic for creating those explicitly named specications. IsSatisfiedBy. System. TPrimaryKey> . We can now dene a repository in the following way: Repository.

} } public IQueryable<TEntity> Find(Expression<Func<TEntity.SingleOrDefault(entity => primaryKey. TPrimaryKey> Members public void Add(TEntity element) { _entityContainer. } public void Remove(TEntity element) { _entityContainer. bool>> expr) { return _entityContainer.Equals(entity. } #region IRepository<TEntity.Where(spec.Where(expr). } . } public IQueryable<TEntity> Find(IBooleanExpressionHolder<TEntity> spec) { return _entityContainer. IEntity<TPrimaryKey> { protected IUnitOfWork _unitOfWork. OID)).GetEntityContainer<T>().Expression). return repHelper. } public bool Exists(Expression<Func<TEntity.FirstOrDefault(expr).Expression). } public TEntity FindFirst(IBooleanExpressionHolder<TEntity> spec) { return _entityContainer. protected IEntityContainer<TEntity> _entityContainer.112 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 where TEntity : class. bool>> expr) { return _entityContainer.Count(expr) > 0. bool>> expr) { return _entityContainer.Add(element).FirstOrDefault(spec. protected IEntityContainer<T> CreateEntityContainer<T>() where T: class { var repHelper = (IRepositoryImplementationHelper) UnitOfWork . } public TEntity FindFirst(Expression<Func<TEntity.Remove(element). } public TEntity this[TPrimaryKey primaryKey] { get { return _entityContainer.

GetEnumerator() { return _entityContainer. } } #endregion #region IUnitOfWorkElement Members public IUnitOfWork UnitOfWork { set { _unitOfWork = value.GetEnumerator(). } #endregion #region IEnumerable Members System.AsQueryable(). } #endregion #region IEnumerable<TEntity> Members public IEnumerator<TEntity> GetEnumerator() { return _entityContainer. } public IQueryable<TEntity> FindAll() { return _entityContainer.IEnumerable. } } public IQueryProvider Provider { get { return _entityContainer.IEnumerator System.Count(spec.Collections.ElementType.Collections. } #endregion #region IQueryable Members public Type ElementType { get { return _entityContainer.Provider.GetEnumerator(). .113 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 public bool Exists(IBooleanExpressionHolder<TEntity> spec) { return _entityContainer. } } public Expression Expression { get { return _entityContainer.Expression.Expression) > 0.

one important reason for using repositories is that a concrete repository implementation. . for example one that uses an SQL server backend. we can implement an in-memory data store.114 121 122 123 124 125 126 127 128 129 130 131 132 _entityContainer = CreateEntityContainer<TEntity>(). the private the CreateEntityContainer function. amongst other things.Domain { public class InMemoryUnitOfWork : IUnitOfWork. The most important thing to notice is in the implementation of the on the class. implements the IRepository interface preIUnitOfWorkElement interface.cs 1 2 3 4 5 6 7 8 9 10 11 12 using System. For this we need. When the UnitOfWork instance is set _entityContainer variable is instantiated by calling sented earlier. This is very useful for those unit tests whose purpose is not to test the data storage system. namespace Safewhere.Core. } get { return _unitOfWork.cs The Repository class.1. IRepositoryImplementationHelper { readonly IInMemoryDataContainer _container. Preparing for test As mentioned in Chapter 3. InMemoryUnitOfWork. but only to test the domain functionality. an an InMemoryUnitOfWork and InMemoryEntityContainer. The CreateEntityContainer function UnitOfWork to a IRepositoryImplementationHelper which GetEntityContainer function. in turn casts the contains the class use this 6. } } #endregion } } Repository. The rest of the functions in this EntityContainer internally to perform the work. By adding a few extra classes to the domain neutral component. can be interchanged with another one. of course. public InMemoryUnitOfWork(IInMemoryDataContainer container) { if (container == null) throw new ArgumentNullException("container").

Generic. new() { return new T { UnitOfWork = this }. namespace Safewhere. an instance of an IInMemoryDataContainer.115 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 _container = container. } public void Complete() { //this method does nothing } #endregion #region IDisposable Members public void Dispose() { //this method does nothing } #endregion #region IRepositoryImplementationHelper Members public IEntityContainer<T> GetEntityContainer<T>() where T : class { return new InMemoryEntityContainer<T>(_container). } #endregion } } InMemoryUnitOfWork. using System. This is solely by decision. } #region IUnitOfWork Members public T Create<T>() where T : IUnitOfWorkElement. using System. this class does not make use of the TransactionScope class.Domain { . Furthermore.cs The InMemoryUnitOfWork class is a lot like its LINQ counterpart.Linq. since it easily could. The most important dierence is the argument to its constructor.Collections.cs 1 2 3 4 5 6 using System.Core. the class can be kept simple. InMemoryEntityContainer. The GetEntityContainer function uses an in-memory version of an entity container. instead of the DataContext instance that is used by the LINQ version. but because its purpose is to facilitate testing without an underlying database.

} #endregion #region IQueryable Members public Type ElementType { get { IQueryable<T> q = _data.116 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 internal class InMemoryEntityContainer<T> : IEntityContainer<T> where T : class { readonly List<T> _data.AsQueryable().IEnumerable.GetEnumerator().Collections. } #endregion #region IEnumerable Members System.GetEnumerator(). internal InMemoryEntityContainer(IInMemoryDataContainer container) { _data = container. } } public System. } #endregion #region IEnumerable<T> Members public IEnumerator<T> GetEnumerator() { return _data.Linq.Expression Expression { get { .ElementType.GetEnumerator() { return _data.Add(element). } public void Remove(T element) { _data.IEnumerator System.Collections.Remove(element).GetData<T>().Expressions. return q. } #region IEntityContainer<T> Members public void Add(T element) { _data.

return q. return q.Collections.AsQueryable().117 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 IQueryable<T> q = _data.AsQueryable(). .Core. and is dened as follows: IInMemoryDataContainer.cs The implementation of the InMemoryEntityContainer class also resembles its LINQ counterpart.Linq the class can perform its logic on that list just in Table instance. } } The IInMemoryDataContainer denes a single generic function that provides data of the correct type.Expression.Provider.cs 1 2 3 4 5 6 7 8 9 using System. By using the LINQ to objects extensions System.Domain { public interface IInMemoryDataContainer { List<T> GetData<T>(). The dened in the same way as the LINQ counterpart does with its IInMemoryDataContainer provides the data. namespace Safewhere. } } #endregion } } InMemoryEntityContainer.Generic. } } public IQueryProvider Provider { get { IQueryable<T> q = _data. diering only in that its internal data-holder is a generic List (the _data variable).

entity objects and specications. of course including some repository implementations using the framework described in the preceding chapter. Figure 54. please feel free to look at the implementation of that part on the enclosed disk media. 10 of which do not contain source code. and therefore not fully documented either. I will focus on the parts that I nd most interesting. As you can see the solution contains 155 les. but this is natural since the system is not fully implemented. Figure 55 shows the structure of the solution.Implementation 7 In the previous chapter we saw how we could use LinqToSql to create a domain-neutral framework to help us with the implementation of repositories. Figure 54 shows an analysis of the solution le. As you can see the solution 118 . entire implementation is too large to be presented here. The enclosed disk media contains a Visual Studio 2008 solution le and all the corresponding les. Source lines of code. In this chapter I will present the Since the implementation of some of the classes described in Chapter 4. As you may have noticed the percentage of lines of comments is quite low. If I have left out some part that is of your particular interest.

.119 structure and le names adhere strictly to the ubiquitous language.

.120 Figure 55. Solution le structure.

121

7.0.1 Runtime system

The runtime system is particularly interesting, since it shows how the IdP delegates the actual work to the dierent plug-ins. The class that handles every request and determines what to do is the class, shown below.

IdPEndpointHandlerFactory

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

using using using using using using

IdPEndpointFactory.cs System.Web; System.Web.SessionState; Safewhere.IdP.Application.Endpoints; Safewhere.IdP.Application.Pages; Safewhere.IdP.Domain.Logging; Safewhere.IdP.Properties;

namespace Safewhere.IdP.Application.HttpHandlers { public class IdPEndpointFactory : IHttpHandlerFactory, IRequiresSessionState { public IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path) { var loginSpec = new IsGlobalLoginUriSpecification(); if(loginSpec.IsSatiesfiedBy(context.Request.Url)) return new IdPLoginPage(); IEndpoint endpoint = EndpointService.GetEndpointForPath(virtualPath); if (endpoint != null) { return endpoint.Handler; } string errorMessage = string.Format(IdPErrorMessages.EndpointNotFound, virtualPath); IdPContext.Current.Trace(TraceLevel.Warning, errorMessage); return new ErrorHandler(errorMessage); } public void ReleaseHandler(IHttpHandler handler) { return; } } }

The

IdPEndpointHandlerFactory class implements the IHttpHandlerFactory

framework interface and is hooked into the web server conguration le. Hereafter, for every request that the web server receives, it will call the

122

GetHandler method of our class to get an appropriate handler.
global login page, and if this is the case, an instance of the is returned. Otherwise, the

In the

GetHandler method, a check is performed to see if the request is for the IdPLoginPage11 EndpointService's GetEndpointForPath method

is called, to nd the endpoint that serves the given path. If an endpoint is found, its handler is returned. Otherwise an error message is traced, and a generic error page is returned.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

using using using using using using

EndpointService.cs Safewhere.Core.Domain; Safewhere.IdP.Domain; Safewhere.IdP.Domain.Credentials; Safewhere.IdP.Domain.Protocol; Safewhere.IdP.Infrastructure.Util; System.Linq;

namespace Safewhere.IdP.Application.Endpoints { public class EndpointService { /// <summary> /// Gets an implementation of IEndpoint that can handle a given path. /// Looks for both protocol and credential endpoints. Protocol endpoints /// take precedence over credential endpoints if two should exist /// with the same path (eventhough this is considered an error). /// </summary> /// <param name="path">The path.</param> /// <returns>An instance of a class that implements IEndpoint, /// or null if no suitable implementation is found.</returns> public static IEndpoint GetEndpointForPath(string path) { var ep = GetProtocolEndpointForPath(path); if (ep != null) return ep; ep = GetCredentialEndpointForPath(path); return ep; } private static IEndpoint GetProtocolEndpointForPath(string path) { using (var uoo = new LinqToSqlUnitOfWork(new IdPDataClassesDataContext())) { var cpr = new ConfiguredProtocolRepository { UnitOfWork = uoo }; var all = cpr.FindAll(); foreach (var cp in all) { var plugin = ActivatorUtil.GetInstance<IPlugIn>(cp.ProtocolDefinition.ProtocolType );
11

The

IdPLoginPage is the page that shows the user the dierent congured credential

providers and lets him choose which one to use for authentication.

123

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

if (plugin == null) continue; plugin.PluginId = cp.OID; var spec = new EndpointHandlesPathSpecification(path); var endpoint = plugin.GetEndpoints().FirstOrDefault(spec.IsSatiesfiedBy); if (endpoint != null) return endpoint; } } return null; } private static IEndpoint GetCredentialEndpointForPath(string path) { using (var uoo = new LinqToSqlUnitOfWork(new IdPDataClassesDataContext())) { var ccpr = new ConfiguredCredentialProviderRepository { UnitOfWork = uoo }; var all = ccpr.FindAll(); foreach (var ccp in all) { var plugin = ActivatorUtil.GetInstance<IPlugIn>(ccp.CredentialProviderDefinition. CredentialProviderType); if (plugin == null) continue; plugin.PluginId = ccp.OID; var spec = new EndpointHandlesPathSpecification(path); var endpoint = plugin.GetEndpoints().FirstOrDefault(spec.IsSatiesfiedBy); if (endpoint != null) return endpoint; } } return null; } } }

The

EndpointService looks for protocol endpoints and credential provider path given as an arguFirst it calls the

endpoints, and tries to nd one that matches the ment. the

GetProtocolEndpointForPath method, which uses

ConfiguredProtocolRepository to nd congured protocols. It uses re- 

ection to instantiate every congured protocol implementation, and it then iterates over the endpoints provided by the implementation to see if any

2 The username/password credential provider Let us see how the username/password credential provider plug-in is implemented. which GetEndpoints is pretty straightforward.Generic.UserNamePassword.IdP.Core.CredentialProviders.CredentialProviders. namespace Safewhere. namespace Safewhere. ConfiguredProtocolRepository.Application. using Safewhere.cs using System. method is implemented by our generic 7.IdP.IdP. because the FindAll Repository class. .Application { public class UsernamePasswordPlugin : IPlugIn { public string Description { get { return "Provides login via username/password". using Safewhere.cs 1 2 3 4 5 6 7 8 9 using Safewhere.Endpoints.UserNamePassword.IdP.Domain.Domain. int> { } } The ConfiguredProtocolRepository is very simple.Application. set. Something very similar is done in the GetCredentialEndpointForPath method. } } } The UsernamePasswordPlugin class implements the IPlugin interface. } } public List<IEndpoint> GetEndpoints() { return new List<IEndpoint> {new UsernamePasswordEndpoint(PluginId)}. which in this case returns a list with only one element. } public int PluginId { get. The most important thing to notice is the method.0.124 endpoint matches the requested path.Protocol { public class ConfiguredProtocolRepository : Repository<ConfiguredProtocol.Endpoints.Collections. an instance of the UsernamePasswordEndpoint class. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 UsernamePasswordPlugin.

IdP. .Application.CredentialProviders. Safewhere.Domain.Credentials. namespace Safewhere.IdP.IdP.IdP.125 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 UsernamePasswordEndpoint.IdP.Collections.Domain. using Safewhere. Safewhere. } } } } The UsernamePasswordEndpoint class implements the IEndpoint interface.cs using System.Properties.Web. Safewhere.SessionState.IdP.Core.Application.Generic. Safewhere.IdP.UI.CredentialProviders.Endpoints.IdP. Safewhere.WebControls.Web.Linq. using Safewhere. System. Safewhere.UserNamePassword.". } } public string Name { get { return "UsernamePasswordEndpoint".IdP. System. System.Claims. } } public IHttpHandler Handler { get { return new UsernamePasswordPage(_pluginId).Application.UserNamePassword. System.UI. public UsernamePasswordEndpoint(int pluginId) { _pluginId = pluginId.Application.Web. } public string Path { get { return "unpwdlogin.Pages. } } public string Description { get { return "Endpoint for username/password login.CredentialProviders.Endpoints { public class UsernamePasswordEndpoint : IEndpoint { private int _pluginId.UserNamePassword.Web. UsernamePasswordPage Handler property.idp". Safewhere.Domain.Application. and most importantly it returns an instance of the class in its 1 2 3 4 5 6 7 8 9 10 11 12 ï ˙ z £ using using using using using using using using using using using using System.Domain.Pages.

_password = new TextBox { Width = 150.IdP. private TextBox _username._content. _username.Domain. _passwordLabel = new Label { Text = Resources. namespace Safewhere._content. private Label _passwordLabel.ID = "username". _content.ID. public UsernamePasswordPage(int credentialProviderDefinitionId) : base( credentialProviderDefinitionId) { } protected override void OnLoad(System.AddControl(_usernameLabel). private Panel _buttonPanel.UsernameLabelText }. base. _password.EventArgs e) { return.CredentialProviders.Logging. _usernameValidator = new RequiredFieldValidator { ControlToValidate = _username.AddControl(new LiteralControl("<br/>")). private RequiredFieldValidator _usernameValidator. /// </summary> public class UsernamePasswordPage : CredentialProviderBasePage. _passwordLabel. _content.Dynamic.UsernameValidationText }.ID = "password". base. IRequiresSessionState { private Label _usernameLabel.UserNamePassword.AddControl(_usernameValidator).AddControl(_username). base.Width = 100. private TextBox _password. Display = ValidatorDisplay. } protected override void CreateChildControls() { _usernameLabel = new Label { Text = Resources. _username = new TextBox{Width = 150}.Pages { /// <summary> /// A page that collects username and password through a form. private Panel _messagePanel.PasswordLabelText }.IdP.Password }. ErrorMessage = Resources.Width = 100. private Button _submit. _usernameLabel.Application. . private RequiredFieldValidator _passwordValidator.AddControl(_passwordLabel). TextMode = TextBoxMode.126 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 using Safewhere._content.

CausesValidation = true} .EventArgs e) { if(IsValid) { var user = UserService. Display = ValidatorDisplay.127 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 _content.ID. _submit. base. foreach(var ccd in ccp. base. } RetrieveCredentialClaims(user).SubmitButtonText. _buttonPanel = new Panel { Width = 255 }.AddControl(_passwordValidator). _buttonPanel.Add(_submit).Add(CredentialClaim.GetUser(_username.AddControl(_password). System. } } private void RetrieveCredentialClaims(User user) { var claims = new List<CredentialClaim>().Add("text−align". _submit = new Button {Text = Resources.VerifyPassword(_password. return. _buttonPanel.Style._content._content. _messagePanel = new Panel {Visible = false}.AddControl(_messagePanel).FindByPrimaryKey(CredentialProviderDefintionId).Dynamic. ccd)).Controls.Click += _submit_Click. } void _submit_Click(object sender.AddControl(new LiteralControl("<br/>")).CredentialClaimDefinitions) { if (ccd.PasswordValidationText }.AddControl(_buttonPanel). base.UserName. ErrorMessage = Resources. if (user == null || !user. var ccp = ccpr._content._content.IsIdentityBearer) claims. using (var uoo = new LinqToSqlUnitOfWork(new IdPDataClassesDataContext())) { var ccpr = new ConfiguredCredentialProviderRepository {UnitOfWork = uoo}. "right"). } } 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 .Text)) { LoginError().Text). base. _passwordValidator = new RequiredFieldValidator { ControlToValidate = _password.FromDefinition(user.

false otherwise</returns> . using Safewhere.128 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 if(claims. This method uses VerifyPassword method in turn implements the two text elds where the user can enter his username and his password.Visible = true. return Find(spec).Domain.Current.</param> <returns>True if the user exists.Error.Domain.Add(new LiteralControl("Wrong username and password combination")). It then calls the on the responds to the one stored in the error message is displayed. "No credential claims found for user " + user.Core.UserName).Repositories { public class UserRepository : Repository<User.cs using System. _messagePanel.Domain. The most interesting method is the the UserRepository class to get an instance of the User class corresponding User class instance. using Safewhere. This page basically displays _submit_Click method. to see if the password entered by the user corUser instance.Controls.IdP. the user's credential claims are extracted and the IdPContext class is called. }else { IdPContext. int> { public IQueryable<User> FindUsersBeginningWith(string beginsWith) { var spec = new UserNameBeginningWith(beginsWith).Users. and the user can try again. } } private void LoginError() { _messagePanel.Count > 0) { IdPContext.Current. an AuthenticationDone method of the to the name entered by the user.AsQueryable()).Trace(TraceLevel.Specifications.IdP. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 UserRepository. The check is performed case insensitively </summary> <param name="userName">the userName.Linq. } } } The UsernamePasswordPage inherits the Page class from the framework (which IHttpHandler interface). namespace Safewhere.AuthenticationDone(claims. If this is not the case. Otherwise. thus nalizing the authentication. } /// /// /// /// /// /// <summary> Checks if a user with the given userName already exists.

set. } } } The UserRepository class also has a simple implementation. The dummy protocol displays all the claims for the user that logs in. even though a FindUserByName method used by _submit_click method described above simply uses an instance of the few extra methods have been added.Application { public class TestProtocolPlugin : IPlugIn { public string Description { get { return "Simple test protocol".IdP.cs using System. 7.Application.0. .Generic.Collections. I will show the following implementation of a dummy protocol.Endpoints.IdP. using Safewhere.3 A dummy protocol Although no production-ready protocol implementation has been developed as part of this thesis. The the ExactUserName specication class to nd the corresponding User instance. namespace Safewhere.Protocols.129 21 22 23 24 25 26 27 28 29 30 31 public User FindByName(string userName) { return FindFirst(new ExactUserName(userName)). using Safewhere.TestProtocol.Application. } public int PluginId{get.Endpoints. } public bool ExistsByName(string userName) { return Exists(new ExactUserName(userName)). } } public List<IEndpoint> GetEndpoints() { return new List<IEndpoint> {new TestEndpoint(PluginId)}.TestProtocol. The dummy protocol responds on a single URI.Protocols. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 TestProtocolPlugin.} } } The TestProtocolPlugin class is very similar to the UsernamePasswordPlugin presented above.IdP.

130 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 TestEndpoint.Application.Endpoints. } } public IHttpHandler Handler { get { return new TestHandler{Path = Path.Web. using Safewhere.Handlers { public class TestHandler : IdPHttpHandlerBase { private NameValueCollection _requestParams.Collections. namespace Safewhere. 1 2 3 4 5 6 7 8 9 10 11 12 using using using using TestHandler.Handlers. } } } } The most important feature of the instance of the TestEndpoint class is that it returns an TestHandler class.IdP.idp". namespace Safewhere. System.Endpoints { public class TestEndpoint : IEndpoint { private readonly int _protocolId.IdP.IdP.TestProtocol. using Safewhere.Application. } } public string Name { get { return "testendpoint". } } public string Description { get { return "Test endpoint". public TestEndpoint(int protocolId) { _protocolId = protocolId. public override bool ValidateRequest(NameValueCollection requestParams) .cs System.TestProtocol.Web.Protocols.IdP.Application.Application. Safewhere.Specialized.Protocols.IdP. } public string Path { get { return "test.Application.cs using System.TestProtocol. which is shown below. ProtocolId = _protocolId}.Application.Protocols. Safewhere.IdP.HttpHandlers.

} public override bool RequiresAuthentication() { return true. claimStr += "</claim>\n". context.Response.Response. the core IdP makes sure that the user is authenticated before . ProtocolId . } public override bool ForceReauthentication() { return false. It does so by overriding the ValidateRequest. } } } You can see that this handler participates in the runtime request sequence described in Section 4.Write(username + "</title></head><body>"). var claims = ClaimMappingService.Current. claimStr += "<name>" + claim. ForceReauthentication and SendResponse methods from its parent class. context.ValueType + "</valuetype>\n". claimStr += "<valuetype>" + claim.GetMappedClaimsForUser(username.Response.DisplayName + "</b><br/>"). RequiresAuthentication.UserName.Value + "</value>\n".Response. string claimStr = "<claims>\n". context.Response.Write("Name: " + claim. claimStr += "<claim>\n".11 on page 79.Response.Write("</textarea></form>").Response.Write("ValueType: " + claim.Write("<b>" + claim.Response.Write("</body></html>"). } public override void SendResponse(HttpContext context) { string username = IdPContext. claimStr += "<nameformat>" + claim.NameFormat + "</nameformat>\n".Write("<html><head><title>Claims for user: ").Response. } claimStr += "</claims>\n".Value + "<br/>").131 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 { _requestParams = requestParams.Response. return true.ValueType + "<br/><br/>"). context. context.Write("<form><textarea cols=100 rows=50>" + claimStr).Response. claimStr += "<value>" + claim. turns Since the RequiresAuthentication method re- true. connectionName).NameFormat + "<br/>").Name + "<br/>").Write("Value: " + claim. foreach(var claim in claims) { context.Write("NameFormat: " + claim. string connectionName = _requestParams["connection"]. context.Write("<h1>" + username + "</h1>"). context. context. context. context.Name + "</name>\n".

132 calling the SendResponse method. this method can make use of IdPContext. Therefore.Current. .UserName and call the ClaimMappingService to get the user's claims. which it then just outputs as html.

most of the developers of Safewhere attended a seminar where we were rst introduced to domain-driven design. and not least. as the code base grew. Safewhere started on a good idea and a prototype written by the founders. but it became increasingly dicult to add new features and refactor existing features. and version one of the product was delivered. there was something missing in our development method.Design validation 8 The purpose of this chapter is to evaluate the design that I have presented in this thesis. not much time was spent on software design and modelling. In the beginning. I presented my work to my 133 . each programmer had his own individual coding style and understanding of the business domain. In retrospect. In the beginning of the company's life money was scarce. and each programmer was given a few high level features to implement. and in order to attract venture capital having an actual product to show for was priority number one. After the initial release the need for new features grew rapidly. as it turned out however. Before looking into what has been learned. to assess the practicability of domain-driven design. extensive test suites and a generally open communication culture. Instead. Upon writing this thesis. Even though domain-driven design was not the main topic of the seminar we were all left with the impression that it was a smart thing to do. One of the ways this manifested itself was that we had several classes in dierent assemblies with similar names but with dissimilar meaning. this did not seem to cause that big of a problem. and these were added on an ad hoc basis. Since I was about to write my thesis it was decided that my current project could be a guinea-pig project for introducing domain-driven design in Safewhere. The product was working well. Despite of established coding guidelines. I wish to present the background for introducing a new design paradigm in Safewhere. As with many small companies. a few programmers were hired. It was also dicult to explain the architecture to new members of the team. myself included. since the code was not organized in a heterogeneous manner. Therefore we decided to try out domain-driven design in practice. the problem clearly was that we did not have either a model (and model framework) nor a ubiquitous language. given the circumstances. Safewhere is a relatively new company with only three years of existence. One day. fully functional. So.

 It will lead to a stable and mature end-product. there were also a number of less positive things. So overall my work has been very well received. Peter.134 colleagues. Another concept which could have been named better is the Logging concept. Only one interviewee though that these names could have been better. found them really good. which I will address below. IdentityProviderClaim IssuedClaim. These include the dierent types of claims and 13 . Another inter- viewee. and even though the names may not be the most elegant.  It represents a concise and expressive ubiquitous language. and there is no doubt that domain-driven design will be the future design paradigm in Safewhere. 8.1. which makes it easy to talk about. and below is what I found. 12 13 The interviews can be found in full length in the Appendix B. they do convey important information. and secondly to make them give me their opinion of domain-driven design. A better name for this model concept could have been business activity monitoring which is both more expressive and unambiguous. CredentialClaim.  It is exible and has a clear distribution of responsibilities between components. First of all it was noted that a few terms could have had better names. and whether they would support the introduction of domain-driven design as a design standard on future projects in Safewhere.  It will reduce total cost of ownership of the software. The word logging is over- loaded and has potentially dierent meanings to dierent people. That said. I interviewed 12 three people. The rst purpose of this was to have them assess the usability and completeness of the model. Model evaluation Based on the interviews. The distinction between the three types of claims is more important than their names. making it easy to refactor. I can conclude that the following is true about the model:  It solves the business problem well. it should probably not have been made part of the model since it is an infrastructure concept and has no real relevance to the business problem. . As for the tracing modelconcept.

It is of course still possible to add more constructors with more parameters. mainly the interfaces. There is however a good reason why using a lot of factories is a good convention for this model. but it is not clear if it even belongs here. since breaking changes for self-developed plug-ins can be handled at compile time and during testing. . I do not think that this is a aw in the model per se. This is denitely a weakness in the model. The problem is that the LinqToSql framework generates parameter-less constructors. Refactoring of the plug-in system. Unfortunately this convention is implicit and I have not been able to come up with a way to express it explicitly in the model. and hopefully avoid unintended use of the parameter-less constructors. So by using factories to create entity objects throughout the code. I have created a convention that others can follow. which they are not. Another weakness of the model has to do with the plug-in nature of the system. There are no current plans to allow third party plug-ins in the IdP. The factories are mainly used to construct entity objects. and I hope that a better solution can be found in the future.135 If anything it could have been part of the domain-neutral component. but rather a natural consequence of any plug-in architecture. it could potentially lead other developers to the impression that the parameter-less constructors are also an option. could lead to breaking backwards compatibility with third party plug-ins. so this is no great concern at the moment. However if constructors instead of factories were used throughout the code. It has also been pointed out that there is an excessive use of factories in the model.

Microsoft Azure. 9. Therefore. And that is exactly one of the points of domain- driven design.1. it is not. when it comes to the domain-neutral component.1 Future perspectives Hosting software in the cloud is most likely going to be become very common in the future. However. and solves the business problem dened in the specication well. the storage mechanisms used in these cloud services are very dissimilar to relational databases. Also. or model framework. 136 . Cloud hosting services are being oered by many of the big players on the market. with products such as Google App Engine.Conclusion 9 This chapter contains my conclusion on what has been learned throughout the process of writing this thesis. The model All in all I think the model that has been developed is good and thorough. Amazon Elastic Cloud and more. The benet of these services is that they provide instant on-demand scaling of the applications they host. 9. I have achieved this exibility to a high degree through distribution of responsibilities and by having made the model storage-agnostic.1. and that is why it is so important that the model is exible so that future refactorings can be carried out with ease. the model will face its greatest test if at some point it is decided to host the IdP in the cloud. a fact that is substantiated by the interviews that were carried out. Now. You will never get your model one hundred percent right the rst time. It would be natural to host a product such as the IdP in the cloud to make sure that even extremely high loads on the application could be handled. I am sure that this will contribute to shorter development times on future projects because it is highly reusable. is the model perfect? No.

such as hotel reservation systems. And using the domain-driven design concepts such as entities.2. and at the beginning of this project I was anxious to nd out if the domain-driven design principles could be applied to this kind of system as well. Domain-driven design is based on some very sound principles that can be applied to any software design task that I can think of. Mastering domain-driven design is not something that can be learned from a single project. having a broad ubiquitous language that is reected in the model and code has made the system so much easier to talk about and discuss. and by practicing my domain-driven design skills I am sure that . Even though there was no sharp distinction between domain experts and developers on this project. has been very positive. Textbooks about domain-driven design often use examples from business domains that are commonly understood. and I look forward to becoming even more adept at applying its principles. recognizable to newcomers to the team. order systems or the like. services. In the modelling phase. repositories. The larger makes the code much more the teams. the more important it becomes to have a common ubiquitous language and a strong and exible model. when the model has already been lined out. it is still important that every developer on the team has knowledge about domaindriven design such that all the concepts used in the model can be understood by everyone. I have not had the opportunity to try domain-driven design on bigger scale since this project has not involved other developers than myself. a lot of time has been saved by the ability to refactor in the model instead of refactoring code that has taken a long time to write. Furthermore. specications. and a thorough understanding of domain-driven design. For me personally. I think that it is safe to conclude that it can. Using domain-driven design on a project requires commitment from all developers. Domain-driven design I can only say that this. etc. my rst encounter with domain-driven design. being able to design software very well is a goal that I strive to achieve because it will give me greater professional satisfaction. The business domain that has been modelled here is of a very technical nature. the developers involved must have strong modelling skills. In the development phase.137 9. I am however convinced that the benets of using domain-driven design will turn out to be even bigger when working on large teams. but my work with it so far has denitely encouraged me to keep using it.

138 I will be able to reach that goal. .

properties. struct types. and assemblies.C# language elements Appendix A This aim of this appendix is to give a short introduction to the C# language. C# programs consist of one or more source les. Types C# programs use type declarations to create new types. generics. Assemblies typically have the le extension .1. depending on whether they implement applications or libraries. namespaces.dll. A type declaration species the name and the members of the new type. When C# programs are compiled. and delegate types. 139 . Please refer to [Microsoft 2009] for the complete reference. enum types. which contain members and can be organized into namespaces. A.exe or . and should by no means be regarded as complete. Programs declare types. they are physically packaged into assemblies. Variables of value types directly contain their data whereas variables of reference types store references to their data. A. and events are examples of members. interface and delegate types all support they can be parameterized with other types. There are two kinds of types in C#: value types and reference types. methods. Five of C#'s categories of types are user-denable: class types.2. Fields. Program structure The key organizational concepts in C# are programs. the latter being known as objects. types. Classes and interfaces are examples of types. The contents presented herein are based on the C# Language Specication [Microsoft 2009]. members. struct. enabling readers without prior knowledge of the C# language to understand the code samples in the thesis. whereby Class. interface types.

With value types. Members The members of a class are either static members or instance members.2. mechanisms whereby derived classes can extend and specialize base classes.140 With reference types. Class types support single inheritance and polymorphism. and instance members belong to objects (instances of classes). properties. The following table provides an overview of the kinds of members a class can contain. Member Constants Fields Methods Description Constant values associated with the class Variables of the class Computations and actions that can be performed by the class Properties Actions associated with reading and writing named properties of the class Indexers Actions associated with indexing instances of the class like an array Events Operators Notications that can be generated by the class Conversions and expression operators supported by the class Constructors Actions required to initialize instances of the class or the class itself Destructors Actions to perform before instances of the class are permanently discarded Types Nested types declared by the class . and it is not possible for operations on one to aect the other A. it is possible for two variables to reference the same object and thus possible for operations on one variable to aect the object referenced by the other variable. Static members belong to classes. the variables each have their own copy of the data. and others).1 Classes A class type denes a data structure that contains data members (elds) and function members (methods.

destructors and static constructors of the base class. which controls the regions of program text that are able to access the member. Base access A base-access consists of the reserved word base followed by either a ". an instance method. Accessibility public protected Meaning Access not limited Access limited to this class or classes derived from this class internal protected internal Access limited to this program Access limited to this program or classes derived from this class private Access limited to this class Inheritance A class inherits the members of its direct base class type. These are summarized in the following table. Inheritance means that a class implicitly contains all members of its direct base class type. There are ve possible forms of accessibility." token and an identier or an expression-list enclosed in square brackets: base-access: base . except for the instance constructors. or an instance accessor. A base-access is permitted only in the block of an instance constructor. . identifier base [ expression-list ] A base-access is used to access base class members that are hidden by similarly named members in the current class or struct.141 Accessibility Each member of a class has an associated accessibility.

1 2 3 4 5 6 7 8 class Text { public Text(): this(0. Likewise. a constructor can invoke the constructor of its base class by using base-access as illustrated below: 1 2 3 4 5 6 7 8 using System. while this can be used to refer to the instance for which the function member was invoked. int y. or an instance accessor. null) {} public Text(int x. which actually does the work of initializing the new instance. int y): this(x... Constructors The this(. this is classied as a value.) constructor initializer to invoke the third instance constructor. string s) { // Actual constructor implementation } } In the above example. Within an instance constructor or instance function member of a class. an instance method. null) {} public Text(int x. y. class A { protected string theString. this-access: this A this-access is permitted only in the block of an instance constructor.) form of constructor initializer is commonly used in conjunc- tion with overloading to implement optional instance constructor parameters.theString = aString.. Both use a this(. 0. } . the rst two instance constructors merely provide the default values for the missing arguments. Thus.142 This access A this-access consists of the reserved word this. it is not possible to assign to this in a function member of a class.. public A(string aString){ this.

A. Delegates are similar to the concept of function pointers found in some other languages. and all struct types implicitly inherit from type object. An interfaces does not provide implementations of the members it denes. structs are value types and do not require heap allocation. and a class or struct may implement multiple interfaces.2 Structs A struct type is similar to a class type in that it represents a structure with data members and function members. An interface may inherit from multiple base interfaces. A.WriteLine("The string: " + theString + ". } } A. An interface can contain methods.143 9 10 11 12 13 14 15 16 17 18 19 20 21 22 } class B : A { private int theInt. properties. } public void PrintIt(){ Console. events. Delegates make it possible to treat methods as entities that can be assigned to variables and passed as parameters. Struct types do not support user-specied inheritance.2.2. The int: " + theInt).2. public B(string aString. unlike classes.theInt = anInt. it merely species the members that must be supplied by classes or structs that implement the interface. .3 Interfaces An interface denes a contract that can be implemented by classes and structs. A class or struct that implements an interface must provide implementations of the interface's function members. However.4 Delegates A delegate type represents references to methods with a particular parameter list and return type. and indexers. int anInt) : base(aString) { this.

} } An instance of the Function delegate type can reference any method that The Apply method takes a double argument and returns a double value. A delegate can reference either a static method Square or Math. } static void Main() { double[] a = {0. Square). that object becomes this in the invocation. return result. m.144 but unlike function pointers. double[] sines = Apply(a. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 using System. Function f) { double[] result = new double[a. double[] doubles = Apply(a. the multiplier example above can be written more easily without using a Multiplier class: .Sin). Thus. delegates are object-oriented and type-safe.Multiply).5.Length]. class Multiplier { double factor. Multiplier m = new Multiplier(2. which are "inline methods" that are created on the y. 0. 1. and when the instance method is invoked through the delegate.Sin in the previous example) or an instance method m. returning a double[] Main method.Multiply in the previous example). for (int i = 0. Anonymous functions can see the local variables of the surrounding methods. i++) result[i] = f(a[i]). The following example declares and uses a delegate type named Function.0}.factor = factor. double[] squares = Apply(a. Delegates can also be created using anonymous functions. public Multiplier(double factor) { this. } public double Multiply(double x) { return x ∗ factor. Math. } } class Test { static double Square(double x) { return x ∗ x. A delegate that references an instance method also references a particular object. Apply is used to apply three dierent double[]. applies a given Function to the elements of a with the results. } static double[] Apply(double[] a.Length.0). delegate double Function(double x).0. i < a. In the functions to a (such as (such as double[].

and the parameter type cannot be a pointer type. non-nested static classes. } } An extension method is a regular static method. 0. The type declaration is constructed from its parts by following the rules in this section. index.2. In addition.2.5 Partial types A type declaration can be split across multiple partial type declarations. An interesting and useful property of a delegate is that it does not know or care about the class of the method it references. } public static T[] Slice<T>(this T[] source. result. The following is an example of a static class that declares two extension methods: 1 2 3 4 5 6 7 8 9 10 11 12 13 public static class Extensions { public static int ToInt32(this string s) { return Int32. The rst parameter of an extension method can have no modiers other than this. Array. that method is said to be an extension method.Length − index < count) throw new ArgumentException(). whereupon it is treated as a single declaration during the remainder of the compile-time and runtime processing of the program. T[] result = new T[count]. return result. where its enclosing static class is in scope.Parse(s). int index. Extension methods can only be declared in non-generic. A. count). an extension method can be invoked using instance method invocation syntax. all that matters is that the referenced method has the same parameters and return type as the delegate.0). using the receiver expression as the rst argument.6 Extension methods When the rst parameter of a method includes the this modier. (double x) => x ∗ 2. The following program uses the extension methods declared above: .145 1 double[] doubles = Apply(a.Copy(source. int count) { if (index < 0 || count < 0 || source. A.

"333". using ordinary static method calls: 1 2 3 4 5 6 7 8 9 static class Program { static void Main() { string[] strings = { "1". foreach (string s in Extensions. foreach (string s in strings. } } } The Slice method is available on the string[]. 1. } } } . "22". "4444" }. "333". The meaning of the program is the same as the following. "22".ToInt32(s)). because they have been declared as extension methods. 2)) { Console.Slice(strings. and the ToInt32 method is available on string.WriteLine(s.Slice(1.WriteLine(Extensions. 2)) { Console. "4444" }.ToInt32()).146 1 2 3 4 5 6 7 8 9 static class Program { static void Main() { string[] strings = { "1".

and I have already done that many times. and they don't have to spend time to come up with good class names. Mikkel Yes. both yes and no.1. before you begin programming. It makes developers understand the relevance of all classes. I do acknowledge that these issues will always be present in systems that use a plug-in structure. Me That is correct. I think you avoid the disconnect between the developers and the business. and that it is not a problem with the model per se. As a matter of fact the model probably does make it easier. I think that DDD allows the model to be described in a short and concise manner. Mikkel Well. Me After having read this thesis. Mikkel Christensen  Developer at Safewhere Me What is your general impression of the model? Mikkel I think the model solves the business requirements presented in the specication well. with regards to refactoring. That makes them more productive. Or rather. I think the readability of this model is better than many other standard-OO models I have seen in the past. I think. Me What do you think about domain-driven design's focus on a ubiquitous language? Does it make sense? Mikkel It makes a lot of sense. I guess that having a well-dened model like this. However. Me Do you think that the model is exible or good enough to make refactoring easy. Me You seem like a fan of domain-driven design already.Appendix B Interviews B. is it obvious for you how you could implement a new plug-in. I think the plug-in structure introduces a few issues with backwards compatibility. I would have to implement the IPlugin interface. because of the way it clearly distributes responsibilities. either the ICredentialProviderPlugin or IProtocolPlugin. Don't you think that there is anything negative about it? 147 . Me Do you think that this specic system benets from being modelled using the domain-driven paradigm? Mikkel Yes. and in a exible way. you can actually perform a lot of refactoring on the model itself.

Me Do you have a better suggestion for the names? Mark Hehe. In my understanding it is more of an infrastructure thing. I agree. since all the decisions have been made already. Mark Also. but they would not have to great business insight to implement the model. Me I wouldn't say that I disagree. anything else? Mark I don't like the naming for Logging. I can't conclude that it is the solution to everything. I think that business activity monitoring. The problem is that the LinqToSql framework generates parameter-less . Mark Seemann  Senior Developer at Safewhere Me What is your impression of the model? Mark My overall impression is that it is good. I think it is an overloaded word and that it doesn't describe the exact meaning. Me Ok. but I am denitely ready to try it out in practice. I think the distinction between dierent claim types is good. it seems eective. Me Good point. Past the modelling phase. no. not really. But apart from that. developers would still have to be familiar with domain-driven design. however I think the names could have been better. I appreciate that the factory pattern is often useful. When the system has been modelled. Me A valid point. everything that these factories do could have just as well been done in constructor functions. but it seems that in this model. would you use domain-driven design on your next project? Mikkel Based on what I have read in your thesis. no. The only reason I have chosen to make it part of the domain model is that I want to expose services that allows inspection of trace messages in the administrator UI. The factories are mainly used to construct entity objects. B. or something like that would have been better.148 Mikkel Well. I think that it should be a piece of cake to implement. Mark I am also not sure that tracing actually belongs to the domain. to bridge the gap between the business and the code. Me In the modelling phase only? Mikkel Yes.2. if I have to say something it would be that it requires quite skilled developers in the modelling phase. you have quite a few factories. Me So. I think.

Both technical maturity for the programmer. Me Yes.ploeh. Me So do you think there is anything negative to say about domain-driven design? Mark Well. And maturity. That is a good convention then. This in-memory equivalent was made . you think that a model such as this renders itself well to TDD? Do Mark Well. You see. And here. 1000 tests often. You want to write tests that cover the entire system. Me Well.149 constructors. that makes sense. to make sure that you are not making breaking changes. you just stop running them. I am concerned with the tight coupling to the relational database that you have presented in your model. require them to be execute really fast. which they are not. TDD is all about rapid feedback. for TDD to be eective you really have to run your tests often. it could potentially lead others to the impression that the parameter-less constructors are also an option. it would not be unnatural to have around 1000 unit-tests. not really. Therefore. because it really is an essential pattern that requires that kind of attention. Therefore. database access really becomes a bottle-neck. But I think that the extra productivity provided by the or-mapper is worth making this sacrice for. In his book. It is of course still possible to add more constructors with more parameters. And running all. For a system such as the one you have modelled. and eectively stop exercising TDD. Me So what is your overall impression of domain-driven design? Mark I think that domain-driven design is a very sound approach. and run these tests over and over again. and I admit that it is a minor aw in the model. If your tests do not run in a few seconds. The domain model pattern was actually introduced by Martin Fowler a long time ago. But using domain-driven design requires strong modelling skills. So by using factories to create entity objects throughout the code. You even have your own blog about TDD (http://blog. and hopefully avoid unintended use of the parameter-less constructors. you are big advocate for test-driven development (TDD).dk). Mark Ok. but also a mature organization. However I like how Eric Evans has written an entire book about it. say. I agree that unit tests should not rely on database access. I create a convention that others can follow. Me Mark. it was presented on 1015 pages. the domain neutral component has an in-memory equivalent to the database access component. However if I used constructors instead of factories throughout the code.

I must have missed that. Do you agree with this.3. ok. Mark Oh. I am very happy with those names.150 exactly with unit testing in mind. Me That is correct. and that having such a good model will make it much easier and faster to develop future releases. seems to require more preparation time before coding can start. making the model easy to talk about on a very detailed level. It will be easier to maintain the code. such as domain-driven design. Peter Haastrup  Technical director of Safewhere Me Do you think that the model covers the specication? Peter Haastrup I think that is generally covers specication well. I am sure that this extra cost is made up for by faster development times. and the entire multi tenancy issue is supposed to be handled at installation time. and think that they convey important information about what they represent. Me Do you think that model presented herein represents a good ubiquitous language? Peter Haastrup Yes. however I don't think that it covers the multi-tenancy aspect at all. The model is multi-tenancy unaware. Me Do you think that using the domain-driven design paradigm and the domain-neutral component presented here will make development faster? Peter Haastrup I think that it is positive that a lot of decisions about how to structure the code have been made already. . I think that the model has made a lot of concepts explicit. will result in a much more stable and mature product. Me One of the other interviewees found that the claim names could have been better. by using separate database schemas. In that case I think the model renders itself well to TDD. Me What impact do you think that using domain-driven design for this IdP project will have on the total cost of ownership for the product? Peter Haastrup Although introducing a new design paradigm. Peter Haastrup No. I think that using domain-driven design the way you have here. and programmers will be able to recognize the concepts used from project to project. separate web applications in IIS. Furthermore. B. and separate machine accounts for execution. As a matter of fact I think that it is made up for already by the time of the rst release. not at all.

com/fwlink/ ?LinkId=64165. Harding. Erich. Johnson. OpenSAML. Evans.microsoft.aspx?ArticleID=33357.Bibliography References Daarbak. C# Language Specication 3. Torben. McCarthy. Domain-driven design through Eric Evans' eyes. http://www. sdtimes. .com/en-us/library/ms172152. http://go. Tim.com. Eric.opensaml. 1995. Kim.0. Implementing an Implicit Transaction using Transaction Scope. computerworld.microsoft.dk/art/49054. http://www. John. Richard. Domain-Driven Design course. 2009. Alex. Wiley Publishing Inc. Gamma. http://www. Addison-Wesley.com/content/article. Microsoft. 2008. http: //msdn. OpenSAML website.kimharding. 151 . Ralph. 2004. Hver tredje CRM-løsning er SaaS-baseret i 2012. 2007. 2008. 2009. Handy.NET Domain-Driven Design with C# . 2009. and Vlissides. Helm. Microsoft.aspx.org. 2008. terns: Elements of Reusable Object-Oriented Software Design Pat- . Addison-Wesley. Domain Driven Design . http://www.

You're Reading a Free Preview

Download
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->