MVC Model Binding Issue always NULL - asp.net-mvc

I am trying to add a new MVC ActionLink that when pressed goes to an action and gets bound to the input parameter but it doesn’t seem to be working
I Have this:
#Html.ActionLink("OPTIN","Optin", "Admin", new {id = Model.Publications[i].ID})
And then the Optin method on the Admin controller:
public ActionResult OptIn(int? id)
{
if (id.HasValue)
{
var temp = id.Value;
}
I want the id to get mapped to the input parameter but it is always NULL and Model.Publications[i].ID is always 5. What am I doing wrong? Do I have to make ID part of a model?

The way that you have your ActionLink method set up is wrong. I'm GUESSING the override you're using is this one. However, you'll want to be using is string, string, string, object, object.
By the URL in the comment on your question, the ID that you're setting is the HTML attribute, not a part of the URL.
If you change your call to the following, it should give you what you need:
#Html.ActionLink("OPTIN","Optin", "Admin", new {id = Model.Publications[i].ID}, new { })

Related

sending string from view to controller in asp.net

I'm trying to get data from view in string
Here's the code in View
And in controller, I'm getting this customer name like this:
public ActionResult ViewCustomerDetails(string c_name) {
List<Sale> customerList = new List<Sale>();
customerList = db.Sales.Where(x => x.sale_customer == c_name).ToList();
double total_cash_recieved = 0;
double total_amount = 0;
foreach (var customer in customerList) {
total_cash_recieved = total_cash_recieved + (double)customer.cash_recieved;
total_amount = total_amount = (double)customer.sale_amount;
}
double remaining_balance = total_amount - total_cash_recieved;
ViewBag.TotalAmount = total_amount;
ViewBag.TotalRecieved = total_cash_recieved;
ViewBag.TotalRemaining = remaining_balance;
return View(customerList);
}
But the problem is, in c_name variable, I'm getting null.
Anyone know how to correct it or solution?
Since your parameter name is c_name, you should include that in your querystring as Burak mentioned in his answer.
If you prefer, you can render the link using Html.ActionLink helper method.
Html.ActionLink("View","ViewCustomerDetails","Admin",new { c_name=customer.name},null)
Or if you prefer to keep the existing url you have, you can update your ViewCustomerDetails method's parameter name to Id so that with the default route definition, your unnamed parameter value will be mapped to Id parameter.
public ActionResult ViewCustomerDetails(string id) {
var c_name=id;
// your existing code
}
It is always a good idea to pass a unique Id ( Customer ID etc..) instead of passing a name to show the details because I know more than one scott in the world.
You should send it like this:
And make sure that #customer.name is not null before going to the server side.
or you can set new route to RouteConfig.cs
routes.MapRoute(
name: "Default2",
url: "Admin/ViewCustomerDetails/{c_name}",
defaults: new { controller = "Admin", action = "ViewCustomerDetails", c_name= UrlParameter.Optional }
);
You didn't pass the parameter to the controller.
You can always simply pass parameters as part of query string as long as action method on controller is expecting them by exactly the the same name in the signature.

Why use "new" for Route Values in "ActionLink" ---- for example

I have 2 examples below:
#Html.ActionLink("Create New", "Create", new { id = Model.Id })
and,
return RedirectToAction("Index", new { id = review.RestaurantId });
My question is regarding the new { id = xxx} part in object route values. Why do we use "new" in this case? What exactly does it do? Does it initialize "id" variable in this case?
Also, it is strange that these methods, create and index definition can only take arguments as defined in the route values...
That is,
public ActionResult create { int id)
{ ...}
is correct but following is wrong....
public ActionResult create { int somethingelse)
{ ...}
So please tell me what is the new {id = xx} in my first 2 examples is doing?
Thanks
new {} creates a new object of type Object. The type is anonymous. You see that syntax when writing linq queries that end in " select new {x = "foo". y="bar"}". It is often used when setting an object to type "var".
What you are doing in your ActionLink is providing Route Values. MVC takes the properties and values in the object and puts them in the QueryString of the request. It is what you might refer to as "magic". You can set a break point in your controller Action and check "HttpContext.Request.QueryString" to see it.
The input values for you Action methods have to match the properties that are being passed in via the QueryString.
That is actually creating an anonymously typed object and passing it into ActionLink(). ActionLink then uses that object, coupled with your routing rules to generate the link. MVC will look for properties on that object that match the routing names (usually of route parameters) and figure out how to build it. Since you likely have the default MVC route (/controller/action/{id}) that is what links everything together.
Further, that is why id "is correct", but somethingelse "is wrong".
If you change "id" to "somethingelse" in your routing rule, you could then see new { soemthingelse = ""} work in your ActionLink().
Does that help?
In both cases your creating a new anonymous object to pass into the query string as a route value. You create a new object because one does not already exist on the view.
The MVC source code:
if (additionalViewData != null) {
foreach (KeyValuePair<string, object> kvp in new RouteValueDictionary(additionalViewData)) {
viewData[kvp.Key] = kvp.Value;
}
}
They use it to create new RouteValueDictionary parameters.
You don't have to use it the this manor. You could create an object on the model and pass it in:
public class SomeModel
{
public SomeModel()
{
MyObject = new { id = 10 };
}
public int Id {get;set;}
public object MyObject {get;set;}
}
#Html.ActionLink("Create New", "Create", Model.MyObject)
This would also work though is probably not something you would attempt.
For the second part of your question. The RouteValueDictionary searches by key and assigns the value to the key that was given.
So whatever you call the key in the anonymous object, MVC will attempt to assign the value to it on the action. The name must match or they key cannot assign the value.

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 })

