5

目前我有一个这样的文件夹结构:

Area (folder)
 - Toolkit (folder)
    - Controllers (folder)
        - AdminController.cs
    - Views (folder)
        - Admin (folder)
           - Privledges (folder)
              - Create.cshtml
              - Edit.cshtml
              - Delete.cshtml

这转化为

/Toolkit/{controller}/{action}/{tool}/{id}

将操作设置为像控制器一样根据传递给操作的字符串 {tool} 参数和参数 {id} 提供视图是一种不好的做法吗?

我所说的实现:

    private const string FOLDER_PRIVILEGES = "./Privileges/";

    public ActionResult Privileges(string tool, string id = "")
    {
        dynamic viewModel = null;
        ToolViews view; // enum for the views
        // Parse the tool name to get the enum representation of the view requested
        bool isParsed = Enum.TryParse(tool, out view);

        if (!isParsed)
        {
            return HttpNotFound();
        }

        switch (view)
        {
            case ToolViews.Index:
                viewModel = GetIndexViewModel(); // call a function that gets the VM
                break;
            case ToolViews.Edit:
                viewModel = GetEditViewModelById(int.Parse(id)); // sloppy parse
                break;
            default:
                viewModel = GetIndexViewModel();
                break;
        }
        // The folder path is needed to reach the correct view, is this bad?
        // Should I just create a more specific controller even though it would
        // require making about 15-20 controllers?
        return View(FOLDER_PRIVILEGES + tool, viewModel);
    }

当我写一个视图时,我必须确保路径名称用于文件夹

@Html.ActionLink("Edit", "./Toolkit/Admin/Priveleges/Edit", "Admin", new { id = item.id })

这似乎是一种糟糕的做法,因为如果文件夹结构发生变化,则需要大量维护。

但是,如果我必须将操作分解为控制器,那么其中会有很多(几乎 20 个,随着时间的推移会增加更多)。

如果我正在做的是一种不好的做法,那么为这样的路线提供服务的最佳方式是什么?

/Toolkit/Admin/Privileges/Edit/1

我想避免执行以下操作:

/Toolkit/Admin/CreatePrivileges/1
/Toolkit/Admin/EditPrivileges/1
/Toolkit/Admin/DeletePrivileges/1

如果我没有任何意义,请告诉我,因为我很难用语言表达这个问题。

4

2 回答 2

1

我认为您正试图将违背其原始意图的约定强加到 MVC 中。

使用 MVC,你的控制器是一个名词,你的动作是一个动词。使用您的示例,您有:

  • 工具包(名词) - 区域
    • 管理员(名词?) - 子区域?<--这是一个有点时髦的
      • 特权(名词) - 控制器
        • 创造(动词)——行动
        • 编辑(动词) - 动作
        • 删除(动词) - 动作

如您所见,如果您可以将 Toolkit + Admin 视为区域 + 子区域,或者将它们组合成一个区域(TookitAdmin),它将使您回到控制器和操作的原始目的。

根据评论,听起来您可能已经决定走这条路。但是我想指出的是,您迂回地得出的结论是回到 MVC 的根源。

作为旁注,您是否考虑过迁移到 MVC4?它的Web API为 RESTful API 提供了更好的支持,听起来您可能正在尝试使用它。

于 2012-11-13T14:52:06.777 回答
1

不是原始问题的答案,但 OP 要求提供枚举约束的样本,而不必检查每个操作中的枚举。IE:

// Parse the tool name to get the enum representation of the view requested
bool isParsed = Enum.TryParse(tool, out view);

if (!isParsed)
{
    return HttpNotFound();
}

不必将枚举值(在本例中为工具)作为字符串接受,您可以强制该值进入您已经转换为适当枚举的操作。这样做的另一个好处是 MVC 框架将负责HttpNotFound在这种情况下返回正确的响应 ()。

这是您的约束方法。它接受任何类型的枚举。无需为每个 Enum 创建单独的约束。

public class EnumConstraint<T> : IRouteConstraint where T : struct
{
    private readonly HashSet<string> enumNames;
    public EnumConstraint()
    {
        string[] names = Enum.GetNames(typeof(T));
        this.enumNames = new HashSet<string>(from name in names select name.ToLowerInvariant());
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        return this.enumNames.Contains(values[parameterName].ToString().ToLowerInvariant());
    }

}

然后,在您的RegisterRoutes方法 (MVC4) 或 global.asax.cs 页面 (MVC3) 中,您只需像这样注册您的路线:

routes.MapRoute(
    url: "/Toolkit/Admin/{Action}/{id}",
    constraints: new { Action = new EnumConstraint<ToolViews>(), id = @"\d+" }
);

我还在id参数上添加了一个数字约束,以使您也不必解析它。

让我知道这对你有什么影响。

于 2012-11-13T18:30:07.093 回答