C# .NET MVC路由-绑定2个路由映射参数
我需要像下面这样解析一个urlC# .NET MVC路由-绑定2个路由映射参数,c#,asp.net-mvc,routes,C#,Asp.net Mvc,Routes,我需要像下面这样解析一个url /controller/action/subaction/id 目前,我正在使用开关的子动作,看看究竟需要做什么。例如: public ActionResult Members(string subaction, long id=0) { switch (subaction) { case "Details": var member = _payment.Ge
/controller/action/subaction/id
目前,我正在使用开关的子动作,看看究竟需要做什么。例如:
public ActionResult Members(string subaction, long id=0)
{
switch (subaction)
{
case "Details":
var member = _payment.GetMember(id);
return View("Members_details", member);
default:
var members = _payment.GetMembers().ToList();
return View("Members_list", members);
}
}
这是可行的,但我更希望每个事件都有单独的操作,直接从路由访问。如果可能的话,我想在routemap中结合动作和子动作来访问正确的动作
- /控制器/动作/将调用动作()
- /控制器/动作/子动作将调用动作\子动作()
- /控制器/动作/子动作/id将调用动作\子动作(id)
是否可以直接从routemap中执行此操作?您是说您实际上希望在同一控制器中使用多个“详细信息”操作?如果是这种情况,那么我认为这是开始拆分控制器的一个很好的理由 您可能应该从名为Members的控制器开始,该控制器包含操作详细信息和列表(或索引) 您是否有一个很好的逻辑理由将它们都放在同一个控制器中 或者,您可以调用操作MemberDetails和MemberList以及URL,如
/Controller/MemberDetails/ID
/Controller/MemberList/
给它一个密码:
[ActionName("Member/Details")]
public ActionResult Members_Details(int id){
return View();
}
自定义操作方法选择器类
如果我是你,我会编写一个操作方法选择器,并使用它来避免在操作中出现分支。我已经编写了一个将采用可选参数的操作分离开来的操作(从而避免了操作简化单元测试中的分支代码)。默认Asp.net MVC定义的路由具有可选的id
参数
{controller}/{action}/{id}
id = UrlParameter.Optional
因此,有两种行动方法是有意义的:
public ActionResult Index() { ... }
public ActionResult Index(int id) { ... }
我通过编写一个自定义操作选择器过滤器就完成了这一点。下面是一个示例,它描述了整个过程,并提供了一些您可以查看的代码
如何解决你的问题
在您的情况下,这意味着您必须编写一个名为SubactionAttribute
的自定义操作方法选择器类,然后简单地用它装饰您的操作:
[Subaction("Details")]
public ActionResult Members(long id)
{
var member = _payment.GetMember(id);
return View("Members.Details", member);
}
[Subaction] // no name would mean default subaction (when not provided)
public ActionResult Members()
{
var members = _payment.GetMembers().ToList();
return View("Members.List", members);
}
我不打算为你写整个课程,但我只会为你指出正确的方向,这样你就可以沿着同样的路径到达你要去的地方:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public sealed class SubactionAttribute : ActionMethodSelectorAttribute
{
#region Properties
/// <summary>
/// Gets subaction name.
/// </summary>
public string Name { get; private set; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="SubactionAttribute"/> class.
/// </summary>
public SubactionAttribute()
: this(null)
{
// does nothing
}
/// <summary>
/// Initializes a new instance of the <see cref="SubactionAttribute"/> class.
/// </summary>
/// <param name="subactionName">Sub-action name</param>
public SubactionAttribute(string subactionName)
{
this.Name = subactionName;
}
#endregion
#region ActionMethodSelectorAttribute implementation
/// <summary>
/// Determines whether the action method selection is valid for the specified controller context.
/// </summary>
/// <param name="controllerContext">The controller context.</param>
/// <param name="methodInfo">Information about the action method.</param>
/// <returns>
/// true if the action method selection is valid for the specified controller context; otherwise, false.
/// </returns>
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
// get the value of subaction here
string subName = /* this part you'll have to write */
// determine whether subaction matches
return this.Name == subName;
}
#endregion
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple=true,Inherited=true)]
公共密封类SubactionAttribute:ActionMethodSelectorAttribute
{
#区域属性
///
///获取子操作名称。
///
公共字符串名称{get;private set;}
#端区
#区域构造函数
///
///初始化类的新实例。
///
公共子动作属性()
:此(空)
{
//无所事事
}
///
///初始化类的新实例。
///
///子动作名称
公共子动作属性(字符串子动作名称)
{
this.Name=子动作名;
}
#端区
#区域操作方法SelectorAttribute实现
///
///确定操作方法选择对于指定的控制器上下文是否有效。
///
///控制器上下文。
///有关操作方法的信息。
///
///如果操作方法选择对指定的控制器上下文有效,则为true;否则为false。
///
公共覆盖布尔值是有效的请求(ControllerContext ControllerContext,MethodInfo MethodInfo)
{
如果(controllerContext==null)
{
抛出新ArgumentNullException(“controllerContext”);
}
//在这里获取subaction的值
string subName=/*您必须编写此部分*/
//确定子动作是否匹配
返回此名称。名称==子名称;
}
#端区
}
控制器是项目中的一种模块。一个项目可以有大约30个模块。这意味着我现在已经有30个控制器了。为每个动作创建一个控制器(比如每个模块/控制器5个)将产生150个控制器。另外,不同的控制器可以有相同的操作,这将导致不必要的控制器和URL命名,所以请使用我的替代示例。基本上,使用MVC,您有一个控制器级别和一个操作级别-没有其他级别,例如子操作,我不知道下面的操作是否有效,但尝试将此属性添加到您的操作中,看看会发生什么(这是一个很长的过程)。。。[见编辑后的答案!]@musefan:这肯定不行,因为路线是用斜线切割的。谢谢。我没有想过这样做,但这正是我所需要的。我认为它是完美的awnser,但在实现时,我发现了一个你在博客评论中也讨论过的缺陷:它不考虑重复。这意味着同时使用ID参数的子操作(“详细信息”)和子操作(“编辑”)将失败。@Hugo:实际上这不是问题。以不同的方式命名这些操作,然后对它们使用[ActionName(“SameName”)]
属性,以便它们在请求级别共享相同的名称。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public sealed class SubactionAttribute : ActionMethodSelectorAttribute
{
#region Properties
/// <summary>
/// Gets subaction name.
/// </summary>
public string Name { get; private set; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="SubactionAttribute"/> class.
/// </summary>
public SubactionAttribute()
: this(null)
{
// does nothing
}
/// <summary>
/// Initializes a new instance of the <see cref="SubactionAttribute"/> class.
/// </summary>
/// <param name="subactionName">Sub-action name</param>
public SubactionAttribute(string subactionName)
{
this.Name = subactionName;
}
#endregion
#region ActionMethodSelectorAttribute implementation
/// <summary>
/// Determines whether the action method selection is valid for the specified controller context.
/// </summary>
/// <param name="controllerContext">The controller context.</param>
/// <param name="methodInfo">Information about the action method.</param>
/// <returns>
/// true if the action method selection is valid for the specified controller context; otherwise, false.
/// </returns>
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
// get the value of subaction here
string subName = /* this part you'll have to write */
// determine whether subaction matches
return this.Name == subName;
}
#endregion
}