MAIN QUESTION
As the title says, i'm asking if anyone knows how to create a validation structure similar to silverlight's dataform. Any hints, materials , ideas would be welcome. I'd like to do a validation like this:
(You can check this out here)
DETAILS
I've been trying to something like the example above, but without results until now. Mostly because i dont' know how the validation message helper works. I've managed to a single validation message by taking the data-val-number attribute and set it into a link title (using a third party jquery plugin callled qTip to show a tooltip error message). However, i can't do the same thing if there are more than one validation.
So, is it possible to rewrite the validation message helper? I'd like to understand more how it shows the validation messages so i can put them on any html content. This would do the tooltip part and i could set as many messages as i want, with any formatting i desire.
And i'd like to be able to show the validation messages through any jquery events (mouseover, click, dblclick, ready, etc.). As far as i understand on it's actual implementation, the validation only occurs when the user changes focus from the actual input to another html element.
I highly recommend that you checkout the validation rules section in Professional ASP.NET MVC. It shows how to do exactly what you describe with ASP.NET MVC v1 and it works all the way up through v3.
The displayed user interface is slightly different; however, you can check the output and write your own CSS to make it look just like your screenshot.
For a quick example:
Action Result
try
{
// code
}
catch
{
foreach (var issue in std.GetRuleViolations())
{
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
}
Model
public IEnumerable<RuleViolation> GetRuleViolations()
{
if (!String.IsNullOrEmpty(this.Phone) && !Utility.IsValidPhoneNumber(this.Phone))
{
yield return new RuleViolation("Phone is invalid. Try this format: ###-###-####.", "HomePhone");
}
yield break;
}
Edit View
<%
using (Html.BeginForm())
{
%>
<fieldset>
<legend>Edit</legend>
<%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>
<%= Html.TextBox("Phone", Model.Phone)%>
<%= Html.ValidationMessage("Phone", "*")%>
<!-- more fields go here -->
</fieldset>
<% } %>
rule violation class -- lifted from link
public class RuleViolation
{
public string ErrorMessage { get; private set; }
public string PropertyName { get; private set; }
public RuleViolation(string errorMessage)
{
ErrorMessage = errorMessage;
}
public RuleViolation(string errorMessage, string propertyName)
{
ErrorMessage = errorMessage;
PropertyName = propertyName;
}
}
Related
I have a method inside MVC Controller which is called from href inside anchor tag.
public ActionResult DoSomething(string value)
{
if(true)
{
return new RedirectResult("http://google.com");
}
}
when I debug and hit that method Response.Redirect does nothing no exceptions either. any ideas?
Thanks in advance!
Use Redirect
return Redirect("http://www.google.com");
Response.Redirect is not preferred way of doing redirects in asp.net mvc
Response.Redirect and ASP.NET MVC – Do Not Mix
Update: It seems that you are trying to redirect ajax request. If you redirect ajax request, your main page won't be redirected.
There are a few things you need to do here to avoid all these issues.
Starting with the AJAX errors you're getting, they most like relate to the javascript debugger, which Microsoft refer to as "BrowserLink".
If you use Firefox or Chrome, this feature simply doesn't work, which is probably the easiest way to avoid the issue, however you can disable the feature here:
You can change the default browser to run the website in just to the left.
In terms of Response.Redirect, I think that's been well covered, you should use return Redirect() instead, however your code needs to be refactored to allow for that.
Assuming that method is a helper method which is required to be separate from the controller itself, there are a couple of main approaches to doing what you're trying to to do.
1) Magic Values
This could include "redirect1" or also commonly null, and would look something like:
public ActionResult MyAction
{
string data = ProcessString("some data");
if (data == null) { return Redirect("google.com"); }
}
public string ProcessString(string input)
{
if (condition) { return null; }
string output = input + "!"; // or whatever you need to do!
return input;
}
2) Handle via exceptions
Assuming the problem is that the data is in some way bad, and you want to redirect away because you cant process it, Exception handling is most likely the way to go. It also allows for different types of exceptions to be raised by a single method and handled independently without having magic values which then can't be used as normal data.
public ActionResult MyAction
{
string data; // remember this will be null, not "" by default
try
{
data = ProcessString("some data");
}
catch (OwlMisalignedException ex)
{
return RedirectToAction("Index", "Error", new { exData = ex.Code });
}
// proceed with controller as normal
}
public string ProcessString(string input)
{
if (condition)
{
throw new OwlMisalignedException(1234);
// this is (obviously) a made up exception with a Code property
// as an example of passing the error code back up to an error
// handling page, for example.
}
string output = input + "!"; // or whatever you need to do!
return input;
}
By using that approach you can effectively add extra return states to methods without having to fiddle with your return type or create loads of magic values.
Don't use throw Exception - either use one of the more specific types ArgumentException and ArgumentNullException will probably come in handy, or create your own types if needs be.
You'll find info on creating your own Exception types on here easily enough.
I want to create a multilingual webpage. To switch between languages I've got a dropdown on my page. If the change event of the dropdown gets fired the Method called "ChangeLanguage" in my Controller is called.
public ViewModels.HomeViewModel HVM { get; private set; }
// GET: Home
public ActionResult Index()
{
this.HVM = new ViewModels.HomeViewModel();
return View(this.HVM);
}
public JsonResult ChangeLanguage(int id) {
return Json(new {Success = true});
}
Now I'd like to to change my "SelectedLanguage" Property in my ViewModel (HVM) - but the Reference is null. May anyone explain why HVM is null in my ChangeLanguage Method?
After my SelectedLanguage Property is changed I'd like to reload my whole page to display it's texts in another language
e.g.
#model ViewModels.HomeViewModel
<html>
<div class="HeaderText">
Text = #{
#Model.TextToDisplay.Where(o =>
o.Language.Equals(Model.SelectedLanguage)).First()
}
</div>
Here's what I want to do in PseudoCode:
PseudoCode:
public JsonResult ChangeLanguage(int id) {
this.HVM.SelectedLanguage =
this.HVM.AvailableLanguages.Where(o =>
o.ID.Equals(id)).First();
Page.Reload();
return Json(new {Success = true});
}
May anyone explain why HVM is null in my ChangeLanguage Method?
Adhering to stateless nature of HTTP protocol, all (unless explicitly added into request header) requests (MVC method calls) loose state data associated with it. Web server treats every request a new request and creates new instances of classes right from controller itself.
In your case since it is a new request, controller has a HVM property defined but in ChangeLanguage it is not instantiated (it gets instantiated only into Index method which is not called when you invoke ChangeLanguage) hence it is null.
After my SelectedLanguage Property is changed I'd like to reload my
whole page to display it's texts in another language.
Option 1: Refresh page
Simple option to implement. Pass the language selection to server, server will return a new view with specific data. Drawback, whole page will refresh.
Option 2: Update view selectively
If option 1 is really not acceptable, then consider this option. There are multiple ways you can achieve it. Basically it involves either (a) breaking you view into partial view and update only the portion that is affect by selection or (b) bind data element with a JS object.
(a) - Not much need to be said for this.
(b) - Data binding can easily be done if you employ a JS library like KnockoutJS.
Change your methods to these methods , This trick will work for you =>pass your model to Change language from view. Also update JsonResult to ActionResult.
public ActionResult ChangeLanguage(ViewModels.HomeViewModel model,int id)
{
this.HVM.SelectedLanguage =
this.HVM.AvailableLanguages.Where(o =>
o.ID.Equals(id)).First();
return RedirectToAction("Index",model);
}
public ActionResult Index(ViewModels.HomeViewModel model)
{
if(model == null)
{
this.HVM = new ViewModels.HomeViewModel();
}
return View(this.HVM);
}
I have a multilingual web-forms web application which I am using resource files and a BasePage class which sets the culture based on the QueryString that was included in the page which is inheriting from this class. This is all working well, if a tad clunky as I am having to do this sort of thing for every button which takes the user to a different page to maintain the culture:
if (Thread.CurrentThread.CurrentCulture.ToString() == "cy-GB")
{
return "~/Secure/Details.aspx?lang=cy-GB&PersonId=" + currentPersonId;
}
else
{
return "~/Secure/Details.aspx?PersonId=" + currentPersonId;
}
I knew there was probably a better way of doing this but being a novice as it worked I simply made do.
This was until I had to implement an asp:SiteMapPath control. I initially assumed that I could simply create a resource entry for the url property like I had done for the title:
<siteMapNode
title="$resources:SiteMapLocalizations,HomePageTitle"
description="Home"
url="~$resources:SiteMapLocalizations,HomePageUrl">
However this resulted in a server error:
A potentially dangerous Request.Path value was detected from the client (:).
I've done some reading and I believe I need to somehow store the current culture to a session variable which will follow the user around so when they click 'Home' on the breadcrumb it will be consistent with the culture and grab the appropriate text from the resource files, I'm also hoping this will allow me to remove all of the IF ELSE statements I've had to write to maintain the current language throughout the application.
My question is however, where do I start with this, I cannot find any guide step by step to follow in order to achieve this, can anyone provide some instructions?
Make sure you have a button of some sort which triggers the change of language. In my case I have two versions of the header, one with an English link which will append the Query String to English and one for Welsh, something like:
ASP
<a id="languagelink" runat="server" title="Cymraeg">Cymraeg</a>
C#
if (Thread.CurrentThread.CurrentCulture.ToString() == "en-GB")
{
Uri uri = new Uri(currentPage);
languagelink.HRef = String.Format(uri.GetLeftPart(UriPartial.Path)+"?lang=cy-GB");
}
Every page which requires the language switch needs to inherit from my custom BasePage like so:
Inheritance
public partial class Secure_CustomerSummary : BasePage
Base_Page
public partial class BasePage : System.Web.UI.Page
{
protected override void InitializeCulture()
{
if (Session["language"] == null)
{
Session["language"] = "en-GB";
}
else
{
if (Request.QueryString["lang"] == null)
{
SetSessionCulture();
}
if (Request.QueryString["lang"] != null)
{
string qs = Request.QueryString["lang"];
Session["language"] = qs;
}
SetSessionCulture();
}
SetSessionCulture();
}
private void SetSessionCulture()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(Session["language"].ToString());
Thread.CurrentThread.CurrentUICulture = new CultureInfo(Session["language"].ToString());
base.InitializeCulture();
}
}
i have the following Action method that return an _error partial view in case an Exception occur:-
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Register(string id, int classid) {
try
{
Thread.Sleep(3000);
User user = r.FindUser(id);
Users_Classes uc = new Users_Classes();
uc.AddedDate = DateTime.Now;
uc.ClassID = classid;
user.Users_Classes.Add(uc);
r.Save();
ViewBag.classid = classid;
return PartialView("_usersearch2", uc);
}
catch (DataException ex)
{
return PartialView("_error");
}
and the following _error partial view:-
<script type="text/javascript">
alert('The user might have been already Assinged, Search Again to get the latest users');
</script>
The above approach is working fine, but does it consider a bad design to return a partial view to display only an alert ? and is there a better way to do this?
The problem is you are now tying your implementation to your user interface. The Controller suddenly decides how an error message should appear on the client.
What if you want to change it from an alert to displaying a red border around a text input with some description next to it?
Determining how something should be displayed is up to your view. Your controller should only return status codes and then your view should decide what to do.
Instead of returning inline js you should have error handling code on your client side within a js library. Rather than returning the hole js only return the message.
In general, I'd say yes. But, sometimes a bad design is just what the doctor ordered ;)
There's a Controller instance method called Javascript that I use to return executable javascript from my controller, on very limited occasions, when taking the time to do it the "right" way isn't feasible:
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Register(string id, int classid)
{
try
{
... stuff
}
catch (DataException ex)
{
return Javascript("alert('The user might have been already Assinged, Search Again to get the latest users');");
}
}
The fact that something like this exists gives me solace that I'm not completely breaking the law.. unless I'm using it wrong, which I probably am.
I have created a new asp.net site (web forms, c#) and looking to make it secure against spam coming through textboxes and being added to the database. Does anyone have any good links on how to implement this?
Thanks
I use ReCaptcha for this.
You can download it from nuget or install with
Install-Package recaptcha
command through package management console
public class NoCache : ActionFilterAttribute
{
public class CaptchaValidatorAttribute : ActionFilterAttribute
{
private const string CHALLENGE_FIELD_KEY = "recaptcha_challenge_field";
private const string RESPONSE_FIELD_KEY = "recaptcha_response_field";
private const string CAPTCHA_MODEL_KEY = "Captcha";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var captchaChallengeValue = filterContext.HttpContext.Request.Form[CHALLENGE_FIELD_KEY];
var captchaResponseValue = filterContext.HttpContext.Request.Form[RESPONSE_FIELD_KEY];
var captchaValidtor = new Recaptcha.RecaptchaValidator
{
PrivateKey = "key",
RemoteIP = filterContext.HttpContext.Request.UserHostAddress,
Challenge = captchaChallengeValue,
Response = captchaResponseValue
};
var recaptchaResponse = captchaValidtor.Validate();
if (!recaptchaResponse.IsValid)
{
filterContext.Controller
.ViewData.ModelState
.AddModelError(
CAPTCHA_MODEL_KEY,
"Entered text is invalid");
}
base.OnActionExecuting(filterContext);
}
}
public static class CaptchaExtensions
{
public static string GenerateCaptcha(this HtmlHelper helper)
{
var captchaControl = new Recaptcha.RecaptchaControl
{
ID = "recaptcha",
Theme = "white",
PublicKey = "key",
PrivateKey = "key"
};
var htmlWriter = new HtmlTextWriter(new StringWriter());
captchaControl.RenderControl(htmlWriter);
return htmlWriter.InnerWriter.ToString();
}
}
Than you can use
#using (Html.BeginForm("activate_user", , FormMethod.Post))
{
#Html.HiddenFor(x => x.Email)
<div class="captcha">
#Html.Raw(#Html.GenerateCaptcha())
<div style="text-align:center; margin-left:-25px;">
#Html.ValidationMessage("Captcha")
</div>
</div>
<input type="submit" class="signUpButton active activation" value="Activate" />
}
And in controller:
[ActionName("activate_user")]
[CaptchaValidator]
[HttpPost]
public ActionResult ActivateUser(string email)
{
if (ModelState.IsValid && !string.IsNullOrEmpty(email))
{
FormsAuthentication.SetAuthCookie(email, false);
Repository.ActivateUser(email);
}
return View();
}
If you do not have spam, I wouldn't worry about it.
That being said, if you do have it, you want to know what kind of spam you are getting. Validating the input against the model should prevent most of it assuming you have restrictions on the valid input. If just about anything validates, or you have to accept everything for some reason, you can start with a honey pot, which is a simple, non intrusive method.
To implement a honey pot, you basically add a field, hide it with CSS and and validate that field is null on the server side. Most spam bots fill out all fields and this will identify when something automated has submitted the form.
If you find this ineffective in preventing all spam on your site, you need to see what kind of spam is getting through and find something that prevents that. As a last resort, you can move to intrusive actions such as recaptcha. The real issue with CAPTCHA's (as Eric Lippert's succinctly states it) is that they assume guilt, that the user is trying to do something bad, and that has a negative effect on your users.
I suggest that you take the Growmap Anti-Spam plugin for WordPress and convert its Javascript and PHP implementation to something you can use in your project. It's not as annoying as CAPTCHA to end users and it's been quite effective in stopping automated spam on my WordPress blogs. It shouldn't be a big deal to do the ASP.NET/C# conversion. I started on one but the project I was doing it for got canceled so I didn't complete it.
Of course, it won't help with manual spamming where somebody pays $5 for someone sitting in a third world Internet cafe to enter nonsense onto dozens of sites. This is also a problem for many other anti-spam systems, including CAPTCHA. This activity is primarily done to get links for SEO purposes so screening out links for moderation or preventing them from being entered can curtail this activity.