Pregunta

Right now I have an ASP MVC web application along a Models project, a Service project, an Utilities project, and a few Datastores projects that function as repository for one or more domain models. I'm pretty happy with the separation of each layer but I'm stuck on what to return from service layer to the web app.

For example, when a user try to register, a RegisterViewModel is received by the controller. Individual pieces (email, password, etc.) are send to service layer which construct the Member domain object with guid, status, createdate, etc., send it to repository for storage and finally return the Member object for the web app to redirect to /Member/{guid}.

But how should the service layer inform the web app if an email already exists? In a more complex situation I may have to check the existence/validity of multiple domain objects and business rules so would have to return multiple errors in one go. In addition, I don't want exception to bubble to the web layer so service layer traps all exceptions but need to notify the web layer some how.

Even if I find a way to return all that, the web layer would be burdened to process all that and provide user various feedback. The controller code would be bulky and error prune. Is there a best practice on service result to the presentation? Should I eliminate separate service layer and have the code inside controller? Any thoughts are welcomed.

¿Fue útil?

Solución

I wrote the operation model library for this purpose, which allows you to write code like this:

public OperationResult Register(RegisterInput input) {

   var errors = new ErrorBuilder();

   if (errors.NotValid(input) // Invoke DataAnnotations validation
      || errors.Not(this.repo.FindUserByEmail(input.Email) == null, "Email '{0}' already exists.", () => input.Email))
      return errors;

   // Do stuff

   return HttpStatusCode.OK;
}

...and in the controller the error messages are copied to ModelState:

[HttpPost]
public ActionResult Register(RegisterInput input) {

   var result = this.service.Register(input);

   if (result.IsError)
      return View().WithErrors(result);

   // Do stuff
}

Check out the source code of the MvcAccount project which is written using this pattern.

Otros consejos

First of all you need to decide if you are writing service layer for distribution purposes or not.

If you are not planning to distribute the service layer to a different process/machine,

  1. Create a Message class
  2. Create an array of message classes and store it in HttpContext.Items
  3. Now add any new message in any layer in to that array
  4. consume it in the views/controller

HttpContext.Items is available for the life time of the request and you can use it all the way up to views.

If you use a DI framework you can achieve the same by using a request per life time object.

If you want to distribute the object nothing wrong in throwing the exceptions from your service layer.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top