2009-08-18 13 views
46

¿Alguien puede decirme cómo llamar a un método en un controlador diferente desde dentro de un método de acción? No quiero redirigir Quiero llamar a un método en un controlador diferente que devuelve una cadena y usar la respuesta dentro de mi método de acción..NET MVC Método de llamada en diferente controlador

+1

¿Cuál es el contexto? Puede haber una mejor manera de lograr lo que quieres. –

+1

Estoy usando IoC y tengo todos los datos de acceso pasando por mis controladores. Quiero recuperar una pieza específica de datos de usuario que está disponible a través de un controlador diferente. – user135498

+1

No sé mucho sobre IoC, pero quizás mover tu método a un ActionFilter podría ayudarte a hacer lo que quieras http://haacked.com/archive/2008/08/14/aspnetmvc-filters.aspx Esto sigue los principios de IoC en mi comprensión del mismo –

Respuesta

11

¿Podría simplemente crear una instancia del controlador en su método de acción y llamar al otro método que necesita?

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

    return View(); 
} 
+1

El caviet es que estoy usando Castle Windsor IoC que inyecta la cadena de conexión para el contexto de datos. Estoy luchando porque el marco mvc automáticamente intantia el controlador. – user135498

+7

Esta solución puede * funcionar *, pero no es elegante. –

2

Parece que está intentando hacer algo para lo que los controladores no están diseñados. Diseñe su método requerido como método público en alguna clase e invoque desde ambas acciones del controlador.

+0

