How are QueryString parameters mapped to Action method parameters?

I have a webforms project, and I'm trying to run some code that allows me to make a call to an MVC route, and then display the result in the body of the web forms page.

There are several HttpResponse / Request / Context shells that I use to make a call to the MVC route, for example:

private static string RenderInternal(string path) { var responseWriter = new StringWriter(); var mvcResponse = new MvcPlayerHttpResponseWrapper(responseWriter, PageRenderer.CurrentPageId); var mvcRequest = new MvcPlayerHttpRequestWrapper(Request, path); var mvcContext = new MvcPlayerHttpContextWrapper(Context, mvcResponse, mvcRequest); lock (HttpContext.Current) { new MvcHttpHandlerWrapper().PublicProcessRequest(mvcContext); } ... 

The code works great for performing simple MVC routes, for example. "/ Home / Index". But I canโ€™t specify the query string parameters (for example, "/ Home / Index? Foo = bar"), because they are simply ignored. I tried setting QueryString directly in the RequestWrapper instance, for example:

 public class MvcPlayerHttpRequestWrapper : HttpRequestWrapper { private readonly string _path; private readonly NameValueCollection query = new NameValueCollection(); public MvcPlayerHttpRequestWrapper(HttpRequest httpRequest, string path) : base(httpRequest) { var parts = path.Split('?'); if (parts.Length > 1) { query = ExtractQueryString(parts[1]); } _path = parts[0]; } public override string Path { get { return _path; } } public override NameValueCollection QueryString { get { return query; } } ... 

When debugging, I see that the correct values โ€‹โ€‹are in "request.QueryString", but the values โ€‹โ€‹are never bound to the method parameter.

Does anyone know how QueryString values โ€‹โ€‹are used and bound from an HTTP request to an MVC controller action?

It seems that handling a QueryString value is more complicated than I expected. I have limited knowledge of the internal components of the MVC query pipeline.

I try to explore the insides on my own and will continue to do so. If I find anything, I will update this post accordingly.

I also created a very simple web form project containing only the code needed to create this problem, and shared it using Dropbox: https://www.dropbox.com/s/vi6erzw24813zq1/StackMvcGetQuestion.zip The project just contains one Default page .aspx, the controller and the MvcWrapper class, used to render the result of the MVC path. If you look at Default.aspx.cs, you will see the route path containing the querystring parameter, which is passed, but it is never associated with the action parameter.

As a quick reference, here are some excerpts from this web project.

Controller:

 public class HomeController : Controller { public ActionResult Index(string foo) { return Content(string.Format("<p>foo = {0}</p>", foo)); } } 

Default.aspx page:

 protected void Page_Load(object sender, EventArgs e) { string path = "/Home/Index?foo=baz"; divMvcOutput.InnerHtml = MvcWrapper.MvcPlayerFunctions.Render(path); } 

I struggled with this for a long time, so I would be grateful for any advice in any form. :)

+4
source share
2 answers

The MVC framework will try to fill in the values โ€‹โ€‹of the parameters of the action method from the query string (and other available data, such as form field fields, etc.), you received this part correctly. The part you missed is that it does this by matching the parameter name with the value names passed to. So if you have a MyMethod method in Controller MyController with a signature:

 public ActionResult MyMethod(string Path) { //Some code goes here } 

The query string (or one of the other variable sources) must contain a variable named "Path" so that the infrastructure can detect it. The query string should be / MyController / MyMethod? Path = Baz

0
source

Ok It was a long debugging session :) and it will be a long answer, so bear with me :)

First, how MVC works. When you call the action method with input parameters, the framework will call a class called "DefaultModelBinder", which will try to provide a value for each base type (int, long, etc.) and an instance of complex types (objects). This binder will depend on something called the ValueProvider collection to search for variable names in the query string, submitted forms, etc. One of ValueProviders that interests us the most is QueryStringValueProvider. As you can guess, it gets the variables defined in the query string. Inside the structure, this class calls HttpContext.Current to retrieve the values โ€‹โ€‹of the query string instead of relying on those that are passed to it. In your setup, this makes it see the original request with localhost: xxxx / Default.aspx as the main request, making it see the empty query string. In fact, inside the Action (Bar method in your case) you can get the value of this.QueryString ["variable"], and it will have the correct value. I modified the Player.cs file to use the web client to invoke the MVC application running on a separate copy of VS, and it worked fine. Therefore, I suggest you run the mvc application separately and call it, and it should work fine.

0
source

Source: https://habr.com/ru/post/1481924/


All Articles