Thinking DDD with Patterns - Part 2 -

In previous post, I described the architecture diagram of our project. In this post I will describe the architecture layers. As shown in the architecture diagram, our layers are based on the approach DDD (UI, Application, Domain and Infrastructure).

  1. User Interface (Presentation Layer): Responsible for presenting information to the user and interpreting user commands. As shown in the diagram above, this layer can be represented by one of the following interfaces:
    • Silverlight or WPF: In this part, you should use the pattern MVVM (Model-View-ViewModel). MVVM offers a flexible way to create applications Silverlight / WPF and allow to reusing of code, simplifying maintenance and testing. It is composed of :
      • View: XAML for WPF or silverlight screens
      • ViewModel: relation between the view and model
      • Model: represents the entities and the business code on the server side.

     

    • ASP.NET MVC: As its name implies, the pattern used here is the MVC (Model-View-Controller).
      • Controller: Allows you to manage user interaction, working with the model and, finally, select the view that will allow rendering the user interface.
      • View: display made ​​in ASP engine or Razor
      • Model: represents the entities and the business code on the server side.

     

    • ASP.NET Webform: It doesn't follow any pattern. It is the strong coupling between the view and the code behind. Additional work is needed from the entire team to reduce the maximum possible code behind.


       

  2. Application layer: This is a thin layer which coordinates the application activity. It doesn't contain business logic. It doesn't hold the state of the business objects, but it can hold the state of an application task progress..
  3. Domain layer: This layer contains the information about the domain. This is the heart of business software. The state of business objects is held here. Persistence of business objects and possibly their state is delegated to the infrastructure layer.
  4. Infrastructure Layer: This layer acts as a supporting library for all the other layers. It provides communication between layers, implements the persistence of business objects contains supporting libraries for UI layer.

Other than main layers, I added two needed libraries:

  • WCF service: exposes the necessary contracts for the UI layer.
  • UTILS: It is a utility containing common code for any generic solution.

In next post, I will describe components used and how to create our project with VS 2010…

Thinking DDD with Patterns - Part 1 -

In this post, I will describe how to create a project using DDD approach and few patterns such as MVVM, MVC and IoC. In future posts, I will describe how create other projects using CQRS (DDDD) architecture.

Our project is a simply scrum tool. For those who are new to Scrum, "Scrum in FiveMinutes - Executive Summary" serves as a canon useful introduction. The project is to manage Scrum Task Board. To understand the needs of the project, I invite you to take a look at this link. The project objective is not to replace cork board hung on the wall. It is rather to keep a copy of the daily scrum progress.

Starting by describe global architecture project :

Our architecture is based on the Domain Driven Design approach. DDD is an approach to software development for complex needs. Firstly, DDD does not a new concept: it is neither a method nor a technology. The Domain Driven Design is "thinking". It is a set of "best practices" to reconcile art and technology in the software design.

Indeed, in the DDD, the business (Domain) that will not drive but inspire development. The main concept of DDD is that, whatever the implementation, it must reflect the business (Customer Requirements).

รจ"It should be possible to read the code, understand the business".

In next post, I will describe the architecture layers…

MongoDB vs CouchDB vs MySQL

Here is a simple comparison between NoSQL ( MongoDB, CouchDB) and RDBMS (MySQL) :

  

MongoDB

CouchDB

MySQL

Data Model 

Document-Oriented

Document-Oriented

Relational

Licence 

AGPL

Apache

GPL 

Large Objects (Files) 

Yes (GridFS)

Yes (attachments)

blobs 

Replication 

Master-slave

Master-master

Master-slave 

Object(row) Storage 

Collection based

One large repository

Table based

Query Language 

Dynamic; object-based

http

Dynamic; SQL

Full Text Search 

No

No 

Yes 

Unicode 

Yes

Yes 

Yes 

Map and Reduce 

Yes

Yes

Yes

Secondary Indexes 

Yes

Yes 

Yes 

Atomicity 

Single document

Single document

Yes - advanced

Interface 

Native drivers ; REST add-on

REST

Native drivers

Written in 

C++

Erlang

C++

Concurrency Control 

Update in Place

MVCC 

 

Geospatial Indexes 

Yes

GeoCouch

?

Transactions

No

Yes

Yes

Referential integrity

No

No

Yes

Distributed Consistency Model

Strong consistency.

Eventually consistent

Strong consistency.

Sharding

Yes

No

No

Horizontal scalable 

Yes

Yes

No

Debugging and Making a Service Available Across Domain Boundaries in Silverlight Application

If you encounter this kind of an error message:

“An error occurred while trying to make a request to URI ‘http://localhost...’. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. Please see the inner exception for more details“

