EditExamining the SharpArch Class Libraries
EditSharpArch.Core
Contains basic utilities, e.g., a Design by Contract class, and persistence agnostic data access support.
- /CommonValidator/*.cs: Defines validator interfaces used by the SharpArch class libraries. This works similarly to the Common Service Locator wherein you can register your own, custom validator implementation if you do not want to use the provided NHibernate Validator adapter which is included in SharpArch.Core.NHibernateValidator. David Hayden has written an example of doing so using the Validation Application Block from Enterprise Library.
- /DomainModel/BaseObject.cs: Acts as a base class for other S#arp Architecture objects, providing a standardized means for comparing two objects with a carefully designed Equals and GetHashCode (which was no walk in the park to get right BTW!). Incidentally, this object contains the following, class level attribute:
[JsonObject(MemberSerializatio.OptIn)] . This means that objects which inherit from BaseObject may be serialized by Json.NET and need to include the following attribute on any property that you would like included in the JSON serialization process: [JsonProperty]
.
- /DomainModelValidatableObject.cs: Inherits from BaseObject and consolidates reusable validation capabilities, leveraging whichever validator service is registered with the IoC container.
- /DomainModel/Entity.cs and EntityWithTypedId<IdT>: As much as I don’t like inheritance chains, this inherits from ValidatableObject to act as a base class for all entity classes in our application. This class, in addition to the capabilities of BaseObject and ValidatableObject , provides persistence support with a protected Id property and a standardized means of performing entity comparisons using a “domain signature,” discussed below. An interface exists for this class in case you’d like to roll your own. Assumptions of this object include:
- Equals and GetHashCode should behave independently from each other, as defined in BaseObject. The current mechanism is the result of hours of conversation with many
people over a long period of time. Some enlightening reading with
respect to this subject may be found at href="http://groups.google.com/group/sharp-architecture/browse_thread/thread/f76d1678e68e3ecehref="http://groups.google.com/group/sharp-architecture/browse_thread/thread/f76d1678e68e3ece.
- If two objects inherit from Entity, and are compared, then it is assumed that the comparison between the two is solely dependent on the properties marked with the attribute
[DomainSignature] . If no properties are decorated with the DomainSignature attribute, then the comparison will only compare the Id properties of each object;
- Two Entity objects which point to the same memory location (i.e., are the same object in memory) are always equal;
- Two DomainModel/Entity objects which have the same Id are always equal;
- If two Entity objects are compared and one of them is transient while the other is persistent, they will always be different from a
standpoint of equality;
- Any Entity properties which are not decorated with the
[DomainSignature] attribute will not be included in the comparison of
two Entity object; i.e., ONLY the properties decorated with the [DomainSignature] attribute will have an impact on
comparison.
As described, the Entity base class gives the object an Id property and extends the comparison capabilities to take the Id property and state of transience into consideration. By default, Entity assumes that the object has an Id of type int; consequently, any object which inherits from Entity automatically has an Id property of type int with a public getter and protected setter. (Due to a variety of hard learned lessons, only the hydration mechanism, e.g., NHibernate, should have access to setting this Id property.)
If you need an Id having a type other than int, such as a string or a composite Id, inherit instead from PersistenObjectWithTypedId. And if you really need to set the Id property manually (and you don’t), then implement the IHasAssignedId interface. Often, it’s useful to set the Id manually in your unit tests, especially for results returned from a mock data repository; in these cases, you can use SharpArch.Testing.EntityIdSetter.SetIdOf() .
-
/DomainModel/ValueObject.cs: This object is a good base class for value objects; it has similar comparison capabilities to Entity but does not have an ID or validation support. Additionally, it may not have any properties decorated with DomainSignature as all of its properties are included in the comparison of two ValueObject instances.
- /PersistenceSupport/IRepository.cs and IRepositoryWithTypedId<>: Provides a base Repository interface to be used by all Repository objects. The latter is used for entities having a typed Id other than int.
-
DesignByContract.cs: A design-by-contract (DbC) utility originally written by Kevin McFarlane and described in detail at http://www.codeproject.com/KB/cs/designbycontract.aspx. The modified version included within S#arp Architecture does not support turning off DbC enforcement with compile time flags.
EditSharpArch.Core.NHibernateValidator
Contains classes for the inclusion of NHibernate Validator within your S#arp Architecture project.
Of particular note:
-
/CommonValidatorAdapter/Validator.cs & ValidationResult.cs: These objects provide a concrete implementation of IValidator, found within SharpArch.Core/CommonValidator, using NHibernate Validator. The Visual Studio template wires the Validator class as the service for the IoC IValidator interface, by default. Note that the ValidationResult class found within this class library, in addition to exposing the properties of the IValidationResult interface, exposes an NHibernate Validator specific property called InvalidValue. To get at you, you’d need to downcast the IValidationResult to this ValidationResult object and retrieve this property. As downcasting is typically a bad practice, it should be done only if have no qualms with being tightly coupled to NHibernate Validator.
-
HasUniqueDomainSignatureValidator.cs: This is a very handy validator for verifying the uniqueness of an entity’s domain signature. To use, simply add the attribute HasUniqueDomainSignature above an entity’s class declaration. This won’t take care of every situation but easily covers the 80/20 rule of situations. The validator will let you know if it encounters a property that it doesn’t know how to work with; at that point, you can either write your own class-specific validator and/or open a new issue on the S#arp Architecture development site.
Concerning NHibernate ValidatorIn order to use NHibernate.Validator on your domain objects, your classes will need to have a reference to the NHibernate.Validator assembly. At first glance, this would imply that you’re adding a data aware concern to your domain layer, analogous to adding a reference directly to NHibernate from your domain layer. But in actuality, there's nothing wrong with your domain layer having a reference to NHibernate.Validator because it introduces no direct link to NHibernate or any other data aware dependencies, for that matter. In a sense, NHibernate.Validator is “just” another validation framework which happens to work well with NHibernate.
In other words, even if you use NHibernate Validator, your domain logic has no idea that you're actually using NHibernate for persistence. You could use NHibernate.Validator in your domain while data access is performed with
ADO.NET. Accordingly, if you'd like to use a nice validation mechanism out of the box, I would recommend adding NHibernate Validator references to your domain model.
Alternatively, if you don't like NHibernate Validator for some reason or another, you still have options. If you have your own validation mechanism, you simply need to supply a wrapper which implements IValidator and IValidatorResult, found in
http://sharp-architecture.googlecode.com/svn/trunk/src/SharpArch/SharpArch.Core/CommonValidator/, and register your validator with your IoC; e.g.,
http://sharp-architecture.googlecode.com/svn/trunk/src/NorthwindSample/app/Northwind.Web/CastleWindsor/ComponentRegistrar.cs registers the NHibernate Validator wrapper with Castle Windsor.
Finally, you can bug other validation vendors to supply an adapter, accordingly. For example, David Hayden has written a S#arp Architecture validation adapter for Enterprise Library:
http://groups.google.com/group/sharp-architecture/msg/507031cffc2700db.
EditSharpArch.Data
Provides “out of the box” data access functionality using NHibernate.
Of particular note:
- /NHibernate/Repository.cs: The “out of the box” data access object that may be used directly, with a generic qualifier, or as a base class for all concrete Repositories
- /NHibernate/NHibernateSession.cs: Provides a means for getting an NHibernate session. It also builds the NHibernate session factory upon creation. The initialization of the NHibernate session factory supports the use of HBMs, Fluent NHibernate, Fluent NHibernate Auto Persistence, or any combination of these.
EditSharpArch.Testing
Provides reusable testing utility classes.
Of particular note:
- EntityIdSetter.cs: This is used to set the Id property of an Entity object within unit tests. Although I highly recommend you never set this property outside of a unit testing scenario, it’s a very useful utility when returning results from a mock repository. You’d use it as follows: EntityIdSetter.SetIdOf(myEntity, 1).
EditSharpArch.Testing.NUnit
Provides NUnit specific testing utility classes.
Of particular note:
- BehaviorSpecificationTestsBase.cs: Provides a base class for writing unit tests following a behavior driven approach. More information about this approach may be found at http://flux88.com/blog/the-transition-from-tdd-to-bdd/.
- /NHibernate/DatabaseRepositoryTestsBase.cs: Provides a base class for unit tests which act upon a live database. A transaction is begun before each test and is then rolled back upon completion of the test, regardless of success or failure. Consequently, database changes made within a unit test will not have a permanent effect on the persisted data. For ease of maintenance, less fragile testing, and for emphasizing a greater focus on behavior testing over integration testing, it is suggested that data communication tests are performed using an in-memory SQLite database. This base class is provided for those of you that would rather test against a persistent, development database or if you encounter a very complicated scenario which is prohibitively difficult to setup within SQLite. Again, the preferred base classes for testing database communications are RepositoryTestsBase and RepositoryBehaviorSpecificationTestsBase which use an in-memory SQLite database.
- /NHibernate/RepositoryTestsBase.cs: Facilitates running database unit tests using an in-memory SQLite database.
- /NHibernate/RepositoryBehaviorSpecificationTestsBase.cs: Facilitates running database unit tests using an in-memory SQLite database in a behavior driven manner.
EditSharpArch.Web
Includes classes for supporting use of SharpArch within an ASP.NET MVC context.
Of particular note:
- /Areas/AreaRouteHelper.cs and AreaViewEngine.cs: Provides support for having nested folders, reflecting a complex namespace, under the Views folder. This approach is discussed further at http://devlicio.us/blogs/billy_mccafferty/archive/2009/01/22/mvc-quot-areas-quot-as-hierarchical-subfolders-under-views.aspx.
- /ComonValidator/MvcValidationAdapter.cs: Provides a simple means to move validation results from the common validator support to MVC validation bindings.
- /JsonNet/JsonNetResult.cs: Provides a nice ActionResult for returned Json.NET serialized results.
- /NHibernate/TransactionAttribute.cs: An ActionFilterAttribute for wrapping MVC actions within a transaction.
- /NHibernate/WebSessionStorage.cs: An ISessionStorage implementation for storing the NHibernate session in a web context. (This is not specific to MVC and may be leveraged in a classic ASP.NET environment.)