【问题标题】:Custom behavior in a web applicationWeb 应用程序中的自定义行为
【发布时间】:2011-01-18 09:53:12
【问题描述】:

我正在处理一个 ASP.NET WebForms 项目,我们需要能够根据当前用户的“组”配置整个应用程序的行为。这适用于应用程序的几乎所有方面,包括站点导航、在页面上显示/隐藏某些用户控件以及在某些情况下执行自定义业务逻辑。但是,绝大多数应用程序行为是在组之间共享的,因此我们排除了创建完全独立的应用程序的想法。

本质上,我正在寻找一种在 ASP.NET WebForms 应用程序中实现自定义行为的架构方法。有没有比在视图层、业务层和持久层的代码库中散布 if/else 语句更好的方法?

编辑:一些例子:

  • 如果 A 组中的用户,他们的 导航将包括所有 B组导航加上一些 其他链接。

  • 如果用户在 A 组中,页面将 显示用户控件 c1、c2 和 c3。 如果用户在 B 组,他们将 只能在同一页面上看到 c1 和 c3。

  • 如果用户在表单上保存一些数据 他们在 A 组,发送一个 通知电子邮件。如果用户是 在 B 组中,发送短信

我们可以解决所有这些特定问题,但正在寻找一种方法来尽可能地封装这种行为,以免它分散在代码库中。

编辑:有一些与动态加载用户控件相关的有趣答案。是否应该将根据用户组确定要加载哪些控件或使用哪些行为的逻辑封装在一个(非内聚的)类中,例如:

GroupManager.GetNavigationControl(int groupId) // loads site nav control based on group
GroupManager.PerformNotification(int groupId) // sends text or email based on group

或者这个逻辑是否应该尽可能靠近代码中使用它的位置,从而分布在代码库的不同层?

【问题讨论】:

  • 也许您可以更详细地说明behavior 的含义

标签: asp.net architecture webforms


【解决方案1】:

没有过多的细节和关于 IoC 之类的事情,我想我会保持它非常简单,并有一个普通的旧工厂类,您可以使用它来返回适当的实例化 UI 元素 [用户控件]基于提出请求的当前用户。在这样做时,您将把所有的“if”语句放在一个位置。为了不使用“if”语句,您可以简单地创建一个映射配置文件或数据库表,其中包含对用户控件的引用,以便在用户属于特定组时使用。

注意:这两个选项都将导致在页面上创建动态控件,这并非没有其自身的复杂性,但我已经成功地在我的应用程序中使用动态控件有一段时间了 - 这只是一个问题让页面生命周期变得比我最初感到舒服的更多。

【讨论】:

    【解决方案2】:

    “组”是指“角色”吗?如果您在谈论角色,则可以通过执行以下操作来设置您的行为

    If User.IsInRole("SomeRandomRole") Then
         'Do some random behavioral crap
    ElseIF User.IsInRole("TheCoolRole") Then
         'Do some cool behavioral crap
    Else
         'Do generic crap
    End If
    

    另一个选项可能是使用基于角色的用户控件。因此,当您加载页面时,它将根据请求它的角色加载用户控件。

    您可以让 PlaceHolder 为空并从代码隐藏中调用 LoadControl 方法。

    那么你所有的用户控件都会匹配你的角色

    角色 = 管理员 | UserControl = Admin.ascx
    角色 = 用户 | UserControl = User.ascx

    【讨论】:

    • 是的,您可以将角色替换为组。问题是是否有比在整个代码库中重复您的建议更好的方法。
    • 你能告诉我们什么行为,不同角色之间有多大区别吗?
    【解决方案3】:

    您也可以从 Principal 对象继承来处理此问题。

    这是我在具有如下自定义规则的应用程序中的操作方式:

    创建了我自己的 IPrincipal 对象,该对象源自我的“Person”对象,以便能够继承查找组和角色等的能力:

    public class Principal : MyNamespace.Person, IPrincipal {
    }
    

    让当前上下文使用我的 IPrincipal 对象:

    protected void Application_AuthenticateRequest(Object Sender, EventArgs E) {
            if (HttpContext.Current.User != null &&
                HttpContext.Current.User.Identity.IsAuthenticated &&
                HttpContext.Current.User.Identity is FormsIdentity) {
                    FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
                    HttpContext.Current.User = new MyNamespace.Principal(id);
            } 
        }
    

    然后我创建了静态方法,这样我就不必每次想像这样获取当前用户时都进行强制转换:

    public class CurrentUser {
    
            /// <summary>
            /// Is the current user authenticated
            /// </summary>
            static public bool IsAuthed {
                get { return System.Web.HttpContext.Current.User.Identity.IsAuthenticated; }
            }
    
            /// <summary>
            /// Returns the Principal object in case it is needed. Also used for other static properties of this class.
            /// </summary>
            static public MyNamespace.Principal User {
                get {
                    return (MyNamespace.Principal)System.Web.HttpContext.Current.User;
                }
            }
    }
    

    然后你可以调用 CurrentUser.User.IsInGroup() 之类的东西。

    【讨论】:

      【解决方案4】:

      这里没有的详细信息,但我怀疑您可能会受益于多态性(即各种接口实现)来处理用户组之间不同的应用程序部分.像Spring.NET 这样的控制反转容器可以帮助您根据当前用户角色将这些不同的实现连接/配置在一起。您还可以从 Spring 的 Aspect Oriented Programming API 中受益,您可以在其中装饰业务层/数据访问层中的方法,以便可以执行授权逻辑。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-07
        • 2014-02-11
        • 2012-05-04
        • 1970-01-01
        相关资源
        最近更新 更多