You need to check for Cross-Domain Issues as follows :

If the domain of the application URL is different from the domain of the service URL, you have a cross-domain situation. Access of a service across domains requires that the service have a cross-domain policy file. There are two kinds of cross-domain policy files: Clientaccesspolicy.xml and Crossdomain.xml.

1. ClientAccessPolicy.xml file: This file is defined by Silverlight. It can be used only granting access to Silverlight applications, however this file provides more granular control over allowed domains. . If you want to use this file you should create a clientaccesspolicy.xml file that allows access to the service and save it to the root of the domain where the service is hosted. The following configuration allows access from any other domain to all resources on the current domain.


  
    
      
        
      
      
        
      
    
  



2. Crossdomain.xml File: This file is defined by Adobe Flash. It can be used if you want your service to grant access to both Adobe and Silverlight application. If you want to use this file you should create a crossdomain.xml file that contains the following configuration and save it to the root of the domain where the service is hosted. The file must be configured to allow access to the service from any other domain, or it is not recognized by Silverlight 4.




  

How to get a MouseLeftButtonDown or MouseLeftButtonUp Event from TextBox in Silverlight ?

In Silverlight, the event leftclickbutton for textbox control does not work. to solve this problem, simply create the following class:
namespace Utils
{
    public class TextBoxClickable : TextBox
    {
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);
            e.Handled = !base.Focus();
        }
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);
            e.Handled = !base.Focus();
        }
    }
}

Your XAML should define your namespace:

And you can use your new clickable TextBox like this:

How to Dependency Injection with NHibernate and Autofac in domain layer ?

There are two ways to DI with nhibernate and Autofac in domain layer (Entities) :
1. You can use directly autofacContainerProvider.Resolve().
Pros:
- simple and quickly
Cons :
- strong coupling between IoC and Entities
- cannot create unit tests for domain layer
- don't support with different UI (Wcf, Web, ..)
2. To resolve these cons, we have implemented this solution :
In Global.asax.cs, in Application_Start add this code after builder.Build() :


var builder = new ContainerBuilder();
builder.RegisterType<SomeDependency>();
// ... continue registering dependencies...
// Once you're done registering things, set the container
// provider up with your registrations.
builder.RegisterAssemblyTypes(typeof (ProductEntity).Assembly).InstancePerDependency();
_containerProvider = new ContainerProvider(builder.Build());


Web Application :

Nhibernate.Cfg.Environment.BytecodeProvider
= new AutofacBytecodeProvider
(new ContainerProviderContainer(AutofacContainerProvider)
, new ProxyFactoryFactory()
, new DefaultCollectionTypeFactory());

WCF Application :
Nhibernate.Cfg.Environment.BytecodeProvider
= new AutofacBytecodeProvider(AutofacContainer
, new ProxyFactoryFactory()
, new DefaultCollectionTypeFactory());

In nhibernate.cfg.xml you should use this factory :
<property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory
, NHibernate.ByteCode.Castle</property>

and in Entities of domain layer, you should declare the repository interfaces in constructors.

How to bulk insert data with Nhibernate Stateless Session ?

With following code we can use NHibernate in bulk data operations, an area where ORM's traditionally perform pretty badly. To deal this, we use the nhibernate StatelessSession.
"A IStatelessSession has no persistence context associated with it and does not provide many of the higher-level life cycle semantics. In particular, a stateless session does not implement a first-level cache nor interact with any second-level or query cache. It does not implement transactional write-behind or automatic dirty checking."

using (IStatelessSession statelessSession = sessionFactoryHelper.OpenStatelessSession())
{
using (ITransaction transaction = statelessSession.BeginTransaction())
{
try
{
statelessSession.Insert(objEntity);
transaction.Commit();
return objEntity;
}
catch (Exception ex)
{
transaction.Rollback();
throw ex;
}
}
}

How to Soft Delete with Nhibernate event listener ?

1. First, we need to define the domain specific interface ISoftDeletable to implement on the entities for which we need to keep a permanent record.
public interface ISoftDeletable
{
DateTime? DateDelete { set; get; }
}


2. Next, we should create the SoftDeleteEventListener class that inherit from NHibernate.Event.Default.DefaultDeleteEventListener, and simply override the DeleteEntity method.


public class SoftDeleteEventListener : DefaultDeleteEventListener
{
protected override void DeleteEntity(IEventSource session, object entity,
EntityEntry entityEntry, bool isCascadeDeleteEnabled,
IEntityPersister persister, ISet transientEntities)
{
if (entity is ISoftDeletable)
{
var e = (ISoftDeletable)entity;
e.DateDelete = DateTime.Now;

//CascadeBeforeDelete(session, persister, entity, entityEntry, transientEntities);
//CascadeAfterDelete(session, persister, entity, transientEntities);
}
else
{
base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled,
persister, transientEntities);
}
}
}



