C# 业务操作建模:将名称链接到代码

C# 业务操作建模:将名称链接到代码,c#,.net,architecture,C#,.net,Architecture,因此,我正在考虑将我的业务操作(或者更确切地说,它们的名称)放到数据库中,这样我就可以将它们链接到用户角色(用于授权)并在操作上设置通知系统 主要的问题是如何将操作(可能由字符串表示,如“Customer.New”或“Customer.View”)从数据库转换为在系统中运行的代码。我想出的大多数方法看起来都很笨拙 示例1-处理所有操作的通用方法 public static object RunOperation(string Op, string User, params object[] Pa

因此,我正在考虑将我的业务操作(或者更确切地说,它们的名称)放到数据库中,这样我就可以将它们链接到用户角色(用于授权)并在操作上设置通知系统

主要的问题是如何将操作(可能由字符串表示,如“Customer.New”或“Customer.View”)从数据库转换为在系统中运行的代码。我想出的大多数方法看起来都很笨拙

示例1-处理所有操作的通用方法

public static object RunOperation(string Op, string User, params object[] Parms)
{
    switch(Op)
    {
        case "Customer.View":
            return BLL.Facade.GetCustomerById((int)Parms[0]);
            break;
        case "Customer.New":
            return BLL.Facade.CreateCustomer(Parms[0] as Customer);
            break;
        ...
    }
}
我讨厌的是所有的演员。但授权是相当容易的<代码>授权(Op,用户)

然后是这样的:

[BusinessOp("Customer.New")]
public static int CreateCustomer(Customer NewCustomer)
{
    ...
}
但是授权有点不可靠,因为我假设必须将CreateCustomer方法引用传递到Authorize方法中(不同的操作将具有不同的方法签名)。然后Authorize方法必须使用反射来查找BusinessOpAttribute并获取操作的字符串名称(它在数据库中的表示方式)

我想我可以做的另一件事是创建一系列表示操作字符串名称的常量,并将它们用于Authorize方法,但在执行操作时只调用业务方法。但是,我仍然没有一个项目(无论是方法还是字符串)向所有各方表示业务操作

有没有人有这方面的经验,有没有其他我没有考虑过的选择

回答

最终决定通过评论与接受的答案。我将为每一个业务操作制作一个课程。大概是这样的:

[BusinessOperation]
public static class CustomerNew
{
    public const string Key = "Customer.New";

    public static bool Authorize(string UserName) // or perhaps IPrincipal User
    {
        // Authorize method will use key to check against database
        ...
    }

    public static int Invoke(Customer NewCustomer)
    {
        // Invoke method has well-defined parameters
        ...
        // Can also use key to notify listeners of operation completion
    }
}

我们处理类似问题的方法是让实际操作表示指定类上的具体方法。最大的问题是参数,我们总是将其留给实现方法来处理

因此,在您的情况下,我将进行如下重构:

var asValues = Op.Split('.');

switch(asValues[0].ToLower())
{

    case "customer":
        Type type = typeof(BLL.CustomerFacade);

        System.Reflection.MethodInfo method = type.GetMethod(asValues[1], System.Reflection.BindingFlags.IgnoreCase);

        if (method != null)
        {
            return method.Invoke(BLL.CustomerFacade, Parms);
        }
        break;
注意,我将外观更改为CustomerFacade,在这个CustomerFacade中,GetCustomerById将更改为View。这只是一种方法

例如,您还可以将所有内容保存在一个facade中,并将方法名称更改为CustomerView。此外,如果还有其他代码依赖于现有的facade名称,则可以更改操作名称或添加重定向方法,将请求重定向到正确的底层facade方法

这可能需要根据您的实现进行一些调整,但它应该能为您提供总体思路


这种方法的好处是,您不必在每次执行新操作时都更新此方法。

谢谢您的回答。这不是我想要的解决方案,因为调用方法仍然必须知道它调用的方法的内部细节(确切地知道要传递哪些参数),这违反了封装原则。但是,如果我找不到更好的解决办法,我可能会做类似的事情。@KaseySpeakman:我同意,这是一种鸡和蛋的情况。但是,您可以通过检查方法的参数,然后询问调用者适当的值来反转控制。例如,您可以添加ValueFetch接口,该接口将由调用者实现,并将根据参数名称或使用反射(假设实现类的值存储在属性中)为参数提供值。然后只传递实现实例,而不是param数组。我正在考虑为每个具有Authorize和Invoke方法的业务操作创建一个类,以及一个const Key,它是操作的数据库名称。Authorize方法将使用密钥来授权操作,但Invoke方法将具有定义良好的参数。这是额外的前期工作,但它确实避免了反射。想法?听起来是个好办法。实际上,我们在移动应用程序视图/模型中使用了非常类似的方法。