Cara memanggil pengontrol lain Tindakan Dari pengontrol di Mvc

153

Saya perlu memanggil action B controller FileUploadMsgView dari Controller A dan perlu melewati parameter untuk itu.

 Code---its not going to the controller B's FileUploadMsgView().
    In ControllerA
  private void Test()
    {

        try
        {//some codes here
            ViewBag.FileUploadMsg = "File uploaded successfully.";
            ViewBag.FileUploadFlag = "2";

            RedirectToAction("B", "FileUploadMsgView", new { FileUploadMsg = "File   uploaded successfully" });
        }

     In ControllerB receiving part
  public ActionResult FileUploadMsgView(string FileUploadMsg)
    {
         return View();
    }
pengguna2156088
sumber
3
Saya tahu pertanyaan ini sudah tua tetapi menurut saya Anda harus menandai jawaban dari ed chapel sebagai yang terbaik, ikatan ties seperti hack, masih valid, tetapi mengapa menggunakan solusi ketika Anda dapat menggunakannya dengan cara yang seharusnya. dan dapatkan hasil yang diinginkan
Anders M.
1
@AndersM. Jawaban Ed melakukan redirect. Bukan itu yang saya inginkan ketika saya menemukan pertanyaan ini mencari solusi.
mxmissile
@mxmissile bukan untuk menjadi kontol tetapi jawaban Ed adalah apa yang penanya butuhkan karena dia menginginkan tampilan yang dikembalikan berdasarkan apa yang diunggah, saya setuju bahwa penanya bisa melakukan pekerjaan yang lebih baik dalam merumuskan pertanyaannya (apakah ini kata yang tepat? ) kami tidak dapat mengetahui hal ini karena bahasa Inggrisnya mungkin terbatas, meskipun jawaban Tiesons membantu Anda - yang bagus - itu tidak mengubah fakta bahwa jawaban Ed paling mencerminkan apa yang dibutuhkan oleh penanya
Anders M.
2
@AndersM. Saya mengerti, komentar saya hanya buruk ... :-) Seharusnya saya menekankan poin yang bukan hasil yang saya inginkan.
mxmissile
@AndersM. Penanya menerima jawaban Tieson sebagai yang terbaik, jadi saya tidak yakin mengapa Anda memutuskannya? Jawaban yang diberikan Tieson membantu saya lebih dari jawaban Ed. SO bukan hanya untuk membantu satu orang, tetapi setiap orang yang memiliki masalah serupa. Jadi mengapa tidak menyimpan jawaban Tieson saja di atas?
Kevin Voorn

Jawaban:

106

Pengendali hanya kelas - yang baru dan memanggil metode tindakan seperti Anda akan anggota kelas lainnya:

var result = new ControllerB().FileUploadMsgView("some string");

Tieson T.
sumber
76
Tidakkah Anda akan kehilangan Controll Controller, Request dan teman-teman jika Anda hanya melakukan ini?
Cirrus
20
Instansiasi pengontrol bukanlah ide yang baik karena siklus hidupnya mungkin dikendalikan oleh bagian lain dari aplikasi. Misalnya ketika menggunakan wadah IoC semua depdensi harus disuntikkan, dll.
Mo Valipour
48
Jika Anda menggunakan IoC, Anda bisa mendapatkan pengontrol yang dihuni melaluivar controller = DependencyResolver.Current.GetService<ControllerB>();
mxmissile
3
@mxmissile Itu layak ditambahkan sebagai jawaban baru, daripada komentar di sini.
Tieson T.
2
@ilasno. Apakah Anda terbiasa dengan istilah "inversi kontrol"? Maksudnya adalah bahwa jika Anda memiliki komponen di controller Anda yang perlu disuntikkan ke konstruktor, jawaban saya tidak benar-benar berfungsi, kecuali jika Anda menggunakan sesuatu seperti DependencyResolver sebagai pencari layanan.
Tieson T.
202

