Cách gọi bộ điều khiển khác Hành động Từ bộ điều khiển trong Mvc


153

Tôi cần gọi bộ điều khiển B hành động FileUploadMsgView từ Bộ điều khiển A và cần truyền tham số cho nó.

 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();
    }

3
Tôi biết câu hỏi này đã cũ nhưng theo tôi, bạn nên đánh dấu câu trả lời từ ed chapel là câu hỏi hay nhất, trông giống như một bản hack, nó vẫn hợp lệ, nhưng tại sao lại sử dụng cách giải quyết khi bạn có thể sử dụng nó theo cách nó có nghĩa và nhận được kết quả mong muốn
Anders M.

1
@AndersM. Câu trả lời của Ed làm một chuyển hướng. Đó không phải là điều tôi muốn khi tôi tìm thấy câu hỏi này để tìm kiếm một giải pháp.
mxmissile

@mxmissile không phải là một người tinh ranh nhưng câu trả lời của Ed là những gì người hỏi cần vì anh ta muốn một quan điểm được trả về dựa trên những gì được tải lên, tôi đồng ý rằng người hỏi có thể thực hiện công việc tốt hơn trong việc đưa ra câu hỏi của mình (đây có phải là từ đúng không? ) chúng tôi không thể biết điều này mặc dù tiếng Anh của anh ấy có thể bị hạn chế, mặc dù câu trả lời của Tiesons đã giúp bạn - điều đó tốt - nó không thay đổi thực tế rằng câu trả lời của Ed phản ánh đúng nhất những gì người hỏi cần
Anders M.

2
@AndersM. Tôi hiểu, từ ngữ nhận xét của tôi chỉ là xấu ... :-) Tôi nên nhấn mạnh điểm không phải là kết quả tôi mong muốn.
mxmissile

@AndersM. Người hỏi chấp nhận câu trả lời của Tieson là tốt nhất, vì vậy tôi không chắc tại sao bạn lại quyết định cho anh ta? Câu trả lời mà Tieson đưa ra đã giúp tôi nhiều hơn sau đó là câu trả lời của Ed. SO không chỉ để giúp đỡ một người, mà tất cả những người có vấn đề tương tự. Vậy tại sao không giữ câu trả lời của Tieson lên hàng đầu?
Kevin Voorn

Câu trả lời:


106

Bộ điều khiển chỉ là các lớp - mới lên và gọi phương thức hành động giống như bất kỳ thành viên lớp nào khác:

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


76
Bạn sẽ không thiếu Trình điều khiển, Yêu cầu và bạn bè nếu bạn chỉ làm điều này?
xơ gan

20
Khởi tạo bộ điều khiển không phải là một ý tưởng hay vì vòng đời của nó có thể được điều khiển bởi một phần khác của ứng dụng. Ví dụ: khi sử dụng bộ chứa IoC, tất cả các khoản phải trả, v.v.
Mo Valipour

48
Nếu bạn sử dụng IoC, bạn có thể nhận được bộ điều khiển dân cư thông quavar controller = DependencyResolver.Current.GetService<ControllerB>();
mxmissile

3
@mxmissile Điều đó đáng để thêm vào như một câu trả lời mới, thay vì nhận xét ở đây.
Tieson T.

2
@ilasno Bạn có quen với thuật ngữ "đảo ngược kiểm soát" không? Điểm anh ấy đưa ra là nếu bạn có các thành phần trong bộ điều khiển cần được đưa vào hàm tạo, câu trả lời của tôi không thực sự hiệu quả, trừ khi bạn sử dụng một cái gì đó như DependencyResolver làm công cụ định vị dịch vụ.
Tieson T.

202

Như @mxmissile nói trong các nhận xét cho câu trả lời được chấp nhận, bạn không nên khởi động bộ điều khiển vì nó sẽ thiếu các phụ thuộc được thiết lập cho IoC và sẽ không có HttpContext.

Thay vào đó, bạn nên lấy một phiên bản của trình điều khiển của bạn như thế này:

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

Chính xác những gì tôi đang tìm kiếm. Lưu ý rằng những người không sử dụng IoC vẫn sẽ không được HttpContexttiêm.
brichin

var controllersẽ được chỉ định loại ControllerB, vâng.
DLeh

1
Điều này khiến tôi gần gũi, nhưng một vấn đề nảy sinh là trong trường hợp của tôi, bộ điều khiển.MyAction () làm tham chiếu đến User.Identity dường như được xác định.
Robert H. Bourdeau

1
@ilasno Tôi gỉ trên MVC những ngày này, nhưng tôi nghĩ rằng tôi có nghĩa là bạn phải thực sự IoC thiết lập để có được một đối tượng điều khiển phổ biến đầy đủ (ví dụ một liên HttpContext). Tôi tin rằng tôi đã sử dụng phương pháp này mà không cần bất kỳ IoC nào để có được một đối tượng điều khiển "nông" (chỉ cần truy cập vào một số chức năng nhất định) và ban đầu bối rối về lý do tại sao các bộ phận bị "mất tích". [sang một bên: Tôi đã làm việc xung quanh nó trong khi vẫn sử dụng phương pháp này, nhưng có lẽ nên tái cấu trúc chức năng đó cho một lớp dùng chung.] Đối với các lựa chọn và thiết lập IoC, tôi phải giới thiệu cho bạn các câu hỏi / bài viết SO khác.
brichin

