Passing params with #Html.Beginform - c#

I'm getting the dreaded "The parameters dictionary contains a null entry for parameter 'equipmentid' of non-nullable type" error when attempting to pass data through with a form. I've scoured google and stack overflow for answers and explanations, but I've come to the conclusion the problem has to me be not understanding how this stuff works. Coming from a traditional programming background the web stuff just doesn't seem as intuitive to me.
Here is my view code
#using (Html.BeginForm("CreateReservation", "ReservationList", FormMethod.Get, new { #equipmentID = 1 }))
{
<button class="btn btn-blue">Click</button>
}
Here is my controller
public ActionResult CreateReservation(int equipmentid)
{
// TODO: Query the piece of equipment being reserved.
return View();
}
Can anyone tell me what exactly am I doing wrong? From the answers I've read before and the examples I've viewed, I feel as though this should work.

I am assuming from your code that this is an Asp.Net MVC project, using C# as the language.
There are a number of issues. The first is that the equipmentID variable is not being passed to the view. There are a number of ways to do this. The simplest will be to do it in your controller using the ViewData dictionary, as follows:
public ActionResult CreateReservation(int equipmentid)
{
// TODO: Query the piece of equipment being reserved.
ViewData["equipmentID"] = equipmentid;
return View();
}
Once this is done, you could modify your view code to use the value as follows:
#using (Html.BeginForm("CreateReservation", "ReservationList", FormMethod.Get, new { equipmentID = ViewData["equipmentID"] }))
{
<button class="btn btn-blue">Click</button>
}
This is fine for one or two values, but when the view gets more complex, you rather want to create a ViewModel class, and pass that class to your view.
Secondly - your use of the # in front of equipmentID inside your BeginForm call indicates that you probably need to study up a bit on Razor syntax. A good place to start is Phil Haack's Razor Syntax Quick Reference. Razor syntax is what tells the parser which parts of your view are static HTML that it should output as is, and which parts are C# code that it should execute before sending to the browser. If you are using Visual Studio as your IDE, it is pretty good at highlighting which parts of your code are being interpreted as C# code, and which parts as ordinary HTML.
In my screenshot below you can see that VS2012 highlights C# code with a light grey background colour. The # symbol is the start of C# code - so you don't need to use it again unless you break out of the C# block and go back to HTML.
And thirdly, you probably wouldn't want to pass the equipment ID as an HTML attribute inside your form tag. You should rather create a hidden form field inside your form body and set the name to equipmentID, and the value to the variable's value. The way you are currently using it will add an HTML attribute to the form tag, and your generated code will look something like this:
<form action="/ReservationList/CreateReservation" method="get" equipmentID="1">
And this extra attribute will not be retrievable in your code. Rather do something like this in your view:
#using (Html.BeginForm("CreateReservation", "ReservationList", FormMethod.Get, new { name = "myFormName", id = "myFormID" }))
{
#Html.Hidden("equipmentID", ViewData["equipmentID"])
<button class="btn btn-blue">Click</button>
}

Related

ViewBag in View without #

I don't get why we sometimes use ViewBag without reference (I mean #) to Controller in View, e.g.:
#{
string urlFilter = Url.Action("Index", "Home", new
{
CustID = ViewBag.custid,
Errors = ViewBag.errors
});}
It looks like a part of c# code in view. I know that razor synthax allow us to inject c# code into View but don't understand what's the point of using ViewBag without # in View
In this case it is because it is within the scope of a C# code block (#{ ... }) and not in the HTML markup.
If however, you were trying to reference the ViewBag inline in an HTML block you would need to prefix it with # to make sure it was processed by the Razor engine.
for example:
<p>#ViewBag.Name</p>
ViewBag is a dynamic property on the WebPageView from which the view is derived.
You can learn about the Razor syntax here: https://learn.microsoft.com/en-us/aspnet/web-pages/overview/getting-started/introducing-razor-syntax-c

How to make Html.TextBox(string name) render sanitized input?

