xVal error messages appearing twice - asp.net-mvc

I'm trying to setup xVal with an ASP.NET MVC 2 Preview 1 project. I'm basically following the example at http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/ to the letter (server-side only, so far).
I have annotated a BlogPost entity, and here is the Post action:
[HttpPost]
public ActionResult Index(BlogPost b)
{
try
{
_blogService.Insert(b);
}
catch (RulesException ex)
{
ex.AddModelStateErrors(ModelState, "");
}
return (View(b));
}
And here's the service method:
public void Insert(BlogPost post)
{
var errors = DataAnnotationsValidationRunner.GetErrors(post);
if(errors.Any())
{
throw new RulesException(errors);
}
_blogRepo.Insert(post);
}
(Note that the DataAnnotationsValidationRunner is verbatim from the example blog post). When I submit a totally invalid BlogPost form, I get this list of validation errors:
A value is required.
Please enter a title
Please enter a posted date
Please enter some content
Please enter a title
Please enter a posted date
Please enter some content
I don't even know what the first message is for, but as you can see, the other errors are appearing twice. What am I doing wrong? Or is this a problem with MVC V2?

Starting in ASP.Net MVC 2 Preview 1 we now get DataAnnotation validation support out of the box, so I guess your issue is that when the ModelBinder logic runs it is applying the DataAnnotation rules:
public ActionResult Index(BlogPost b) //Create BlogPost object and apply rules
and then with your XVal logic you are requesting the check again:
var errors = DataAnnotationsValidationRunner.GetErrors(post);
This is backed up by the fact they are repeated in the same order.
Your code would have worked fine in version 1 of MVC as public ActionResult Index(BlogPost b) would not have run the DataAnnotation rules. I have not read anywhere if it is possible to turn off the new DataAnnotation logic and just use XVal.
There is more information about this on Scott's post able preview 1
To find out what the first item is run debug and check what errors are on the ModelState, as this will tell you what property on the object the errors are related to.
[HttpPost]
public ActionResult Index(BlogPost b)
{
try
{
_blogService.Insert(b); //Add breakpoint here and check ModelState
}
catch (RulesException ex)
{
ex.AddModelStateErrors(ModelState, "");
}
return (View(b));
}

Related

MVC Request - Core .NET - Non HTML Response

