如何以编程方式执行Controller的Action方法?

时间:2010-04-14 15:42:54

标签: c# .net asp.net-mvc

我正在尝试以编程方式执行控制器的Action方法,但我不确定如何。

方案: 当我的ControllerFactory无法找到控制器时,我希望它能够在一个简单的自定义控制器上手动执行一个动作方法。我不想依赖于使用任何路由数据确定控制器/方法..因为该路由可能没有连线。

例如

// NOTE: Error handling removed from this example.
public class MyControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(Type controllerType)
    {
        IController result = null;

        // Try and load the controller, based on the controllerType argument.
        // ... snip
        // Did we retrieve a controller?
        if (controller == null)
        {
            result = new MyCustomController();
            ((MyCustomController)result).Execute404NotFound(); // <-- HERE!
        }

        return result;
    }
}

..那个方法是......

public static void Execute404NotFound(this Controller controller)
{
    result = new 404NotFound();
    // Setup any ViewData.Model stuff.
    result.ExecuteResult(controller.ControllerContext); // <-- RUNTIME 
                                                        //  ERROR's HERE
}

现在,当我运行控制器工厂找不到控制器时,我然后手动创建自己的基本控制器。然后,我在此控制器实例上调用扩展方法“Execute404NotFound”。那很好..直到它运行ExecuteResult(..)方法。为什么?控制器没有ControllerContext数据。因此,ExecuteResult崩溃,因为它需要一些ControllerContext

那么 - 有人可以帮我吗?看看我做错了什么。

记住 - &gt;我试图让我的控制器工厂手动/编程调用控制器上的方法,当然这将返回一个ActionResult。

请帮忙!

更新

我也试图避免使用catchall或抛出在Application_Exception部分中处理的异常的更常见的解决方案。我不相信它们应该是处理这个问题的正确方法。考虑到我们知道问题是什么,因此我们应该在那里处理它。

5 个答案:

答案 0 :(得分:1)

如果您手动创建控制器,则还必须手动为控制器提供上下文。

你走在正确的轨道上,但是你需要更多的代码来完成它。我自己经历了一段时间,并在thread on how to instantiate and fake a request to a controller上有一堆相当完整的代码。

如果您所做的只是想在404上运行一些代码,那么您的方法似乎有些过分。你不能做something like this吗?

答案 1 :(得分:1)

您可以从自定义控制器实例中抛出new HttpException(404, "Not found"),该实例可以在global.asax中的Application_Error中捕获并重定向到正确的页面:

protected void Application_Error(object sender, EventArgs e)
{
    var exception = Server.GetLastError();
    Response.Clear();
    var httpException = exception as HttpException;
    var routeData = new RouteData();
    routeData.Values.Add("controller", "Error");

    if(httpException != null )
    {
        switch( httpException.GetHttpCode() )
        {
            case 404:
                // Page not found.
                routeData.Values.Add("action", "HttpError404" );
                break;
            case 500:
                // Server error.
                routeData.Values.Add("action", "HttpError500" );
                break;
            default:
                routeData.Values.Add("action", "General" );
                break;
        }
    }

    routeData.Values.Add("error", exception);
    Server.ClearError();
    var errorController = new ErrorController();
    errorController.Execute(new RequestContext(
        new HttpContextWrapper(Context), routeData ) );
}

答案 2 :(得分:0)

这里的问题是调用操作方法不是控制器工厂的工作。

除了Application_Error之外,我可以想到两种处理方法:

  1. 覆盖System.Web.Mvc.MvcHandler的ProcessRequest方法。在我看来,这是一个核选择。

  2. 如果找不到控制器,则返回404控制器,并且有多种方法可以直接执行此操作,覆盖控制器ExecuteCore方法,以便您的操作方法始终是一个名为。< / p>

答案 3 :(得分:0)

一个简单的简单

RedirectToAction("ActionName");

希望这有帮助吗?

答案 4 :(得分:0)

修改路线怎么样:

public class MyControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(Type controllerType)
    {
        IController result = null;

        // Try and load the controller, based on the controllerType argument.
        // ... snip
        // Did we retrieve a controller?
        if (controller == null)
        {
            result = new MyCustomController();
            requestContext.RouteData.Values["action"] = "My404Action";
        }

        return result;
    }
}