Two ways of passing model back from view to controller - asp.net-mvc

I'm new in MVC and have a question of principle about the way how the model is passed back from the view to the controller.
In the usual way the model-object comes from the controller, "spreads" its data into fields of the view and is then gone. The data will then be re-collected by a FormCollection-object passed back to the controller.
But there is also the other way where the model-object itself can be passed back to the controller as routedObject of e.g. an ActionLink, URL-Action or whatever. Then it's not necessary to spread and re-collect all the data.
In my work-place the other way is blocked, I get a warning about forbidden chars in the link-string. When investigating the issue I found that the other way seems mostly unknown.
For many reasons I think it's much better to pass the model-object back instead of the elaborate re-collecting of data.
So what is the reason for this curiosity please?
Update: Added View-Example
#model MvcApplication2.Models.TestClass
#{
#(Model.TestValue = 111);
}
<a href="#Url.Action("ValueBack", Model)">
<span>Test</span>
</a>
public void ValueBack(MvcApplication2.Models.TestClass testClass)
{
int x = testClass.TestValue;
}

In MVC we can get the values of the form in the controller by 3 ways.
Using the FormCollection Object.
Using the Parameters.
Strongly type model binding to view.
And I think it is not possible to send the model to the controller through the actionlink (as an ActionLink helper generates an anchor tag which when clicked sends a GET request to the server)
The Another Way :
Send the id of current model so that the controller action can fetch it back from the datastore from which it initially fetched it when rendering the View.
View:
#Ajax.ActionLink(
"Next",
"Step",
new {
StepId = 2,
id = Model.Id
},
new AjaxOptions { UpdateTargetId = "stepContainer" },
new { #class = "button" }
)
Controller:
public ActionResult Step(int StepId, int id)
{
var model = Repository.GetModel(id);
//Code
}

Related

How to capture the values in a gridview dynamically in asp.net DevExpress MVC