I'm new to Core.NET and would greatly appreciate some enlightenment.
I've watched many PluralSight videos, and have Core .NET book 'Pro ASP.NET Core MVC'.
All very well cover Routing / Controller Initialization / Action Method Execution / Action Result / View Engine. I'm hung up on the Non HTML Response though. (Please see image below)
In Traditional ASP.NET if I wanted to call some class that did something and returned no value, I'd simply:
// Call Twilio class that sends a test message
TwilioRest Send_Test_SMS = new TwilioRest();
Send_Test_SMS.testSMS_Send();
My question is:
How do I call the above class's function from the controller.
When adding a controller or when modifying a controller for that - do I need to alter or add something to the Startup.cs file
The course materials I have do a great job at covering returning HTML views - such as:
//------book examples below-----
public IActionResult Index()
{
return View();
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
But I feel like an idiot trying to do something so simple and would appreciate some insight into this.
Thank you in advance.
So I'm not sure whether I got your point, but I guess you want to do sth like that:
//------book examples below-----
public IActionResult Index()
{
// Call Twilio class that sends a test message
TwilioRest Send_Test_SMS = new TwilioRest();
Send_Test_SMS.testSMS_Send();
return Ok(); // Similiar meaning as => return StatusCode(200);
}
It's up to your design / contract which status code you want to return here you can find a list of http codes: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
So to summarize you don't need to return 'HTML response', but obviously 'HTTP response' must be returned.
If I misunderstood you then apologize.

ValidateInputAttribute not working in Post Request of ASP.NET MVC controller

My understanding was OOTB, MVC will validate input to prevent XSS Attack and SQL Injection.
For example, In one of my app, the "a dangerous input has been detected" error will be received when I put in HTTP Get request. However, the post actions can let these values posted successfully through html input element without error. Even after I marked the controller action as [ValidateInput(true)]. How can I make them validate those post input?
Any advice will be appreciated!
Without seeing your GET handler, or what you're sending to it, it's tough to say why it behaves that way. However, OOTB MVC guards against SQL injection through the use of Entity Framework, and against XSS through ModelState validation.
Inside the body of your POST action that handles this forms submission you'll want to use code much like the following:
if (ModelState.IsValid)
{
//do the stuff I want to do when things are valid and free of XSS
}
else
{
//something went wrong. Probably shouldn't process this one. Have the user try again
}
Update: please disregard my filthy lies. ValidateInput(true) is not necessary because it is on by default. So, the only things I can think of would be that you have the AllowHtml attribute on your class or properties, or you are not posting back a model for modelBinding, and therefore input validation, to occur. At this point, you're probably going to need to put up some code for further help. There's too many unknowns right now.
I ran into a similar issue - we had JQuery using $.ajax to post JSON to the MVC action. The default model binder does not validate posted JSON allowing unsafe XSS to be posted against our action.
To solve this, I found the RequestValidator has a static method InvokeIsValidRequestString that allowed
public class ValidateJsonXssAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext?.Request;
if (request != null && "application/json".Equals(request.ContentType, StringComparison.OrdinalIgnoreCase))
{
if (request.ContentLength > 0 && request.Form.Count == 0) //
{
if (request.InputStream.Position > 0)
request.InputStream.Position = 0; // InputStream has already been read once from "ProcessRequest"
using (var reader = new StreamReader(request.InputStream))
{
var postedContent = reader.ReadToEnd(); // Get posted JSON content
var isValid = RequestValidator.Current.InvokeIsValidRequestString(HttpContext.Current, postedContent,
RequestValidationSource.Form, "postedJson", out var failureIndex); // Invoke XSS validation
if (!isValid) // Not valid, so throw request validation exception
throw new HttpRequestValidationException("Potentially unsafe input detected");
}
}
}
}
}
Then, you can just decorate relevant MVC actions expecting JSON-posted data that might bypass the standard XSS prevention:
[HttpPost]
[ValidateJsonXss]
public ActionResult PublishRecord(RecordViewModel vm) { ... }
You can see other options for customizing request validation with OWASP .NET recommendations by extending the RequestValidator object, which exposes the string validation done by the ValidateInput automatically utilized by MVC for other scenarios of query string, form collection, and cookie values.
For more info: https://www.owasp.org/index.php/ASP.NET_Request_Validation

How to use business validations in DbDataController ?

There is a crud operations in default Single Page Application template of ASP.NET MVC 4 as below.
upshot.js is interacted with response from DbDataController's actions and if operation fails then upshot.js takes validation errors and it is able to show on client side.
What i need to do is putting my own business rules in operations. But it is not clear that where to put validation errors in DbDataController.
For example : InsertEntity(entity); Operation can put validation errors if it fails and validation errors sent to client automaticly. But i want to put my business validation errors if it is occur. So where can i put it there ?
public partial class TasksSPAController : DbDataController<MvcApplication8.Models.TasksSPAContext>
{
public IQueryable<MvcApplication8.Models.TodoItem> GetTodoItems() {
return DbContext.TodoItems.OrderBy(t => t.TodoItemId);
}
public void InsertTodoItem(MvcApplication8.Models.TodoItem entity) {
//before this action i want to check business validation rules.
// if it is not validated so i want to put errors to response
// that is usable by upshot.js
InsertEntity(entity);
}
public void UpdateTodoItem(MvcApplication8.Models.TodoItem entity) {
UpdateEntity(entity);
}
public void DeleteTodoItem(MvcApplication8.Models.TodoItem entity) {
DeleteEntity(entity);
}
}
Check Fluent Validation, there is nothing better and easier!

TempData & Redirect for Errors

