2009-08-18 20 views
46

Czy ktoś może mi powiedzieć, jak wywołać metodę na innym kontrolerze w ramach metody działania? Nie chcę przekierowywać. Chcę wywołać metodę na innym kontrolerze, który zwraca ciąg znaków i użyć odpowiedzi w ramach mojej metody działania..NET MVC Metoda wywołania na innym kontrolerze

+1

Jaki jest kontekst? Może istnieć lepszy sposób na osiągnięcie tego, co chcesz. –

+1

Używam IoC i mam dostęp do wszystkich danych przez moje kontrolery. Chcę pobrać konkretną część danych użytkownika, która jest dostępna za pośrednictwem innego kontrolera. – user135498

+1

Nie wiem zbyt wiele o IoC, ale może przeniesienie metody do ActionFilter może pomóc Ci zrobić to, co chcesz http://haacked.com/archive/2008/08/14/aspnetmvc-filters.aspx Jest to zgodne z zasadami IoC w moim rozumieniu. –

Odpowiedz

11

Możesz tylko utworzyć instancję kontrolera w swojej metodzie akcji i wywołać inną metodę, której potrzebujesz?

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

    return View(); 
} 
+1

W cavie używam IoC Castle Windsor, który wstrzykuje ciąg połączenia dla kontekstu danych. Walczę, ponieważ framework mvc automatycznie intantuje kontroler. – user135498

+7

To rozwiązanie może * działać *, ale jest nieeleganckie. –

2

Wygląda na to, że próbujesz zrobić coś, do czego nie są przeznaczone kontrolerzy. Zaprojektuj wymaganą metodę jako metodę publiczną w niektórych klasach i wywołaj z obu działań kontrolera.

+0