Esto también se conoce como un servicio de aplicación. (http://wiki.sharparchitecture.net/SettingUpNorthwind.ashx) Normalmente pertenece a una capa de servicio, aunque podría refactorizarse en el modelo de dominio si los métodos son específicos del objeto de dominio. (http://martinfowler.com/eaaCatalog/serviceLayer.html) –

41

Suena como que debería refactorizar su aplicación, y extrae la funcionalidad que genera la cadena a una nueva clase separada (o reutiliza una clase existente, si tiene una que encaja) y deja que ambos controladores usen esa clase .

+1

también conocido como capa de servicio. (http://martinfowler.com/eaaCatalog/serviceLayer.html) http: //wiki.sharparchitecture.net/SettingUpNorthwind.ashx –

+12

Quizás la cadena que quiere generar es una cadena HTML que ya está siendo compilada por un controlador diferente. Considere el ejemplo de alimentar esta cadena luego en un generador de HTML a PDF. Invocar una acción del controlador y capturar el resultado de la vista en una secuencia me suena como una buena forma de hacerlo. – pettys

+1

Solo un pensamiento: crea un "supercontrolador" que herede y adhiera la funcionalidad común allí. – user230910

8

No he usado Castle Windsor IoC, pero la teoría es que deberías poder crear una clase de fábrica de Controlador personalizada, y luego ordenar al framework MVC que use esta fábrica de controlador personalizado, registrándolo en Global. asax.css archivo, en caso Application_Start:

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

[Ver Pro Marco Asp.Net MVC 2, Steven Sanderson, Apress, páginas 64 - 66]

esta manera, se puede crear instancias de los controladores de en cualquier parte de tu código.

La noción de NO llamar a las acciones de otro controlador desde el controlador "actual", o desde otro código es bastante incorrecta. Los controladores son solo clases. Solo se convierten en "Controladores" cuando MVC Framework los invoca de manera especial.

Por lo tanto, lo correcto e incorrecto de esto se reduce a POR QUÉ estás haciendo esto, no SI TENDRÍAS que hacerlo o no.

Si solo está utilizando un controlador como clase, entonces esto está bien. Si está intentando usar esto para enviar una respuesta al usuario, entonces debe usar un RedirectToAction como se sugirió anteriormente.

Existen varias razones para utilizar un controlador como clase en lugar de como controlador. Por ejemplo, cuando prueba su controlador. Por lo tanto, es necesario tratar a sus controladores como una clase en lugar de tratarlos de manera incorrecta.

Un ejemplo no escenario de la prueba de la utilización de un controlador como una Clase:

Estoy escribiendo un mini marco que aprovecha las capacidades de plantillas del marco MVC para producir el código HTML de correos HTML, algo que todas las aplicaciones web necesitan hacer, por una razón u otra (por ejemplo, correos electrónicos de confirmación de pedido).

En términos muy generales, se ejemplariza su MailManagerController (para simplificar, presumir que no está utilizando COI) en la acción de tu NormalController (que tiene que enviar un correo electrónico) y luego hacer:

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

Dónde RenderToString es una extensión método en ViewResultBase que representa la salida de una Acción (que devuelve un objeto ViewResultBase) a una cadena, y Postman es una clase estática que se ocupa de enviar correos electrónicos una vez que tiene el texto.

La belleza de esta técnica es que puede usar el marco MVC para producir correos electrónicos con plantillas, porque OrderConfirmation Action tendrá una vista asociada que no es nada si no una plantilla html para su correo electrónico que va a enviar.

+2

"Por lo tanto, lo correcto e incorrecto de esto se reduce a POR QUÉ estás haciendo esto, no SI TENDRÍAS que hacerlo o no. " Uno podría argumentar de manera muy diferente. La funcionalidad común a menudo puede y debe ser refactorizada en una capa de servicio. (http://martinfowler.com/eaaCatalog/serviceLayer.html) Esta partición lógica se ve en muchos lugares, incluida la pila de tecnología Grails MVC (consulte el excelente libro, Grails in Action) (http://www.grails.org). /doc/1.0.x/guide/8.%20The%20Service%20Layer.html) y SharpArchitecture .NET stack (http://wiki.sharparchitecture.net/SettingUpNorthwind.ashx) –

+0

Además, se podría argumentar que el MailManagerController aquí debería haber un servicio de aplicación que se inyecta en un controlador. Utilizando los principios de IoC: pubilc ActionResult SendMail() {mailService.sendMail (new OrderConfirmation (order)); // supongamos que el servicio ha sido inyectado por el contenedor IoC} –

+0

Me estoy acercando a una necesidad similar: un pequeño poco de funcionalidad seleccionada de la acción de un controlador. De hecho, específicamente se refiere a una función de administrador de correo. Sería útil escuchar más ideas sobre los méritos de los enfoques anteriores. – justSteve

10

Puede lograrlo a través del método Action de HtmlHelper.

En una vista, que lo haría así:

@Html.Action("OtherAction") 

Sin embargo, no es sencillo obtener una instancia de HtmlHelper en un método de acción (por diseño). De hecho, es un truco tan horrible que soy reacio a incluso publicarlo ...

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"); 

Esto funciona en MVC 3. Es posible que tenga que quitar la arg StringWriter del ViewContext constructor para MVC 2, IIRC.

</piratear>

+1

Para obtener el método 'Acción', también necesita agregar una referencia de uso a System.Web.Mvc.Html. – JasonRShaver

+0

¿Qué es ControllerContext? ¿Dónde conseguirlo? –

+0

Dan, lo obtiene del controlador actual, que es al que está llamando al otro controlador desde ... –

-5

que estaba buscando lo mismo, pero en serio la gente, por eso la necesidad de escribir estas respuestas complicadas.

Aquí hay un post que responderá de manera muy simple: Using Html.ActionLink to call action on different controller

Básicamente sólo hay que utilizar esta sobrecarga de la ActionLink: ActionLink(HtmlHelper, String, String, String, Object, Object)

por lo que tendrá: ActionLink("linkText", "actionName", "controllerName", routeValues, htmlAttributes)

Si no tiene ningún valor de ruta (que son las entradas para la acción) o htmlAttributes, debe establecerlos como nulos.

He aquí un ejemplo de llamada: @Html.ActionLink("Add New Student", "Create", "Student", null, new { @class = "btn btn-primary" })

+0

Desafortunadamente, esta respuesta tiene cero que ver con la pregunta real. –

21

Se puede utilizar el siguiente método para invocar un método sobre el otro controlador:

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

Esto funcionó para mí en ASP.NET MVC5. Espero que funcione también para ti.

+0

El problema con esto es que no hay Contexto. Entonces, si está usando, diga "Server.MapPath (...." por ejemplo, error porque el Servidor no es nada. –

Cuestiones relacionadas