I am trying to create a service layer, however I am unsure how can I decouple my validation from the service, as it doesn't really look DRY for me. I am using ASP.net 4.0 c# with EF.
Here are my layers
BO - Business Object - Share accross all layers
DAL - Data Access Layer
BLL - Business Layer
Service - Service layer
This is one of my business object
public class Person:Base
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime DOB { get; set; }
//public virtual Prefix PrefixID { get; set; }
public virtual Gender GenderID { get; set; }
//public virtual Ethnicity EthnicityID { get; set; }
}
In my DAL folder I have two things, I have PersonDAL, GenderDAL and I have Repository Pattern IGenderRepository, IPersonRepository.
This is how they look
Repository
public interface IPersonRepository : IDisposable
{
Person PersonID(int id);
IEnumerable<Person> PersonFN(string _firstname);
IEnumerable<Person> PersonLN(string _lastname);
IEnumerable<Person> PersonDOB(DateTime _dob);
IEnumerable<Person> List();
void Edit(Person entity);
void Add(Person entity);
void Delete(Person entity);
void Save();
}
public interface IGenderRepository : IDisposable
{
IEnumerable<Gender> List();
Gender GenderID(int _id);
Gender GenderDesc(string desc);
void Edit(Gender entity);
void Add(Gender entity);
void Delete(Gender entity);
void Save();
}
Data Access Layer
public class PersonDAL : IPersonRepository
{
private AppContext db;
public PersonDAL(AppContext _context)
{
this.db = _context;
}
public IEnumerable<Person> List()
{
return db.Person.ToList<Person>();
}
public Person PersonID(int id)
{
return db.Person.FirstOrDefault((p) => p.ID == id);
}
public IEnumerable<Person> PersonFN(string _firstname)
{
return db.Person.Where<Person>((p) => p.FirstName == _firstname );
}
public IEnumerable<Person> PersonLN(string _lastname)
{
return db.Person.Where<Person>((p) => p.LastName == _lastname);
}
public IEnumerable<Person> PersonDOB(DateTime _dob)
{
return db.Person.Where<Person>((p) => p.DOB == _dob);
}
public void Add(Person p)
{
db.Person.Add(p);
Save();
}
public void Edit(Person p)
{
db.Entry(p).State = EntityState.Modified;
Save();
}
public void Delete(Person p)
{
Person _p = db.Person.Find(p.ID);
db.Person.Remove(_p);
Save();
}
public void Save()
{
db.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
db.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
public class GenderDAL : IGenderRepository
{
private AppContext db;
public GenderDAL(AppContext _context)
{
this.db = _context;
}
public IEnumerable<Gender> List()
{
return db.Gender.ToList();
}
public Gender GenderID(int id)
{
return db.Gender.FirstOrDefault((g) => g.ID == id);
}
public Gender GenderDesc(string desc)
{
return db.Gender.FirstOrDefault((g) => g.Description == desc);
}
public void Add(Gender g)
{
db.Gender.Add(g);
Save();
}
public void Edit(Gender g)
{
db.Entry(g).State = EntityState.Modified;
Save();
}
public void Delete(Gender g)
{
Gender _g = db.Gender.Find(g.ID);
db.Gender.Remove(_g);
Save();
}
public void Save()
{
try
{
db.SaveChanges();
}
catch (Exception e)
{
Console.Write(e.Message);
}
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
db.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
My business logic still follow the repository pattern
Repository for BLL
public interface IPersonBLL
{
IEnumerable<Person> List();
Person ID(int id);
IEnumerable<Person> FirstName(string _first);
IEnumerable<Person> LastName(string _last);
IEnumerable<Person> DOB(DateTime dt);
Boolean Update(Person p);
Person Add(Person p);
Boolean Delete(Person p);
}
public class PersonBLL : IPersonBLL
{
#region Constant
private PersonDAL db = null;
#endregion
public PersonBLL(AppContext context)
{
db = new PersonDAL(context);
}
public IEnumerable<Person> List()
{
return db.List();
}
public Person ID(int id)
{
var found = db.PersonID(id);
if (found == null)
{
return null;
}
return found;
}
public IEnumerable<Person> FirstName(string _first)
{
if (_first == null)
{
return null;
}
return db.PersonFN(_first);
}
public IEnumerable<Person> LastName(string _last)
{
if (_last == null)
{
return null;
}
return db.PersonLN(_last);
}
public IEnumerable<Person> DOB(DateTime dt)
{
if (dt > DateTime.Now )
{
return null;
}
return db.PersonDOB(dt);
}
public Person Add(Person p)
{
if (p.FirstName != null)
{
if (p.LastName != null)
{
p.createdOn = DateTime.Now;
p.updatedOn = DateTime.Now;
db.Add(p);
return p;
}
}
return null;
}
public Boolean Update(Person p)
{
if (db.PersonID(p.ID) != null)
{
p.updatedOn = DateTime.Now;
db.Edit(p);
return true;
}
return false;
}
public Boolean Delete(Person p)
{
var found = db.PersonID(p.ID);
if (found == null)
{
return false;
}
db.Delete(found);
return true;
}
}
To avoid extra text, the gender follow the same concept. Here is my service layer and this is where I am unsure how to proceed
My first question should I have each parameter seperated, or should I wrapped them in an object like Person but not knowing if I can access BO further more. Because it the data may come from the WebAPI or it could come from WPF application.
This is my interface for IPersonService
public interface IPersonService
{
IEnumerable<Person> FindAllPerson(Person p, string errorMessage);
Person FindPerson(int id, string errorMessage);
Person CreatePerson(string first, string mid, string last, DateTime dob, string pref, string gend, string ethnic, string errorMessage);
Boolean RemovePerson(int id, string errorMessage);
Boolean UpdatePerson(int id, string first, string mid, string last, DateTime dob, string pref, string gend, string ethnic, string errorMessage);
}
I am not to sure how can I seperate the validation, it just seem not the right place for it.
public class PersonService : IPersonService {
private PersonBLL _personRep = null;
private GenderBLL _genderRep = null;
//private PrefixBLL prefix = null;
//private AddressBLL address = null;
public PersonService()
{
_personRep = new PersonBLL(new AppContext());
}
public Person CreatePerson(string first, string mid, string last, DateTime dob, string pref, string gend, string ethnic, string errorMessage)
{
Person p = new Person();
if (validatePerson(first, mid, last, dob, pref, gend, ethnic, errorMessage))
{
p.FirstName = first;
p.MiddleName = mid;
p.LastName = last;
p.DOB = dob;
Gender g = validateGender(gend, errorMessage);
p.GenderID = g;
return _personRep.Add(p);
}
return null;
}
public Boolean RemovePerson(int id, string errorMessage)
{
Person p = _personRep.ID(id);
if (p == null)
{
errorMessage = "Person not found";
return false;
}
else
{
return _personRep.Delete(p);
}
}
public Boolean UpdatePerson(int id, string first, string mid, string last, DateTime dob, string pref, string gend, string ethnic, string errorMessage)
{
Person p = _personRep.ID(id);
if (p == null)
{
errorMessage = "Person not found";
return false;
}
else
{
if (validatePerson(first, mid, last, dob, pref, gend, ethnic, errorMessage))
{
if (first != "")
{
p.FirstName = first;
}
if (first != "")
{
p.MiddleName = mid;
}
if (first != "")
{
p.LastName = last;
}
if (first != "")
{
p.DOB = dob;
}
Gender g = validateGender(gend, errorMessage);
if (g != null)
{
p.GenderID = g;
}
return _personRep.Update(p);
}
return false;
}
}
public IEnumerable<Person> FindAllPerson(Person p, string errorMessage)
{
var list = _personRep.List();
if (list == null)
{
errorMessage = "No user found";
return null;
}
return list;
}
public Person FindPerson(int id, string errorMessage)
{
if (_personRep.ID(id) == null)
{
errorMessage = "No ID matches this person";
return null;
}
return _personRep.ID(id);
}
protected Boolean validatePerson(string first, string mid, string last, DateTime dob, string pref, string gend, string ethnic, string errorMessage)
{
if (first == null)
{
errorMessage = "First Name Missing";
return false;
}
return true;
}
protected Gender validateGender(string gend, string errorMessage)
{
Gender g = _genderRep.GetGenderDesc(gend);
if (g != null)
{
return g;
}
errorMessage = "Gender Description Did not match";
return null;
}
}