我目前正在从UI编写ASP.Net应用程序。 我正在实施一个MVP架构,因为我厌倦了Winforms并希望能够更好地分离关注点。

因此,使用MVP,Presenter处理由View引发的事件。 这是我用来处理用户创建的一些代码:

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" });
        }
    }
}

我使用内置的.Net验证控件完成了主表单验证,但现在我需要验证数据是否足以满足服务层的标准。

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

  • 电子邮件帐户已存在(失败)
  • 引用用户输入不存在(失败)
  • 密码长度超过数据存储允许的长度(失败)
  • 会员创建成功(成功)

我们还要说,UI无法预期的服务层中会有更多规则。

目前,如果事情没有按计划进行,我正在让服务层抛出异常。 这是一个足够的策略吗? 这段代码对你们有异味吗? 如果我写了这样的服务层,你会不得不编写以这种方式使用它的Presenters吗? 返回代码似乎太旧了,bool只是没有足够的信息。


不是由OP编辑:合并后续评论,由OP发布为答案


Cheekysoft,我喜欢ServiceLayerException的概念。 我已经有一个全局异常模块用于我不期望的异常。 你觉得让所有这些自定义异常变得单调乏味吗? 我认为捕获基础Exception类有点臭,但不确定从那里取得进展。

tgmdbm,我喜欢在那里聪明地使用lambda表达式!


感谢Cheekysoft的后续行动。 因此,如果您不介意用户显示单独的页面(我主要是Web开发人员),如果不处理异常,我猜这将是策略。

但是,如果我想在用户提交导致错误的数据的同一视图中返回错误消息,那么我是否必须在Presenter中捕获异常?

以下是Presenter处理ServiceLayerException时CreateUserView的样子:

创建用户

对于这种错误,最好将它报告给同一个视图。

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

===============>>#1 票数:15 已采纳

这对我来说听起来很合适。 异常是可取的,因为它们可以从服务层内的任何位置抛到服务层的顶部,无论它在服务方法实现中嵌套有多深。 这样可以保持服务代码的清洁,因为您知道调用演示者将始终获得问题通知。

不要抓住异常

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

规划简单的异常层次结构

如果要以这种方式使用异常,则应为自己的异常类设计异常层次结构。 在最小值创建一个ServiceLayerException类,并在出现问题时在服务方法中抛出其中一个。 然后,如果您需要抛出一个异常,该异常应该/可以由演示者以不同方式处理,您可以抛出ServiceLayerException的特定子类:例如,AccountAlreadyExistsException。

然后,您的演示者可以选择这样做

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.

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

我总是试着将我的服务层视为一个单独的可分发库,并将其视为具体的异常。 然后由演示者/控制器/远程服务实现决定是否需要担心特定细节或仅将问题视为一般错误。

===============>>#2 票数:3

正如Cheekysoft建议的那样,我倾向于将所有主要的异常移动到ExceptionHandler中,并让这些异常冒出来。 ExceptionHandler将为异常类型呈现适当的视图。

但是,任何验证异常都应该在视图中处理,但通常这种逻辑对于应用程序的许多部分是通用的。 所以我喜欢这样的帮手

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;
    }
}

然后在致电您的服务时,请执行以下操作

var errors = Try.This( () => {
  // call your service here
  tasks.CreateMember( ... );
} );

然后在错误是空的,你很高兴。

您可以进一步使用自定义异常处理程序扩展它,它处理不常见的异常。

===============>>#3 票数:1

在回答后续问题时:

至于创建异常变得乏味,你有点习惯。 使用优秀的代码生成器或模板可以在大约5或10秒内创建具有最少手动编辑的异常类。

但是,在许多现实世界的应用程序中,错误处理可能是工作的70%,因此它只是游戏的一部分。

