I am a bit confused about the service layer and using it validation.
So I am looking through this tutorial: http://www.asp.net/learn/mvc/tutorial-38-cs.aspx
First if you look at List 3
using System.Collections.Generic;
using System.Web.Mvc;
namespace MvcApplication1.Models
{
public class ProductService : MvcApplication1.Models.IProductService
{
private ModelStateDictionary _modelState;
private IProductRepository _repository;
public ProductService(ModelStateDictionary modelState, IProductRepository repository)
{
_modelState = modelState;
_repository = repository;
}
protected bool ValidateProduct(Product productToValidate)
{
if (productToValidate.Name.Trim().Length == 0)
_modelState.AddModelError("Name", "Name is required.");
if (productToValidate.Description.Trim().Length == 0)
_modelState.AddModelError("Description", "Description is required.");
if (productToValidate.UnitsInStock < 0)
_modelState.AddModelError("UnitsInStock", "Units in stock cannot be less than zero.");
return _modelState.IsValid;
}
public IEnumerable<Product> ListProducts()
{
return _repository.ListProducts();
}
public bool CreateProduct(Product productToCreate)
{
// Validation logic
if (!ValidateProduct(productToCreate))
return false;
// Database logic
try
{
_repository.CreateProduct(productToCreate);
}
catch
{
return false;
}
return true;
}
}
public interface IProductService
{
bool CreateProduct(Product productToCreate);
IEnumerable<Product> ListProducts();
}
}
They same interface just with a different name basically why not just use one?
public interface IProductRepository
{
bool CreateProduct(Product productToCreate);
IEnumerable<Product> ListProducts();
}
public interface IProductService
{
bool CreateProduct(Product productToCreate);
IEnumerable<Product> ListProducts();
}
In my book though(the author who I think wrote this tutorial) has changed it to have IProductRepository to void. So that confuses me even more.
So can someone explain why I need 2 interfaces that seems to do the same thing?
My next questions is my repository has a delete function. Do I put this one in my Service layer too(I guess mandatory if you use one Interface but if you use 2 like about then it could be optinal).
So what would I have in my service layer? Would it just call delete function in the repository? Should it just be a void method or should it return bool? I don't think for this method any validation would need to be done?
So I am not sure if a bool would be needed.
From the tutorial you are reading:
So, application flow control logic
belongs in a controller and data
access logic belongs in a repository.
In that case, where do you put your
validation logic? One option is to
place your validation logic in a
service layer.
A service layer is an additional layer
in an ASP.NET MVC application that
mediates communication between a
controller and repository layer. The
service layer contains business logic.
In particular, it contains validation
logic.
EDIT:
I'm not sure if I can explain it to you in a clear way('cause I'm not fluent in English), but I will try:
A service layer is an additional layer in an ASP.NET MVC application that mediates communication between a controller and repository layer, in that you can handle both validation and application businness. Sometimes you service will need to work with two or more methods of its correspondent repository layer so it doesnt need to have the same interface.
A basic example, let's think you have a register form.
you will have the following interfaces
public interface IUserService
{
bool Register(User mUser);
bool Validate(User mUser);
}
public interface IUserRepository
{
User FindUserByEmail(string Email);
bool Insert(User mUser);
}
so you will end up with two class that will do something like:
public class UserRepository: IUserRepository{
User FindUserByEmail(string Email)
{
//do a ninja search and return an user or null
}
bool Insert(User mUser);
{
//Insert user into db
}
}
public class UserService: IUserService
{
public bool Validate(User mUser)
{
//validate user
}
IUserRepository _respository = new UserRepository();
bool Register(User mUser)
{
if(Validate(mUser);
var hasUser = _respository.FindUserByEmail(User.Email);
if(hasUser==null)
return _respository.Insert(mUser);
return false;
}
}
I think you've made an argument for a single interface in this limited case, but the service and repositories perform two very different functions and you may run into issues down the road if they shared a single interface.
What if the CreateProduct() or ListProducts() needed to have different method signatures in either the service or repository?
What if ValidateProduct() should be defined in the interface? The repository certainly shouldn't have to implement that.
As you've pointed out, there's no need for two interfaces that define the same thing in this particular example, but I assume the author's assumption is that down the road they would be different and therefore necessary.
Related
Currently I'm using DI and service locator pattern to get the instance of Service. (Note that Service just generic term im using, and is nothing but the C# class which calls EF repository and perform data operations. Its NOT WCF service)
Is it okay to have Service instance in ViewModel? If yes, the what's the proper way to pass Service instance?
1>Should the controller pass the service instance to ViewModel. In this case Service properly get disposed when controller get disposed
2>or should the ViewModel get service instance using DI & Service Locator. In this case how service will get disposed?
BaseController
public class BaseController:Controller
{
private MyDomainService _myDomainServiceInstance = null;
protected MyDomainService MyDomainServiceInstance
{
get
{
if (_myDomainServiceInstance == null)
{
_myDomainServiceInstance = DefaultServiceLocator.Instance.GetInstance<MyDomainService>();
}
return _myDomainServiceInstance;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (_myDomainServiceInstance != null)
{
_myDomainServiceInstance.Dispose();
}
}
}
Controller
public class MyController:BaseController
{
public ActionResult DoSomething()
{
var model = new SummaryVM(MyDomainServiceInstance);
}
}
ViewModel
public class SummaryVM
{
MyDomainService _myDomainService = null;
public SummaryVM(MyDomainService myDomainService)
{
//Approache 1: Controller is passing the service instance
_myDomainService = myDomainService;
}
public SummaryVM()
{
//Aprooche 2: Use DI & Service locator pattern to get the instance
_myDomainService = DefaultServiceLocator.Instance.GetInstance<MyDomainService>();
}
public int[] SelectedClients { get; set; }
public string[] SelectedStates { get; set; }
public IEnumerable<Clients> PreSelectedClients
{
get
{
if (SelectedClients == null || !SelectedClients.Any())
{
return new List<AutoCompletePreSelectedVM>();
}
return _myDomainService.GetClients(SelectedClients);
}
}
}
View models are intended to provide information to and from views and should be specific to the application, as opposed to the general domain. Controllers should orchestrate interaction with repositories, services (I am making some assumptions of the definition of service here), etc and handle building and validating view models, and also contain the logic of determining views to render.
By leaking view models into a "service" layer, you are blurring your layers and now have possible application and presentation specific mixed in with what should focused with domain-level responsibilities.
Just don't mix concepts. If your service deals with view models then it should be a presentation service and be layered over top of the actual Model.
View models should be flat and simple DTOs purposed toward binding with the view. They should not be part of a DI container graph because that complicates things and makes reasoning about the code more difficult.
I had passed through similar situation. I think it is okay having the domain service get instantiated inside view model. The domain service can implement IDisposable, so I would instantiate it inside the get method instead of create the service as an attribute.
I am learning Onion Architecture by Jeffrey Palermo for more than 2 weeks now. I have created a test project by following this tutorial. While studying I came across this question on SO. According to accepted answer, one person nwang suggests that Methods like GetProductsByCategoryId should not be in Repository and one the other hand Dennis Traub
suggests that it is the responsibility of the Repository. What I am doing is :
I have a General Repository in Domain.Interface in which I have a method Find :
public interface IRepository<TEntity> where TEntity : class
{
IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> filter = null);
.......
.......
.......
}
Then I created a BaseRepository in Infrastucture.Data:
public class RepositoryBase<TEntity> : IRepository<TEntity> where TEntity : class
{
internal readonly DbSet<TEntity> dbSet;
public virtual IEnumerable<TEntity> Find(
Expression<Func<TEntity, bool>> filter = null)
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
return query.ToList();
}
}
And I have a concrete repository in Infrastructure.Data
public class ProductRepository : RepositoryBase<Product>, IProductRepository
{
public ProductRepository(MyDBContext context)
: base(context)
{
}
}
Now what I am doing in my Service Layer is Injecting Repository into Service and calling Repository.Find for methods like GetProductsByCategoryId. Like :
public class ProductService : IProductService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IProductRepository _productRepository;
public ProductService(IUnitOfWork unitOfWork, IProductRepository productRepository)
{
_unitOfWork = unitOfWork;
_productRepository = productRepository;
}
public IList<Product> GetProductsByCategoryId(int CategoryId)
{
// At the moment, My code is like this:
return _productRepository.Find(e => e.CategoryId == CategoryId).ToList();
// My confusion is here. Am I doing it right or I need to take this code to
// ProductRepository and call _productRepositoy.GetProductsByCategoryId(CategoryId) here instead.
// If I do this, then Service Layer will become more of a wrapper around repository. Isn't it?
// My question is : What exactly will be the responsibility of the Service Layer in Onion Architecture?
}
}
The way you designed your application is ok... but only if your service will come to handle other things than just wrap up the repository methods!
Always keep in mind the YAGNI principle that says:
Always implement things when you actually need them, never when you just foresee that you need them
Let's say that you have a user story that says that whenever a product description is not found in your DB, you should retreive it from somewhere else (calling an external service or something). Then it seems obvious that your ProductService will have to have a
private readonly IProductRepository _productRepository;
but also a
private readonly IProductDescriptionService _productDescriptionService;
In that situation it really makes sense to add a service layer on top of your repositories.
I find that sometimes things can get over abstracted for the sake of it and offer no real value. I would say that the structure in your example is fine and follows the pattern correctly. Your service layer, correctly, is acting to serve the needs of the client UI, it is loosely coupled to the data layer and contains any business logic needed to manipulate the data.
I always think it is more productive to start simple and build upon your structure than it is to over abstract, over complicate and over bloat a project. A business or technical case will often drive the project, and dictate whether it is needed.
Although, in this case it seems that service later is just a wrapper, sometimes you might have the need to add some business logic or call two repositories. Lets say you have a service called CartService and you have a method called AddToCart in which you need to first get the product, do some calculation and then call insert to another repository like below.
public class CartService : ICartService
{
private readonly IUnitOfWork _unitOfWork;
public CartService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public void AddToCart (int productId, int quantity)
{
var product = _unitOfWork.ProductRepository
.Find(p => p.ProductId == productId).Single();
var cartItem = new CartItem {
ProductId = productId,
Desc = product.Desc,
Quantity = quantiry
};
_unitOfWork.CartRepository.Add(cartItem);
}
}
More, complex scenarios include calling a third party web service etc.
I've got a problem with a bog standard three tier project using MVC that I'm trying to use Ninject with. I've got a MemberRepository:
public class MemberRepository : IMemberRepository{
public bool Save(Member member){
//saves member
}
}
I then have my Service Layer:
public class MemberService : IMemberService{
public bool Register(string email){
//Do Stuff & Populate Member Object
_repo.Save(member);
}
}
Given I'll be using Ninject what is the best way of me setting up my AccountController. Should I pass in the MemberService to the constructor like so:
public class AccountController : Controller
{
IMemberService _memberService;
public AccountController(IMemberService memberService)
{
_memberService = memberService;
}
}
Or pass in the repository:
public class AccountController : Controller
{
IMemberService _memberService;
public AccountController(IMemberRepository memberRepo)
{
_memberService = new MemberService(memberRepo);
}
}
Or Both?
I originally had just a repository (no service layer) but I've had to implement a service layer and I'm not sure how I'd handle the 'dependency' when registering the kernal in my NinjectWebCommon.cs file. Which was originally just this:
kernel.Bind<IMemberRepository>().To<SqlMemberRepository>();
But now I'm wondering if I need to register the IMemberService and have the repo as some kind of parameter.
:s Feeling kind of lost. Hope I'm making sense and someone can help out.
I've never used Ninject, I've been using Unity, but the same principles exist so hopefully this might help.
The service layer is the thing that is exposed to the controller - the controller needs to know nothing about the underlying repository. The flow is as follows, and each layer doesn't know about the layers above it:
Controller -> Service > Repository
So I would go with option 1, and then inject the repository into the constructor of the service.
public class MemberService : IMemberService {
private readonly IMemberRepository _repo;
[Inject]
public MemberService (IMemberRepository repo){
this._repo = repo;
}
public bool Register(string email){
//Do Stuff & Populate Member Object
_repo.Save(member);
}
}
and
public class AccountController : Controller
{
private readonly IMemberService _memberService;
[Inject]
public AccountController(IMemberService memberService)
{
_memberService = memberService;
}
}
That example obviously uses constructor injection but you can use property/field injection if you want instead. When you register your dependencies, you'll have to register both:
kernel.Bind<IMemberRepository>().To<SqlMemberRepository>();
kernel.Bind<IMemberService>().To<MemberService>();
I'm trying to build a real-world app using this tutorial as a basis for the framework. I understand MVC, but am new to the whole IOC/NHibernate world. After reading a few Q&A here on SO, I am thinking of adding a Service layer between the controller and the repository as I'll be adding some business rule validations down the line.
The source on github also has a 'ServiceInstaller' that proved really useful as it allows me to add any services to the application i.e.
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(AllTypes.FromThisAssembly().Pick()
.If(Component.IsInSameNamespaceAs<SectionService>())
.Configure(c => c.LifeStyle.Transient)
.WithService.DefaultInterface());
}
My question is specific to this tutorial, and its basically that I'm not sure if the ISession (which is the UoW) is passed from the Service layer to the Repository, or if there's another approach.
Here's what I have so far:
// Controller
public class SectionsController : Controller
{
public ILogger Logger { get; set; }
private readonly ISectionService sectionService;
public SectionsController(ISectionService sectionService)
{
this.sectionService = sectionService;
}
public ActionResult Index()
{
return View(sectionService.FindAll());
}
// other action methods
}
// Service Layer
public class SectionService : ISectionService
{
private ISectionRepository repository;
public SectionService(ISession session)
{
this.repository = new SectionRepository(session);
}
public IQueryable<Section> FindAll()
{
return repository.FindAll();
}
// other methods
}
// Repository
public class SectionRepository : ISectionRepository
{
private readonly ISession session;
public SectionRepository(ISession session)
{
this.session = session;
}
public IQueryable<Section> FindAll()
{
return session.QueryOver<Section>().List().AsQueryable();
}
// other CRUD methods
}
Is this correct way to implement this?
There's a reason why the sample app is implemented that way. Well, actually two reasons.
First reason that it is relatively simple and there's not enough logic to warrant a separate layer yet.
Second is, that this kind of controller --> service --> repository --> ISession abstractions are pointless and add nothing to the table. Only thing they do is increase the complexity of the app and amount of work you do for no benefit.
Ayende has a nice, recent, series of blogposts about it which I highly recommend. (here's the first of them, followed by few others).
What sorts of real-world requirements do you have that would warrant those two additional layers?
In closing, YAGNI and KISS.
I'm using the following T4 to create my Repository & UoW:
http://blogs.microsoft.co.il/blogs/gilf/archive/2010/07/05/repository-and-unit-of-work-t4-template-for-entity-framework.aspx
Now I'm trying to add a Service Layer. I was able to accomplish something like this:
public ActionResult Index()
{
using (DataEntities context = new DataEntities())
{
UnitOfWork uow = new UnitOfWork(context);
//Service
ClientService cli = new ClientService(uow);
var col = cli.getActive();
//Map results to ViewModel
var list = AutoMapper.Mapper.Map<IEnumerable<Client>, IEnumerable<ClientListViewModel>>(col);
return View(list);
}
}
This works fine, but...
Is architecturally correct to pass the UoW instance to the Service Layer?
(I'm using IUnitOfWork in its ctor)
I tried to move the context & UoW inside the service layer, but the context is not available when I try to map the results to ViewModel in the controller.
Thanks!
I would argue no it isn't. Then again, I'm not a huge fan of unit of work -- I feel like it knows too much. I would pass the necessary repository(ies) to the service you create. Typically, I end up with special "GetService" or "CreateService" but this might work for you... (I'm writing this freehand so it might not build)
Public class DoSomethingCoolService : IDoSomethingCoolService
{
private IRepository<SomethingINeed> _neededRepository;
public DoSomethingCoolService(connectionOrContext)
{
//setup
}
public DoSomethingCoolService(IRepository<SomethingINeed> neededRepository)
{
_neededRepository = neededRepository;
}
public List<SomethingINeed> ReturnWhatIWant()
{
_neededRepository.Where(x => x.WhatIWant = true);
}
}
Personally, I don't like this. I prefer something more like this ...
public interface IGetService<T>
{
//usual get suspects here
}
public class GetService<T> : IGetService<T>
{
private IRepository<T> _repository;
GetService(IRepository<T> repository)
//use repository to call gets
}
now for the complicated-ish stuff...
public interface IGetClientService : IGetService<Client>
{
List<Client> GetClientsForSomething(int someId);
}
public class GetClientService : GetService<Client>, IGetClientService
{
private IRepository<Client> _repository;
GetClientService(IRepository<Client> repository) : base(repository)
public List<Client> GetClientsForSomething(int someId)
{
//some crazy cool business logic stuff here you want to test!
}
}
Then inside my controller, I just have a dependency on the IGetClientService, and use it where necessary. Easy to test, easy to make another that isn't dependent on it.
Does this make any sense?