【问题标题】:Manually instantiate a Controller instance from an arbitrary URL?从任意 URL 手动实例化控制器实例?
【发布时间】:2011-01-05 05:09:04
【问题描述】:

我的技能让我失望了,我知道我已经看过代码,但我找不到。

获取任意 URL、通过您的 asp.net mvc 路由系统运行它并在另一端引用控制器实例的最快方法是什么?

例如,代码执行是在一些任意的控制器方法中。我想做这样的事情:

...
string myURL = "http://mysite/mycontroller/myaction/myparameters";

RouteData fakeRouteData = new RouteData(Route???, IRouteHandler???)
RequestContext ctxt = new RequestContext(this.ControllerContext.HttpContext,
                                         fakeRouteData);

ControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
Controller result = factory.CreateController(ctxt, controllername???)

无论代码在哪里执行,我都在尝试像路由系统一样获取控制器的实例。在这一点上,我不清楚如何将这些部分组合在一起。虽然我最终会发现它,但我想我可以通过在这里提问来节省时间;)

【问题讨论】:

  • 是的,我一直在使用 Reflector 和各种文章。虽然我希望节省一些时间,但我知道我在某个地方看到过一个线程,其中有两种或三种方法可以做到这一点,而且代码量相当简洁。
  • 我写了一个不涉及模拟的完整示例 [这里][1]。 [1]:stackoverflow.com/a/19382567/126574

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


【解决方案1】:

嗯...我不知道这是否是最好的解决方案,因为它需要模拟,但也许这会有所帮助。您走在正确的轨道上,一旦您知道要实例化 什么 控制器,控制器工厂部分就很简单了,所以问题是获取 RouteData 对象的最快方法是什么任意网址。

而我知道的唯一方法是使用起订量:

string url = "~/Account/LogOn";  //trying to create Account controller in default MVC app

RouteCollection rc = new RouteCollection();
MvcApplication.RegisterRoutes(rc);
System.Web.Routing.RouteData rd = new RouteData();
var mockHttpContext = new Moq.Mock<HttpContextBase>();
var mockRequest = new Moq.Mock<HttpRequestBase>();
mockHttpContext.Setup(x => x.Request).Returns(mockRequest.Object);
mockRequest.Setup(x => x.AppRelativeCurrentExecutionFilePath).Returns(url);

RouteData routeData = rc.GetRouteData(mockHttpContext.Object);

string controllerName = routeData.Values["controller"].ToString();

IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController controller = factory.CreateController(this.ControllerContext.RequestContext, controllerName);

我进行了相当多的谷歌搜索,但找不到很多与单元测试/模拟无关的内容。我不知道是否有 一种快速简便的方法,但肯定想知道是否有人有更好的解决方案!

【讨论】:

  • 库尔特 - 太棒了!当您发布此内容时,我刚刚到达那里,我与 RouteData 的内容相差两行。我想我可能也有办法避免使用当前的 HttpContext 进行模拟 - 如果您调用 this.HttpContext.RewritePath("~/Account/LogOn") 它会在此之后正确找到控制器。不过,我不确定这是否完全安全,因为 HttpContext 的下游消费者可能会感到困惑,所以我必须对其进行更多测试,并且可能会退回到可信赖的起订量……对你来说很多 +1。
  • 酷!请张贴你想出的任何东西。使用 RewritePath 进行巧妙思考,但确实可能存在问题。
  • 我发布了我最终得到的结果。 RewritePath() 方法似乎有效,让我暂时避免使用模拟。再次感谢您的帮助;)
【解决方案2】:

好的,经过几周的努力,这就是我的最终结果。它就像一种魅力,避免了对模拟的依赖,但对我来说仍然感觉很老套。

// Get the application's route collection.
UrlRoutingModule module = new UrlRoutingModule();
RouteCollection col = module.RouteCollection;

// Fake a request to the supplied URL into the routing system
string originalPath = this.HttpContext.Request.Path;
this.HttpContext.RewritePath(urlToGetControllerFor);
RouteData fakeRouteData = col.GetRouteData(this.HttpContext);

// Get an instance of the controller that would handle this route
string controllername = fakeRouteData.Values["controller"].ToString();
var ctxt = new RequestContext(this.ControllerContext.HttpContext, fakeRouteData);
IController controller = ControllerBuilder.Current.GetControllerFactory()
                          .CreateController(ctxt, controllername);

// Reset our request path.
this.HttpContext.RewritePath(originalPath.ToString());

到目前为止,RewritePath() 调用绝对没有下游副作用。感谢 Kurt 的代码,如果有人能提出更好的建议,请不要犹豫。

【讨论】:

  • 我有点晚了,但是您有任何信息如何使用 .NET Core 2.1 实现这一目标吗?
【解决方案3】:

显然,您指的是 MVC 网站上的任何后域 URL 字符串,对吧?所以,在http://yourdomain/something/thatSomeone/might/type/here 中,你的意思是something/thatSomeone/might/type/here 部分。

在 RegisterRoutes 方法中转到您的 Global.asax.ca 文件并添加如下内容:

routes.MapRoute("foo", "foo/bar/in/a/jar", new { controller = "Home", action = "Index", id = "" });

现在,当有人输入 http://yourdoamin/foo/bar/in/a/jar 时,他们将被路由到 Home/Index 控制器操作。

希望对您有所帮助。

干杯, -jc

【讨论】:

  • 感谢您的回复。我实际上想在我的代码中的任何地方利用路由系统。我将编辑问题以使其更清晰。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多