I have a controller action in my project that has a situation where it needs to display an error message to the user under certain scenarios. This action occurs in a POST:
[HttpPost]
public ActionResult DoSomeAction() {
if( someCondition )
return RedirectToAction("SomeActionError");
return RedirectToAction("Index");
}
public ActionResult SomeActionError() {
return View();
}
Currently I have it set up so that it will redirect to an error controller action. I'm not really fond of this approach because in the URL they see /SomeActionError and it also means that the user can directly navigate to this URL.
Is it a bad design/approach to put some flag in TempData and redirect to another controller that checks for the TempData error flag?
Example:
[HttpPost]
public ActionResult DoSomeAction() {
if( someCondition ) {
TempData["DoSomeActionError"] = true;
}
return RedirectToAction("Index");
}
public ActionResult Index() {
// check for error
if( TempData["DoSomeActionError"] ) {
return View("SomeActionError");
}
}
Is this a bad idea? Is there another approach that does something similar (doesn't allow the user to directly navigate to the error action)? I don't want to return the View on the POST action because I don't want them to refresh and cause another POST.
TempData is not per se a bad concept. TempData is for transporting an information to some consumer that reads that information and the information should vanish after it's been read.
The way your're using TempData is odd. A more elegant implementation for your requirements (you should show an error message) is to implement an equivalent to the rails flash concept and don't redirect to an error page but display an error message in your index view. Something like a red banner that says "The record could not be saved".
This question shows a nice flash implementation including the view stuff (not the accepted answer but the answer by #jim)
using tempdata in mvc is not a good approach.
If i were you i'll do as following:
[HttpPost]
public ActionResult DoSomeAction() {
if( someCondition ) {
return RedirectToAction("Index", new{error=true}
}
return RedirectToAction("Index");
}
public ActionResult Index(bool? error) {
// check for error
if(error?? false ) {
return View("SomeActionError");
}
}
While I don't agree TempData is always bad (I find it great for status messages I absolutely don't want passed on the url such as "record saved", I think in your case there may be a better option.
First you don't want an error page to be accessible - may I ask why?
To do a redirect when an error happens only to redirect again is a bit odd. I would throw the exception and handle that exception by your error view. MVC automatically adds the [HandleError] attribute as a global filter, so throw your exception (a custom type if necessary) and handle it in your error page as you see fit since you can access exception details there and it doesn't require a redirect.

MVC Entity Framework validation to prevent duplicate records

Hi i'm new to MVC and EF so this may be a really simple question but what is the best way to prevent the user from trying to enter duplicate records?
I have a simple look up table with one column which is the primary key. I'm creating a maintenance screen so admins can add extra items to the look up list. My controller looks like :
public ActionResult Index(string NewRow)
{
try
{
CaseType t = new CaseType { ID = NewRow };
if (ModelState.IsValid)
{
UOW.CaseTypes.Add(t);
UOW.Save();
}
}
catch (Exception ex)
{
ModelState.AddModelError("", ex.Message);
}
return View(UOW.CaseTypes.All());
}
Which stops the duplicate records and stops the yellow screen of death but the message displayed is : "An error occurred while updating the entries. See the inner exception for details." which is no good for the users.
I was just wondering if there is a better way to catch the error.
For show validation error I use something like this:
MainEmail it's property from ViewModel
var mod = ModelState.First(c => c.Key == "MainEmail"); // this
mod.Value.Errors.Add("Row's shouldn't duplicates."); // this
if (ModelState.IsValid)
{
return RedirectToAction("Details");
}
return View(client);
Error will show's in this field in view:
<div class="editor-label">
#Html.LabelFor(model => model.MainEmail)
</div>
And for future, you must hide your error screen! You need to display a custom error page:
If you use asp-mvc-3, add to web.config such string:
<system.web>
<customErrors mode="On" defaultRedirect="~/Error" />
...
And users will have /Shared/Error.cshtml page insted of page with exception message (which can show sequrity data).
ADD
About unique constraint creation was discussed here
Unique Constraint in Entity Framework Code First
than you can check about records duplication with your try code.
In my application I use code first and don't add unique constraint because it's lead to low testability. In that case use simple Find before saving changes.
First aproach is little bit faster.
Approach two is grow up testability.
If you want to get the inner exception you can do like this,
catch (Exception ex)
{
while(ex.InnerException!=null){
ex=ex.InnerException;
}
ModelState.AddModelError("", ex.Message);
}
no too sure about the syntax :)

Resources