【问题标题】:Event subscription best practices活动订阅最佳实践
【发布时间】:2023-04-08 22:10:02
【问题描述】:

我最近在我们的应用程序中偶然发现了以下内容,我很想知道这是好的还是坏的做法。我看到的是在应用程序、业务逻辑和最终我们的框架的不同级别上订阅的事件。

我们有对用户进行身份验证和授权的功能,它由一个 HttpModule 编排,它基本上执行以下操作(我只包括了最相关的部分):

    public class FooModule : IHttpModule
    {
        private IIdentityProvider _identityProvider;

        public void Init(HttpApplication context)
        {
            _identityProvider = TypeFactory.Create<IIdentityProvider>("...type string from configuration...");
            identityProvider.Init(context, ...);

            context.PostAuthenticateRequest += OnAuthenticateRequest;
            context.PostAuthenticateRequest += OnAuthenticateRequestLogging;
        }

        ...
    }

到目前为止,一切都很好:HttpModule 识别配置的身份提供者,对其进行初始化并订阅一些事件。事件处理程序在这里没有问题,所以我省略了它们。

然后,在任意身份提供者的初始化中:

public class BarIdentityProvider : IIdentityProvider
{
    public void Init(HttpApplication httpApplication, ...)
    {
        var authorizer = new BarAuthorizationProvider();
        authorizer.Init(httpApplication, ...);

        httpApplication.PostAuthenticateRequest += httpApplication_PostAuthenticateRequest;
        httpApplication.AuthorizeRequest += httpApplication_AuthorizeRequest;
    }

    ...
}

在 AuthorizationRequestHandler 中会发生以下情况:

public class BarAuthorizationProvider
{
    public void Init(HttpApplication httpApplication, ...)
    {
        httpApplication.PostAuthorizeRequest += OnAuthorizeRequest;
    }

    ...
}

如您所见,在 FooModule、BarIdentityProvider 和 BarAuthorizationProvider 中订阅了一些事件,对我来说,这些事件被视为事件意大利面。另外,当这样做时:

var authorizer = new BarAuthorizationProvider();
authorizer.Init(httpApplication, ...);

我不希望authorizer 订阅各种事件并“神奇地”工作。

作为一名软件开发人员,我希望:

  1. 一个 HttpModule,它订阅必要的事件并向身份提供者和授权提供者请求身份和访问信息。事件处理在提供程序中被最小化。
  2. 多个 HttpModules(即一个身份验证和一个授权模块),每个都订阅必要的事件。事件处理在提供程序中被最小化。

我是正确的还是有反对我期望的论据?

【问题讨论】:

    标签: c# events frameworks


    【解决方案1】:

    我的第一个问题是,“在提供程序中最小化事件处理”是否重要? IE。实现该目标有什么具体优势?

    我也想知道“事件意大利面”应该是什么意思。我的意思是,它清楚地引用了古老的“意大利面条代码”概念,但该概念指的是执行路径复杂的代码,通常是由于使用了非结构化流控制(即goto 语句)。我不明白在讨论事件处理时,有什么类似于意大利面条的东西。

    换句话说,“事件意大利面”这个词在这里似乎带有偏见。 IE。 “spaghetti”这个词被扔进去了,因为它已经被理解为贬义词了。但由于缺乏对实施的明确反对,贬义词本身似乎没有道理,而且“意大利面条”一词似乎不像在“意大利面条代码”的上下文中那样提供真正有用的隐喻。


    所以,回到“最小化提供程序中的事件处理”。为什么这很重要?您写道“这里的事件处理程序没有问题”,但这似乎表明提供程序中的处理程序 是合适的。 IE。他们所做的工作与提供者相关(可能仅与提供者有关)。那么他们还能如何做这项工作呢?

    在我看来(我写的事实表明您的问题可能被认为是题外话,“主要基于意见”,但我认为有一种客观的方式来看待这个问题,即使这只是我的意见:) ),基于事件的编程模型的一大优势是减少耦合。假设工作必须在某处完成,订阅这些事件的这些提供者对象的替代方案是让其他对象了解提供者对象的需求,并满足提供者对象的需求'代表。

    但是你只是用提供者对象的特定知识装载了另一个对象。这增加了类型之间的耦合。这通常是一件坏事。


    另一方面,如果您觉得提供程序中的事件处理程序可以移动到其他类型而无需更紧密地耦合这些类型,那么这表明事件处理程序确实不适合提供程序。但在这种情况下,这些事件处理程序的特定细节在这里肯定是相关的,这与你的断言相反。

    即在哪里 事件处理程序在很大程度上取决于它的作用。但是由于您似乎并不关心这些处理程序的具体内容,这表明它们是正确的,因此订阅事件根本不是问题。

    【讨论】:

      猜你喜欢
      • 2018-04-19
      • 1970-01-01
      • 2020-02-04
      • 1970-01-01
      • 2015-03-11
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      • 2012-05-04
      相关资源
      最近更新 更多