【问题标题】:How to avoid repeating conditional logic?如何避免重复条件逻辑?
【发布时间】:2020-08-12 17:20:36
【问题描述】:

我正在为我的 .NET Core 应用程序实现安全功能,我发现自己一遍又一遍地重复相同的条件逻辑。 有没有一种方法可以将其概括在一个地方并将其应用于我想要的细分市场? 我记得在这类事情上使用了代表或 Func,但我不太确定......有什么想法吗?

以下是我尝试编写一次并在多个地方应用的代码。

var currentUser = _httpContext.HttpContext.Session.GetCurrentUser<SessionContext>();
if(currentUser.Roles.Any())
{
    // ex query here. This could be any piece of code
    var q = from u in _dbContext.Users
            join d in _dbContext.Users on u.DoctorId equals d.Id into ud
            from docU in ud.DefaultIfEmpty()
            select new
            {
                User = u,
                Doctor = docU
            };

    if(!currentUser.Roles.Contains("Administrator"))
    {
        if(currentUser.Roles.Contains("Doctor"))
        {
            //do something here
           //ex.
           q = q.Where(x => (x.Doctor != null ? x.Doctor.Id == currentUserId : false));
        }
        else if (currentUser.Roles.Contains("Patient"))
        {
            //do something else here
            //ex.
            q = q.Where(x => x.User.Id == currentUserId);
        }
    }
}
else
    throw new Exception("No roles applied to logged in user");

【问题讨论】:

  • 你是说你在多个地方都有这个特定的代码块,还是你在为这个单一代码块中的多个 if 语句而烦恼?
  • 我在多个地方都有这段代码。我不太担心多个 if 语句。
  • 如果不知道您在 If 语句中所做的事情,很难知道会发生什么变化。如果这是针对控制器方法上的 API,您可以添加 Authorize 属性,例如 [Authorize(Roles = "Doctor", "Patient")]
  • 我正在我的 if 语句中编写 linq 查询。但我想我的目标是在这些 if 语句中写任何东西,但保持外部逻辑。我已经更新了我的示例。干杯!
  • 我认为你应该看看 C# 中的规范模式

标签: c# .net-core delegates func code-reuse


【解决方案1】:

您可以创建一个新的service

public class MyHttpContextService : IMyHttpContextService
{
    IHttpContextAccessor _httpContext;

    public MyHttpContextService(IHttpContextAccessor httpContext)
    {
        _httpContext = httpContext;
    }

    public string CheckUserRoles()
    {
        try
        {
            var currentUser = _httpContext?.HttpContext?.Session?.GetCurrentUser<SessionContext>();
            if (currentUser != null)
            {
                if(currentUser.Roles.Any())
                {
                    if(!currentUser.Roles.Contains("Administrator"))
                    {
                        if(currentUser.Roles.Contains("Doctor"))
                        {
                            //do something here
                        }
                        else if (currentUser.Roles.Contains("Patient"))
                        {
                            //do something else here
                        }
                    }
                }
            }
            else
            {
                // if currentUser == null
            }
        }
        catch (Exception ex)
        {
            // exception handling
        }

    }
}

注意这条线

var currentUser = _httpContext.HttpContext.Session.GetCurrentUser<SessionContext>();

被替换为

var currentUser = _httpContext?.HttpContext?.Session?.GetCurrentUser<SessionContext>();

创建适当的interface

public interface IMyHttpContextService
{
    string CheckUserRoles();
}

在这个例子中,string 是返回类型,但它不是必须的。

最后,使用line注册这个服务

services.AddScoped<IMyHttpContextService, MyHttpContextService>();

services 在哪里

IServiceCollection services

您可以使用AddTransientAddSingleton,而不是AddScopedMore about objects' lifetime and dependency injection。这三个关键字决定了对象的生命周期,或者在这种情况下,服务的生命周期。

注册从Startup.cs 开始(但老实说,一切都从Startup.cs 开始,因此得名)。 More about Startup.cs。也就是说,在Startup.cs调用方法中

public void ConfigureServices(IServiceCollection services)

由运行时调用。

内部方法ConfigureServices调用另一个方法,例如MapInterfaces,用于接口映射并传递services。方法MapInterfaces 将是ServiceExtensions.cs 中的static 方法。

public static void MapInterfaces(IServiceCollection services)
{
    services.AddScoped<IMyHttpContextService, MyHttpContextService>();
}

更好的是创建一个扩展方法More about extension methods

ServiceExtensions.cs 是一个static 类,是创建扩展方法的条件。扩展方法也需要为static。这将是方法签名

static void MapInterfaces(this IServiceCollection services)

当然,不要忘记访问修饰符(至少与ServiceExtensions.cs 类具有相同的可见性)。注意this关键字。

然后像这样在Startup.csConfigureServices 方法中调用来自ServiceExtensions.cs 的扩展方法MapInterfaces

services.MapInterfaces();

最后,只要你需要方法CheckUserRoles,就这样调用它

_myHttpContextService.CheckUserRoles();

编辑:您更改了方法的实现,但这并没有改变您执行其余解决方案的方式。

【讨论】:

    【解决方案2】:

    这是一些用 Swift 编写的代码。 我正在使用面向函数的编程,带有字典


    struct User {
        var Roles: Set<String> = ["Doctor"]
    }
    
    func channel(user: User, _ roles: [String:() -> ()]) {
        for i in roles {
            if user.Roles.contains(i.key) { i.value() }
        }
    }
    
    let currentUser = User()
    channel(user: currentUser,
           [
            "Doctor": {
            // Code for doctor
            },
    
            "Admin": {
            // Code for admin
            },
    
            "Blah": {
            // Code for blah
            },
    
            // You can even add more
        ]
    )
    

    你可以枚举创建一个枚举
    为什么是枚举?
    您可以使用常规字符串轻松打错字
    对于 Enum,如果你打错字,Swift 会给你一个错误。超级有用!

    enum UserRolls { case doctor, admin, patient, other(String) }
    extension UserRolls: Hashable {}
    
    struct User {
        var Roles: Set<UserRolls> = [.doctor]
    }
    
    func channel(user: User, _ roles: [UserRolls:() -> ()]) {
        for i in roles {
            if user.Roles.contains(i.key) { i.value() }
        }
    }
    
    let currentUser = User()
    channel(user: currentUser,
           [
            .doctor: {
            // Code for doctor
            },
    
            .admin: {
            // Code for admin
            },
    
            .other("Blah"): {
            // Code for blah
            },
    
            // You can even add more
        ]
    )
    

    【讨论】:

      猜你喜欢
      • 2021-11-27
      • 2010-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-22
      • 2015-02-12
      相关资源
      最近更新 更多