How to use business validations in DbDataController ? - asp.net-mvc

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!

Related

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

MVC Custom error and exception handling - standard through out the project

I am new to ASP.NET MVC , Kendo UI (razor) , Jquery. I have an application that throws 3 kinds of errors
Unhanded exceptions (400, 403,500 503 etc) - throw generic exceptions
Expected exceptions/ errors (custom exceptions) - e.g. Trying to create a contact that already exist in the system - The system needs to throw "Contact_duplicated_exception" and show this to the user as "Contact was previously created. This action could not proceed".
Model state errors (UI). Errors that I add to modelstate to showup on the page using #Html.ValidationSummary(true)
What is the best standard way of handling the above throughout the application ?
I need to send these messages back to the user using Jquery Ajax [POST].
I have used the following concepts but I need to implement a standard way of dealing with the above
1. I have used ELMAH (for unhanded exceptions)
2. Application_Error(object sender, EventArgs e) in global.asax.cs
3. Custom HandleErrorArrtibute
public class HandleErrorWithAjaxFilter : HandleErrorAttribute, IExceptionFilter
Thanks!
For #1 and #3, you're looking good, IMHO. However, I think your weak-point is #2 and here is why:
If the exception is expected it should not be allowed to fall to Application_Error; because, well... it's expected, it's workflow, not an exception.
Therefore as a reaction to user input and part of workflow, it should be handled as part of #3.
So, in your shoes, I would go about in the specific instance of finding duplicates adding a validation attribute onto the potentially duplicate class like so:
[AttributeUsage(AttributeTargets.Class)]
public class UniqueContactAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
bool isValid = true;
Contact contact = value as Contact;
if(contact != null)
{
// check for your duplicate in the database and set isValid to false if you find one.
}
return isValid;
}
}
Usage for your metadata class:
[UniqueContact(ErrorMessage = "Contact was previously created. This action could not proceed.")]
public class Contact_Validation
{
}

MVC Repository pattern with services - how to get errors on DAL?

So I have a method in my service, which I will call from a controller:
public void SendMessage(Message message) {
message.Property = "Random";
try {
// try some insert logic
}
catch (Exception) {
// if it fails undo some stuff
// return the errors
throw;
}
// if there are no errors on the return the operation was a success
// but how do I get the Service generated data?
}
Edit:
So the question isn't really about getting my code to work it's a problem I have with the Repository Pattern whilst using a Service Layer as a 'go between' for communication between the DAL and Presentation
So I have a separate assembly called DataLibrary.
The DataLibrary has my models (Message), my repositories and Services (MessageService)
In my MVC site I would typically have a controller, with CRUD functionality. It would look something like this:
public ActionResult Create(Message message) {
if(ModelState.IsValid) {
db.insert(message);
}
Return View(message);
}
But by using the Repository Pattern, with a service layer for communication I have this instead:
public ActionResult Create(MessageCreateModel message) {
if(ModelState.IsValid) {
MessageService.SendMessage(message.ToDTO());
}
Return View(message);
}
How do I know that the operation was successful or unsuccessful and for what reason?
How do I retrieve the populated data from the service's business logic at the same time as the above?
And how do I achieve both of these two above while sticking as close as possible to MVC design pattern / spearation of concerns for extensibility?
First of all, why do you go through as service if it's just delegating the work to your repository? If you have implemented your repository properly (i.e. being a complete abstraction) there is no need to use the service. Simply call the repository directly from your controller. You can read more about the repository pattern in my blog.
But that doesn't really adress the issue.
So how do you handle errors? When it comes to exceptions: Simply do not catch it ;) Exceptions are after all exceptions and is not something that you typically can handle to deliver the expected result.
As we are talking about the data layer that usually means a stable database engine where it's expected that the read/write will succeed. Hence there is no need for any other error handling than using exceptions.
In ASP.NET MVC you can handle transactions with an attribute and use try/catch to fill the model state as shown here:
[HttpPost, Transactional]
public virtual ActionResult Create(CreateModel model)
{
if (!ModelState.IsValid)
return View(model);
try
{
model.Category = model.Category ?? "Allmänt";
var instruction = new Instruction(CurrentUser);
Mapper.Map(model, instruction);
_repository.Save(instruction);
return RedirectToAction("Details", new {id = instruction.Id});
}
catch (Exception err)
{
// Adds an error to prevent commit.
ModelState.AddModelError("", err.Message);
Logger.Error("Failed to save instruction for app " + CurrentApplication, err);
return View(model);
}
}
You really didn't provide enough information about your architecture is structured to answer this question. However, if you want to get a value back from the SendMessage method, adding a return value instead of void is a good place to start.
I think you should first decide how are you going to design your architecture. Are you go with service oriented, if so your service methods have to be return something for inform controllers. So think your service layer like a border of a country, and the other country's borders are controllers. And you have to let trade these two countries. This can be done with return object which contains return data and also service errors and so on.
If you only want to put your some business logic into your service layer then you probably dont need independent layers. Just some loose coupling is enough for you. So you can return basic clr objects or domain objects or application objects. In a very basic example like this:
//AService service method
public AnEntity ServiceMethod(AFilterViewModel aFilter)
{
//do some validation
try
{
//some transactional operations
}
catch
{
//do some log and rollback it...
throw;
}
var anEntity = _aRepository.GetSomeEntity(x=> x.Something == aFilter.Something);
return anEntity;
}
//controller method
public ActionResult GetSomething(AFilterViewModel aFilter)
{
try
{
var entity = _aService.ServiceMethod(aFilter);
AViewModel model = MapToView(entity);
return View(model);
}
catch
{
return RedirectToAction("Error");
}
}
As you see above the controller and service layer methods can share each others objects. They have boundaries to each other and they coupled. But your architecture decides how much they coupled.
You can also do these mappings one way only. Something like service to Controller only or Controller to service only. If you dont want to use your viewmodel in service layer, you should always do mappings in service layer. Otherwise do your object mapping in controllers. And also dont forgot to put your viewmodel's into another library, its very important. These are something like "value objects".

