I am developing MVC application and am testing it now.
I am trying to insert <test> in the Database for address field. As it contains anguler brackets it's giving an error. For that I use the below code in controller.
[HttpPost]
public ActionResult Create(Employee employee)
{
if (ModelState.IsValid)
{
employee.Address.Replace("<", "<").Replace(">", ">");
db.Employees.Add(employee);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ReportsToId = new SelectList(db.Employees, "Id", "FirstName", employee.ReportsToId);
return View(employee);
}
But cursor didn't come to this code. Where to write replace code?
Before cursor comes to that code, it's giving an error:
A potentially dangerous Request.Form value was detected from the client
(Address ="<test>").
Read this answer for similar question.
Conclusion: Use the [AllowHtml] attribute over the Address property or change the web.config to use requestValidationMode 2.0:
<configuration>
<system.web>
<httpRuntime requestValidationMode="2.0" />
</system.web>
<pages validateRequest="false">
</pages>
</configuration>
Change employee.Address.Replace("<", "<").Replace(">", ">"); to employee.Address = employee.Address.Replace("<", "<").Replace(">", ">");
This way it is taking the employee.Address string and replacing the < and > symbols then saving the string back to employee.Address.
Also it may need to be before the if (ModelState.IsValid) part.
There are two problems in your code that you have to solve.
First, as you pointed out, the error:
A potentially dangerous Request.Form value was detected from the client (Address ="<test>").
This error happens because, for the sake of security, MVC does not allow such string (your is like some html element) to be sent to your action method by default. That is to prevent the user submit some dangerous input to attach your site. For example, rather than , you could type alert('hahaha'), and if you does not encode that input, everyone access the page that contains this address field will get an alert box. And that is why you cannot get to the "Replace code" when debugging, the whole method just won't run because of this error.
That said, there are many options to solve this first error, but you can simply add a ValidateInput attribute to your action method.
[HttpPost]
[ValidateInput(false)]
public ActionResult Create(Employee employee)
By doing this, you are telling MVC to trust you that you will encode that dangerous input at some point. And you are doing that by the Replace code. That is pretty fine. But if you are just using #yourTable.Address to render the data in some view, you don't need to bother Replacing < and > in your action code. MVC Razor engine would do the encoding for you when you are rendering the data through #yourTable.Address syntax.
Related
I am using CKEditor/CKFinder as wysiwyg editor on my MVC.NET site.
I have set [ValidateInput(false)] and it works when debugging it locally, but I receive the following error when I have published the site:
A potentially dangerous Request.Form value was detected from the client (message="<p>
<em>Testing</e...").
can anyone explain why the published site is different from the locally site, especially when I have set [ValidateInput(false)]?
*Update:*I am using .Net 3.5 so shouldn't [ValidateInput(false)] work out the box?
Have you tried setting the htmlEncodeOutput property?
CKEDITOR.replace('editor1', {
htmlEncodeOutput: true });
This should encode the output and you should be able to avoid setting the requestValidationMode.
Documentation for it is here: ckEditor documentation
Add this to your web.config:
<httpRuntime requestValidationMode="2.0" />
Just add an Annotation to the Post method Action as [ValidateInput(false)]
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Detail(ModelClass m)
{ return View(); }
ValidateRequest="false"
Add this in the particular Page.
Example:
Add ValidateRequest="false" to your Page:
<%# Page Language="C#" AutoEventWireup="false" Codebehind="MyForm.aspx.cs" Inherits="Proj.MyForm" ValidateRequest="false"%>
Or add to web.config if using .NET Framework 4.0 (Visual Studio 2010)
<httpRuntime requestValidationMode="2.0" />
Use Request.Unvalidated["myTextBox"]
for example,
var text = Request.Unvalidated["myTextBox"];
where "myTextBox" is the form field you want to allow HTML to be posted from.
In my view I have
<%:Html.LabelFor(model => model.IPAddress)%>
<div class="editor-field">
<%:Html.TextBoxFor(model => model.IPAddress)%>
<%:Html.ValidationMessageFor(model => model.IPAddress)%>
</div>
In my controller(post method), I have this
[HttpPost]
public ActionResult Manipulation(MyModel model){
//I change modele here
if(something)
model.IPAddress="100.100.100.100";
return View(model);
}
So, my question is:
When I change model, the TextBoxFor does not change his value.
TextBoxFor get his value when I get from get method to the post, and later I cannot change value of TextBoxFor.
I debug, and my model have new value, but TextBoxFor does not show new value.
Can you help me?
Try:
ModelState.Clear();
return View(model);
If not result! return a JSON Result and then update by javascript
Mr Grok had a similar problem this site. He had already found the ModelState.Clear() solution, but was wanting an explanation of why it worked. The highest ranked answer on the linked site proposed that the behavior of the html helper is a bug, for which ModelState.Clear() is a workaround. However, bradwils at this site says that the behavior is by design, and gives the following explanation:
The reason we use the posted value for editors rather than the model value is that the model may not be able to contain the value that the user typed. Imagine in your "int" editor the user had typed "dog". You want to display an error message which says "dog is not valid", and leave "dog" in the editor field. However, your model is an int: there's no way it can store "dog". So we keep the old value.
If you don't want the old values in the editor, clear out the Model State. That's where the old value is stored and pulled from the HTML helpers.
Despite the fact that it’s by design, this is very unexpected behavior for the developer, and it is unfortunate that interaction with the ModelState is required for a common programming need.
Furthermore, clearing the entire ModelState might cause unexpected issues in other areas (I think with respect to validation on unrelated model fields). So many thanks to Peter Gluck (responding in a comment within Mr Grok’s page) for proposing the more limited ModelState.Remove(“key”), and to Toby J for developing a more convenient method that works when you’re not sure what the key should be if the model property is nested. I also like Toby’s method because it doesn’t depend on a string as input.
That method, with minor changes, follows:
/// <summary>
/// Removes the ModelState entry corresponding to the specified property on the model. Call this when changing
/// Model values on the server after a postback, to prevent ModelState entries from taking precedence.
/// </summary>
/// <param name="model">The viewmodel that was passed in from a view, and which will be returned to a view</param>
/// <param name="propertyFetcher">A lambda expression that selects a property from the viewmodel in which to clear the ModelState information</param>
/// <remarks>
/// Code from Tobi J at https://stackoverflow.com/questions/1775170/asp-net-mvc-modelstate-clear
/// Also see comments by Peter Gluck, Metro Smurf and Proviste
/// Finally, see Bradwils http://forums.asp.net/p/1527149/3687407.aspx.
/// </remarks>
public static void RemoveStateFor<TModel, TProperty>(
this ModelStateDictionary modelState,
TModel model,
Expression<Func<TModel, TProperty>> propertyFetcher
) {
var key = ExpressionHelper.GetExpressionText(propertyFetcher);
modelState.Remove(key);
}
Instead of using model binding, id suggest using a tryupdate call.
[HttpPost]
public ActionResult Manipulation(FormCollection formCollection)
{
MyModel model = new MyModel();
if(TryUpdate(Model))
{
enter code here
}
if(somthing)
model.IPAddress="100.100.100.100";
return View(model);
}
Check out my answer to another post for the general structure i use. Its never failed me before and i believe it covers all bases when updating models from user input.
asp.net mvc controller post best practices
Here's another work around that I found.
Instead of
#Html.TextBoxFor(m=>m.PropertyName)
do this
#{
var myModel = Model;
}
#Html.TextBoxFor(m=>myModel.PropertyName)
This could be useful if you don't want to override the default behavior for every input.
In one of our ASP.NET MVC application we are using FCKEditor to allow users to enter rich text. In order to turn off the validation in the controller actions we set the attribute
[ValidateInput(false)]
Users are able to save and modify the rich text as long as there are no business validation errors in the page.
If any of the business validations fail and the ModelState.IsValid is set to false, on rendering the page the following exception is raised. Can someone let me know how to solve this issue?
A potentially dangerous Request.Form value was detected from the client (Programme_Overview="
Here is the code
[ValidateInput(false)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Schedule(FormCollection formValues)
{
// some code
if (ModelState.IsValid)
{
//do something here...
}
else
{
return View(programDetails);
}
}
//// View code that render the fckeditor text area
<%= Html.TextArea("Programme_Overview", Model.Programme.Overview, new { row = 7 })%>
just had this crop up, fix was to update the fck config file
fckconfig.js
FCKConfig.HtmlEncodeOutput = false;
should be
FCKConfig.HtmlEncodeOutput = true ;
Just add the following to your action:
[ValidateInput(false)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SomeAction() {}
I'm guessing this project was migrated from a pre-1.0 RTM project.
Original ASP.NET has page-level "dangerous input" validation that you're tripping up. We have turned it off system-wide with a change to the Web.config file in the Views folder, but I don't remember exactly when we made that change. If your project pre-dates this change, then you won't have that setting in your Web.config file in the Views folder.
So you can make a new MVC project and look at the Web.config file to see what setting(s) you might want to copy over. You can also disable this on a page-by-page basis if you want.
http://www.asp.net/learn/whitepapers/request-validation/
It is likely some HTML output from your FCKEditor gets somehow submitted.
You can try to switch the validation off:
public MyController
{
[ValidateInput (false)]
public ActionResult MyAction ()
{
}
}
Using Forms Authentication in ASP.NET MVC when trying to log back into a site, it puts a ReturnUrl parameter in the query string. My Logon action method accepts a "returnUrl" string. However it seems that returnUrl string is always null, even when it is clearly in the query string. Any thoughts on why this might be the case or a possible fix?
This tends to happen when you're using one generic logon form, but you're explicitly specifying the Controller and ActionMethod (which is causing a form post, but losing the querystring)
Just to clarify, this is what your code should look like in your BeginForm:
Html.BeginForm("LogOn", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"] })
EDIT: This is by design as RickAnd mentions in comments below. However it doesn't allow for the UI pattern of being deep in a site, clicking on LogOn, then returning to the page you were previously on, if it allows anonymous users. It's a commonly requested pattern. David Allen's approach to LogOff would also work nicely for a clean redirect at LogOn.
Maybe you don't include the ReturnURL parameter into you login form's action attribute, thus posting to a URL without that parameter?
Basically, The Asp.net MVC has some hidden features. For Example when you pass variable 'id' to controller action, it interprets 'id' as default identifier and puts it on browser query with fore slash.By using another name instead of 'id' we will see '?' rather than fore slash. Because of setting the 'id' name on RegisterRoutes method on global.asax file.
In this Problem you have created a custom data passer to controller by using this code:
using(Html.BeginForm("LogOn", "Account", FormMethod.Post))
{
//form fields
}
So Asp.net MVC ignores other useful data to pass to controller action, and we'll see returnUrl always null.
While, by using this, Asp.net MVC acts Correctly and returnUrl is mounted:
using(Html.BeginForm())
{
//form fields in LogOn View
}
By the way, When we use custom data passer to controller action, must pass another data manually like this:
using(Html.BeginForm("LogOn", "Account", new {ReturnUrl = Request.QueryString["ReturnUrl"] }))
{
//form fields
}
There are two ways I can think of to deal with logon and logoff scenarios.
Dave Beer outlined one way, above.
There is another approach that works in many situations. I used it when I coded the NerdDinner tutorial. The tutorial provides us with a logoff function that logs you off and takes you home. I did not want that. I wanted to return to the page I was on before I logged off. So I modified my Account controller logoff action to look like this
public ActionResult LogOff()
{
FormsService.SignOut();
return Redirect(Request.UrlReferrer.ToString());
}
You can get fancier and pass in a returnUrl and test for it, in case you want to override this behavior. But I don't need that. This achieves the desired result. The Logon can work similarly. Maybe there are ways to use the MVC framework to do this for me, but until I learn them, this is VERY simple and works reliably.
Try the following:
public static MvcForm BeginForm(this HtmlHelper htmlHelper, string id)
{
string formAction = htmlHelper.ViewContext.HttpContext.Request.RawUrl;
TagBuilder tagBuilder = new TagBuilder("form");
tagBuilder.MergeAttribute("id", id);
tagBuilder.MergeAttribute("action", formAction);
tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(FormMethod.Post), true);
HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
}
First ensure you have set the login url in the web.config, Next, ensure your Signin Form does not contain anything like action, for example:
View:
If you specify action you will always get null for return url:
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SignIn(string userName, string password, bool? rememberMe, string returnUrl)
{
}
I have a controller with two actions:
[AcceptVerbs("GET")]
public ActionResult Add()
{
PrepareViewDataForAddAction();
return View();
}
[AcceptVerbs("POST")]
public ActionResult Add([GigBinderAttribute]Gig gig, FormCollection formCollection)
{
if (ViewData.ModelState.IsValid)
{
GigManager.Save(gig);
return RedirectToAction("Index", gig.ID);
}
PrepareViewDataForAddAction();
return View(gig);
}
As you can see, when the form posts its data, the Add action uses a GigBinder (An implemenation of IModelBinder)
In this binder I have:
if (int.TryParse(bindingContext.HttpContext.Request.Form["StartDate.Hour"], out hour))
{
gig.StartDate.Hour = hour;
}
else
{
bindingContext.ModelState.AddModelError("Doors", "You need to tell us when the doors open");
}
The form contains a text box with id "StartDate.Hour".
As you can see above, the GigBinder tests to see that the user has typed in an integer into the textbox with id "StartDate.Hour". If not, a model error is added to the modelstate using AddModelError.
Since the gigs property gigs.StartDate.Hour is strongly typed, I cannot set its value to, for example, "TEST" if the user has typed this into the forms textbox.
Hence, I cant set the value of gigs.StartDate.Hour since the user has entered a string rather than an integer.
Since the Add Action returns the view and passes the model (return View(gig);) if the modelstate is invalid, when the form is re-displayed with validation mssages, the value "TEST" is not displayed in the textbox. Instead, it will be the default value of gig.StartDate.Hour.
How do I get round this problem? I really stuck!
I think the problem is that your ViewModel does not match closely enough with your View. It's really important in MVC that your ViewModel matches your View as closely as possible.
In your ViewModel you're assuming an integer, but in your View you're using a TextBox to render the property, which will allow any kind of text. There's a mismatch here and the difficulties you are experiencing trying to map them is a symptom of the mismatch.
I think you should either:
1. Change the type of the ViewModel property to string and then do validation in your controller to ensure the string entered is actually a number or:
2. Change the control that the View renders to a control that will only allow a number to be entered via a custom control or Javascript validation (as #Qun Wang recommends)
Personally, I'd recommend option 1. That way the ViewModel is not dependent on the View implementation.
Could you do this in your PrepareViewDataForAddAction method?..
if (!ViewData.ModelState.IsValid)
{
ViewData["StartDate.Hour"] = "Error";
}
The other fields on the form will still populate based on the properties of the Gig object.
I think you need to do some basic client side validation first.
don't allow it to post to the server.