Вручную создать экземпляр Controller из произвольного URL-адреса?

Мои навыки меня терпят неудачу, и я знаю, что я видел код для этого, но я не могу его найти.

Какой самый быстрый способ получить любой произвольный 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???)

Я пытаюсь получить экземпляр контроллера, как это делает система маршрутизации, независимо от того, где выполняется код. Я не совсем понимаю, как скомбинировать их вместе. Хотя я, в конце концов, обнаружу это, я подумал, что могу сэкономить время, спросив здесь;)

Ответ 1

Хм... Я не знаю, лучшее ли это решение, потому что это требует насмешек, но, возможно, это поможет. Вы на правильном пути, а часть контроллера factory проста, как только вы знаете, какой контроллер должен создать экземпляр, поэтому вопрос заключается в том, что самый быстрый способ получить объект RouteData​​strong > из произвольного URL-адреса.

И единственный способ, которым я знаю, как было бы так, с Moq:

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

Я сделал довольно много поисковых запросов и не мог найти много, что не касалось модульного тестирования/насмешки. Я не знаю, можно ли быстро и легко это сделать, но, конечно, хотелось бы знать, есть ли у кого-то лучшее решение!

Ответ 2

Хорошо, после работы с этим в течение пары недель, это то, с чем я закончил. Он работает как шарм и избегает зависимостей от насмешек, но все еще чувствует себя взломанным.

// Get the application 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(). Спасибо Курту за его код, и если кто-нибудь может придумать что-то лучшее, пожалуйста, не стесняйтесь публиковать сообщения.

Ответ 3

Очевидно, что вы имеете в виду любую строку URL-адреса после домена на сайте MVC, правильно? Итак, в http://yourdomain/something/thatSomeone/might/type/here вы имеете в виду что-то/thatSomeone/might/type/here part.

Перейдите в файл Global.asax.ca в методе RegisterRoutes и добавьте что-то вроде следующего:

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

Теперь, когда кто-то вводит http://yourdoamin/foo/bar/in/a/jar, они будут перенаправлены на действие контроллера Home/Index.

Надеюсь, что это поможет.

Cheers, -jc