有没有一种方法可以在不必覆盖整个方法的情况下覆盖动作方法中的属性?

5

我正在使用MVC 5中的属性路由,但我开始注意到一个痛点。我的情况是,我想要子类化控制器,因为所有的操作都将执行相同的操作。然而,显然我需要为子类的操作使用不同的路由。目前,我正在做类似于以下的事情:

public class FooController : Controller
{
    [Route("foo", Name = "Foo")]
    public virtual ActionResult Foo()
    {
        ...

        return View();
    }
}

public class BarController : FooController
{
    [Route("bar", Name = "Bar")]
    public override ActionResult Foo()
    {
        return base.Foo();
    }
}

这对我来说似乎很糟糕。我不会重复实际操作方法的代码(在某些情况下,这可能相当多),但这让我感觉不对劲。此外,在基本操作方法定义因某些原因更改的情况下,这将成为一种维护上的噩梦。是否有一些我没有注意到的通用方法来更改属性而不必覆盖方法?也许是某些特定于属性路由的方法。还是我只是运气不好?


4
我认为你运气不太好。由于属性是在程序集元数据中定义的,如果你没有一个“存根”方法来装饰属性,那么你就不能更改它。这可能是一个情况,使用标准路由机制比使用属性路由更好。 - Nathan A
我已经删除了我的回答,并同意Nathan的观点。 - jamesSampica
2个回答

0

我知道我来晚了一百万年,但我会将两个控制器之间的共同代码抽象成一个抽象控制器类,然后在Foo和Bar控制器上继承该类。然后你可以覆盖每个控制器中需要不同的方法,并为它们在派生控制器中设置属性,或者根本不将需要被覆盖的方法放入基础控制器类中。无论如何,我可能会选择通过Routing.config的方式指定路由名称等,而不是通过属性的方式。

编辑

你原本拥有的

public class FooController : Controller
{
    [Route("foo", Name = "Foo")]
    public virtual ActionResult Foo()
    {
        ...

    return View();
    }
}

public class BarController : FooController
{
    [Route("bar", Name = "Bar")]
    public override ActionResult Foo()
    {
        return base.Foo();
    }
}

我所建议的

public abstract class _baseController : Controller
{
    public ActionResult ActionThatDoesNotNeedToBeOverridden()
    {
        ...
        return View();
    }

    public virtual ActionResult Foo()
    {
        ...
        return View();
    }
}

public class FooController : _baseController
{
    [Route("foo", Name = "Foo")]
    public override ActionResult Foo()
    {
        return base.Foo();
    }
}

public class BarController : _baseController
{
    [Route("bar", Name = "Bar")]
    public override ActionResult Foo()
    {
        return base.Foo();
    }
}

编辑2 如果您不想覆盖或烦扰路由,可以这样做

public class _baseController : Controller
{
    public ActionResult Foo()
    {
        ...
        return View();
    }
}

public class BarController : Controller
{
    public ActionResult Bar()
    {
        var b = new _baseController();
        return b.Foo();
    }
}

抱歉,但我不确定这与我的做法有什么不同。代码被封装在一个抽象的基本控制器中。问题是,我仍然必须覆盖该方法,即使只是为了调用基本方法,以应用新属性。确实,标准路由可以避免这个问题,但整个问题是如何绕过这个问题,同时仍然使用属性路由 - Chris Pratt
我认为我的观点是,在基类中不会有任何路由属性,而只会在派生的FooController和BarController中应用它们。这样,每个控制器中重写的方法最终只会有一个附加到它们上的路由属性集合。 - Kevin Heidt
那我可能有点困惑了。你的代码示例中有一个名为Foo的方法的FooController,它具有路由属性,然后有一个BarController继承自FooController并覆盖了Foo方法,并具有另一个路由属性。因此,BarController中的Foo方法实际上有两个路由属性。我将在编辑中更新我的答案,以展示我所说的内容,然后你告诉我你的代码是否相同。 - Kevin Heidt
更新了我的回答,请告诉我是否有误。 - Kevin Heidt
抱歉,我们有点绕口令了。我的示例代码有点牵强附会,并且我确实展示了基类上的属性。然而,那从来不是真正的问题。我的问题在于必须重写方法,没有其他原因,只是为了应用属性。你的代码对此没有任何帮助。 - Chris Pratt
显示剩余3条评论

0

感谢尝试,但这并没有解决问题。实际上,它并没有做任何有用的事情,因为每个单独的控制器都有一个常规的路由前缀。事实上,路由属性中唯一引起问题的是 Name,因为如果我仅仅是子类化控制器,就会出现多个名为 Foo 的路由的错误。如果我不命名任何路由,那么只要每个控制器中每个操作使用相同的路由部分,它实际上可以正常工作。但实际上,在我的情况下,我确实需要为路由命名。 - Chris Pratt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接