正如tgmdbm建议的那样,在MVC / MVP应用程序中,我让所有不可处理的异常冒泡到顶部,并被委派给ExceptionHandler的调度程序捕获。 我进行了设置,以便它使用ExceptionResolver查看配置文件,以选择适当的视图来显示用户。 Java的Spring MVC库做得非常好。 这是来自Spring MVC的异常解析器的配置文件的片段 - 它用于Java / Spring,但你会明白这一点。

这会占用演示者/控制器的大量异常处理。

<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>

  ask by Scott Muc translate from so

未解决问题?本站智能推荐:

1回复

C#N层解决方案Web服务客户端到服务层的异常行为

我正在用C#创建我的第一个n层解决方案。 我已经创建了自己的层,包括仅用于练习的服务层(不是必需的) 我正在使用Visual Studio 2017,对于后端数据库,我使用SQL Express版本14。 因此,我在主应用程序中创建了一个Web服务客户端,引用了服务层的Web服务。
2回复

Web表单中的MVP模式,界面,错误消息显示

我正在做一个Webform项目,我想在其中实现MVP模式。 我浏览了几篇基于MVP的文章和项目。 对我来说似乎很好。 在大多数地方,如果需要显示错误消息,则已在视图界面中将其作为方法。 为了清楚起见,我在这里举一个例子。 这是我实现IAdminSettingsView的控件
2回复

N层Web服务器与N层业务服务器

从体系结构上讲,当您有单独的n层业务服务器要连接到进行逻辑处理时,是否需要n层ASP.net MVC Web服务器? 除了分离业务逻辑之外,还有其他原因为Web服务器使用n层体系结构吗? 业务服务器也可以处理数据层吗? 在我看来,Web服务器似乎不需要n层?
2回复

N层/ N层错误处理设计

Out团队正在构建一个N-Tier应用程序,该应用程序将处理许多数据库和网络方法。 基本上,我们设计了以下几层(从下到上): 数据层:可以是Oracle或SQL(基本上是EF实体和使用数据库优先自动生成的上下文)。持久层:处理数据层。 我们有一个用于Oracle的持久层和一个用于S
1回复

使用实体框架Codefirst在N层应用程序中迁移数据库

我正在尝试在分层项目结构中使用实体框架代码优先方法创建数据库。 我使用标准的代码优先控制台命令; enable-migrations =>确定 add-migration Init =>问题:它不产生迁移代码,只有上下方法 更新数据库 =>无事可做;
2回复

如何使用3层在gridview中进行CRUD操作

我正在使用n层架构这是我的aspx.cs代码 这是我的标记 这是我的数据访问层 这是我的业务对象 我能够执行选择查询。 我无法执行创建,删除或更新。
1回复

LINQ to SQL和N层分层

我的经验使我更习惯于程序中的以下结构。 假设它是一个.NET WPF应用程序。 您创建一个WPF项目,一个业务逻辑项目(类库),一个数据访问项目(类库)和一个实体项目(类库)。 WPF项目通过业务逻辑层到达数据访问层。 实体是轻量级的DTO,可以在各层之间自由流动。 我的问题是这个
3回复

asp.net中的3层架构[关闭]

我正在asp.net中开始一个项目。 我想使用3层架构。 现在我的图层有问题。 我像这样管理这些图层: 但我已经看到某处使用App_Code和其他一些格式。 你能帮我一个真实而标准的吗?
4回复

3层架构中的循环引用问题C#

我想在ASP.NET中构建一个具有3层架构的Web应用程序。 但是我遇到了循环引用的问题。 我有3层: 包含UI的应用层。 包含所有逻辑和域类的业务层。 包含所有数据库交互方法的数据层。 我在业务层中使用数据层方法来执行数据库操作,在这些方
2回复

ASP.NET 3层/ 3层架构 - 如何分离UI和BLL

我目前正在攻读计算机科学学位的最后一年,并正在研究我的最终项目和论文。 我将使用ASP.NET Web Forms和C#创建一个3层项目 - 我不能真正称之为3层,因为它很可能永远不会托管在我本地PC以外的任何其他地方进行测试,因为它是仅限于单一目的。 我的主要问题是: 根据我的理