Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to invoke one controller method from another given only the uri

for simplicity consider a person resource such as

{"name":"Fred Flintston",
"worksAt":
   {"href":"api/sites?cn=Slate%20Rock%20and%20Gravel%20Company"}
}

When I receive this on the POST to the PeopleController I need to get the site resource from the worksAt.href.

What I would like to do is invoke the correct GET on the SitesController leveraging the routing engine that already knows how to parse the uri and invoke the correct method.

I have seen one suggestion here which seems rather heavy handed, and I'm not at all sure how that would allow the authorization that has already happened to carry through.

like image 784
Ralph Shillington Avatar asked Mar 24 '26 04:03

Ralph Shillington


1 Answers

You can try the following, but if you describe in detail what you want to achieve, we might be able to find a better solution. It is MVC based, but should work for web API too.

var baseUrl = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
var requestUrl = new Uri(baseUrl + "Home/Index?i=42");

//get method info
var httpContext = new HttpContextWrapper(new HttpContext(new HttpRequest("/", requestUrl.AbsoluteUri, ""), new HttpResponse(new StringWriter())));
var requestContext = new RequestContext(httpContext, RouteTable.Routes.GetRouteData(httpContext));
var controllerType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(x => x.Name == requestContext.RouteData.Values["controller"].ToString() + "Controller");
var controllerContext = new ControllerContext(requestContext, Activator.CreateInstance(controllerType) as ControllerBase);
var controllerDescriptor = new ReflectedControllerDescriptor(controllerType);
var actionDescriptor = controllerDescriptor.FindAction(controllerContext, controllerContext.RouteData.Values["action"].ToString());
var methodInfo = (actionDescriptor as ReflectedActionDescriptor).MethodInfo;

//parse the query string
var qscoll = HttpUtility.ParseQueryString(requestUrl.Query);
//and use the only item in it as an int when calling the action
var ret = methodInfo.Invoke(Activator.CreateInstance(controllerType), new object[] { int.Parse(qscoll[0]) });

The parameter passing is now baked in, so you'd need to create a correctly ordered parameter array, based on the parameter names, and types.

like image 68
Tamas Avatar answered Mar 25 '26 17:03

Tamas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!