Reputation: 4484
I'm working on a asp.net mvc3 solution that has 3 projects Data, Service, and Web. I've been using interfaces to abstract the service layer as much as possible so the web only knows about the service layer, and not the Data where the true domain models are held. The web project uses view models and simply passes things to the service model as broken out parameters vs a domain object. For example creation of a user I'd use an interface like this.
public interface IUserService
{
void CreateUser(string userName, string firstName, string lastName....);
}
But after thinking about it for a while something like GetUsers I'd need to return a domain object of some type, and this would require me adding a data reference in the web project.
public interface IUserService
{
void CreateUser(string userName, string firstName, string lastName....);
**IEnumerable<User>** GetUsers();
}
So I think I have two choices, either break my domain objects into their own project which all projects then have reference to or possibly add the data reference to the web project. I think the first option is the best but I'm curious if there are other options. Thanks
Upvotes: 0
Views: 134
Reputation: 54628
Instead of returning User
, I would:
// MyCompany.Data Project
public interface IUserService
{
IUserServiceResult<IUser> CreateUser(IUser User);
IUserServiceResult<IEnumerable<IUser>> GetUsers();
}
public interface IUserServiceResult<T>
{
bool IsSuccessful { get; }
string UserErrorMessage { get; }
T Data { get; }
}
public interface IUser
{ // Some Getter Properties
}
// MyCompany.Service
public class UserService : IUserService
{
public UserServiceResult<User> CreateUser(IUser User)
{
var result = new UserServiceResult<User>();
if (User == null)
{
// log the error AND
result.UserErrorMessage = "User information was not valid.";
// or
throw new ArgumentNullException("User");
}
// example only
result.IsSuccessful =
(Context.Users.FirstOrDefault(x => x.Email == User.Email) == null)
if (result.IsSuccessful)
{
User newUser;
// create user...
result.Data = newUser;
}
return result;
}
public IUserServiceResult<IEnumerable<IUser>> GetUsers()
{
// Similar to above, can check for authentication
// Maybe return IsSuccessful = false,
// UserErrorMessage = "Requires administrative privileges".
// or result.Data = new List<User>();
}
}
public class UserServiceResult<T> : IUserServiceResult<T>
{
bool IsSuccessful { get; set; }
string UserErrorMessage { get; set; }
T Data { get; set; }
}
public class User : IUser { } //
I like having the service or data tier always return a result type with a generic typed data. I find it especially helpful when passing it back to jQuery.
Upvotes: 2
Reputation: 8189
One way to do it is to have two separate projects, one for you Data classes, and one for your Models/ViewModels.
Now the controller works with the UserModel instead of the User. Which keeps your web application out of messing with your data classes.
You can also put the interfaces for your service into the models project and allow consumers of the Rest service access to the models and interfaces.
Upvotes: 1