How to Handle Variable Number of Parameters in Route Method - asp.net-mvc

I want to use the same post Action method for multiple number of input fields. How can I get hold of all the parameters passed to MVC engine (in addition to the method parameter)?
e.g. Both these list of values should be handled by the method below
1,A,A
1,B,A,A
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(int id)
{
//for each variable in POST store in DB
}

You can access the Request.Form collection.
foreach (string field in Request.Form) {
string name = field;
string value = Request.Form[field];
//...
}

Related

How does MVC 5 generate url for GET redirect action result?

So in my mvc 5 app, I got this default 'Index' action, which simply redirects to the search action, with the default model values:
[Route]
public ActionResult Index()
{
var model = new T();
return RedirectToAction("Search", model);
}
What i got puzzled about is how i end up with the url like '.../search?xxx=xxx...'? Is there anything i can do to customize or at least inject/replace the url generation, especially the query string part? e.g. i might want to display 1/0 for bool properties in the search model, and customize query string key names etc?
and why would someone vote down for my question? psst...
The query string generated depend on the model property name and type + value you passed in.
For example, say if your pass in model is like
public class MyModel
{
bool IsSort{get;set;}
}
If your model is like this and IsSort value is true, then you will get url like /search?IsSort=true
Say you want to change your query string to 1/0 instead of true or false, then create viewModel which has property string then assing it properly like:
public class MyModel
{
string IsSort{get;set;}
}
var model = new MyModel();
model.IsSort = true? "1":"0";
same apply to querystring key (which correspond to property name)

How to map querystring to action method parameters in MVC?

I have a url http://localhost/Home/DomSomething?t=123&s=TX and i want to route this URL to the following action method
public class HomeController
{
public ActionResult DoSomething(int taxYear,string state)
{
// do something here
}
}
since the query string names does not match with action method's parameter name, request is not routing to the action method.
If i change the url (just for testing) to http://localhost/Home/DomSomething?taxYear=123&state=TX then its working. (But i dont have access to change the request.)
I know there is Route attribute i can apply on the action method and that can map t to taxYear and s to state.
However i am not finding the correct syntax of Route attribute for this mapping, Can someone please help?
Option 1
If Query String parameters are always t and s, then you can use Prefix. Note that it won't accept taxYear and state anymore.
http://localhost:10096/home/DoSomething?t=123&s=TX
public ActionResult DoSomething([Bind(Prefix = "t")] int taxYear,
[Bind(Prefix = "s")] string state)
{
// do something here
}
Option 2
If you want to accept both URLs, then declare all parameters, and manually check which parameter has value -
http://localhost:10096/home/DoSomething?t=123&s=TX
http://localhost:10096/home/DoSomething?taxYear=123&state=TX
public ActionResult DoSomething(
int? t = null, int? taxYear = null, string s = "", string state = "")
{
// do something here
}
Option 3
If you don't mind using third party package, you can use ActionParameterAlias. It accepts both URLs.
http://localhost:10096/home/DoSomething?t=123&s=TX
http://localhost:10096/home/DoSomething?taxYear=123&state=TX
[ParameterAlias("taxYear", "t")]
[ParameterAlias("state", "s")]
public ActionResult DoSomething(int taxYear, string state)
{
// do something here
}

MVC 5 - RedirectToAction - Cannot pass parameter correctly

