Application Architecture using Unity 2.0

21 בנובמבר 2010

no comments

In my previous post, I've showed how to use dependency injection to create loose coupled components in order to achieve a greater flexibility

For your application's architecture.

Today I'll be showing the real thing : achieving loose coupled layers using dependency injection via Unity 2.0

Let's assume that this is your common basic server architecture:

clip_image001

Services layers / WCF Services layers – responsible for the entire application server business logic and data sources encapsulation from the client.

Business logic layerrepresenting the entire application business logic

Data access layer – responsible for data access to the application internal resources ( application databases , XML files and etc.) and to service agents to external data sources (3rd party web services and etc.)

Decoupling these layers help create a more flexible application, easy to test and maintain and is more extendible.

By using Unity 2.0 you can configure each layer to work with dependency injection pattern and "disconnect" or "replace" each

Of the components without making in code change, in addition you could write mock components for unit testing purposes.

Let's start at the bottom on the data access layer :

Here's our example interface for our data access component :

public interface IExampleDAL
{
DataSet SyncSelecet(string param1, string param2);
int Insert(string param1, string param2);
IAsyncResult AsyncUpdate(string param1, string param2, AsyncCallback callabckMethod);
void EndAsyncUpdate(IAsyncResult result);
}

We'll use the following base DAL which uses an IDataAccess member in order to access the database (in the case using enterprise library 5.0)

public class BaseDAL
{
protected IDataAccess da;

public BaseDAL()
{
da = DataAccessManager.GetDataAccess();
}

public BaseDAL(string containerName)
{
da = DataAccessManager.GetDataAccess(containerName);
}
}

The first constructor will be the default one and therefore must use the injection constructor attribute so Unity 2.0 will know which constructor to use

When resolving the type.

The second constructor can be used for testing purposes by setting unity's container name at runtime and therefore using mock components when needed

Here's our example DAL component and it's counter mock component :

public class ExampleDAL : BaseDAL,IExampleDAL
{
public DataSet SyncSelecet(string param1,string param2)
{
// Set Command
DbCommand cmd = da.GetStoredProcedureCommand("someProcedure");
da.AddInParameter(cmd, "param1", DbType.String, param1);
da.AddInParameter(cmd, "param2", DbType.String, param2);

return da.ExecuteDataSet(cmd);
}

public int Insert(string param1, string param2)
{
// Set Command
DbCommand cmd = da.GetStoredProcedureCommand("someProcedure");
da.AddInParameter(cmd, "param1", DbType.String, param1);
da.AddInParameter(cmd, "param2", DbType.String, param2);

return da.ExecuteNonQuery(cmd);
}

public IAsyncResult AsyncUpdate(string param1, string param2,AsyncCallback callabckMethod)
{
// Set Command
DbCommand cmd = da.GetStoredProcedureCommand("someProcedure");
da.AddInParameter(cmd, "param1", DbType.String, param1);
da.AddInParameter(cmd, "param2", DbType.String, param2);

AsyncCallback callback = new AsyncCallback(EndAsyncUpdate);
return da.BeginExecuteNonQuery(cmd, callabckMethod);
}

public void EndAsyncUpdate(IAsyncResult result)
{
int rc;
// TODO : Check Async State
if (result.IsCompleted)
rc = da.EndExecuteNonQuery(result);
}
}
public class MockExampleDAL : IExampleDAL
{
public System.Data.DataSet SyncSelecet(string param1, string param2)
{
return new DataSet();
}

public int Insert(string param1, string param2)
{
return 0;
}

public IAsyncResult AsyncUpdate(string param1, string param2, AsyncCallback callabckMethod)
{
return null;
}


public void EndAsyncUpdate(IAsyncResult result)
{

}
}

 

Now the same principle can be used for the business logic layer:

Here's our interface and it's implemented components :

