Reputation: 1794
I'm trying to make simple 3-tier architecture application with ASP.NET and C#. I walked to an problem with circular dependency. I have Student Class at Business tier. I have an interface to presentation tier with those methods:
void SaveStudent(Student student);
Student[] GetStudents();
This looks like ok.
But I have also interface from Data Access tier to Business with those methods:
void InsertStudent(Student student);
Student[] ReadAllStudents();
The problem is with Student class. Because my Business tier depends on DAL, I cannot put reference to Business tier from my data access layer. I know that DAL should not depend from Business tier. But don't know how to solve that problem.
How should I pass the data then?
If I place Student class to DAL then my presentation tier would be forced to depends on data access layer which isn't good.
I never tried to make 3 tier architecture before.
How to solve this problem? Be free to change my interface methods if it is needed.
Upvotes: 2
Views: 3439
Reputation: 308763
You should put a service in between the presentation and persistence tiers. The persistence tier calls the service, which interacts with your model and persistence tiers to fulfill the request.
Three-tier architecture is an artifact of client/server programming. A service-oriented architecture is a more modern take on the problem. It injects a service layer in-between the presentation and the others. There are several benefits:
Here's how the interfaces might look in Java - translate to the language of your choice:
package model;
public class Foo
{
private Long id;
private String name;
}
package service;
public interface FooService
{
Foo findFoo(Long id);
List<Foo> findAllFoos();
void saveAllFoos(List<Foo> foos);
void delete(Foo foo);
}
package persistence
public interface GenericDao<K, V>
{
List<V> find();
V find(Long id);
K save(V value);
List<K> save(List<V> values);
void update(V value);
void delete(V value);
}
So presentation->service->persistence
; service uses model and persistence packages to fulfill requests, which should map to use cases.
Your presentation need not know about the model objects at all. Send along something like XML or JSON or some other serialized format and the presentation just renders it.
Upvotes: 1
Reputation: 7523
You need to introduce one more layer called Model. This layer will define a Student class as a data object only. ( No Save or Get methods in this layer).
The Model layer can be in its own project ( and so its own dll ). Now reference the dll across all layers ( Presentation , Business and DA ).Use the Student type to hold the data elements only.
In the Business layer , reference DA layer and have a class Student that has the SaveStudent method. In the DA layer , reference only the Model layer and implement the save student method. ( Note this only shows the layer and the classes these layers should have , ideally the classes should implement interfaces designed towards this purpose, but this itself is not a part of your question )
namespace Model{
class Student
{
public string Name { get; set; }
public String Address { get; set; }
// more student properties here ..
// No methods like SaveStudent in this class , thats up into the business layer
public bool IsValid(){ // validate the student here }
}
}
namespace Business{
class Student
{
// call this method from your Presentation layer
public void SaveStudent(Model.Student student)
{
if (student.IsValid())
{
DataAccess.StudentDAO student = new DataAccess.StudentDAO();
student.SaveStudent(student);
}
else
{
throw new ApplicationException("Invalid student");
}
}
}
}
namespace DataAccess{
class StudentDAO
{
public void SaveStudent(Model.Student student)
{
// impl here to save a student informatin to a
// persistent storage
}
}
}
Upvotes: 1
Reputation: 2385
You should not call from DAL to BLL (business logic layer), just the other way around.
// Will contain details about your UI - taking data from text fields, etc
// and passing it to the business object
class Student_UI
{
Student_BL _blObject = new Student_BL();
void SaveStudent()
{
Student student = new Student();
// Get student details from UI...
_blObject.SaveStudent(student);
}
DisplayStudents()
{
Student[] students = _blObject.GetStudents();
// display students...
}
}
class Student_BL
{
Student_DAL _dalObject = new Student_DAL();
void SaveStudent(Student student)
{
_dalObject.InsertStudent(student);
}
Student[] GetStudents()
{
return _dalObject.ReadAllStudents();
}
}
Upvotes: 1
Reputation: 1827
The code below illustrates the separate of concerns from the service (or business logic) layer providing a method to inject in a repository.
This ensures that the StudentService has no knowledge of how or where students are persisted. It also provide you with the ability to unit test the behaviour of the repository and the service separately.
If you are using an IoC approach (such as StructureMap or Unity) you could use the container to do the injection.
public class StudentService
{
private IStudentRepository _studentRepository;
public StudentService(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
}
public interface IStudentRepository
{
void Save(Student student);
Student[] GetStudents();
}
public class StudentRepository : IStudentRepository
{
... implement the methods defined in the interface ...
}
Upvotes: 0
Reputation: 8488
This problem is generally solved by placing your Student class in a separate Models assembly (call it what you like) which will be shared across all layers. In large scale n-tier architectures these classes will generally contain nothing more than data and are usually referred to as Data Transformation Objects (DTO). Any business logic which acts upon these objects will be held in the Business Layer (BL) which is usually exposed as a service (i.e WCF). The service is just an intermediary, you can design in this way even when all code is sitting on the same machine and even in the same process. As a minimum you want to separate your concerns (UI, Business Layer, DTO, DAL)at the assembly level.
In your case the GetStudents method would be exposed on the Business Layer Service and would return the Student DTO. The Business Layer would hold a reference to the Data Access Layer (DAL) upon which it would call InsertStudent. Again as I've said both the DAL and and BL have a reference to the Models assembly but most importantly the DAL doesn't have a dependency on the BL.
Client --> Business Layer Service --> Data Access Layer
<------------------ Student (DTO) ------------------>
Upvotes: 4
Reputation: 47373
The key concept in n-tier
architecture is that the n-th
tier knows only of the n+1-th
tier. So your user-interface will call the business logic and the business logic will call the data access layer.
Upvotes: 2