Seperti @mxmissile mengatakan di komentar untuk jawaban yang diterima, Anda tidak boleh baru membuat controller karena dependensi akan hilang yang diatur untuk IoC dan tidak akan memilikinya HttpContext.

Sebagai gantinya, Anda harus mendapatkan instance pengontrol Anda seperti ini:

var controller = DependencyResolver.Current.GetService<ControllerB>();
controller.ControllerContext = new ControllerContext(this.Request.RequestContext, controller);
DLeh
sumber
Persis apa yang saya cari. Perhatikan bahwa mereka yang tidak menggunakan IoC masih tidak akan mendapatkan HttpContextsuntikan.
brichins
var controllerakan diberikan tipe ControllerB, ya.
DLeh
1
Ini membuat saya dekat, tetapi satu masalah yang muncul adalah bahwa dalam kasus saya, controller.MyAction () membuat referensi ke User.Identity yang tampaknya tidak terinstalasi.
Robert H. Bourdeau
1
@ilasno Saya berkarat di MVC hari ini, tapi saya pikir saya maksudkan bahwa Anda harus benar - benar mengatur IoC untuk mendapatkan objek Pengendali penuh (misalnya yang terkait HttpContext). Saya percaya saya menggunakan pendekatan ini tanpa IoC untuk mendapatkan objek kontroler "dangkal" (hanya perlu akses ke fungsi tertentu) dan pada awalnya bingung tentang mengapa bagian-bagian "hilang". [samping: Saya mengatasinya saat masih menggunakan pendekatan ini, tetapi mungkin seharusnya refactored fungsionalitas itu ke kelas bersama.] Adapun pengaturan dan pilihan IoC, saya harus merujuk Anda ke artikel lain / pertanyaan SO.
brichins
3
Beberapa orang terbawa oleh pengeditan yang tidak ada gunanya ... perhatikan bahwa seseorang mengedit jawaban yang mengubah variabel "controller" menjadi "ctrlr" ... jadi ia harus membaca "ctrlr.ControllerContext = new ControllerContext (this.Request.RequestContext, ctrl) ; " jika pengguna itu mengeditnya dengan benar
JoeSharp
62

Sampel Anda terlihat seperti kode psuedo. Anda harus mengembalikan hasil RedirectToAction:

return RedirectToAction("B", 
                        "FileUploadMsgView",
                        new { FileUploadMsg = "File uploaded successfully" });
Kapel Ed
sumber
4
Harus ditunjukkan bahwa jika tindakan target hanya menerima POST, ini tidak akan berhasil.
Marco Alves
13
Ini mengembalikan 302 yang menyebabkan hit lain ke server yang bukan pertanyaannya.
rboarman
16

seperti @DLeh mengatakan Gunakan saja

var controller = DependencyResolver.Current.GetService<ControllerB>();

Tetapi, memberikan controller, konteks controller adalah penting terutama ketika Anda perlu mengakses Userobjek, Serverobjek, atau di HttpContextdalam controller 'child'.

Saya telah menambahkan sederet kode:

controller.ControllerContext = new ControllerContext(Request.RequestContext, controller);

atau Anda bisa menggunakan System.Web untuk mengakses konteks saat ini juga, untuk mengakses Serveratau objek metion awal

NB: saya menargetkan kerangka kerja versi 4.6 (Mvc5)

Nishanth Shaan
sumber
4
Jika Anda mencoba untuk memanggil tindakan di controller yang menggunakan tampilan (..) atau PartialView (...), Anda perlu secara manual mengubah routeData, sehingga ASP.NET tahu cara menemukan tampilan Anda. controller.RouteData.Values["controller"] = "Home";controller.RouteData.Values["action"] = "Index";Dengan asumsi Anda mencoba mengembalikan hasil dari tindakan Indeks di HomeController.
Steven
@ Seven saya harus menerapkan nilai-nilai ini thisdaripada controller. Pada akhirnya hasilnya kembali melalui pengontrol lokal (ini) sehingga itulah yang akhirnya mencoba menemukan tampilan.
aaaantoine
Saya akan menambahkan juga bahwa properti Url tidak diinisialisasi pada DependencyResolver.Current.GetService <ControllerB> (). Jadi, Anda harus menyalinnya dari pengontrol saat ini secara manual.
Ralfeus
Dalam Aksi penargetan Anda harus menggunakan return View("ViewName");sebagai gantinya hanyareturn View();
mNejkO
9