In Asp.Net MVC 2 is there a better way to return 401 status codes without getting an auth redirect

I have a portion of my site that has a lightweight xml/json REST API. Most of my site is behind forms auth but only some of my API actions require authentication.
I have a custom AuthorizeAttribute for my API that I use to check for certain permissions and when it fails it results in a 401. All is good, except since I'm using forms auth, Asp.net conveniently converts that into a 302 redirect to my login page.
I've seen some previous questions that seem a bit hackish to either return a 403 instead or to put some logic in the global.asax protected void Application_EndRequest()
that will essentially convert 302 to 401 where it meets whatever criteria.
Previous Question
Previous Question 2
What I'm doing now is sort of like one of the questions, but instead of checking the Application_EndRequest() for a 302 I make my authorize attribute return 666 which indicates to me that I need to set this to a 401.
Here is my code:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == MyAuthAttribute.AUTHORIZATION_FAILED_STATUS)
{
//check for 666 - status code of hidden 401
Context.Response.StatusCode = 401;
}
}
Even though this works, my question is there something in Asp.net MVC 2 that would prevent me from having to do this? Or, in general is there a better way? I would think this would come up a lot for anyone doing REST api's or just people that do ajax requests in their controllers. The last thing you want is to do a request and get the content of a login page instead of json.
How about decorating your controller/actions with a custom filter:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class RequiresAuthenticationAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
var user = filterContext.HttpContext.User;
if (!user.Identity.IsAuthenticated)
{
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.HttpContext.Response.End();
}
}
}
and in your controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[RequiresAuthentication]
public ActionResult AuthenticatedIndex()
{
return View();
}
}
Another way of doing this is to implement a custom ActionResult. In my case, I wanted one anyway, since I wanted a simple way of sending data with custom headers and response codes (for a REST API.) I found the idea of doing a DelegatingActionResult and simply added to it a call to Response.End(). Here's the result:
public class DelegatingActionResult : ActionResult
{
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
Command(context);
// prevent ASP.Net from hijacking our headers
context.HttpContext.Response.End();
}
private readonly Action<ControllerContext> Command;
public DelegatingActionResult(Action<ControllerContext> command)
{
if (command == null)
throw new ArgumentNullException("command");
Command = command;
}
}
The simplest and cleanest solution I've found for this is to register a callback with the jQuery.ajaxSuccess() event and check for the "X-AspNetMvc-Version" response header.
Every jQuery Ajax request in my app is handled by Mvc so if the header is missing I know my request has been redirected to the login page, and I simply reload the page for a top-level redirect:
$(document).ajaxSuccess(function(event, XMLHttpRequest, ajaxOptions) {
// if request returns non MVC page reload because this means the user
// session has expired
var mvcHeaderName = "X-AspNetMvc-Version";
var mvcHeaderValue = XMLHttpRequest.getResponseHeader(mvcHeaderName);
if (!mvcHeaderValue) {
location.reload();
}
});
The page reload may cause some Javascript errors (depending on what you're doing with the Ajax response) but in most cases where debugging is off the user will never see these.
If you don't want to use the built-in header I'm sure you could easily add a custom one and follow the same pattern.
TurnOffTheRedirectionAtIIS
From MSDN, This article explains how to avoid the redirection of 401 responses : ).
Citing:
Using the IIS Manager, right-click the
WinLogin.aspx file, click Properties,
and then go to the Custom Errors tab
to Edit the various 401 errors and
assign a custom redirection.
Unfortunately, this redirection must
be a static file—it will not process
an ASP.NET page. My solution is to
redirect to a static Redirect401.htm
file, with the full physical path,
which contains javascript, or a
meta-tag, to redirect to the real
ASP.NET logon form, named
WebLogin.aspx. Note that you lose the
original ReturnUrl in these
redirections, since the IIS error
redirection required a static html
file with nothing dynamic, so you will
have to handle this later.
Hope it helps you.
I'm still using the end request technique, so I thought I would make that the answer, but really
either of the options listed here are generally what I would say are the best answers so far.
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == MyAuthAttribute.AUTHORIZATION_FAILED_STATUS)
{
//check for 666 - status code of hidden 401
Context.Response.StatusCode = 401;
}
}

xVal error messages appearing twice

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

Resources