I have a simple feedback form on our website. When users enter html in the page, they should get a validation error message. But they don't. The exception is thrown and caught in:
void Application_Error(object sender, EventArgs e)
{
...
}
The exception caught here is:
A potentially dangerous Request.Form value was detected from the
client
at System.Web.HttpRequest.ValidateString(String value, String
collectionKey, RequestValidationSource requestCollection)
Here is the Asp.net MVC markup:
<form action="<%=Url.Action("Create") %>" method="post" class="data-entry-form">
<fieldset class="comment">
Your thoughts:
<div class="editor-field">
<%= Html.TextAreaFor(model => model.Comment, 10, 2, new { placeholder="your message" }) %>
<%= Html.ValidationMessageFor(model => model.Comment) %>
</div>
<br />
E-mail address (optional)
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Email, new { placeholder="you#youremailaddress.com" }) %>
<%= Html.ValidationMessageFor(model => model.Email) %>
</div>
<input type="submit" value="Send" />
</fieldset>
</form>
and here is the generated html:
<form action="/feedback/Create/" method="post" class="data-entry-form">
<fieldset class="comment">
Your thoughts:
<div class="editor-field">
<textarea cols="2" id="Comment" name="Comment" placeholder="your message" rows="10">
</textarea>
</div>
<br />
E-mail address (optional)
<div class="editor-field">
<input id="Email" name="Email" placeholder="you#youremailaddress.com" type="text" value="" />
</div>
<input type="submit" value="Send" />
</fieldset>
</form>
And here is the controller code:
[HttpPost]
public ActionResult Create(Feedback feedback)
{
if (ModelState.IsValid)
{
FillFeedbackObject(feedback);
feedbackRepository.AddFeedback(feedback);
return View("SuccessMessage", new SuccessMessageModel("Thanks for your message!"));
}
return View(feedback);
}
I also have <add key="ClientValidationEnabled" value="true" /> in the appSettings section of the web.config file and I am including jquery.validate.js. So both client side and server side validation fail.
What is wrong?
It's not technically a Model's error, that's why you cannot handle it with Model.IsValid code statement.
If you actually allow html to be submitted in this field or want to sanitize submitted value on server you may annotateComment property of your model with [AllowHtml] attribute. Also, if you want to notify user that they cannot include tags in the text, you may add an error to ModelState during feedback parsing on server side with ModelState.AddModelError() method.
Obviously, leaving request validation in place has it's advantages, and you're correct disabling request validation shouldn't be taken lightly. But there's no graceful way to handle this exception in ASP.NET because it happens so early in the pipeline. It's the actual framework protecting you from yourself.
You can use the Application_Error event that you pointed out in your original post. The come up with some code like:
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
if (exception is HttpRequestValidationException)
{
// use Response.Redirect to get the user back to the page, and use session/querystring to display an error
}
}
Try adding the [ValidateInput(false)] attribute to your controller action method.
Source: http://msdn.microsoft.com/en-us/library/system.web.mvc.validateinputattribute.aspx
Edit: If you still want to validate, you should encode the input before sending to the server, for example using HttpUtility.HtmlEncode. The reason the validation blocks the code is because it could be malicious. By encoding it you can allow it to pass through and still have validation enabled. However you may need to change your validation rules/attributes to account for the encoding. In case it wasn't clear before, this option requires validating on the server side once you get to the controller, adding an error to the ModelState as needed, and returning the same view or partial view as needed in case of errors.
With MVC 3 and above you can use the AllowHtml attribute with the property that can contain some html
Related
When I click submit on view, the system redirects to a new view. If validation fails, the system redirects to the same page highlighting the fields. However, I also require the system to show a label with the error message.
<label for="label6" style="color:red; font-weight:normal !important; visibility: hidden">
The Corporate Email, FEIN or SSN does not match.<br /><br />
<span style="margin-left: 10%"></span>The following might be the case:<br />
<span style="margin-left: 12%"></span>- The Corporate Email entered is wrong. Please check the Corporate Email.<br />
<span style="margin-left: 12%"></span>- The FEIN entered is wrong. Please check the FEIN.<br />
<span style="margin-left: 12%"></span>- The SSN entered is wrong. Please check the SSN.<br />
<span style="margin-left: 12%"></span>- Please verify whether FEIN or SSN entered during registration.<br />
<span style="margin-left: 16%"></span>If you have registered using FEIN please submit using FEIN.<br />
<span style="margin-left: 16%"></span>If you have registered using SSN please submit using SSN.<br />
</Label>
Can someone help me with this.
I don't think you want to do it like that. Why tell them what the error might be when you can tell them what the error actually is?
In your view, after each #Html.EditorFor put a #Html.ValidationMessageFor.
#Html.TextAreaFor(a => a.EmailID)
#Html.ValidationMessageFor(a => a.EmailID)
#Html.TextAreaFor(a => a.Password)
#Html.ValidationMessageFor(a => a.Password)
If your model state is invalid and you return to the view, the validation messages are automatically displayed for the invalid fields.
Going further, you can get the validation to be done using JavaScript in the browser, so that if the data is invalid the error message(s) will be displayed without needing a trip back to the server.
Simply add the following to the end of your view:
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
(This assumes your site is based on the standard ASP.NET MVC template, and that you view uses a layout view. If not, you may have to do a bit of tweaking to get the correct JavaScript files.)
WARNING: Never rely solely on browser validation checking. It is there as a benefit to users so they get errors reported slightly faster. However, it is very easy for hackers to bypass browser checking, so always check the model state on the server as well.
If you want exactly that content, then in your controller, when the model is invalid, put
ViewBag.InvalidModel = true;
Then in your view put
#if(ViewBag.InvalidModel)
{
<!-- Your label here-->
}
In controller
public ActionResult Index()
{
if (ModelState.IsValid)
{
//do something
return Redirect("/yournewpage");
}
if (!someChecks)
{
ModelState.AddModelError("", "Your custom error");
}
if (!someChecks2)
{
ModelState.AddModelError("", "Your custom error 2");
}
return View();
}
You can use in view
<p>
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<p>
I have an UnderConstruction page which is being handled by MVC. The view has the following code to route a user, after entering their email address to the registration page which is part of the identity scaffolded razor area. The intent is to bring up the register page with their email already populated in the email input.
<!-- route to Register Form -->
<form class="form-inline push-10" method="get">
<div class="form-group">
<label class="sr-only text-white" asp-for="Email">Email Address</label>
<input class="form-control" type="email" asp-for="Email" placeholder="Your Email..">
</div>
<div class="form-group">
<button class="btn btn-default" type="submit" asp-area="Identity" asp-page="/Account/Register" asp-page-handler="WithEmail">
<i class="fa fa-plus"></i> Register
</button>
</div>
<div class="form-group">
<a class="btn btn-default" asp-controller="Home" asp-action="Index">
<i class="fa fa-home"></i> Home
</a>
</div>
and the pages view model
public class UnderConstructionViewModel
{
public string Email { get; set; }
}
Clicking the Register button after entering an email address produces this url
https://localhost:44367/Identity/Account/Register?Email=testemail#mydomain.com
This brings you to the register page with the email address NOT populated in the email input.
Here is the method in register.cshtml.cs (scaffolded razor area for identity)
public IActionResult OnGetWithEmail(string email)
{
return RedirectToPage("Register", new InputModel{ Email = email });
}
The problem is, the method never gets hit. The handler is following convention, and the model is following convention, so I am not sure why the method is not getting hit.
I also tried the asp- tag helpers in the form call, but that produces the same result.
Any help sorting this out would be appreciated.
Any query string values that are appended to the form's action attribute, or in this case the formaction attribute are wiped out by the routing system when the form is submitted. This appears to be by design: https://github.com/aspnet/Mvc/issues/8621
You can resolve this by adding "{handler?}" to the #page directive in the Register page. Then the handler name is appended to the URL as a segment rather than as a query string value.
So I'm relatively new to ASP.NET Razor and I'm getting a consistent error that I'm not sure how to fix. I've created an ASP.NET Core Web Application MVC with Razor Pages.
I'm currently getting the error: InvalidOperationException: Incorrect Content-Type: Microsoft.AspNetCore.Http.Features.FormFeature.ReadForm()
when I load the project. It's telling me that the error is in the line email = Request.Form["email];
File the error is relating to:
#page
#model IndexModel
#{
ViewData["Title"] = "Login";
var email = "";
var pswd = "";
bool rem = false;
email = Request.Form["email"];
pswd = Request.Form["pswd"];
}
<div class="progress mt-5">
<div class="progress-bar progress-bar-striped progress-bar-animated"
style="width:40%"></div>
</div>
<br />
<div class="container mx-auto bg-warning" style="width:50%;">
<h1 class="title" style="text-align:center">TestWebApp</h1>
<form method="post" class="px-3 py-5">
<div class="form-group input-group">
<div class="input-group-prepend">
<span class="input-group-text bg-primary border-0 text-light" style="width:100px">Email</span>
</div>
<input type="email" class="form-control" id="email" placeholder="Enter email" name="email" value="">
</div>
<div class="form-group input-group">
<div class="input-group-prepend">
<span class="input-group-text bg-primary border-0 text-light" style="width:100px">Password</span>
</div>
<input type="password" class="form-control" placeholder="Enter password" name="pswd" value="#pswd">
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="remember" value="#rem"> Remember me
</label>
</div>
<button type="submit" class="btn btn-primary" name="submit">Submit</button>
</form>
</div>
The weird thing is I ran this code multiple times before, just making small design changes with no relation to the form itself and it worked fine without an error but has now started showing this error and I'm not sure how to fix it. Would be very thankful for some help.
I don't know what does Request stand for in your code. Because nothing in your page is named that way. If you have some sort of shortcut somewhere I guess you're getting the Request property from your model. So you're referring to the PageModel's Request property that gets exposed because your model IndexModel inherits from PageModel.
If the aforementioned is true, then I suspect you're using the Request.Form in the wrong place here.
What are you trying to accomplish reading Request.From at that point in time, i.e - when the razor engine parses and renders your template? Please note, there's no form there yet. So that's probably why you're getting such error.
The error could be misleading because your code is messing with the request too early in the process. You're basically forcing the engine to read the form when nothing is there and the exception that pops out is telling you that the form doesn't have, neither application/x-www-form-urlencoded nor multipart/form-data as its Content-Type header value. But again, the main reason for the failure is that you're using the Request.Form in the wrong place.
Perhaps you should explain better what your final goal is, so we can get a better idea of what can be wrong?
Hope this helps!
Bit of an odd one here:
The following razor syntax renders a nce simple html from with a submit button inside the bottom of it.
When i hit that button i would expect a postback to performed but for reason it dosn't ... any ideas??
Oh by the way this is the entire code for the view ...
#model FLM.PRL.EComms.Models.ReplySMS
#using (Html.BeginForm("Reply", "SMS", FormMethod.Post)) {
<h2>Follow Up</h2>
#Html.ValidationSummary(true)
#Html.HiddenFor(model => Model.From)
#Html.HiddenFor(model => Model.To)
<div class="editor-label">Reply</div>
<div class="editor-field">
#Html.EditorFor(model => Model.Message)
#Html.ValidationMessageFor(model => Model.Message)
</div>
<input type="submit" value="Reply" />
<br />
}
EDIT: Resulting markup generated by this view ...
<form action="/SMS/Reply" method="post">
<h2>Follow Up</h2>
<input data-val="true" data-val-required="The From field is required." id="From" name="From" type="hidden" value="xxxxxxxx" /><input data-val="true" data-val-required="The To field is required." id="To" name="To" type="hidden" value="xxxxxxx" /> <div class="editor-label">Reply</div>
<div class="editor-field">
<textarea class="text-box multi-line" id="Message" name="Message">
</textarea>
<span class="field-validation-valid" data-valmsg-for="Message" data-valmsg-replace="true"></span>
</div>
<input id="submitReply" type="submit" value="Reply" />
<br />
</form>
The only reason for this form not to be submitted are scripts interfering with the process. Maybe the validation scripts.
I noted that the Message field is required. Did you provided a value to this field? Don't you have any validation error message?
In the case validation is fine, I suggest removing selectively all the scripts from the page and see what happens. If removing a script results in your form working, you know it is the source of the problem.
I figured it out ... it's the hidden fields ... they are required but populated by the server during the postback so the auto validation prevents the postback client side before the server is able to populate the fields ...
solution:
Don't add empty required fields to an MVC form or turn off validation (not a good idea)
I have started an MVC project and it has created the AccountController Class for me.
So to login to my current site I would have to go to, localhost:2500\Account.mvc\LogOn
I wanted to make the login on my HomeController in the Index view. So basically if you go to my root of the site if not authenticated you would have to login to go anywhere else.
So what I did was add the form to my Index View and tried to have it post to my
Account view calling the LogOn action.
I have called the BeginForm method passing it my action and the respective view (LogOn, Account). When I click the button, it doesn't post to the Account view therefore doesn't execute the LogOn action. Instead, it just posts to the Home view calling the Index action again. So it really does nothing for me... haha.
Not sure what I am doing wrong. Below is my raw form code from Home/Index.aspx and then I also will show you the source after its rendered before hitting the logon button.
Here's my code from Home/Index.aspx:
<% using (Html.BeginForm("LogOn", "Account")) { %>
<div>
<fieldset>
<legend>Account Information</legend>
<p>
<label for="username">Username:</label>
<%= Html.TextBox("username") %>
<%= Html.ValidationMessage("username") %>
</p>
<p>
<label for="password">Password:</label>
<%= Html.Password("password") %>
<%= Html.ValidationMessage("password") %>
</p>
<p>
<%= Html.CheckBox("rememberMe") %> <label class="inline" for="rememberMe">Remember me?</label>
</p>
<p>
<input type="submit" value="Log On" />
</p>
</fieldset>
</div>
<% } %>
View Source of Home.mvc/Index:
<form action="/Account.mvc/LogOn" method="post">
<div>
<fieldset>
<legend>Account Information</legend>
<p>
<label for="username">Username:</label>
<input id="username" name="username" type="text" value="" />
</p>
<p>
<label for="password">Password:</label>
<input id="password" name="password" type="password" />
</p>
<p>
<input id="rememberMe" name="rememberMe" type="checkbox" value="true" /><input name="rememberMe" type="hidden" value="false" /> <label class="inline" for="rememberMe">Remember me?</label>
</p>
<p>
<input type="submit" value="Log On" />
</p>
</fieldset>
</div>
</form>
I set a break point at my LogOn action and it never gets hit, so its not a login error either.
It looks like the action in the html source is set correctly, I just don't understand why it doesn't post correctly. I'm not doing something right. Please let me know if you have any ideas. Thanks!
LogOn Action in the Account View:
[AcceptVerbs(HttpVerbs.Post)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
Justification = "Needs to take same parameter type as Controller.Redirect()")]
public virtual ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl)
{
if (!ValidateLogOn(userName, password))
{
return View();
}
FormsAuth.SignIn(userName, rememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
Can you confirm that /Account.mvc/LogOn is a valid route?
Things to check:
Is the route valid?
Does the LogOn action have ActionVerb on it, preventing post requests - such as:
[ActionVerbs(HttpVerbs.Get)]
Edit:
Looking at your code, ignoring the fact that the breakpoint. get redirected to the home page, since you're not passing the returnUrl, won't it just send you back to the home page when it's successful?
Put this in your master page. What does it return?
<%=Request.IsAuthenticated %>
Edit 2:
Apparently this returns false.
Okay... So the controller is okay, and the view looks okay, and is rendering the correct url... I assume that ASP.NET MVC is installed and is in the GAC, given that you can also browse to other urls such as LogOn directly. And it looks like you're running it on Windows XP, given the '.mvc' in the route.
What do your routes look like? Have you made any changes to them?