Biarkan resolver secara otomatis melakukan itu.

Di dalam controller:

public class AController : ApiController
{
    private readonly BController _bController;

    public AController(
    BController bController)
    {
        _bController = bController;
    }

    public httpMethod{
    var result =  _bController.OtherMethodBController(parameters);
    ....
    }

}
David Castro
sumber
2
imo jawaban terbersih, tetapi Anda harus mengatur konteks controller ke controller baru.
Mafii
8

Jika ada yang melihat bagaimana melakukan ini dalam. Net core saya menyelesaikannya dengan menambahkan controller di startup

services.AddTransient<MyControllerIwantToInject>();

Kemudian Menyuntikkannya ke pengontrol lain

public class controllerBeingInjectedInto : ControllerBase
{
    private readonly MyControllerIwantToInject _myControllerIwantToInject

     public controllerBeingInjectedInto(MyControllerIwantToInject myControllerIwantToInject)
{
       _myControllerIwantToInject = myControllerIwantToInject;
      }

Kemudian panggil saja seperti itu _myControllerIwantToInject.MyMethodINeed();

Leonardo Wildt
sumber
4

Inilah yang saya cari setelah menemukan yang RedirectToAction()tidak akan melewati objek kelas yang kompleks.

Sebagai contoh, saya ingin memanggil IndexComparisonmetode di LifeCycleEffectsResultscontroller dan memberikannya objek model kelas bernama kompleks.

Berikut adalah kode yang gagal:

return RedirectToAction("IndexComparison", "LifeCycleEffectsResults", model);

Perlu dicatat adalah bahwa Strings, integer, dll selamat dari perjalanan ke metode controller ini, tetapi objek daftar generik menderita dari apa yang mengingatkan pada kebocoran memori C.

Seperti yang disarankan di atas, inilah kode yang saya ganti dengan:

var controller = DependencyResolver.Current.GetService<LifeCycleEffectsResultsController>();

var result = controller.IndexComparison(model);
return result;

Semua berfungsi sebagaimana dimaksud sekarang. Terima kasih telah memimpin.

cghore
sumber
3

Jawaban Dleh benar dan menjelaskan cara mendapatkan turunan dari pengontrol lain tanpa kehilangan dependensi yang diatur untuk IoC

Namun, kita sekarang perlu memanggil metode dari pengontrol lain ini.
Jawaban lengkapnya adalah:

var controller = DependencyResolver.Current.GetService<ControllerB>();
controller.ControllerContext = new ControllerContext(this.Request.RequestContext, controller);

//Call your method
ActionInvoker.InvokeAction(controller.ControllerContext, "MethodNameFromControllerB_ToCall");
AlexB
sumber
Bagaimana Anda memanggil tindakan "MethodNameFromControllerB_ToCall" jika mengharapkan parameter? misalnya MethodNameFromControllerB_ToCall (int somenum, string somethingext)?
Patee Gutee
3

Saya tahu ini sudah tua, tetapi Anda dapat:

  • Buat lapisan layanan
  • Pindahkan metode ke sana
  • Metode panggilan di kedua pengontrol
Watth
sumber
2

jika masalahnya adalah menelepon. Anda dapat memanggilnya menggunakan metode ini.

yourController obj= new yourController();

obj.yourAction();

sumber
1
Pfft! Bagaimana jika Anda mengharapkan hasil dari suatu tindakan? var res = new ControllerB().SetUpTimer(new TimeSpan(23, 20, 00));
DirtyBit