如何使用MVP将服务层消息/错误传达给更高层? [英] How Do You Communicate Service Layer Messages/Errors to Higher Layers Using MVP?

查看:237
本文介绍了如何使用MVP将服务层消息/错误传达给更高层?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从UI下载一个ASP.Net应用程序。我正在实施一个MVP架构,因为我对Winforms感到厌烦,并希望有更好的分离问题。



所以使用MVP,Presenter处理由风景。这里有一些代码来处理用户的创建:

  public class CreateMemberPresenter 
{
私人ICreateMemberView视图;
私人IMemberTasks任务;

public CreateMemberPresenter(ICreateMemberView view)
:this(view,new StubMemberTasks())
{
}

public CreateMemberPresenter(ICreateMemberView查看,IMemberTasks任务)
{
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 =创建新成员时出错});
}
}
}

我有我的主窗体验证使用内置的.Net验证控件完成,但现在我需要验证数据是否足够满足服务层的条件。



假设以下服务层消息可以显示:




  • 电子邮件帐户已存在(失败)

  • 参与用户输入不存在(失败)

  • 密码长度超过数据存储允许长度(失败)

  • 成功创建成功(成功)



我们还说在UI不能预期的服务层中会有更多的规则。



目前我如果没有按计划进行,服务层会抛出异常。这是一个足够的策略吗?这个代码嗅到你们吗?如果我写了一个这样的服务层,你会不得不用这种方式写演讲者吗?返回代码似乎太老了,一个布尔只是没有足够的信息。







编辑不是OP:在后续评论中合并作为OP 的答案







Cheekysoft,我喜欢ServiceLayerException的概念。我已经有一个全局异常模块,用于我不期望的例外。你发现所有这些自定义异常繁琐吗?我认为捕捉基础异常类有点臭,但不完全确定从那里进展。



tgmdbm,我喜欢巧妙地使用lambda表达式!






感谢Cheekysoft进行后续工作。所以我猜测,如果您不介意用户显示单独的页面(我主要是Web开发人员),如果未处理异常,那将是策略。



但是,如果我想在用户提交导致错误的数据的同一个视图中返回错误消息,那么我将需要捕获演示者中的异常?



当Presenter处理ServiceLayerException时,CreateUserView看起来像这样:





对于这种错误,很高兴将其报告给同一个视图。



无论如何,我想我们现在超出了我原来的问题的范围。我会玩你发布的内容,如果我需要更多的细节,我会发布一个新的问题。

解决方案

这听起来恰到好处。例外是优选的,因为它们可以从服务层内的任何地方抛出到服务层的顶部,无论它在服务方法实现中嵌套多深。这样可以保持服务代码的清洁,因为您知道主叫方将始终收到问题的通知。



不要抓住异常



然而,不要在演示者中捕获异常,我知道它很诱人,因为它使代码更短,但是您需要捕获特定的异常以避免捕获系统级异常。



计划一个简单的异常层次结构



如果要使用例外这样,您应该为自己的异常类设计异常层次结构。
在最小时创建一个ServiceLayerException类,并在发生问题时将其中的一个抛在您的服务方法中。那么如果你需要抛出一个应该/可以由演示者处理不同的异常,你可以抛出一个特定的ServiceLayerException子类:说,AccountAlreadyExistsException。



你的主持人可以选择执行

  try {
// call service etc
// handle success to查看
}
catch(AccountAlreadyExistsException){
//设置视图中的消息和一些其他唯一数据
}
catch(ServiceLayerException){
//在视图
}
//系统异常中设置消息,允许不可恢复的异常使
//向上调用堆栈,以便向用户显示一般错误,而不是再次显示该表单,而是
//。

在您自己的异常类中使用继承意味着您不需要在演示者中捕获多边形异常 - 你可以如果有需要 - 而且你最终不会意外捕捉你无法处理的例外。如果您的演示者已经在调用堆栈的顶部,请添加一个catch(异常)块以用不同的视图来处理系统错误。



我总是尝试思考作为一个单独的可分发库,并将其作为具体的异常抛出是有道理的。然后由演示者/控制器/远程服务实现来决定是否需要担心具体的细节,或只是将问题视为一般错误。


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:

  • E-mail account already exists (failure)
  • Refering user entered does not exist (failure)
  • Password length exceeds datastore allowed length (failure)
  • Member created successfully (success)

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.

解决方案

That sounds just right to me. Exceptions are preferable as they can be thrown up to the top of the service layer from anywhere inside the service layer, no matter how deeply nested inside the service method implementation it is. This keeps the service code clean as you know the calling presenter will always get notification of the problem.

Don't catch Exception

However, don't catch Exception in the presenter, I know its tempting because it keeps the code shorter, but you need to catch specific exceptions to avoid catching the system-level exceptions.

Plan a Simple Exception Hierarchy

If you are going to use exceptions in this way, you should design an exception hierarchy for your own exception classes. At a minumum create a ServiceLayerException class and throw one of these in your service methods when a problem occurs. Then if you need to throw an exception that should/could be handled differently by the presenter, you can throw a specific subclass of ServiceLayerException: say, AccountAlreadyExistsException.

Your presenter then has the option of doing

try {
  // call service etc.
  // handle success to view
} 
catch (AccountAlreadyExistsException) {
  // set the message and some other unique data in the view
}
catch (ServiceLayerException) {
  // set the message in the view
}
// system exceptions, and unrecoverable exceptions are allowed to bubble 
// up the call stack so a general error can be shown to the user, rather 
// than showing the form again.

Using inheritance in your own exception classes means you are not required to catch multipile exceptions in your presenter -- you can if there's a need to -- and you don't end up accidentally catching exceptions you can't handle. If your presenter is already at the top of the call stack, add a catch( Exception ) block to handle the system errors with a different view.

I always try and think of my service layer as a seperate distributable library, and throw as specific an exception as makes sense. It is then up to the presenter/controller/remote-service implementation to decide if it needs to worry about the specific details or just to treat problems as a generic error.

这篇关于如何使用MVP将服务层消息/错误传达给更高层?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