2009-08-18 91 views
46

任何人都可以告诉我如何从一个操作方法内的另一个控制器上调用一个方法吗?我不想重定向。我想在不同的控制器上调用一个方法,该方法返回一个字符串并在我的操作方法中使用响应。在不同的控制器上的.NET MVC调用方法

+1

什么是上下文?可能有更好的方法来达到你想要的。 – 2009-08-18 21:45:40

+1

我正在使用IoC,并通过我的控制器访问所有数据。我想要检索通过不同控制器可用的特定用户数据。 – user135498 2009-08-18 22:01:21

+1

我不知道很多关于IoC的知识,但是可能将您的方法移动到ActionFilter可以帮助您做你想做的事情http://haacked.com/archive/2008/08/14/aspnetmvc-filters.aspx这遵循原则IoC对我的理解 – 2009-08-18 22:56:36

回答

11

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

public ActionResult YourActionMethod() 
{ 
    SomeController c = new SomeController(); 
    ActionResult result = c.SomeMethod(); 

    return View(); 
} 
+1

该caviet是我使用Castle Windsor IoC注入数据上下文的连接字符串。我很挣扎,因为mvc框架会自动化化控制器。 – user135498 2009-08-18 21:52:19

+7

该解决方案可以*工作*,但它不雅观。 – 2010-10-22 18:18:20

2

看起来你正在试图做一些控制器不是为了设计的。 在某些类中将您所需的方法设计为公共方法,并从两个控制器操作中调用。

+0

这也被称为应用程序服务。 (http://wiki.sharparchitecture.net/SettingUpNorthwind.ashx)它通常属于服务层,但您可以重构到域模型中,方法是Domain Object Specific。 (http://martinfowler.com/eaaCatalog/serviceLayer.html) – 2010-10-22 18:17:12

41

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

+1

也被称为服务层。 (http://martinfowler.com/eaaCatalog/serviceLayer.html)http://wiki.sharparchitecture。net/SettingUpNorthwind.ashx – 2010-10-22 18:25:32

+12

也许他想要生成的字符串是一个已由另一个控制器构建的HTML字符串。考虑将此字符串提供给HTML生成器的示例。调用一个控制器动作并捕获字符串中的视图结果听起来像是一种很好的方法。 – pettys 2011-04-20 13:57:16

+1

只是一个想法:做一个“超级控制器”,既继承,并坚持共同功能在那里.. – user230910 2015-04-12 06:41:57

8

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

protected void Application_Start() 
{ 
    RegisterRoutes(RouteTable.Routes); 
    ControllerBuilder.Current.SetControllerFactory(new MyCustomControllerFactor()); 
} 

[见临Asp.Net MVC 2框架,史蒂芬·桑德森,Apress出版,页64 - 66]

这样的话,你可以从你的实例化控制器代码中的任何地方。

从“当前”控制器或从其他代码调用另一个控制器的操作的概念是非常错误的。控制器只是类。当MVC框架以特殊方式调用它们时,它们只会成为“控制器”。

因此,这是正确的和错误的归结为什么你这样做,而不是你是否应该。

如果你只是使用控制器作为一个类,那么这很好。如果您尝试使用此功能向用户发送响应,则应如上所述使用RedirectToAction。

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

使用控制器作为一个类的非测试场景例如:

我写一个利用MVC框架的模板功能来产生HTML邮件的HTML迷你框架,所有的Web应用程序需要的东西出于某种原因(例如订单确认电子邮件)。

大致来说,你实例化MailManagerController(为简单起见,假设你没有使用IOC)在NormalController的行动(即需要发送电子邮件),然后执行:

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模板,该视图就是无关紧要的。

+2

“因此,这是正确和错误归结为什么你这样做,而不是你是否应该或不。 “人们可能会有很大的不同。通常的功能通常可以并且应该被重构为服务层。 (http://martinfowler.com/eaaCatalog/serviceLayer.html)在许多地方都可以看到这种逻辑分区,包括Grails MVC技术栈(请参阅优秀的书,Grails in Action)(http://www.grails.org /doc/1.0.x/guide/8.%20The%20Service%20Layer.html)和SharpArchitecture .NET栈(http://wiki.sharparchitecture.net/SettingUpNorthwind.ashx) – 2010-10-22 18:19:16

+0

此外,有人可能会争辩说,MailManagerController这里应该是一个注入控制器的应用程序服务。使用IoC的原则:pubilc ActionResult SendMail(){mailService.sendMail(new OrderConfirmation(order)); //假设服务已被IoC容器注入} – 2010-10-22 18:23:39

+0

我正在接近类似的需求 - 从一个控制器的动作中选择一点功能。实际上,特别关注邮件管理器角色。听取更多关于上述方法优点的想法会有所帮助。 – justSteve 2010-11-30 18:52:45

10

您可以通过方法HtmlHelper来实现此目的。但是它不是简单的一个动作方法(设计)获得的HtmlHelper实例

@Html.Action("OtherAction") 

在视图中,你会做这样的。事实上,它是这样一个可怕的黑客,我不愿意,甚至张贴...

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,你可能需要从ViewContext构造函数删除StringWriter ARG的MVC 2,IIRC。

< /黑客>

+1

要获得'Action'方法,还需要添加对System.Web.Mvc.Html的使用引用。 – JasonRShaver 2012-05-14 20:18:10

+0

什么是ControllerContext?从哪里得到它? – 2012-06-28 03:20:55

+0

丹,你从当前的控制器得到它,那是你从另一个控制器调用的那个... – 2012-08-01 12:35:36

-5

我一直在寻找同样的事情,但严重的人,为什么需要写这样复杂的答案。

这里有一个帖子说会回答很干脆: Using Html.ActionLink to call action on different controller

基本上你只需要使用ActionLink的这个过载: 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" })

+0

不幸的是,这个答案与实际问题无关。 – 2016-09-30 19:04:51

21

您可以用下面的办法来调用一个方法的其他控制器上:

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

这在ASP.NET MVC5为我工作。希望它也能为你工作。

+0

与此有关的问题是没有上下文。所以如果你使用的话,比如说“Server.MapPath(....”),它会出错,因为服务器什么都不是。 – 2016-09-30 19:03:41

相关问题