I am using ASP.NET MVC4 with .NET Framework 4.5. I have a controller action that accepts a model of one type with a property named 'Name' but renders a view using a model of another type. I am still able to use #Html.TextBox("Name") and #Html.ValidationMessage("Name").
I want the textbox to display the sanitized input, that is, the input without leading/trailing/extra spaces the user may have entered. The setter for my model sanitizes the value for me, and I am successfully obtaining the sanitized value using the getter within the controller action. It's just that upon submitting the form, the textbox still displays the unclean input.
Is there some mechanism I am missing? Is the #Html.TextBox(string name) helper looking at the raw request data and not the model? If so, how come the validation message is working?
Update
I have just tried defining a new view model that includes my textbox field so I could hopefully just use the #Html.TextBoxFor helper. Everything is still working as it was after a re-build, I am still not getting sanitized input appearing in the textbox. I still don't know a solution for this.
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult MyAction(MyViewModel model)
{
if (this.ModelState.IsValid)
{
using (var service = new MyService())
{
model.MyResults = service.DoSomething(model.MySanitizedProperty);
}
}
return this.View("MyView", model);
}
Then, in "MyView":
#Html.TextBoxFor(m => m.MySanitizedProperty)
<input type="submit" value="Go" />
#Html.ValidationMessageFor(m => m.MySanitizedProperty)
In the controller, invoking model.MySanitizedProperty returns the sanitized value while the textbox goes on to display the unsanitized data.
It sounds like a problem with the models; make sure you are properly accessing the value from the model you wish to populate it with, i.e., possibly discretely specifying the model "Name" is coming from.
Also, check to see that the setter has a chance to operate on the value - if the controller is activating before the setter function is used, then you'll only get the original input value.
Realize you have to go to the server for the setter to work, possibly you need a async postback or such, and the value reloaded.

Does ASP.NET MVC form post autopopulate fields?

I have a form like ...
#using (Html.BeginForm("create", "Account", FormMethod.Post, new { id = "accountform_form" }))
{
#Html.TextBoxFor(e => e.ShipFirstName)
...
}
while testing, I was surprised to see the field retained its value on postback even without me assigning it to the view-model. Using the debugger, the value for ShipFirstName is null right at the end of the action when returning the view, so why would it show the value that was in the field? Have I been unnecessarily assigning posted values to view-model properties all this time? Or is there something else going on?
Update: the action is like so...
[HttpPost]
public ViewResult Create(AccountFormModel postModel)
{
var model = new AccountFormModel(postModel, stuff, stuff); //I use posted values and paramters to create the actual view model
return view(model);
}
So, I see the GET form, enter values, say I enter a field and leave a required field blank, submit, the resulting page has the value I entered in the other field, who's putting it there when in the model it's null?
I ran into something similar earlier today (a checkbox was always checked). Have a look at Changing ViewModel properties in POST action and see if this is similar.
Basically calling ModelState.Clear() fixed it for me.
As you're passing the model back to the view after it has been POSTed, MVC is taking the stance that you're doing so because the form contains errors. So, rather than making the user fill out the form again, it repopulates it using the ModelState collection. In this case, the values in the ModelState collection take precedence over the changes you make in the action (which does feel a bit weird).
You can get around this either by calling ModelState.Clear() or using ModelState.Remove(string key), where key is the name of the property.
If you'd like a full explanation of why this is the case, see ASP.NET MVC’s Html Helpers Render the Wrong Value!. Excerpt:
Why?
ASP.NET MVC assumes that if you’re rendering a View in response to an HTTP POST, and you’re using the Html Helpers, then you are most likely to be redisplaying a form that has failed validation. Therefore, the Html Helpers actually check in ModelState for the value to display in a field before they look in the Model. This enables them to redisplay erroneous data that was entered by the user, and a matching error message if needed.

How to include #Html.Actionlink in C# text string?

