I'm currently writing an ASP.Net app from the UI down. I'm implementing an MVP architecture because I'm sick of Winforms and wanted something that had a better separation of concerns.
So with MVP, the Presenter handles events raised by the View. Here's some code that I have in place to deal with the creation of users:
public class CreateMemberPresenter
{
private ICreateMemberView view;
private IMemberTasks tasks;
public CreateMemberPresenter(ICreateMemberView view)
: this(view, new StubMemberTasks())
{
}
public CreateMemberPresenter(ICreateMemberView view, IMemberTasks tasks)
{
this.view = view;
this.tasks = tasks;
HookupEventHandlersTo(view);
}
private void HookupEventHandlersTo(ICreateMemberView view)
{
view.CreateMember += delegate { CreateMember(); };
}
private void CreateMember()
{
if (!view.IsValid)
return;
try
{
int newUserId;
tasks.CreateMember(view.NewMember, out newUserId);
view.NewUserCode = newUserId;
view.Notify(new NotificationDTO() { Type = NotificationType.Success });
}
catch(Exception e)
{
this.LogA().Message(string.Format("Error Creating User: {0}", e.Message));
view.Notify(new NotificationDTO() { Type = NotificationType.Failure, Message = "There was an error creating a new member" });
}
}
}
I have my main form validation done using the built in .Net Validation Controls, but now I need to verify that the data sufficiently satisfies the criteria for the Service Layer.
Let's say the following Service Layer messages can show up:
Let's also say that more rules will be in the service layer that the UI cannot anticipate.
Currently I'm having the service layer throw an exception if things didn't go as planned. Is that a sufficent strategy? Does this code smell to you guys? If I wrote a service layer like this would you be annoyed at having to write Presenters that use it in this way? Return codes seem too old school and a bool is just not informative enough.
Edit not by OP: merging in follow-up comments that were posted as answers by the OP
Cheekysoft, I like the concept of a ServiceLayerException. I already have a global exception module for the exceptions that I don't anticipate. Do you find making all these custom exceptions tedious? I was thinking that catching base Exception class was a bit smelly but wasn't exactly sure how progress from there.
tgmdbm, I like the clever use of the lambda expression there!
Thanks Cheekysoft for the follow-up. So I'm guessing that would be the strategy if you don't mind the user being displayed a separate page (I'm primarily a web developer) if the Exception is not handled.
However, if I want to return the error message in the same view where the user submitted the data that caused the error, I would then have to catch the Exception in the Presenter?
Here's what the CreateUserView looks like when the Presenter has handled the ServiceLayerException:
For this kind of error, it's nice to report it to the same view.
Anyways, I think we're going beyond the scope of my original question now. I'll play around with what you've posted and if I need further details I'll post a new question.
In reply to the follow-up question:
As for creating exceptions becoming tedious, you kinda get used to it. Use of a good code generator or template can create the exception class with minimal hand editing within about 5 or 10 seconds.
However, in many real world applications, error handling can be 70% of the work, so it's all just part of the game really.
As tgmdbm suggests, in MVC/MVP applications I let all my unhandlable exceptions bubble up to the top and get caught by the dispatcher which delegates to an ExceptionHandler. I set it up so that it uses an ExceptionResolver that looks in the config file to choose an appropriate view to show the user. Java's Spring MVC library does this very well. Here's a snippet from a config file for Spring MVC's Exception resolver - its for Java/Spring but you'll get the idea.
This takes a huge amount of exception handling out of your presenters/controllers altogether.
<bean id="exceptionResolver"
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="UserNotFoundException">
rescues/UserNotFound
</prop>
<prop key="HibernateJdbcException">
rescues/databaseProblem
</prop>
<prop key="java.net.ConnectException">
rescues/networkTimeout
</prop>
<prop key="ValidationException">
rescues/validationError
</prop>
<prop key="EnvironmentNotConfiguredException">
rescues/environmentNotConfigured
</prop>
<prop key="MessageRejectedPleaseRetryException">
rescues/messageRejected
</prop>
</props>
</property>
<property name="defaultErrorView" value="rescues/general" />
</bean>
As Cheekysoft suggests, I would tend to move all major exceptions into an ExceptionHandler and let those exceptions bubble up. The ExceptionHandler would render the appropriate view for the type of exception.
Any validation exceptions however should be handled in the view but typically this logic is common to many parts of your application. So I like to have a helper like this
public static class Try {
public static List<string> This( Action action ) {
var errors = new List<string>();
try {
action();
}
catch ( SpecificException e ) {
errors.Add( "Something went 'orribly wrong" );
}
catch ( ... )
// ...
return errors;
}
}
Then when calling your service just do the following
var errors = Try.This( () => {
// call your service here
tasks.CreateMember( ... );
} );
Then in errors is empty, you're good to go.
You can take this further and extend it with custome exception handlers which handle uncommon exceptions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With