Extending MVC FoolProof validation - regex

I would like to use MVC FoolProof Validation in my MVC 3 application.
I need a Numeric validation and also accepts N/A or n/a. So i decided to create my own custom validation attribute like NumericAllowNAAttribute and add a jQuery validation custom adopter method.
I revisited MVC Foolproof and decided to use that, since it has other helpful method build already. I want those also. Now how can i write a CustomValidationAttribute that works on client side using jQuery validate and Server side?
Searched google on extending MVC Foolproof i didnt get any.
Is any one came across extending or implementing this kind of
validation works in server and client with jQuery validation plugin?

You can extend foolproof MVC by defining a new attribute that inherits ContingentValidationAttribute (or one of the other attributes in foolproof, but continent is pretty close to barebones).
You will need to define the following method overrides.
public override bool IsValid(object value, object dependentValue, object container)
protected override IEnumerable<KeyValuePair<string, object>> GetClientValidationParameters()
public override string ClientTypeName
ClientTypeName string value is used by jquery unobtrusive validation.
Also, be sure to register your adapter with DataAnnotationsModelValidatorProvider (foolproof does it in the constructor for their classes).
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MyCustomValidationAttribute), typeof(FoolproofValidator));
Once you've defined your server-side validation logic you will need to register with jquery unobtrusive validation on the client-side:
jQuery.validator.addMethod("clienttypenameyouemitontheserver", function(value, element, params) {
// perform your checks here and return true or false
return true;
});
var $Unob = $.validator.unobtrusive;
$Unob.adapters.add("clienttypenameyouemitontheserver", ["param1", "param2", "paramZ"], function (options) {
var value = {
param1: options.params.param1,
param2: options.params.param2,
paramZ: options.params.paramZ
};
setValidationValues(options, "clienttypenameyouemitontheserver", value);
});

Related

Sitecore|WFFM| Custom Error Message with details| on Same Page with Form

