不同控制器上的.NET MVC调用方法

Posted

技术标签:

【中文标题】不同控制器上的.NET MVC调用方法【英文标题】:.NET MVC Call method on different controller 【发布时间】:2010-11-20 18:24:36 【问题描述】:

谁能告诉我如何在动作方法中调用不同控制器上的方法?我不想重定向。我想在返回字符串的不同控制器上调用一个方法,并在我的操作方法中使用响应。

【问题讨论】:

上下文是什么?可能有更好的方法来实现您想要的。 我正在使用 IoC 并且所有数据访问都通过我的控制器。我想检索可通过不同控制器获得的特定用户数据。 我对 IoC 不太了解,但也许将您的方法移至 ActionFilter 可以帮助您做您想做的事haacked.com/archive/2008/08/14/aspnetmvc-filters.aspx 这符合我对 IoC 的理解的原则 你指的是哪个版本的MVC? 【参考方案1】:

听起来你应该重构你的应用程序,并将生成字符串的功能提取到一个新的单独类中(或重用现有类,如果你有一个合适的类)并让两个控制器都使用该类。

【讨论】:

也称为服务层。 (martinfowler.com/eaaCatalog/serviceLayer.html)wiki.sharparchitecture.net/SettingUpNorthwind.ashx 也许他想要生成的字符串是一个 HTML 字符串,它已经由不同的控制器构建。考虑将此字符串输入 HTML 到 PDF 生成器的示例。调用控制器操作并以字符串形式捕获视图结果在我看来是一种好方法。 只是一个想法:制作一个“超级控制器”,既继承自其中,又将常用功能保留在其中..【参考方案2】:

您可以使用以下方法调用另一个控制器上的方法:

var otherController = DependencyResolver.Current.GetService<OtherController>();
var result = otherController.SomeMethod();

这在 ASP.NET MVC5 中对我有用。希望它也对你有用。

【讨论】:

这个问题是没有上下文。因此,如果您正在使用,例如说“Server.MapPath(....”,它将出错,因为 Server 什么都不是。【参考方案3】:

您可以通过HtmlHelperAction 方法实现此目的。

在视图中,你会这样做:

@Html.Action("OtherAction")

但是,在操作方法中获取HtmlHelper 的实例并不简单(按设计)。事实上,这是一个非常可怕的 hack,我什至都不愿意发布它......

var htmlHelper = new HtmlHelper(new ViewContext(
                                      ControllerContext, 
                                      new WebFormView(ControllerContext, "HACK"),
                                      new ViewDataDictionary(),
                                      new TempDataDictionary(),
                                      new StringWriter()),
                                new ViewPage());

var otherViewHtml = htmlHelper.Action("ActionName", "ControllerName");

这适用于 MVC 3。您可能需要从 MVC 2 IIRC 的 ViewContext 构造函数中删除 StringWriter arg。

【讨论】:

要获取 'Action' 方法,还需要添加对 System.Web.Mvc.Html 的 using 引用。 什么是 ControllerContext ?去哪里买? dan,你从当前控制器中得到它,也就是你正在调用另一个控制器的那个...... 再次,问题是如何从另一个控制器调用控制器中的方法。这个答案与问题无关。【参考方案4】:

您可以在您的操作方法中实例化控制器并调用您需要的其他方法吗?

public ActionResult YourActionMethod()

   SomeController c = new SomeController();
   ActionResult result = c.SomeMethod();

   return View();

【讨论】:

我正在使用 Castle Windsor IoC,它为数据上下文注入连接字符串。我很挣扎,因为 mvc 框架会自动实例化控制器。【参考方案5】:

我没用过Castle Windsor IoC,但是理论上你应该可以创建一个自定义的Controller工厂类,然后通过在Global.asax中注册来指示MVC框架使用这个自定义的控制器工厂.css 文件,在 Application_Start 事件中:

protected void Application_Start()

   RegisterRoutes(RouteTable.Routes);
   ControllerBuilder.Current.SetControllerFactory(new MyCustomControllerFactor());

[参见 Pro Asp.Net MVC 2 Framework,Steven Sanderson,Apress,第 64 - 66 页]

这样,您可以在代码中的任何位置实例化您的控制器。

不从“当前”控制器或其他代码调用另一个控制器的操作的概念是完全错误的。控制器只是类。它们只有在被 MVC 框架以特殊方式调用时才成为“控制器”。

因此,这件事的对与错归结为你为什么要这样做,而不是你是否应该这样做。

如果您只是将控制器用作类,那么这很好。如果您尝试使用它向用户发送响应,那么您应该使用上面建议的 RedirectToAction。

将控制器用作类而不是控制器的原因有很多。例如,在测试您的控制器时。因此,将控制器视为一个类是必要的,而不是错误的。

使用Controller作为类的非测试场景示例:

我正在编写一个迷你框架,它利用 MVC 框架的模板功能为 HTML 电子邮件生成 HTML,这是所有 Web 应用程序都需要做的事情,出于某种原因(例如,订单确认电子邮件)。

非常粗略地,您在 NormalController 的操作(需要发送电子邮件)中实例化 MailManagerController(为简单起见,假设您没有使用 IoC),然后执行以下操作:

MailManagerController mailmanager = new MailManagerController();
string html = mailmanager.OrderConfirmation(order).RenderToString();
Postman.SendEmail(html, order.UserEmailAddress, "MyApp order confirmation");

其中 RenderToString 是 ViewResultBase 上的扩展方法,它将 Action 的输出(返回 ViewResultBase 对象)呈现为字符串,而 Postman 是一个静态类,一旦您拥有文本就可以处理发送电子邮件。

这种技术的美妙之处在于您可以使用 MVC 框架来生成模板化的电子邮件,因为 OrderConfirmation Action 将有一个关联的视图,如果不是您要发送的电子邮件的 html 模板,它就什么都不是。

【讨论】:

“因此,这件事的对错归结为你为什么要这样做,而不是你是否应该这样做。”人们可能会提出非常不同的论点。通用功能通常可以而且应该重构为服务层。 (martinfowler.com/eaaCatalog/serviceLayer.html) 这种逻辑分区在很多地方都可以看到,包括 Grails MVC 技术堆栈(请参阅优秀书籍,Grails in Action)(grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.html) 和 SharpArchitecture .NET 堆栈 (wiki.sharparchitecture.net/SettingUpNorthwind.ashx) 另外,有人可能会争辩说这里的 MailManagerController 应该是一个注入到控制器中的应用程序服务。使用 IoC 的原则: pubilc ActionResult SendMail() mailService.sendMail(new OrderConfirmation(order)); // 假设服务已经被 IoC 容器注入 我正在接近一个类似的需求 - 从一个控制器的操作中选择一点点功能。实际上,专门针对 Mail Manager 角色。听到更多关于上述方法优点的想法会很有帮助。 @justSteve,我发布了一个答案,展示了如何在控制器中执行此操作。这很丑,但这是你能得到的最好的,afaik。【参考方案6】:

看起来您正在尝试做一些控制器不适合做的事情。 将您需要的方法设计为某个类中的公共方法,并从两个控制器操作中调用。

【讨论】:

这也称为应用服务。 (wiki.sharparchitecture.net/SettingUpNorthwind.ashx) 它通常属于服务层,尽管您可以重构为域模型,因为方法是特定于域对象的。 (martinfowler.com/eaaCatalog/serviceLayer.html)【参考方案7】:

我一直在寻找同样的东西,但认真的人,为什么需要写这么复杂的答案。

这是一个可以非常简单地回答它的帖子: Using Html.ActionLink to call action on different controller

基本上你只需要使用这个动作链接的重载: ActionLink(HtmlHelper, String, String, String, Object, Object)

所以你将拥有: ActionLink("linkText", "actionName", "controllerName", routeValues, htmlAttributes)

如果您没有任何 routeValues(这是 Action 的输入)或 htmlAttributes,则必须将它们设置为 null。

这是一个示例调用: @Html.ActionLink("Add New Student", "Create", "Student", null, new @class = "btn btn-primary" )

【讨论】:

ActionLink 用于生成&lt;a&gt; 标签,它返回的只是IHtml,它实际上并没有回答所提出的问题,即如何调用一个动作。您的答案是如何生成 HTML 链接。 不幸的是,这个答案与实际问题的关系为零。

以上是关于不同控制器上的.NET MVC调用方法的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET MVC 中:从 Razor 视图调用控制器操作方法的所有可能方式

我如何在不同的控制器中调用方法,包括使用 mvc 6 的参数

我应该将 BLL 方法直接调用到我的 Asp.Net MVC 3 控制器中吗?

ASP.NET MVC 4 视图

ASP.net MVC - 视图上的多个表单,每个调用不同的操作,但需要再次显示相同的视图

ASP.NET MVC API 操作返回 404,所有其他操作都有效