While the #Html.Actionlink() helper is very convenient for building <a> elements in the .cshtml files, is it possible to construct them inside C# strings, such that they are subsequently rendered correctly in the HTML output?
For example, if I assign a string variable a value similar to the following:
Book.ReadMore = "Click #Html.ActionLink(\"this link\", \"About\", \"Home\") to read more.";
And then I try to display it (the literal text plus the link) through my .cshtml page, using code similar to:
<p>#Model.ReadMore</p>
All I get in the browser is the whole string exactly as I typed it, including the #Html... etc:
Click #Html.ActionLink("this link", "About", "Home") to read more.
Now, for proper SoC, I know that it's not the best of practices to have HTML stuff included in C# code, but is it at all possible to get the proper <a> link in this scenario, instead of the string itself?
EDIT: More information - This string is just one item in a collection of about 20-30 strings (displayed using a for loop in the View). Only a small handful of those items need a link (which is different in each case). Since, as mentioned above, I agree that it's obviously not good practice to use Razor/HTML in Model code, I'm trying to get a simple approach (if possible) which would give me the flexibility of building the link somewhere at the right place, while still yielding the maintainability of MVC SoC.
There must be a "right" way of doing this, which is simple yet maintainable.
Your model should not contain HTML, that's a view concern and belongs in view code. Probably you should be using a Razor helper.
In your App_Code folder (create one if you don't have one), add a file, ReadMoreHelpers.cshtml:
#helper ReadMore() {
<text>Click #Html.ActionLink("this link", "About", "Home") to read more.</text>
}
Then in any view:
#ReadMoreHelpers.ReadMore()
And that will output what you want. If you insist on putting that property in your view, you could do:
Book.ReadMore = "Click " + #Html.ActionLink("this link", "About", "Home").ToHtmlString() + " to read more.";
Then in your view, make sure you use Raw:
#Html.Raw(Book.ReadMore)
However, I couldn't recommend more strongly that you do not put HTML in your model properties.
I don't think so. The Razor view engine will interpret the ActionLink code during run-time while stuffing it as part of a C# string will be interpreted during compile time.

Write additional HTML comments in razor

I'm struggling with the following problem and I can't find an acceptable way to solve it.
My challenge: write out HTML comments just before the actual property value in a Razor view.
This is my (simplyfied) Viewmodel:
public class Article
{
public string Title {get;set;}
}
To write out this title I simply do this in my Razor view:
<h2>#Model.Title</h2>
Now I want to write out a html comment just before the actual title so the generated HTML looks like this (simplyfied):
<h2><!-- some parameters for a 3th party system --> This is my title</h2>
The HTML comment comes from an Attribute I applied to the 'Title' attribute. It's value is generated, so the attribute-value is added at runtime using the TypeDescriptor from the .NET framework.
Now I know I could achieve this by simply writing out all my properties using an HTML helper. Like this: #MyHelper.Write(m => m.Title)
But since potentially ALL my properties need this HTML comment I want to avoid the use of an HTML helper since it clutters the View and doesn't make the view look nice and (more) readable.
This is what I have tried:
Created a custom Razor base page (Inheriting from WebViewPage<TModel>). And overwriting it's 'Write' method.
This kind of works but the BIGGEST problem here is that I don't know which property is been written out at that moment. There is no way of getting the current property name in the 'Write' method. So now I dynamically search my Model to find a property with the value that's been written out and prepend the HTML comment from the attribute.
My question: is there another approach to accomplish what I want. As sais before: I want to avoid using an HTML helper to write out all my properties. (Think about loops, etc. It's just not nice).
Also, adding this HTML comment in my Controller is no option since:
it's not part of the actual value. Is a sort of metadata.
The HTML comment should be added to int's, double's and DateTime's. There is no way to adjust a double property to include a string. (Image a List<DateTime>. All date's need this HTML comment)
the HTML comment should be added based on a web.config setting. Yes or No. (The actual HTML comment is different for each value of a property)
I realize this question is rather long. Sorry for that. Any thoughts are appreciated.
You can use the existing #Html.Raw(Model.Title)
Alternatively you can use a display templates. Add a UIHintAttribute to the properties you wish to behave this way.
public class MyModel
{
[UIHint("Raw")]
public string MyString { get; set; }
}
Create a new display template called Raw.cshtml that accepts model of type string:
#model string
#Html.Raw(model)
Then in your view you can use:
#Html.DisplayFor(m => m.MyString)
This still requires that you use a helper (DisplayFor). This is a recommended practice that allows you to easily change the behavior of one or many fields with minimal code changes.

Categories

Resources