3
Một số người bị mang đi với các chỉnh sửa vô nghĩa ... lưu ý rằng ai đó đã chỉnh sửa câu trả lời thay đổi biến "trình điều khiển" thành "ctrlr" ... vì vậy, nên đọc "ctrlr.ContoderContext = new ControllerContext (this.Request.RequestContext, ctrl) ; " nếu người dùng đó chỉnh sửa chính xác
JoeSharp

62

Mẫu của bạn trông giống như mã psuedo. Bạn cần trả về kết quả của RedirectToAction:

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

4
Cần phải chỉ ra rằng nếu hành động đích chỉ chấp nhận POST, thì điều này sẽ không hoạt động.
Marco Alves

13
Điều này trả về một 302 gây ra một cú đánh khác cho máy chủ không phải là câu hỏi.
rboarman

16

như @DLeh nói Sử dụng thay

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

Nhưng, đưa ra bộ điều khiển, bối cảnh của trình điều khiển rất quan trọng đặc biệt là khi bạn cần truy cập vào Userđối tượng, Serverđối tượng hoặc HttpContextbên trong bộ điều khiển 'con'.

Tôi đã thêm một dòng mã:

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

hoặc nếu không, bạn cũng có thể đã sử dụng System.Web để xác định bối cảnh hiện tại, để truy cập Serverhoặc các đối tượng được đo lường sớm

Lưu ý: tôi đang nhắm mục tiêu phiên bản khung 4.6 (Mvc5)


4
Nếu bạn cố gắng gọi một hành động trong bộ điều khiển sử dụng View (..) hoặc PartialView (...), bạn cần thay đổi thủ công routeData, để ASP.NET biết cách tìm chế độ xem của bạn. controller.RouteData.Values["controller"] = "Home";controller.RouteData.Values["action"] = "Index";Giả sử bạn đang cố gắng trả về kết quả từ hành động Index trong HomeContoder.
Steven

@Steven Tôi đã phải áp dụng các giá trị này thishơn là controller. Cuối cùng, kết quả quay trở lại thông qua bộ điều khiển cục bộ (cái này) vì vậy đó là những gì cuối cùng cố gắng tìm ra chế độ xem.
aaaantoine

Tôi cũng thêm rằng thuộc tính Url không được khởi tạo khi DependencyResolver.C Hiện.GetService <ControllerB> (). Vì vậy, bạn phải sao chép nó từ bộ điều khiển hiện tại bằng tay.
Ralfeus

Trong hành động nhắm mục tiêu bạn nên sử dụng return View("ViewName");thay vì chỉreturn View();
mNejkO

9

Hãy để trình giải quyết tự động làm điều đó.

Bên trong bộ điều khiển:

public class AController : ApiController
{
    private readonly BController _bController;

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

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

}

2
Imo câu trả lời rõ ràng nhất, nhưng bạn nên đặt bối cảnh của bộ điều khiển thành bộ điều khiển mới.
Mafii

8

Nếu bất cứ ai đang xem làm thế nào để làm điều này trong lõi .net, tôi đã hoàn thành nó bằng cách thêm bộ điều khiển khi khởi động

services.AddTransient<MyControllerIwantToInject>();

Sau đó tiêm nó vào bộ điều khiển khác

public class controllerBeingInjectedInto : ControllerBase
{
    private readonly MyControllerIwantToInject _myControllerIwantToInject

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

Sau đó chỉ cần gọi nó như vậy _myControllerIwantToInject.MyMethodINeed();


4

Đây chính xác là những gì tôi đang tìm kiếm sau khi tìm thấy nó RedirectToAction()sẽ không vượt qua các đối tượng lớp phức tạp.

Ví dụ, tôi muốn gọi IndexComparisonphương thức trong LifeCycleEffectsResultsbộ điều khiển và truyền cho nó một đối tượng lớp phức tạp có tên là mô hình.

Đây là mã thất bại:

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

Đáng chú ý là các chuỗi, số nguyên, v.v ... đã sống sót sau chuyến đi đến phương thức điều khiển này, nhưng các đối tượng danh sách chung đang phải chịu đựng những gì gợi nhớ đến rò rỉ bộ nhớ C.

Như đã đề xuất ở trên, đây là mã tôi đã thay thế bằng:

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

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

Tất cả đang hoạt động như dự định bây giờ. Cảm ơn bạn đã dẫn đường.


3

Câu trả lời của Dleh là chính xác và giải thích làm thế nào để có được một phiên bản của bộ điều khiển khác mà không bỏ lỡ các phụ thuộc được thiết lập cho IoC

Tuy nhiên, bây giờ chúng ta cần gọi phương thức từ bộ điều khiển khác này.
Câu trả lời đầy đủ sẽ là:

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

//Call your method
ActionInvoker.InvokeAction(controller.ControllerContext, "MethodNameFromControllerB_ToCall");

Làm thế nào để bạn gọi hành động "MethodNameFromControllB_ToCall" nếu nó mong đợi các tham số? ví dụ: MethodNameFromControllB_ToCall (int somenum, chuỗi đôi khi)?
Patee Gutee

3

Tôi biết nó đã cũ, nhưng bạn có thể:

  • Tạo một lớp dịch vụ
  • Di chuyển phương pháp đến đó
  • Phương thức gọi trong cả hai bộ điều khiển

2

nếu vấn đề là gọi. bạn có thể gọi nó bằng phương pháp này.

yourController obj= new yourController();

obj.yourAction();

1
Pfft! Điều gì xảy ra nếu bạn đang mong đợi một kết quả từ một hành động thay thế? var res = new ControllerB().SetUpTimer(new TimeSpan(23, 20, 00));
DirtyBit 29/03/18
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.