How does a service layer fit into my repository implementation? How does a service layer fit into my repository implementation? asp.net asp.net

How does a service layer fit into my repository implementation?


Take a look at S#arp Architeture . It's like a best practices architectural framework for building ASP.NET MVC applications. The general architecture pattern is to have 1 repository per entity which is responsible only for data access and 1 service per repository which is responsible only for business logic and communicating between controllers and services.

To answer your questions based on S#arp Architeture:

In addition to the service layer, should there also be a separate business logic layer, or is that the role of the service layer?

Models should be responsible for field-level validation (ex. using required field attributes) while controllers can validate data before saving (ex. checking state before saving).

Should there be one service layer per repository?

Yes - there should be one service per repository (not 1 service layer per repository but I'm guessing you meant that).

Is the service layer the only way that the UI can instance the model objects or does the repository provide the new model instance to the service?

Repositories and services can return a single entity, a collection of entities, or data transfer objects (DTOs) as required. Controllers will pass these values to a static constructor method in the model which will return an instance of the model.

ex Using DTOs:

GiftCertificateModel.CreateGiftCertificate(int GiftCerticiateId, string Code, decimal Amount, DateTime ExpirationDate)

Do I put my parameter, model and other validations in the service layer that do things like check to make sure a input is valid and that a item to update exists in the database before updating?

Models validate field-level values ex. making sure input is valid by checking for required fields, age or date ranges, etc. Services should do any validation needed that requires checking outside of the model value ex. Checking that the gift certificate hasn't been redeemed yet, checking properties of the store the gift certificate is for).

Can the model, repository and UI all make calls to the service layer, or is it just for the UI to consume?

Controllers and other services should be the only ones making calls to the service layer. Services should be the only one makes making calls to repositories.

Is the service layer supposed to be all static methods?

They can be but it's easier to maintain and extend if they aren't. Changes to entities and adding/removing subclasses are easier to change if there's 1 service per entity / subclass.

What would be a typical way to call the service layer from the UI?

Some examples of controllers calling the service layer:

giftCertificateService.GetEntity(giftCertificateId); (which in turn is just a call to the giftCertificateRepository.GetEntity(giftCertificateId)giftCertificateService.Redeem(giftCertificate);

What validations should be on the model vs the service layer?

Already answered above.

UPDATE

Since you're using WebForms it may be a little harder to grasp some of the concepts but everything I've mentioned is applicable since what I'm describing is a general MVC paradigm. ADO.NET for data access doesn't matter since data access is decoupled via repositories.

Do I add the same (and possibly more) properties to the service as I have on my model (amount, code, etc) or do I only offer methods that accept GiftCertificate objects and direct parameters?

You need to look at the services as exactly what their name implies - actions that controllers can invoke. You won't need properties that are defined in your model since they are already available in the model.

Do I create a default instance of the GiftCertificate entity when the Service constructor is called or just create new ones as needed (eg - for validation methods in the service that need to call validation methods in the entity? Also, same question about creating a default repository instance...?

Controllers and services should have private fields for services and repositories respectively. You shouldn't be instantiating for every action / method.

I know i expose the functionality of the repo via the service, do I also expose the methods from the entity as well (eg - IsValidCode, etc)?

Not too sure what you mean here. If services return entities then those methods on the entities are already exposed. If they return DTOs then that implies you're interested only in certain information.

For validation I can see why you're a bit concerned since there's validation done directly on the model and other types of validation done in services. The rule of thumb I've used is that if validation requires calls to the db then it should be done in the service layer.

It is ok for the UI to simply create a new GiftCertificate object directly without going through the service (eg - to call parameter validation methods from the entity). If not, how to enforce it?

On the UI layer, when I want to create a new gift certificate, do I call the model/service validations (like IsValidExpirationDate, etc) directly from the UI layer OR do I hydrate the object first, then pass it in to be validated and then return some sort of validation summary back to the UI?

For these 2 questions lets go through a scenario:

User enters information to create a new certificate and submits. There is field level validation so if a textbox is null or if the dollar amount is negative it throws a validation error. Assuming all fields are valid the controller will call the service gcService.Save(gc).

The service will check other business logic, such as if the store already has issued too many gift certificates. It either returns an enum for the status if there are multiple error codes or throws an exception with the error information.

Finally, the service calls gcRepository.Save(gc).


  1. You don't have to create repository per entity,see here for more,

    Usually one defines a repository per aggregate in the domain. That is: we don't have a repository per entity! If we have a look at a simple order entry system the entity Order might be the root of a Order aggregate. Thus we will have an Order Repository.

  2. Should there be one service per repository? -> Not always, as you may use multiple repositories in one service.

  3. Service creates Model instance, repository will never interact to Model, in fact it returns the Entity which model will use subsequently.

  4. Handle Input/range etc kind of validation at UI level(u can use javascript or any other library), and let Services handle only business aspects. You can get the benefits of Attributes which will does the same.

  5. UI->Service->Repository, if repository is calling service than thr must be something wrong IMO.


You code changes,

  1. Make Model and Repositories separate.

    public class GiftCertificateModel{}public class GiftCertificateRepository{   //Remove Model related code from here, and just put ONLY database specific code here, (no business logic also). Common methods would be Get, GetById, Insert, Update etc.     Since essence of Repository is to have common CRUD logic at one place soyou don't have to write entity specific code.     You will create entity specific repository in rare cases, also by deriving base repository.}public class GiftCertificateService(){    //Create Model instance here    // Use repository to fill the model (Mapper)}


You can create a service called GiftCertificateService.

That way you will coordinate any task that does not belong to the responsibility of the GiftCertificateModel into it's service. (Not to be confused with a WCF service).

The service will control all the tasks so your UI (or whatever caller that might be) will use the methods defined in the service.

The service will then call methods on the model, use the repository, create transactions, etc.

For ex. (based on the sample code you provided):

public class GiftCertificateService {   public void CreateCertificate()    {      //Do whatever needs to create a certificate.      GiftCertificateRepository gcRepo = new GiftCertificateRepository();      GiftCertificateModel gc = gcRepo.CreateNew();      gc.Amount = 10.00M;      gc.ExpirationDate = DateTime.Today.AddMonths(12);      gc.Notes = "Test GC";      gcRepo.Save(gc);   }}

The UI will call the CreateCertificate method (passing arguments, etc) and the method may return something also.

NOTE: If you want the class to act on the UI though then create a controller class (if you are doing MVC) or a presenter class (if you are doing MVVM, and don't want to put everything inside the ViewModel) and use the GiftCertificateService from that class.