I'm working on a MVC web application. I need to download a file which I've stored as a byte[] stream in DB and its working fine. What I used to do on a button click I call a JS function and that calls a function in the C# backend and eventually download the file. Following is my JQuery code.
var DownloadDRR = function ()
{
var InvoiceId = $(".invoiceid").text();
location.href = location.origin + "/Invoicing/DownloadDRR?InvoiceId=" + InvoiceId;
}
And in the backend I normally get query string like this
Request.Querystring("InvoiceId");
But accidental I've discovered in my application if I write the following it still gets the InvoiceId without using Request.QueryString().
public FileResult DownloadDRR(int InvoiceId)
{
InvoicingService Invoices = new InvoicingService(Client);
byte[] RawExcel = Invoices.GetExcelService(InvoiceId);
MemoryStream stream = new MemoryStream(RawExcel);
stream.Seek(0, SeekOrigin.Begin);
return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "test.xlsx");
}
Can anyone explain why please?
MVC specifically automates a lot of that binding (model binding is the term used).
myurl.com/MyController/MyMethod?something=a&anotherthing=1234
//example 1
public ActionResult MyMethod(string something, string anotherthing)
//example2
public ActionResult MyMethod(string something, int anotherthing)
It works for both examples. Even though your querystring technically only contains string values, MVC will try to parse it to the desired type.
The only thing you need to pay attention to is that the querystring parameter names match the method's parameter names. The rest is done automagically :)
//example3
public ActionResult MyMethod(int something, int anotherthing)
In this example, something cannot be converted, as "a" cannot be put into an int. The method call will fail (expect an ASP.Net error page). However, there are ways around this:
If the type is nullable, the method will still be called, and null will be the value. int? something will be set as null if conversion fails, and this makes sure the method still gets called.
You can make it an optional parameter: MyMethod(int anotherthing, int something = 0). Notice the inversion of the parameters. Optional parameters must always be placed after normal (required) parameters! This will make sure that, when something either cannot be converted (or simply isn't part of the querystring), it will receive the default value you specified (in my example, 0)
Some remarks:
You can write custom modelbinders that go way deeper than just converting a value. However, this is not default MVC behavior. It's still good to know you can add it if you need it.
Not all parameters are always part of the querystring. If you make a POST request (as opposed to the more lax GET request), you won't see a querystring. The values are still passed, but not as part of the requested URL. This is a topic you can find tons of information on via Google.
Related
Under ASP.NET MVC are you supposed to pick up QueryString params the same way you do in ASP.NET WebForms? or does the [AcceptVerbs(HttpVerbs.Get)] declaration get used somehow?
Query string parameters can be accepted simply by using an argument on the action - i.e.
public ActionResult Foo(string someValue, int someOtherValue) {...}
which will accept a query like .../someroute?someValue=abc&someOtherValue=123
Other than that, you can look at the request directly for more control.
I think what you are looking for is
Request.QueryString["QueryStringName"]
and you can access it on views by adding #
now look at my example,,, I generated a Url with QueryString
var listURL = '#Url.RouteUrl(new { controller = "Sector", action = "List" , name = Request.QueryString["name"]})';
the listURL value is /Sector/List?name=value'
and when queryString is empty
listURL value is /Sector/List
You can always use Request.QueryString collection like Web forms, but you can also make MVC handle them and pass them as parameters. This is the suggested way as it's easier and it will validate input data type automatically.
I recommend using the ValueProvider property of the controller, much in the way that UpdateModel/TryUpdateModel do to extract the route, query, and form parameters required. This will keep your method signatures from potentially growing very large and being subject to frequent change. It also makes it a little easier to test since you can supply a ValueProvider to the controller during unit tests.
Actually you can capture Query strings in MVC in two ways.....
public ActionResult CrazyMVC(string knownQuerystring)
{
// This is the known query string captured by the Controller Action Method parameter above
string myKnownQuerystring = knownQuerystring;
// This is what I call the mysterious "unknown" query string
// It is not known because the Controller isn't capturing it
string myUnknownQuerystring = Request.QueryString["unknownQuerystring"];
return Content(myKnownQuerystring + " - " + myUnknownQuerystring);
}
This would capture both query strings...for example:
/CrazyMVC?knownQuerystring=123&unknownQuerystring=456
Output: 123 - 456
Don't ask me why they designed it that way. Would make more sense if they threw out the whole Controller action system for individual query strings and just returned a captured dynamic list of all strings/encoded file objects for the URL by url-form-encoding so you can easily access them all in one call. Maybe someone here can demonstrate that if its possible?
Makes no sense to me how Controllers capture query strings, but it does mean you have more flexibility to capture query strings than they teach you out of the box. So pick your poison....both work fine.
This is the correct way in .NET 6 (and other netcore)
var Param = Request.Query["IndexString"];
If need to be string
string Param = Request.Query["IndexString"].ToString();
#Context.Request.Query["yourId"]
Under ASP.NET MVC are you supposed to pick up QueryString params the same way you do in ASP.NET WebForms? or does the [AcceptVerbs(HttpVerbs.Get)] declaration get used somehow?
Query string parameters can be accepted simply by using an argument on the action - i.e.
public ActionResult Foo(string someValue, int someOtherValue) {...}
which will accept a query like .../someroute?someValue=abc&someOtherValue=123
Other than that, you can look at the request directly for more control.
I think what you are looking for is
Request.QueryString["QueryStringName"]
and you can access it on views by adding #
now look at my example,,, I generated a Url with QueryString
var listURL = '#Url.RouteUrl(new { controller = "Sector", action = "List" , name = Request.QueryString["name"]})';
the listURL value is /Sector/List?name=value'
and when queryString is empty
listURL value is /Sector/List
You can always use Request.QueryString collection like Web forms, but you can also make MVC handle them and pass them as parameters. This is the suggested way as it's easier and it will validate input data type automatically.
I recommend using the ValueProvider property of the controller, much in the way that UpdateModel/TryUpdateModel do to extract the route, query, and form parameters required. This will keep your method signatures from potentially growing very large and being subject to frequent change. It also makes it a little easier to test since you can supply a ValueProvider to the controller during unit tests.
Actually you can capture Query strings in MVC in two ways.....
public ActionResult CrazyMVC(string knownQuerystring)
{
// This is the known query string captured by the Controller Action Method parameter above
string myKnownQuerystring = knownQuerystring;
// This is what I call the mysterious "unknown" query string
// It is not known because the Controller isn't capturing it
string myUnknownQuerystring = Request.QueryString["unknownQuerystring"];
return Content(myKnownQuerystring + " - " + myUnknownQuerystring);
}
This would capture both query strings...for example:
/CrazyMVC?knownQuerystring=123&unknownQuerystring=456
Output: 123 - 456
Don't ask me why they designed it that way. Would make more sense if they threw out the whole Controller action system for individual query strings and just returned a captured dynamic list of all strings/encoded file objects for the URL by url-form-encoding so you can easily access them all in one call. Maybe someone here can demonstrate that if its possible?
Makes no sense to me how Controllers capture query strings, but it does mean you have more flexibility to capture query strings than they teach you out of the box. So pick your poison....both work fine.
This is the correct way in .NET 6 (and other netcore)
var Param = Request.Query["IndexString"];
If need to be string
string Param = Request.Query["IndexString"].ToString();
#Context.Request.Query["yourId"]
I've some code like the following;
We're going to create a Note but we may know the CustomerId when we do so I've two URLs;
public ActionResult CreateByCustomer(int id)
{
Session["ncAppointmentId"] = 0;
Session["ncNoteDate"] = null;
SetConsultant(0);
return RedirectToAction("Create", "Note", new { id = id });
}
public ActionResult Create(int id = 0)
{
int _CustomerId = id == 0 ? Convert.ToInt32(Session["CustomerId"]) : id;
Session["TemplateIds"] = null;
and so on.......
ViewBag.CustomerId = _CustomerId;
When I look at the performance in Firebug the RedirectToAction causes a GET with a '302 Found' status which can incur up to 1 second's delay.
If I change the RedirectToAction line to
return Create(0);
Then the GET doesn't happen and performance is improved.
But I'm looking for opinions on what the downside is or what I've missed ?
The RedirectToAction result tells the client to request a new page, so it will naturally incur overheads since the client is now having to make a second request to your server. Sometimes this is necessary, sometimes - as in your example - not.
Generally I use RedirectToAction to return the client to a specific page after performing an action such as creating a note. This can be useful if you're on a page that lists notes and you want to refresh the page after creating a new one. The end result is that the page is refreshed, and the Create action does not appear in the user's browser history.
If your Create method returns a View, there can be some interesting side effects of calling it directly. In general the MVC code will handle it, but you can get some weird results - like the client's URL being different to what you expect in the subsequent requests, etc. If you're OK with this, fine.
Another option would be to get rid of the CreateByCustomer action and simply call the Create view with a parameter - named customerID for instance. This gives you the same ability to call it different ways without having to have multiple entry points. The client's location would reflect (in the query string) the difference between Create and Create?customerId=12345 which may or may not be what you're after.
<opinion>
Some Style Notes:
If you're storing lots of session data, create a class to hold it instead of creating lots of entries in Session[].
It's not particularly difficult to use jQueryUI to create an in-page editor for your notes rather than defining a view - check out this example. More elegant too :P
</opinion>
The RedirectToAction method is going to return an HTTP response that has a Found status code and a Location URL pointing to the place you are redirecting the client. The cost is simply another GET request, which I would not consider expensive. The decision to redirect or not should be made based on whether it conceptually makes sense, not based on whether you are making one less GET request.
I don't entirely understand the motivation here, however. If you elaborate on why you are trying to redirect, maybe I can help you choose a pattern that makes more sense.
Typically, you would not name a method Create* in an HTTP API. The idiomatic, correct prefix is Post* or Put*, depending on whether you are adding a new resource (but naming it) or creating/replacing a resource (and naming it), respectively.
The big difference is regarding if you want the url to change to the "Create" one. If it's ok to show whatever you are showing with that url, then avoid the redirect. Redirect is useful when you have an old url and you want it to point to a new one and also in the situation when you want to avoid saving new stuff if the user refresh de page (as it will refresh only the redirect request and not the post).
I dont get it, I have this code:
return JavaScript(string.Format(
"window.location = '{0}'",
UrlHelper.GenerateContentUrl("Index", this.HttpContext)));
The code is inside two pretty generic "Create" methods that works with POST. Each of the two methods are in different controller classes.
Now for method A that is called with the URL http://localhost:56688/Businessrule/Create, when the code is executed I get redirected to http://localhost:56688/Index.
But for method B called from http://localhost:56688/FormulaField/Create I get redirected to http://localhost:56688/FormulaField/Index.
... really I don't get it, and the microsoft documentation isn't helping out much http://msdn.microsoft.com/en-us/library/system.web.mvc.urlhelper.generatecontenturl.aspx (now, IMHO, that's a pretty crappy documentation for a method)
Sounds like your missing the controller name. apperently, you're being redirected to the Index action in the same controller.
It's what the MVC Route engine do, if he does not find the controller name, he assign a default value, in this case, the controller from witch the action has been executed.
Try something like :
UrlHelper.GenerateContentUrl(#"~\ControllerName\Index", this.HttpContext)
So, as pointed by asawyer how it works is answered by the code itself:
https://github.com/aspnet/AspNetWebStack/blob/master/src/System.Web.Mvc/UrlHelper.cs
It turns out that if the string that you pass begin with "~" the method will call PathHelpers.GenerateClientUrl, but if the string doesn't begin with "~" it will just return the same string unchanged.
But still I don't undertand why I'm getting different results. Anyway seems that I'll have to look closer to the raw response passed to the browser...
Are there any pros/cons of using the following two alternatives in your action signature:
public ActionResult Action(int? x) // get MVC to bind null when no parameter is provided
{
if(x.HasValue)
{
// do something
}
}
OR
public ActionResult Action(int? x = null) // C# optional parameter (virtual overload)
{
if(x.HasValue)
{
// do something
}
}
I have never seen the second action signature in practice and can't see any usefulness of it.
The first one usually covers all the scenarios:
If no parameter is sent (GET /somecontroller/action), the value of the x argument will be null inside the action
If a x parameter is sent, but it is not a valid integer (GET /somecontroller/action?x=abc), the value of the x argument will be null inside the action and the modelstate will be invalid
If a x parameter is sent and the value represents a valid integer (GET /somecontroller/action?x=123), then x will be assigned to it.
In my examples I have used GET requests with query string parameters but obviously the same applies with other HTTP verbs and if x was a route parameter.
You only need to specify the optional parameter value if it is going to be anything else other than null.
MVC3 will automatically set null as the value of your parameter if nothing is specified in the overload, or in the call to the Action.
However, its worth noting that if there are any non-optional parameters after this parameter in the signature, then null would have to be specified in the call.
Therefore its best to put all optional params at the end of the signature.
Best Asp.net MVC solution - use action method selector
Why not simplify controller action methods by removing unnecessary code branch and have this kind of code as seen here:
public ActionResult Index()
{
// do something when there's no id
}
[RequiresRouteValues("id")]
public ActionResult Index(int id)
{
// do something when id is present
}
This is of course possible, as long as you provide the very simple code for RequiresRouteValuesAttribute action method selector. You can find code in this blog post that does exactly this.
By my opinion this is the best possible solution to this problem, because:
It simplifies code by removing unnecessary branch
Makes code easier to maintain (due to lower complexity)
Extends Asp.net MVC framework as it can and should
Keeps parameter types as they should be without the need to make them nullable
etc.
Anyway. All the details about this technique is explained in great detail in linked post.