C# 处理控制器绑定角色解析的最佳方法

C# 处理控制器绑定角色解析的最佳方法,c#,asp.net-mvc,asp.net-core,roles,C#,Asp.net Mvc,Asp.net Core,Roles,我有一个模式,用于根据用户角色更改通用控制器的ViewResult。我经常重复使用这段代码,因为偶尔我需要添加ViewBag项来处理特殊情况 我不得不复制和粘贴代码,这让我很烦恼,但我想不出一种有效的方法来在控制器之外创建一个不需要大量技巧(在签名中传递控制器和ViewBag等)就能正常工作的类或方法 有没有正确的方法 public async Task<IActionResult> Index() { if (User.Identity.IsAuthenticated)

我有一个模式,用于根据用户角色更改通用控制器的
ViewResult
。我经常重复使用这段代码,因为偶尔我需要添加
ViewBag
项来处理特殊情况

我不得不复制和粘贴代码,这让我很烦恼,但我想不出一种有效的方法来在控制器之外创建一个不需要大量技巧(在签名中传递控制器和ViewBag等)就能正常工作的类或方法

有没有正确的方法

public async Task<IActionResult> Index()
{
    if (User.Identity.IsAuthenticated)
    {
        string email = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
        Profile profile = 
            await Helper.GetProfile(HttpContext, User.FindFirstValue(ClaimTypes.NameIdentifier));
        if (profile == null)
        {
            return RedirectToAction("Index", "Profile", new { exists = false });
        }
        else
        {
            switch (profile.Role)
            {
                case Role.VendorRepresentative:
                    ViewBag.Invoices = await Invoices.Instance.GetInvoicesByVendorRepIdAsync(profile.id);
                    return View("~/Views/Home/VendorRep.cshtml", profile);
                case Role.VendorCustomerService:
                    return View("~/Views/Home/VendorService.cshtml", profile);
                case Role.VendorSalesManager:
                    ViewBag.Invoices = new List<Invoice>();
                    return View("~/Views/Home/VendorManager.cshtml", profile);
                case Role.Distributor:
                    ViewBag.Invoices = new List<Invoice>();
                    return View("~/Views/Home/Distributor.cshtml", profile);
                default:
                    return View();
            }
        }
    }
    return View();
}
公共异步任务索引()
{
if(User.Identity.IsAuthenticated)
{
字符串email=User.Claims.FirstOrDefault(c=>c.Type==ClaimTypes.email)?.Value;
配置文件配置文件=
wait Helper.GetProfile(HttpContext,User.FindFirstValue(ClaimTypes.NameIdentifier));
if(profile==null)
{
返回RedirectToAction(“Index”,“Profile”,new{exists=false});
}
其他的
{
交换机(profile.Role)
{
案例角色。供应商代表:
ViewBag.Invoices=wait Invoices.Instance.getInvoicesbByvendorRepidasync(profile.id);
返回视图(“~/Views/Home/VendorRep.cshtml”,profile);
案例角色.VendorCustomerService:
返回视图(“~/Views/Home/VendorService.cshtml”,profile);
案例角色。供应商销售经理:
ViewBag.Invoices=新列表();
返回视图(“~/Views/Home/VendorManager.cshtml”,profile);
案例角色。分销商:
ViewBag.Invoices=新列表();
返回视图(“~/Views/Home/Distributor.cshtml”,profile);
违约:
返回视图();
}
}
}
返回视图();
}

这就是集中化流程时发生的情况。它必须包含标识每个消费者组的逻辑,并且必须包含每个消费者组的处理

重复使用同一个模型,然后将这些特定于消费者的“附加内容”附加到ViewBag,这一事实只能证明该模型不能代表该过程。当一个过程对每个消费群体只有很小的改变时,模型就像一个产品系列。每个组由一个变量表示。这些场景将鼓励您设计基础模型。例如,您可以将角色枚举与其各自的索引视图以及可能修改的操作相关联。要真正代表一个产品系列,您的模型应该为您正在倾倒的ViewBag项目分配空间

然而,标准化(集中化)变体的核心产品并不能防止需求冲突。管理者将希望模拟用户或给用户页面访问加上时间戳。一个组希望UI元素保存其他组无法访问的数据。产品系列模型一直工作到某一点,直到每个组的请求包含足够的处理,由于集中化的复杂性需要分离

与通过解释进行处理(需要阅读整个代码体以确定每个组的处理情况)不同,通过将请求转换为流程来解决问题

将流程中的每一步都视为消费者的索引请求。它们不仅仅是由对索引的web页面调用显式指定的,而且可能会发生变化。每个角色的索引请求实际上是它所表示的步骤的复合指令。因此,根据请求变量(角色)发出流程,并最终调用序列

VendorRepresentative
* Authenticate
* Load invoices
Index for VendorRepresentative role translates to -> Auth + LoadInvoices

VendorSalesManager
* Authenticate
* Instantiate invoices
Index for VendorSalesManager role translates to -> Auth + InstantiateInvoices

现在,如果需要添加另一个组,您的流程可以轻松增长。此外,如果用户需要控制来运行步骤(或不运行步骤,或为步骤指定值),此模型允许您将其参数直接映射到进程指令。

您是否考虑过使用
[Authorize]
属性?^^如果他们不在该角色中,这将向他们显示一个拒绝访问的页面。看起来他想根据角色动态更改视图。你可能想编写一个自定义过滤器,根据角色重定向到正确的操作。第一件事是保留代码S-O-L-I-D。因为每个场景都在做同样的事情,我会用多态性替换条件语句。这将是重构代码的一个良好开端,并将真正清除您可以使用的任何设计模式,这样您就不必复制和粘贴。filter属性可以像上面提到的那样很好地工作,但是我会首先清理条件语句
IHomeView
使用诸如“.GetView()和GetViewBag”之类的方法,以及诸如
homeVendorView:IHomeView
之类的类,我还将进行重构,将
httpContext
Helper
与一些IOC容器一起注入这些类构造函数中,这样您就不必为每个类传递它们。如果我有更多的时间,我可以试着做点什么。