I have a method that looks as follows:
[Authorize]
public ActionResult Create(int? birdRowId, Entities.BirdSighting sighting)
{
...
...
}
I want to call the above method from another method in the same controller as follows:
[Authorize]
[HttpPost]
public ActionResult Create(Entities.BirdSighting birdSighting, FormCollection collection)
{
...
...
return RedirectToAction("Create", new {birdRowId = 10, sighting = birdSighting});
}
The RedirectToAction method calls the method correctly. And, the first parameter of the method being called (birdRowId) does equal 10. However, the second parameter, sighting, is always null, even though I'm passing an instantiated object with values. What am I doing wrong?
Remember, HTTP is stateless !
RedirectToAction method returns a 302 response to the client browser and thus the browser will make a new GET request to the specified URL.
If you are trying to follow the PRG pattern, I think you should not try to pass complex objects. You should only pass the ID of the resource so that the GET action can build the resource( the model) again using that ID.
return RedirectToAction("Created", "YourControllerName", new { #id=10} );
and in the Created action, read the id and build the object there.
public ActionResult Created(int id)
{
BirdSighting sighting=GetSightingFromIDFromSomeWhere(id);
// to do :Return something back here (View /JSON etc..)
}
If you really want to pass some data across (Stateless) HTTP Requests, you may use some temporary storage mechanism like TempData
Set your object to TempData in your HttpPost action method.
[HttpPost]
public ActionResult Create(BirdSighting birdSighting, FormCollection collection)
{
// do something useful here
TempData["BirdSighting"] =birdSighting;
return RedirectToAction("Created", "YourControllerName");
}
And in your GET action method,
public ActionResult Created()
{
var model=TempData["BirdSighting"] as BirdSighting;
if(model!=null)
{
//return something
}
return View("NotFound");
}
TempData uses Session object behind the scene to store the data. But once the data is read, the data is terminated.

How to add a query string from surface controller in umbraco mvc in order to persist model values

How to add a query string from surface controller in umbraco mvc . This is my current code.
Initially I wrote a code like
public ActionResult Registration(RegisterModel model)
{
//Code to insert register details
ViewBag.Success="Registered Successfully"
return CurrentUmbracoPage();
}
with this I could successful persist my ViewBag and model properties value but I could not add a query string with it.
For certain requirement I have to change the code that returns a url with querystring.
which I did as below
public ActionResult Registration(RegisterModel model)
{
//Code to insert register details
ViewBag.Success="Registered Successfully"
pageToRedirect = AppendQueryString("success");
return new RedirectResult(pageToRedirect);
}
public string AppendQueryString(string queryparam)
{
var pageToRedirect = new DynamicNode(Node.getCurrentNodeId()).Url;
pageToRedirect += "?reg=" + queryparam;
return pageToRedirect;
}
and with this my values of the properties in model could not persist and the ViewBag returned with null value.
Can any one suggest me how to add query string by persisting the values in the model and ViewBag.
Data in ViewBag will not be available on the View when it redirects. Hence you have to add message in TempData which will be available in the View after the redirect like TempData.Add("CustomMessage", "message");

How do I include a model with a RedirectToAction?

In the RedirectToAction below, I'd like to pass a viewmodel. How do I pass the model to the redirect?
I set a breakpoint to check the values of model to verify the model is created correctly. It is correct but the resulting view does not contain the values found in the model properties.
//
// model created up here...
//
return RedirectToAction("actionName", "controllerName", model);
ASP.NET MVC 4 RC
RedirectToAction returns a 302 response to the client browser and thus the browser will make a new GET request to the url in the location header value of the response came to the browser.
If you are trying to pass a simple lean-flat view model to the second action method, you can use this overload of the RedirectToAction method.
protected internal RedirectToRouteResult RedirectToAction(
string actionName,
string controllerName,
object routeValues
)
The RedirectToAction will convert the object passed(routeValues) to a query string and append that to the url(generated from the first 2 parameters we passed) and will embed the resulting url in the location header of the response.
Let's assume your view model is like this
public class StoreVm
{
public int StoreId { get; set; }
public string Name { get; set; }
public string Code { set; get; }
}
And you in your first action method, you can pass an object of this to the RedirectToAction method like this
var m = new Store { StoreId =101, Name = "Kroger", Code = "KRO"};
return RedirectToAction("Details","Store", m);
This code will send a 302 response to the browser with location header value as
Store/Details?StoreId=101&Name=Kroger&Code=KRO
Assuming your Details action method's parameter is of type StoreVm, the querystring param values will be properly mapped to the properties of the parameter.
public ActionResult Details(StoreVm model)
{
// model.Name & model.Id will have values mapped from the request querystring
// to do : Return something.
}
The above will work for passing small flat-lean view model. But if you want to pass a complex object, you should try to follow the PRG pattern.
PRG Pattern
PRG stands for POST - REDIRECT - GET. With this approach, you will issue a redirect response with a unique id in the querystring, using which the second GET action method can query the resource again and return something to the view.
int newStoreId=101;
return RedirectToAction("Details", "Store", new { storeId=newStoreId} );
This will create the url Store/Details?storeId=101
and in your Details GET action, using the storeId passed in, you will get/build the StoreVm object from somewhere (from a service or querying the database etc)
public ActionResult Details(string storeId)
{
// from the storeId value, get the entity/object/resource
var store = yourRepo.GetStore(storeId);
if(store!=null)
{
// Map the the view model
var storeVm = new StoreVm { Id=storeId, Name=store.Name,Code=store.Code};
return View(storeVm);
}
return View("StoreNotFound"); // view to render when we get invalid store id
}
TempData
Following the PRG pattern is a better solution to handle this use case. But if you don't want to do that and really want to pass some complex data across Stateless HTTP requests, you may use some temporary storage mechanism like TempData
TempData["NewCustomer"] = model;
return RedirectToAction("Index", "Users");
And read it in your GET Action method again.
public ActionResult Index()
{
var model=TempData["NewCustomer"] as Customer
return View(model);
}
TempData uses Session object behind the scene to store the data. But once the data is read the data is terminated.
Rachel has written a nice blog post explaining when to use TempData /ViewData. Worth to read.
Using TempData to pass model data to a redirect request in Asp.Net Core
In Asp.Net core, you cannot pass complex types in TempData. You can pass simple types like string, int, Guid etc.
If you absolutely want to pass a complex type object via TempData, you have 2 options.
1) Serialize your object to a string and pass that.
Here is a sample using Json.NET to serialize the object to a string
var s = Newtonsoft.Json.JsonConvert.SerializeObject(createUserVm);
TempData["newuser"] = s;
return RedirectToAction("Index", "Users");
Now in your Index action method, read this value from the TempData and deserialize it to your CreateUserViewModel class object.
public IActionResult Index()
{
if (TempData["newuser"] is string s)
{
var newUser = JsonConvert.DeserializeObject<CreateUserViewModel>(s);
// use newUser object now as needed
}
// to do : return something
}
2) Set a dictionary of simple types to TempData
var d = new Dictionary<string, string>
{
["FullName"] = rvm.FullName,
["Email"] = rvm.Email;
};
TempData["MyModelDict"] = d;
return RedirectToAction("Index", "Users");
and read it later
public IActionResult Index()
{
if (TempData["MyModelDict"] is Dictionary<string,string> dict)
{
var name = dict["Name"];
var email = dict["Email"];
}
// to do : return something
}
Another way to do it is to store it in the session.
var s = JsonConvert.SerializeObject(myView);
HttpContext.Session.SetString("myView", s);
and to get it back
string s = HttpContext.Session.GetString("myView");
myView = JsonConvert.DeserializeObject<MyView>(s);

Resources