当前我有一个像这样的文件夹结构:
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} parameter和参数{id}传递给操作? <</strong> <</strong>
我在说什么的实现:
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
请让我知道我是否没有任何意义,因为我很难将这个问题插入文字中。
我认为您正在试图将惯例迫使其违背其主观意图的MVC。
使用MVC,您的控制器是一个名词,您的动作是动词。使用您的示例,您有:
- 工具包(名词) - 区域
- 管理员(名词?) - 子区域?&lt; - 这是一个有点时髦的
- 特权(名词) - 控制器
- 创建(动词) - 动作
- 编辑(动词) - 动作
- 删除(动词) - 动作
- 特权(名词) - 控制器
- 管理员(名词?) - 子区域?&lt; - 这是一个有点时髦的
您可以看到,如果您可以将工具包 admin视为区域 Subarea,或将它们合并到一个区域(Takeitadmin),它将使您回到控制器和动作的原始目的。
根据评论,听起来您可能决定这样做。但是我想指出,您以圆形方式得出的结论是回到MVC的根源。
作为旁注,您是否考虑过搬到MVC4?它的Web API为RESTFUL API提供了更好的支持,听起来您可能正在尝试实现。
不是对原始问题的答案,但是OP要求提供枚举约束的样本,而不必检查每个动作中的枚举。即:
// 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
)。
这是您的约束方法。它接受任何类型的枚举。无需为每个枚举创建一个单独的约束。
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
参数添加了一个数字约束,以节省您必须解析。
让我知道这是如何为您服务的。