Joni 的个人资料Data Matters日志列表 工具 帮助

日志


2007/7/5

Dependency Injection -pattern

Dependency injection -pattern (and a related pattern, Inversion of Control, IoC) helps to make code more maintainable and modular. It can be used for replacing implementation on the fly or add functionality at the runtime. If you aim to make code more loosely coupled or want to make a plugins, then you should be aware of the dependency injection. It helps automated testing, too.

Lately I have been building an architecture for an interesting product at work. As it aims to be a major business for a long while, I have to make sure it is easy to test, maintain and expand later as requirements will evolve. The "let's make complete specs first and then code it" -days are over as the more agile methods gradually take over.

Loose coupling

One of the main rule I decided was to make sure that the most important layers are loosely coupled. A data access layer (DAL) is a natural example where it is useful. In this project I decided that we'll use the SubSonic as the object-relational mapping tool until final releases of .NET 3.5/LINQ or Entity Framework arrive.

While SubSonic creates usable classes, using them directly would tie us to the tool too tightly for years to come. Instead, the goal is to keep our own entities/object model as abstract as possible and separated from actual implementations, like DAL-technologies. It means (with the current proof-of-concept, at least) a little bit more work is required to map classess that the SubSonic creates to own own entities that need to be maintained by hand. However, it reduced lot's of trouble in the future as things can be replaced easily.

Another example is an integration layer between our business logic and MS CRM API's. When we abstract the integration layer with loose coupling we are safe, should the underlaying API change or MS CRM be replaced with completely different product.

How to implement

Before you can add dependency injection to your application, you should know how interfaces work. Essentially, they define a contract that the classes that inherit the interface must implement. As long as two or more classes share the required interface(s), they can be injected to the class that requires one of them.

Once you have the classes that implement the interface, you need to decide what kind of dependency injection you want to use. Do you want to supply the class being injected via constructor or set it through a property after instantiation? Here is an article at DevX by Joydip Kanjilal that discussess this choice.

Finally, you need to decide where to store information about the class that should be injected. You can hard code the reference and construction of the dependent classes to the calling code (DI) or add reference to the dependent class dynamically with reflection and configuration file to avoid the need of recompilation (which is really Inversion of Control -pattern).

I didn't bother writing code samples this time as all the linked resources have plenty of them to give the idea and a simple search gives even more.

Related Resources
2005/11/23

Reporting made easy

In case you haven't checked out the ReportViewer control in WinForms 2.0 yet, do it now.
 
I have been using the SQL Server Reporting Services for a while and the only problem with it is the need for Reporting Server to be installed somewhere in the network. Also, it is hard to integrate it as a part of your own client-side solutions.
 
After fiddling around with the ReportViewer for a while, it was apparent that there is still all the power of the Reporting Services -reports, but in much more manageable form.
 
The best part is that it really is stand-alone. You can build, view and print full reports with the Report Viewer from your own Windows apps. It also supports exporting to PDF.
 
Solves at least all my printing needs
2005/9/2

C# 2.0 generics and factories

Lately, I have been coding a lot with .NET 2.0 beta 2. The more I use and understand the generics, the more I love them. Obviously, they are useful for collections, but they help on many layers of architectures, too.
 
For example, recently I changed methods in data access layer to return the given parameterized type with the help of generics. With this I aimed to reduce the amount of code required for each type. It is a good example, why being a lazy coder is not a bad thing.
 
Initially the first version had one specific DAL-layer for each type. Like PersonDAL would have methods for getting single and multiple objects and return factored classes.
 
Changing it to use generics went well, until I had to find a way to submit the resulted type to the right factory. I didn't want to resort to if..else or switch/case -constructs (if foo=type then generate fooType), as they would require manual updating for each new/changed type. Not to mention it would be ugly
 
After some searching, it seems to be a common problem with many solutions. However, those were too complicated for my needs and I kept on looking for some ideas. Finally I stumbled upon Wes's blog and his post about Using C# Generics on Static Classes. Although the topic is about static classes, it had nice pattern for factoring classes.
 
I adopted some parts from the idea and created my own implementation. I'll post more details and code later, when I have tested and cleaned it bit more!  In the meantime, currently some of the important parts are like this (remember, it is still a work in progress, but thought somebody could have use for it):
//From GenericDAL:

internal class GenericDAL<T> where T: EntityBase { ..

 

public T GetSingleEntity<F>(QueryBase queryBase)

where F: IFactory, new() { ..

 ....

if (reader.HasRows)

{ reader.Read();

//An instance of the submitted factory class is generated:

F factory =

new F();

return (T)factory.Generate(reader, true);  }

 

//From PersonFactory.cs:

public class PersonFactory : IFactory

{

   public PersonFactory()

  { }

  public EntityBase Generate(SqlDataReader reader, bool expanded)

 {

  Person person = new Person(); ...

 

//IFactory -interface:

public interface IFactory

{

EntityBase Generate(SqlDataReader reader, bool expanded); }

 

//And finally an example of calling the DAL from the business logic layer:

public Person FetchSinglePerson(Person person)

{

//Query class, not important in this example:

PersonQuery pq = new PersonQuery(person);

pq.QueryType =

QueryType.GetByID;

pq.CommandType =

CommandType.Text;

 

GenericDAL<Person> gd = new GenericDAL<Person>(ConnectionString);

//Here I simply submit the type of the desired (Person-) factory:

return gd.GetSingleEntity<PersonFactory>(pq);

}