3. Finally, we need to configure the listener with nhibernate :

Nhibernate.cfg.Configuration configuration = new Configuration().Configure();
configuration.SetListener(ListenerType.Delete, new SoftDeleteEventListener());
configuration.BuildSessionFactory();


4. Now, to hide a deleted data, we define a soft delete filter in mapping file for which we need to keep a permanent record :

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" ...>
<class ...>

<property name="DateDelete" column="DateDelete" type="DateTime" />
<filter name="SoftDeleteFilter"> </filter>
</class>
<filter-def name="SoftDeleteFilter" condition="DateDelete IS NULL">
</filter-def>
</hibernate-mapping>



5. and, in the application_beginrequest, you should enable soft delete filter on the nhibernate session :

nhibernateSession.EnableFilter(“SoftDeleteFilter”).Validate();

Create Multi-Language domain model (dynamic resource) with Nhibernate and database ?



1. Create a Culture Filter on one nhibernate mapping file :

 <?xml version="1.0" encoding="utf-8" ?>  
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" ...>
<class ...>
...
</class>
<filter-def name="CultureFilter">
<filter-param name="CultureCode" type="System.String" />
</filter-def>
</hibernate-mapping>


2. Declare the following tag of culture code in the mapping files related to the language table :

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping ...>
<class name="ProductTypeCulture" table="Product_Type_Culture" mutable="false">
<id name="ID" column="ProductTypeId" type="Int64" unsaved-value="0" >
<generator class="native" />
</id>
<property name="Label" column="Label" type="String" not-null="true"/>
<property name="CultureCode" column="CultureCode" type="String" not-null="true"/>
<filter name="CultureFilter" condition=":CultureCode = CultureCode"/>
</class>
</hibernate-mapping>



3. In the application_beginrequest, you should enable filter on the nhibernate session :

CultureCode = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
public string CultureCode
{
get { return CultureInfo.CurrentCulture.TwoLetterISOLanguageName; }
set
{
nhSession.EnableFilter(“CultureFilter”).SetParameter(“CultureCode”,value)
.Validate();
}
}



4. Now, the entity ProductTypeCulture should inherit the following class :

public class EntityCulture : Entity<EntityCulture>, ICloneable, IEntityCulture
{
#region Constructors
public EntityCulture() {}

public EntityCulture(string label)
{
_label = label;
}
#endregion

#region Properties
private string _label;
public virtual string CultureCode { get; set; }
public virtual string Label
{
get { return _label; }
set { _label = value; }
}
#endregion

#region ICloneable Members
public virtual object Clone()
{
var cloned = new EntityCulture {Label = Label};
return cloned;
}
#endregion

#region override
private int? _oldHashCode;
public override bool IsTransient()
{
return ID.Equals(0) || string.IsNullOrEmpty(CultureCode);
}
public virtual bool Equals(EntityCulture other)
{
if (ReferenceEquals(this, other))
return true;

if (other == null || !GetType().Equals(other.GetType()))
return false;

if (!IsTransient() && !other.IsTransient() && ID.Equals(other.ID) && CultureCode.Equals(other.CultureCode))
return true;

return IsTransient() && other.IsTransient();
}

public override bool Equals(object obj)
{
var compareTo = obj as EntityCulture;

return Equals(compareTo);
}

public override int GetHashCode()
{
if (_oldHashCode.HasValue)
return _oldHashCode.Value;

if (IsTransient())
{
_oldHashCode = base.GetHashCode();
return _oldHashCode.Value;
}

return ID.GetHashCode() + CultureCode.GetHashCode();
}

public override string ToString()
{
return GetType().FullName + "#" + ID + "-" + CultureCode;
}
#endregion
}
public interface IEntityCulture
{
string Label { get; set; }
object Clone();
}



5. Finally, the entity ProductType should inherit the following class :



public class EntityMultiLanguage<T, TCulture> : Entity<T>, IEntityMultiLanguage<TCulture> where T : class where TCulture : class, IEntityCulture
{
private IDictionary<string, TCulture> _resources;

#region IEntityMultiLanguage<TCulture> Members
public virtual string Label
{
get
{
TCulture res = GetResource();
return res != null ? res.Label : null;
}
set
{
GetOrCreateResource().Label = value;
}
}

public virtual IDictionary<string, TCulture> Resources
{
get { return _resources ?? new Dictionary<string, TCulture>(); }
set { _resources = value; }
}
#endregion

protected virtual TCulture GetDefaultResource()
{
return Resources.ContainsKey(CultureFilter.DefaultCulture.TwoLetterISOLanguageName)
? Resources[CultureFilter.DefaultCulture.TwoLetterISOLanguageName]
: null;
}

protected virtual TCulture GetOrCreateResource()
{
if (Resources.ContainsKey(CultureFilter.CultureCode))
return Resources[CultureFilter.CultureCode];

var newResource = GetResource().Clone() as TCulture;
Resources.Add(CultureFilter.CultureCode, newResource);
return newResource;
}
protected virtual TCulture GetResource()
{
return Resources.ContainsKey(CultureFilter.CultureCode)
? Resources[CultureFilter.CultureCode]
: GetDefaultResource();
}
}