Jest to tak zwana usługa aplikacji. (http://wiki.sharparchitecture.net/SettingUpNorthwind.ashx) Zazwyczaj jest to warstwa usługowa, ale można ją przekształcić w model domeny, ponieważ metody są specyficzne dla domeny. (http://martinfowler.com/eaaCatalog/serviceLayer.html) –

41

Dźwięki w moich uszach, tak jak powinieneś refaktoryzować swoją aplikację i wyodrębnić funkcjonalność, która generuje ciąg do nowej oddzielnej klasy (lub ponownie użyć istniejącej klasy, jeśli masz taką, która pasuje) i pozwolić obu kontrolerom użyć tej klasy .

+1

znany również jako Warstwa usług. (http://martinfowler.com/eaaCatalog/serviceLayer.html) http: //wiki.sharparchitecture.net/SettingUpNorthwind.ashx –

+12

Być może ciąg, który chce wygenerować, jest łańcuchem HTML, który jest już tworzony przez inny kontroler. Zastanówmy się nad przykładem podania tego ciągu do generatora HTML na PDF. Wywołanie akcji kontrolera i przechwycenie wyniku widoku powoduje, że ciąg brzmi jak dobry sposób na zrobienie tego. – pettys

+1

Pomyśl tylko: Stwórz "SuperControllera", który dziedziczy i umieści w nim wspólną funkcjonalność. – user230910

8

Nie użyłem Castle Windsor IoC, ale teoria mówi, że powinieneś być w stanie stworzyć niestandardową klasę Factory kontrolera, a następnie poinstruować framework MVC, aby użył tej niestandardowej fabryki kontrolerów, rejestrując ją w Global. asax.css plik, w przypadku Application_Start:

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

[Zobacz Pro Asp.Net MVC 2 Framework, Steven Sanderson, Apress, strony 64 - 66]

w ten sposób można utworzyć wystąpienia z kontrolerów w dowolnym miejscu w kodzie.

Pojęcie NIE wywoływania akcji innego kontrolera z "bieżącego" kontrolera lub z innego kodu jest całkowicie błędne. Kontrolery to tylko klasy. Stają się one jedynie "kontrolerami", gdy są wywoływane w specjalny sposób przez MVC Framework.

Dlatego też, dobro i zło tego sprowadza się do DLACZEGO robisz to, a nie CZY Trzeba, czy nie.

Jeśli używasz kontrolera jako klasy, to jest w porządku. Jeśli próbujesz użyć tego do wysłania odpowiedzi do użytkownika, powinieneś użyć metody RedirectToAction, jak zasugerowano powyżej.

Istnieje kilka powodów, aby używać kontrolera jako klasy, a nie jako kontrolera. Na przykład podczas testowania kontrolera. Dlatego leczenie swoich kontrolerów jako klasy jest konieczne, w przeciwieństwie do zła.

Non Przykładowy scenariusz testowania przy użyciu kontrolera jako klasę:

piszę mini ramy, który wykorzystuje możliwości szablonów MVC Framework produkować HTML dla wiadomości e-mail w formacie HTML, coś, że wszystkie aplikacje internetowe potrzebne do zrobienia, z tego czy innego powodu (np. e-maile z potwierdzeniem zamówienia).

grubsza, to instancję swoje MailManagerController (dla uproszczenia przyjmijmy, że nie używasz IOC) w swoim działaniu NormalController'S (który musi wysłać e-mail), a następnie wykonaj:

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

Gdzie RenderToString jest rozszerzeniem metoda na ViewResultBase, która renderuje wynik działania (zwracającego obiekt ViewResultBase) do łańcucha znaków, a Postman jest klasą statyczną, która zajmuje się wysyłaniem wiadomości e-mail po otrzymaniu tekstu.

Piękno tej techniki polega na tym, że można używać szkieletu MVC do tworzenia szablonów wiadomości e-mail, ponieważ akcja OrderConfirmation będzie miała skojarzony widok, który jest niczym, jeśli nie jest szablonem html dla wiadomości e-mail, którą zamierzasz wysłać.

+2

"Zatem, dobro i zło tego sprowadza się do DLACZEGO robisz to, a nie cokolwiek powinieneś lub nie. " Można argumentować bardzo odmiennie. Typowa funkcja często może i powinna być refaktoryzowana w warstwie serwisowej. (http://martinfowler.com/eaaCatalog/serviceLayer.html) Ten partycjonowanie logiczne jest widoczne w wielu miejscach, w tym stosie technologii Grails MVC (zobacz wspaniałą książkę Grails in Action) (http://www.grails.org /doc/1.0.x/guide/8.%20The%20Service%20Layer.html) i stosu SharpArchitecture .NET (http://wiki.sharparchitecture.net/SettingUpNorthwind.ashx) –

+0

Dodatkowo można argumentować, że MailManagerController tutaj powinna być usługa aplikacji, która jest wstrzykiwana do kontrolera. Korzystanie z zasad IoC: pubilc ActionResult SendMail() {mailService.sendMail (new OrderConfirmation (kolejność)); // zakładam, że usługa została wstrzyknięta przez kontener IoC} –

+0

Zbliżam się do podobnej potrzeby - jednego małego wyboru funkcjonalności z działania jednego kontrolera. W rzeczywistości dotyczy to szczególnie roli menedżera poczty. Byłoby pomocne usłyszeć więcej przemyśleń na temat zalet powyższych podejść. – justSteve

10

Można to osiągnąć za pomocą metody Action z HtmlHelper.

W widoku, byś zrobił to tak:

@Html.Action("OtherAction") 

Jednak nie jest to łatwe do uzyskania instancję HtmlHelper w sposobie działania (wg projektu). W rzeczywistości jest to takie straszne siekać, że jestem niechętny, aby nawet po to ...

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

Działa to na MVC 3. Być może trzeba usunąć StringWriter Arg od konstruktora ViewContext dla MVC 2, IIRC.

</siekać>

+1

Aby uzyskać metodę "działania", należy również dodać odwołanie do pliku System.Web.Mvc.Html. – JasonRShaver

+0

Co to jest ControllerContext? Skąd je wziąć? –

+0

dan, otrzymujesz go od bieżącego kontrolera, czyli od tego, z którym wywołujesz drugi kontroler od ... –

-5

Szukałem tego samego, ale poważnie ludzi, dlaczego trzeba pisać takich skomplikowanych odpowiedzi.

Oto post, który będzie go odpowiedzieć bardzo prosto: Using Html.ActionLink to call action on different controller

Zasadniczo po prostu trzeba użyć tego przeciążenie actionlink: ActionLink(HtmlHelper, String, String, String, Object, Object)

Więc trzeba będzie: ActionLink("linkText", "actionName", "controllerName", routeValues, htmlAttributes)

Jeśli nie masz żadnych parametrów routeValues ​​(które są wejściami do działania) lub htmlAttributes, musisz ustawić je jako null.

Oto przykład połączenia: @Html.ActionLink("Add New Student", "Create", "Student", null, new { @class = "btn btn-primary" })

+0

Niestety, ta odpowiedź ma zero wspólnego z faktycznym pytaniem. –

21

Można używać następujące podejście do wywołania metody na drugim kontrolerze:

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

ten pracował dla mnie w ASP.NET MVC5. Mam nadzieję, że będzie działać również dla Ciebie.

+0

Problem polega na tym, że nie ma kontekstu. Więc jeśli używasz, powiedz "Server.MapPath (...." na przykład, będzie to błąd, ponieważ serwer jest niczym. –

Powiązane problemy