I have a Web Form for Marketer set up done for one of my Pages.
I have Custom Submit Action written for it as shown below in the code snippet -
public class **CustomFormSubmit : ISaveAction**
{
public void Execute(ID formid, AdaptedResultList fields, params object[] data)
{
try
{
**//var returnValue= Custom Logic to save form data // returns true or false**
}
catch (Exception ex)
{
Logger.Log(ex.Message + ":" + builder, ExceptionCategory.Error);
throw;
}
}
In my above Web form - Success Mode is - SuccessMode/Redirect and I have a success Page configured for it.
My requirement in above scenario is to keep user on the same Page(with Form) if returnValue is false . (as shown in above code snippet)
Can anyone Please guide me in the above scenario as - how to keep user on the same Page with values filled in the form so that user can submit it again.
Product Details - 7.2 rev. 141226 , Web Forms for Marketers 2.4 rev.140117
To add further details -
I am not sure how can I go back to my page instead of the redirection in case if return is false in the above code snippet.
As soon the submit button is clicked the above function- Execute- gets called.
How do I go back to the Page - Do I need to override any function or customize something.
If any exception comes while saving data- then the control goes back to the same Page with all values filled by user retained -with the Save Action Failed Message which is configured in Sitecore .
So my requirement will be to go to to the form as happening in case of Exception when false comes as return value while saving data and to put customised Error Messages which might change each time, so not statically configured ,rather a dynamic one.
Thanks!
Saurabh
One option will be to redirect to the original page with the Form on.
Enable your form to populate the fields via Query String using the ReadQueryString property, via Presentation Details of the Form Renderer:
So on false of your Save Action you create a collection of query strings with the name of each Field, as it appears in the Form, followed by the User's value.
The code below will loop through all your fields and arrange them into a QueryString with its FieldName and Value;
string urlOfForm = HttpContext.Current.Request.Url.AbsolutePath;
var queryString = new StringBuilder("?");
foreach (AdaptedControlResult field in fields)
{
queryString.Append(string.Format("{0}={1}&", field.FieldName, field.Value));
}
urlOfForm = urlOfForm + queryString;
HttpContext.Current.Response.Redirect(urlOfForm);
Sitecore will then automatically populate the appropriate fields with the values, achieving your requirement.
EDIT
I have found that most Exceptions thrown will take the user back to the Form with their values populated. You can then pass in the cause of the failure to write to your CRM. See below for Example
if (submitFailed)
{
throw new Exception("The email address entered already exists in our System");
}
The complexity then comes in dynamically swapping out the Save Action Failed Message to show this Exception Message. All posts I find about custom Save Action Message state the only real approach is to redirect via your Custom Save Action to a different page showing a different message. Which is not suitable to your requirements.
I have found the pipeline Args you are going to need to patch FormSubmitFailedArgs and SubmitFailedArgs. The Former will need the following change
public FormSubmitFailedArgs(ID formID, AdaptedResultList fields, ID actionFailed, Exception ex)
: base(formID, actionFailed, ex)
{
this.Fields = fields;
this.ErrorMessage = ex.Message;
}
and the Latter will need
public SubmitFailedArgs(ID formID, ID actionFailed, string errorMessage, Exception innerException)
{
this.FormID = formID;
this.ActionFailed = actionFailed;
this.ErrorMessage = innerException.Message;
this.InnerException = innerException;
}
Location and Styling of Submit Message:
You need to find the FormRender sublayout file, this is defaulted to website\sitecore modules\Web\Web Forms for Marketers\Control\SitecoreSimpleFormAscx.ascx inside there you will find a compont called SubmitSummary this renders out the submit message so move it to where you require.
Also note it references the CssClass scfSubmitSummary this is what you will need to target to change the styling of the Message. This Answer is already REALLY long so I won't give a blow by blow how to change the styling of that class, see here for example - http://www.awareweb.com/awareblog/10-1-13-wffmguide
Pipeline Patching
I've dug in deeper, in order to use the custom Args we created for using the exception error message you will need to control the Pipeline which ultimately uses those Args, this is the processor Sitecore.Form.Core.Pipelines.FormSubmit.FormatMessage, Sitecore.Forms.Core in the <errorSubmit> Pipeline.
From my investigation it shouldn't take much effort then its a matter of patching it, you can modify if the Sitecore.Forms.config directly or use patch:instead from a config file within the App_Config/Includes folder - see here for more info.
One option would be to create a Custom Form Verification Action. You could save the data here, although it would be better to verify the data against your API here and then save the data in custom save action, simply since this seems more logical as to how WFFM was meant to function.
using Sitecore.Data;
using Sitecore.Form.Core.Controls.Data;
using Sitecore.Form.Core.Submit;
using System;
using System.Collections.Generic;
namespace Custom.WFFM
{
public class CustomVerificationStep : BaseCheckAction
{
public string FailedMessage { get; set; }
public override void Execute(ID formid, IEnumerable<ControlResult> fields)
{
// Call your API
// You have access to the fields, so you can pass them through as parameters to your if needed
bool flag = ServiceAPI.ValidateUserData(param1, param2, etc);
if (!flag)
{
throw new Exception(string.Format(this.FailedMessage ?? "There was an error while verifying the data against the service call"));
}
}
public override ActionState QueryState(ActionContext context)
{
return ActionState.DisabledSingleCall;
}
}
}
Create the corresponding Verification Action under /sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Form Verification:
You can change the error message by setting it in the Parameters field as <FailedMessage>Custom Failed Error Message</FailedMessage>.
And then add your verification step to your form:
If you need a different error message per form then you can set the error message to display from the Error Messages tab.
The user will then be returned to the same without any of the save actions being called and the form fields still filled in.

ASP.NET MVC XSS Validation

We are using ASP.NET MVC 5.0 to build a website. If I enter into a textbox some javascript when I save I get a "potentially unsafe input detected" error page - great.
However a couple of our screens use a ajax submit to pass json directly to the controller this seems to skip the validation above.
Is there any way to call the standard validation on the model (or each text field in the model) in the controller in order to throw the error above.
i.e. something like
public override ActionResult Create(MyModel myModel)
{
/* Any dubious input this should throw an error*/
AntiXSS.ValidateInput(myModel);
...
I ran into a similar issue, and as noted in comments on other answer, 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
[ValidateInput] attribute can be attached to each method. http://www.c-sharpcorner.com/UploadFile/dacca2/validateinput-attribute-to-prevent-css-attack-in-mvc/

Force a controller to always act as a proxy to a model in Ember

I'm looping through a content of an ArrayController whose content is set to a RecordArray. Each record is DS.Model, say Client
{{# each item in controller}}
{{item.balance}}
{{/each}}
balance is a property of the Client model and a call to item.balance will fetch the property from the model directly. I want to apply some formatting to balance to display in a money format. The easy way to do this is to add a computed property, balanceMoney, to the Client object and do the formatting there:
App.Client = DS.Model({
balance: DS.attr('balance'),
balanceMoney: function() {
// format the balance property
return Money.format(this.get('balance');
}.property('balance')
});
This serves well the purpose, the right place for balanceMoney computed property though, is the client controller rather than the client model. I was under the impression that Ember lookup properties in the controller first and then tries to retrieve them in the model if nothing has been found. None of this happen here though, a call to item.balanceMoney will just be ignored and will never reach the controller.
Is it possible to configure somehow a controller to act always as a proxy to the model in all circumstances.
UPDATE - Using the latest version from emberjs master repository you can configure the array controller to resolve records' methods through a controller proxy by overriding the lookupItemController method in the ArrayController. The method should return the name of the controller without the 'controller' suffix i.e. client instead of clientController. Merely setting the itemControllerClass property in the array controller doesn't seem to work for the moment.
lookupItemController: function( object ) {
return 'client';
},
This was recently added to master: https://github.com/emberjs/ember.js/commit/2a75cacc30c8d02acc83094b47ae8a6900c0975b
As of this writing it is not in any released versions. It will mostly likely be part of 1.0.0.pre.3.
If you're only after formatting, another possibility is to make a handlebars helper. You could implement your own {{formatMoney item.balance}} helper, for instance.
For something more general, I made this one to wrap an sprintf implementation (pick one of several out there):
Ember.Handlebars.registerHelper('sprintf', function (/*arbitrary number of arguments*/) {
var options = arguments[arguments.length - 1],
fmtStr = arguments[0],
params = Array.prototype.slice.call(arguments, 1, -1);
for (var i = 0; i < params.length; i++) {
params[i] = this.get(params[i]);
}
return vsprintf(fmtStr, params);
});
And then you can do {{sprintf "$%.2f" item.balance}}.
However, the solution #luke-melia gave will be far more flexible--for example letting you calculate a balance in the controller, as opposed to simply formatting a single value.
EDIT:
A caveat I should have mentioned because it's not obvious: the above solution does not create a bound handlebars helper, so changes to the underlying model value won't be reflected. There's supposed to be a registerBoundHelper already committed to Ember.js which would fix this, but that too is not released yet.

Attaching a cookie to a view in Symfony2

I've found a few questions and pages dealing with cookies in Symfony2 but there doesn't seem to be any clear consensus on exactly how this is supposed to work. I can, of course, just fall back to using PHP's native setcookie function but I feel that it should be an easy thing to do with Symfony2 as well.
I have an action in my controller from which I simply want to return a view with a cookie attached. Thus far I have seem examples basically like this:
use Symfony\Compentnt\HttpFoundation\Response;
public function indexAction() {
$response = new Response();
$response->headers->setCookie(new Cookie('name', 'value', 0, '/');
$response->send();
}
The problem with this is that it sends the response... and doesn't render the view. If I set the cookie without sending the headers the view is rendered but the header (cookie) is not sent.
Poking around I found the sendHeaders() method in the Response object so I'm now manually calling that in my action before returning and that seems to work:
public function indexAction() {
...
$response->sendHeaders();
return array('variables' => 'values');
}
But is this really the expected pattern to use? In previous versions of symfony I could set the headers in my controller and expect the view controller to handle sending whatever I had sent. It seems now that I must manually send them from the action to get it to work, meaning I have to call this from any action that I set headers in. Is this the case or is there something that I'm missing that's so obvious that no one has bothered to even mention it in any of the documentation?
I think you're on the right lines with:
$response->headers->setCookie(new Cookie('name', 'value', 0, '/'));
If you're trying to render a template then check out the docs here:
Symfony2 Templating Service
If you look at the line:
return $this->render('AcmeArticleBundle:Article:index.html.twig');
basically the render method is returning a response (which the controller then returns) which has the content of the twig template, all you have to do is intercept this:
$response = $this->render('AcmeArticleBundle:Article:index.html.twig');
$response->headers->setCookie(new Cookie('name', 'value', 0, '/'));
return $response;
I think that's it anyway...

MVC - open page in View mode

Hi
I am trying to see if anybody has a briliant idea on how to implement View mode concept in MVC. So if the user opens a page, the page should open in view mode (all controls disabled), if they dont have edit priviledges else should open as normal. Please note that the View page has partial pages as well
I think you have total control on your page under MVC framework. If you are using standard MVC method to generate input controls, you could do following ways.
#Html.TextBox("MyTextBoxID", Model==null?"":Model.MyFieldValue, new {disabled = "disabled})
If you are not using standard MVC method to generate input controls. You can create your own method to generate input controls. For example in MyExt.cs
public static class MyExt
{
public static MvcHtmlString MyTextBox(this HtmlHelper html, string id, object value)
{
// check user privilege
if (CurrentUser.CanEditThisPage /*Implement your own logic here */)
return html.TextBox(id, value);
else
return html.TextBox(id, value, new {disabled = "disabled"});
}
}
And in your page
#using MyNamespace
...
#Html.MyTextBox("MyTextBoxID", Mode==null?"":Model.MyFieldValue)
Another Way
Pass an indicator from server side to client side and using javascript or JQuery to disable all controls.
#Html.Hidden("CanEdit", CurrentUser.CanEditThisPage)
In javascript
void pageLoad() {
if ($("#CanEdit").val() == "true"))
$("input").attr("disabled", "disabled");
}
Something like that (not sure about correctness of syntax :P)