Generic Entity and Value Object in DDD

In the Domain Layer of DDD architecture, it's necessary to create generic entity and value object.

Generic Entity :


public interface IEntity<t> where T : class
{
long ID { get; set; }
bool IsTransient();
bool Equals(object obj);
bool Equals(Entity<t> other);
int GetHashCode();
string ToString();
}
[Serializable]
public abstract class Entity : IEntity where T : class
{
private int? _oldHashCode;
public virtual long ID { get; set; }
public virtual bool IsTransient()
{
return ID.Equals(0);
}
public virtual bool Equals(Entity other)
{
if (ReferenceEquals(this, other))
return true;
if (other == null || !(other is T))
return false;
if (!IsTransient() && !other.IsTransient() && ID.Equals(other.ID))
return true;
return IsTransient() && other.IsTransient();
}

public override bool Equals(object obj)
{
var compareTo = obj as Entity;
return Equals(compareTo);
}
public override int GetHashCode()
{
unchecked
{
if (_oldHashCode.HasValue)
return _oldHashCode.Value;
if (IsTransient())
{
_oldHashCode = base.GetHashCode();
return _oldHashCode.Value;
}
return ID.GetHashCode();
}
}
public override string ToString()
{
return GetType().FullName + "#" + ID;
}
public static bool operator ==(Entity left, Entity right)
{
return Equals(left, right);
}

public static bool operator !=(Entity left, Entity right)
{
return !Equals(left, right);
}
}




Generic ValueObject

public interface IValueObject<t> where T : class
{
bool IsTransient();
bool Equals(ValueObject<t> other);
bool Equals(object obj);
int GetHashCode();
string ToString();
}

[Serializable]
public abstract class ValueObject<t> : IEquatable<t>, IValueObject<t> where T : class
{
private int? _oldHashCode;
public abstract bool IsTransient();
public virtual bool Equals(T other)
{
var compareTo = other as ValueObject<t>;

return Equals(compareTo);
}
public virtual bool Equals(ValueObject<t> other)
{
if (ReferenceEquals(this, other))
return true;

if (ReferenceEquals(null, other) || !GetType().Equals(other.GetType()))
return false;

if (!IsTransient() &amp;&amp; !other.IsTransient() &amp;&amp; PropertiesEquals(other))
return true;

return IsTransient() &amp;&amp; other.IsTransient();
}
public override bool Equals(object obj)
{
var compareTo = obj as ValueObject<t>;

return Equals(compareTo);
}

public override int GetHashCode()
{
unchecked
{
if (_oldHashCode.HasValue)
return _oldHashCode.Value;

if (IsTransient())
{
_oldHashCode = base.GetHashCode();
return _oldHashCode.Value;
}

return PropertiesGetHashCode();
}
}

public override string ToString()
{
return GetType().FullName;
}

protected abstract bool PropertiesEquals(ValueObject<t> obj);
protected abstract int PropertiesGetHashCode();

public static bool operator ==(ValueObject<t> left, ValueObject<t> right)
{
return Equals(left, right);
}

public static bool operator !=(ValueObject<t> left, ValueObject<t> right)
{
return !Equals(left, right);
}

public static bool IsTransient<tentity>(IEntity<tentity> entity) where TEntity : class
{
return entity == null || entity.IsTransient();
}
}

Example of Value Object :


public class Address : ValueObject<address>
{
...
public override bool IsTransient()
{
return StreetAddress == null &amp;&amp; City == null &amp;&amp; ZipCode == null;
}

protected override bool PropertiesEquals(ValueObject<address> obj)
{
Address adr = obj as Address;
if (adr != null)
{
return StreetAddress == adr.StreetAddress &amp;&amp; City == adr.City
&amp;&amp; ZipCode == adr.ZipCode;
}
return false;
}

protected override int PropertiesGetHashCode()
{
return (StreetAddress ?? string.Empty).GetHashCode() ^ (City ?? string.Empty).GetHashCode()
^ (ZipCode ?? string.Empty).GetHashCode() ;
}
}