as I can make this code dynamically
public ActionResult EditingUpdate()
{
//...
string fName = GridViewExtension.GetEditValue<string>("FirstName");
string lName = GridViewExtension.GetEditValue<string>("LastName");
//...
}
There are several ways of doing this, it depends on how you want to present the action to the user. I would recommend you follow the example on the DevExpress Demo Page. They show you how to pass the model into your controller.
Controller:
public ActionResult EditingUpdate(MyObject model)
{
string fName = model.FirstName;
....
....
{
Now, the following step is where you have few choices. You can call the controller method in several different ways, all from the gridview partial view. Again, refer to the DevExpress Demo Page. If you want to call the method from an edit action (which is what I assume based on your method name), then you use:
settings.SettingsEditing.UpdateRowRouteValues = new { Controller = "MyController", Action = "EditingUpdate" };
But there are other ways of calling this method, such as
settings.CustomActionRouteValues = new { Controller = "MyController", Action = "EditingUpdate" };
It all depends when you want the gridview to call this method.
Follow the example in the demo, that will help you decide how you want it. Good luck!

How can I return a view(model) and also pass a query string param to the view?

I have an MVC app where users fill in a 4-step form then go to a "confirm" screen. On the confirm screen, if they select to modify their info I use RedirectToAction to take them back to the first step view, and I pass a URL parameter "modify=true", which tells the controller to use the session object already created as opposed to creating a new object from the DB and displaying an empty form. But once they submit the form for step 1 I want to send them from my controller to the step 2 view along with the "modify=true" parameter. There doesn't seem to be a way to return a viewmodel to a view and also pass a query string parameter. How can I accomplish this?
I have considered adding a bool to the viewmodels to signify "inReview" but i use different viewmodels for each of these views and they're all pretty clean, it seems like this bool would muck things up a bit.
I have also considered adding the bool to viewbag or viewdata, but then i'd be using the submit button to pass that value and the "modify=true" parameter would drop off the URL, possibly confusing the user and definitely confusing the code.
Thanks
If you use the Html.BeginForm() helper (without parameters) it will automatically append existing query string parameters to the generated form action attribute. If you use some of the other overloads such as Html.BeginForm("SomeAction", "SomeController", FormMethod.Post) then you're gonna lose those parameters. This could be easily fixed by writing a custom helper that will take into account those parameters:
public static class HtmlHelpers
{
public static IDisposable BeginRequestForm(this HtmlHelper html, string action, string controller, FormMethod method)
{
var builder = new TagBuilder("form");
var urlHelper = new UrlHelper(html.ViewContext.RequestContext);
var routeValues = new RouteValueDictionary();
var query = html.ViewContext.HttpContext.Request.QueryString;
foreach (string key in query)
{
routeValues[key] = query[key];
}
builder.MergeAttribute("action", urlHelper.Action(action, controller, routeValues));
builder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
html.ViewContext.Writer.Write(builder.ToString(TagRenderMode.StartTag));
return new MvcForm(html.ViewContext);
}
}
and then use in your view (after bringing it into scope of course):
#using (Html.BeginRequestForm("SomeAction", "SomeController", FormMethod.Post))
{
...
}
You can either use ViewBag or your view model. You just need to pass the value somehow to the view:
ViewBag.modify = true;
return View(model);
Then in your view:
Html.BeginForm("MyAction", "MyController", new { modify = ViewBag.modify })

Passing ArrayList parameter to controller action ASP.NET MVC

I am writing an application wherein I need to send a System.Collections.ArrayList data as a parameter from one controller action to another.
I am using
return RedirectToAction("action1","controller1", new { arrList = arrListInFirstAction});
But since the ArrayList goes out of scope in the first action, the parameter in the redirected to action receives a null parameter.
Can someone please help me find an answer to this problem.
Thanks.
you can not send complex types as route parameters. you can, however, use TempData collection to keep that object for one request and on next request it will be automatically removed from collection
publci ActionResutl action()
{
TempData["arr"] = new int[]{1,2,3};
return RedirectToAction("action1");
}
Public ActionResult action1()
{
int[] arr = TempData["arr"];
return View();
}

MVC: How can I pass a list from one view to another?

I've got some data in a view that I would like to pass to a child partial view. Part of that data is a list of dates that I would like to display in the partial view. I'm pretty sure I can't pass an IEnumerable from one view to another (when I try list is null in the controller). Assuming that is the case, is there a good work around?
I've thought about just concatenating the values into a string and then just parsing that string in the controller. That seems a bit hackish, but I think it would work. Is there a problem with doing it like that? Is there a better way?
It just seems like such a shame to have to re-fetch the data that I've got in the parent view. I'm hoping there's another way to do it.
Update:
This is the model for the partial view:
public class SiteVisitDetailModel
{
public String URL
{
get;
set;
}
public List<DateTime> Dates
{
get;
set;
}
}
And this is the code from the parent view to add the partial view:
<% Html.Telerik().PanelBar().Name("PanelBar").HtmlAttributes(new { style = "padding-left: 0em;" }).Items(items =>
{
foreach (var item in Model.Visits)
{
SiteVisitDetailModel model = new SiteVisitDetailModel();
model.URL = item.Key;
model.Dates = (from siteVisit in item
select siteVisit.Time).ToList();
items.Add()
.Text(item.Key.ToString() + " " + item.Count().ToString() + " visits")
.LoadContentFrom("SiteViewDetail", "Report", model);
}
}).Render();
In the SiteVisitDetail action method, model.URL is properly set, and model.Dates is null.
If I understood your problem correctly...
If your partial view can be strongly typed, its model could be the list, and you can do:
<%Html.RenderPartial("PartialView",myList);%>
Otherwise, the parent view can add the list to its ViewData, which would be accessible from the partial view.
Check this post out on how to pass models around.
Essentially you shoiuld probably pass a model to the view that contains your list. then you can extend it later on.
Multiple models sent to a single view instance

How do you persist querystring values in asp.net mvc?

What is a good way to persist querystring values in asp.net mvc?
If I have a url:
/questions?page=2&sort=newest&items=50&showcomments=1&search=abcd
On paging links I want to keep those querystring values in all the links so they persist when the user clicks on the "next page" for example (in this case the page value would change, but the rest would stay the same)
I can think of 2 ways to do this:
Request.Querystring in the View and add the values to the links
Pass each querystring value from the Controller back into the View using ViewData
Is one better than the other? Are those the only options or is there a better way to do this?
i use a extension method for that:
public static string RouteLinkWithExtraValues(
this HtmlHelper htmlHelper,
string name,
object values)
{
var routeValues = new RouteValueDictionary(htmlHelper.ViewContext.RouteData.Values);
var extraValues = new RouteValueDictionary(values);
foreach (var val in extraValues)
{
if (!routeValues.ContainsKey(val.Key))
routeValues.Add(val.Key, val.Value);
else
routeValues[val.Key] = val.Value;
}
foreach (string key in htmlHelper.ViewContext.HttpContext.Request.Form)
{
routeValues[key] = htmlHelper.ViewContext.HttpContext.Request.Form[key];
}
foreach (string key in htmlHelper.ViewContext.HttpContext.Request.QueryString)
{
if (!routeValues.ContainsKey(key) && htmlHelper.ViewContext.HttpContext.Request.QueryString[key] != "")
routeValues[key] = htmlHelper.ViewContext.HttpContext.Request.QueryString[key];
}
var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
return string.Format("{1}", urlHelper.RouteUrl(routeValues), name);
}
I would process the QueryString in the view (your option #1), instead of passing it in from the controller. This approach makes the view more self-contained, allowing you to convert it into a view control and re-use it across different views.
Note: Accessing the QueryString directly in the view may seem like a violation of the design principle of separating the Model and View, but in reality this data is a navigational concern which is related to the view, not really part of the model.
I would just keep the values in the Session that way the paging links only need to have;
/questions?page=2
/questions?page=3
The one reason why I would not us the QueryString is because I don't want the user to see the values that I am passing to the program. It makes it way too easy for them to go into the address bar and start changing the values to 'see what happens'. With this code all they could do is change the page number.
Here's how I done it in Asp.Net Core, first assign the query string parameters to ViewBags in your controller:
[HttpGet("/[controller]/[action]/{categoryId?}/{contractTypeId?}/{locationId?}")]
public IActionResult Index(Guid categoryId, int contractTypeId, Guid locationId)
{
ViewBag.CategoryId = categoryId;
ViewBag.ContractTypeId = contractTypeId;
ViewBag.LocationId = locationId;
...
}
Then pass the values to your links like so:
<a asp-action="Index" asp-controller="Jobs"
asp-route-categoryId="#teachingCategory.Id"
asp-route-contractTypeId="#ViewBag.ContractTypeId"
asp-route-locationId="#ViewBag.LocationId">
#teachingCategory.Description (#teachingCategory.Rank)
</a>
<a asp-action="Index" asp-controller="Jobs"
asp-route-categoryId="#ViewBag.CategoryId"
asp-route-contractTypeId="#typeOfEmployment.Id"
asp-route-locationId="#ViewBag.LocationId">
#typeOfEmployment.Name
</a>
<a asp-action="Index" asp-controller="Jobs"
asp-route-categoryId="#ViewBag.CategoryId"
asp-route-contractTypeId="#ViewBag.ContractTypeId"
asp-route-locationId="#item.Id">
#item.Id
</a>
Note that every link keep its own actual value and pass the rest of the route values through what we passed to ViewBag.

Resources