public interface IExampleBL
{
List<ExampleEntity> Select(string param1, string param2);
int Insert(string param1, string param2);
IAsyncResult Update(string param1, string param2);
void EndUpdate(IAsyncResult result);
IExampleDAL GetExampleDAL(string containerName);
}
public class ExampleBL : IExampleBL
{
IExampleDAL da;
IUnityContainer container;

[InjectionConstructor]
public ExampleBL()
{
da = GetExampleDAL(string.Empty);
}

public ExampleBL(string containerName)
{
da = GetExampleDAL(containerName);
}

public List<ExampleEntity> Select(string param1,string param2)
{
DataSet ds = da.SyncSelecet(param1: param1, param2: param2);

List<ExampleEntity> list = new List<ExampleEntity>()
{
new ExampleEntity(){Id="1",Name="John",Phone="555-5555",BirthDate=new DateTime(1979,5,4),Balance=0.0},
new ExampleEntity(){Name="Empty",Phone="555-5555",BirthDate=DateTime.Now,Balance=0.0}
};

// Validate
Validator<ExampleEntity> validator = ValidationFactory.CreateValidator<ExampleEntity>();
ValidationResults results = validator.Validate(list[0]);

if (!results.IsValid)
{
foreach (ValidationResult result in results)
{
// Check result properties
}

// Handle Error (maybe throw exception)
return list;
}

return list;

}

public int Insert(string param1, string param2)
{
return da.Insert(param1: param1, param2: param2);
}

public IAsyncResult Update(string param1, string param2)
{
AsyncCallback callback = new AsyncCallback(EndUpdate);
return da.AsyncUpdate(param1: param1, param2: param2,callabckMethod:callback);
}

public void EndUpdate(IAsyncResult result)
{
// TODO : Check Async State
if (result.IsCompleted)
da.EndAsyncUpdate(result);
}

public IExampleDAL GetExampleDAL(string containerName)
{
container = new UnityContainer();
if (string.IsNullOrEmpty(containerName))
container.LoadConfiguration();
else
container.LoadConfiguration(containerName);

return container.Resolve<IExampleDAL>();
}
}
public class MockExampleBL : IExampleBL
{
public List<ExampleEntity> Select(string param1, string param2)
{
return new List<ExampleEntity>();
}

public int Insert(string param1, string param2)
{
return 0;
}

public IAsyncResult Update(string param1, string param2)
{
return null;
}

public void EndUpdate(IAsyncResult result)
{

}

public DataAccess.IExampleDAL GetExampleDAL(string containerName)
{
return new MockExampleDAL();
}
}

It's the same as the DAL components with the difference of the get example DAL method which is responsible for resolving the DAL object

And therefore injecting it to the BL component while creating loose coupled components.

The last thing is to configure all of it in your application configuration file (in my case a web config):

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<!--
interfaces -->
<
alias alias="IExampleService" type="Common.Contracts.ServiceContracts.IExampleService,Common.Contracts"/>
<
alias alias="IExampleBL" type="Server.BusinessLogic.IExampleBL,Server.BusinessLogic"/>
<
alias alias="IExampleDAL" type="Server.DataAccess.IExampleDAL,Server.DataAccess"/>
<
alias alias="IDataAccess" type="Common.DataAccess.IDataAccess,Common.DataAccess"/>

<!--
components -->
<
alias alias="ExampleService" type="Server.Services.ExampleService,Server.Services"/>
<
alias alias="ExampleBL" type="Server.BusinessLogic.ExampleBL,Server.BusinessLogic"/>
<
alias alias="ExampleDAL" type="Server.DataAccess.ExampleDAL,Server.DataAccess"/>
<
alias alias="DataAccess" type="Common.DataAccess.DataAccess,Common.DataAccess"/>

<!--
mocks -->
<
alias alias="MockExampleService" type="Server.Services.MockExampleService,Server.Services"/>
<
alias alias="MockExampleBL" type="Server.BusinessLogic.ExampleBL,Server.BusinessLogic"/>
<
alias alias="MockExampleDAL" type="Server.DataAccess.ExampleDAL,Server.DataAccess"/>
<
alias alias="MockDataAccess" type="Common.DataAccess.DataAccess,Common.DataAccess"/>
<
container>
<
register type="IExampleService" mapTo="ExampleService" />
<
register type="IExampleBL" mapTo="ExampleBL" />
<
register type="IExampleDAL" mapTo="ExampleDAL" />
<
register type="IDataAccess" mapTo="DataAccess" />
</
container>
<
container name="Mock">
<
register type="IExampleService" mapTo="MockExampleService" />
<
register type="IExampleBL" mapTo="MockExampleBL" />
<
register type="IExampleDAL" mapTo="MockExampleDAL" />
<
register type="IDataAccess" mapTo="MockDataAccess" />
</
container>
</
unity>

The same principle can be used in any layer needed.

Enjoy and let me know if you have any questions or remarks.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*