ASP.NET MVC Map String Url To A Route Value Object

I am creating a modular ASP.NET MVC application using areas. In short, I have created a greedy route that captures all routes beginning with {application}/{*catchAll}.
Here is the action:
// get /application/index
public ActionResult Index(string application, object catchAll)
{
// forward to partial request to return partial view
ViewData["partialRequest"] = new PartialRequest(catchAll);
// this gets called in the view page and uses a partial request class to return a partial view
}
Example:
The Url "/Application/Accounts/LogOn" will then cause the Index action to pass "/Accounts/LogOn" into the PartialRequest, but as a string value.
// partial request constructor
public PartialRequest(object routeValues)
{
RouteValueDictionary = new RouteValueDictionary(routeValues);
}
In this case, the route value dictionary will not return any values for the routeData, whereas if I specify a route in the Index Action:
ViewData["partialRequest"] = new PartialRequest(new { controller = "accounts", action = "logon" });
It works, and the routeData values contains a "controller" key and an "action" key; whereas before, the keys are empty, and therefore the rest of the class wont work.
So my question is, how can I convert the "/Accounts/LogOn" in the catchAll to "new { controller = "accounts", action = "logon" }"??
If this is not clear, I will explain more! :)
Matt
This is the "closest" I have got, but it obviously wont work for complex routes:
// split values into array
var routeParts = catchAll.ToString().Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
// feels like a hack
catchAll = new
{
controller = routeParts[0],
action = routeParts[1]
};
You need to know what part is what in the catchAll parameter. Then you need to parse it yourself (like you are doing in your example or use a regexp). There is no way for the framework to know what part is the controller name and what is the action name and so on, as you haven't specified that in your route.
Why do you want to do something like this? There is probably a better way.

ASP.NET MVC: action methods with one param not named ID and non-integer

Consider an ASP.NET MVC 1.0 project using the Areas convention as described on this Nov. 2008 Phil Haack blog post. This solution works great once it's set up!
My trouble is starting thanks to my limited knowledge of ASP.NET MVC's routing rules.
My intention is to create an action method and URL structure like this:
http://mysite/Animals/Dogs/ViewDog/Buster
DogsController.ViewDog() looks like this:
public ActionResult ViewDog(string dogName)
{
if (dogName!= null)
{
var someDog = new DogFormViewModel(dogName); //snip a bunch more
return View(someDog);
}
else { return View("DogNotFound"); }
}
The task at hand is ensuring that the RegisterRoutes() has the correct entries.
UPDATE
Here's the new route being mapped:
routes.MapRoute("ViewDog", "Animals/{controller}/{action}/{dogName}",
new { controller = "Dogs",
action = "ViewDog", dogName = "" });
The link to the URL is created:
<%= Html.RouteLink("Brown Buster", "ViewDog", new RouteValueDictionary(new { controller="Dogs", action="ViewDog", dogName="Buster" }))%>
The URL is created as expected. Thanks to Craig Stuntz and his blog post on Html.RouteLink.
http://mySite/Animals/Dogs/ViewDog/Buster
New Problem: The param dogName doesn't pickup the string value "Buster" from the URL. The call to the method succeeds, but the argument evaluates to null.
Questions
How can you:
make this route work with a string, and remove the default convention int id in the route? I'd like to change the name of the parameter away from int.
Are you sure that ActionLink is actually matching the route you show them the question? When you have more than one route, I strongly recommend using RouteLink instead of ActionLink, as I explain in great detail in this post. When you use RouteLink, there is no possibility that you will match the wrong route, at least in URL generation.
The default parameter "id" doesn't have to be an int. It'll match whatever type you declare in your action method. Why not just do the following?
public ActionResult ViewDog(string id)
{
if (id!= null)
{
var someDog = new DogFormViewModel(id); //snip a bunch more
return View(someDog);
}
else { return View("DogNotFound"); }
}

Resources