ASP.NET MVC 3 - Nick and Email taken validation (Ajax calls) - c#

What is the recommended way to handle "Nick / Email taken" AJAX validation in MVC that integrates nicely with validators provided by DataAnnotantion (#Html.ValidationMessageFor(model => model.Email))? I understand that I would probably have something like this:
<input id="email" onBlur="emailTaken();" onchanged="emailTaken();" />
<script type="text/javascript">
function emailTaken() {
var encodedEmail = enc($("#email").val());
$.getJSON("/Ajax/EmailTaken/" + encodedEmail, function (data) {
if (data.res) {
// all is OK
} else {
// TODO: Show Error?
}
});
}
</script>
I already know that on Server I can do ModelState.AddModelError and I am doing it... but I want to know what is recommended way for ClientSide validation? Do I need to invoke some method provided by jquery.validate.unobtrusive.js?

You would probably want to use Remote Validation for this. It's built-in, so you don't have to do any of your own javascript.
http://msdn.microsoft.com/en-us/library/gg508808(v=vs.98).aspx

Related

Is sending Session from javascript safe?

Well, this is a bit weird i think to ask this question, because i am not sure if that's the place to ask that.
OK, into the question..
I have this code
<script>
var session = "<%= Session["User"]%>";
</script>
So, i was thinking, is that safe? let me tell you what i mean..
I have a web api which you can get the name, last name, age and everything about the user with his Session, can i send this web api this session and use it?
Is that a safe thing to do ? in matter of securiy? if not, is there any better way?
EDIT 1:
What am i trying to aaccomplish? simple, i will store the UserId in the session, the UserId will Guid, when the user is loogin in the javascript can send post to an API server to get info, the API will send the UserId from the session.
Is That ok?
Workflow that you describe looks fine. For me it seems safe to use some ID to get more information about some user, especially if this is supposed to be an API, at least, Facebook API uses such principle not being afraid of some hackers :)
My main concern here is the coding style when you try to mix code and view which is not good. If you really need to share some information between client and server sides then I would go with one of these options.
Option # 1 - Cookies
What is the difference between a Session and a Cookie?
You can keep some simple information in a cookie and get it this way :
Client : $.cookie('ID')
Server : Response.Cookies["ID"]
In this case there is no need to put in a mess your client side JS with C# code and cookies will be saved on users PC which means that nobody will see them except him.
Option # 2 - Templates
Server : put all needed information into hidden form or ViewState
Client : take information from hidden form using HTML selectors
Straight answer :
In general, if you worry only about safety then it is fine to use this code, it should not break security of your site.
Although, personally I do not like this approach because :
you will mix code and view, MVC was created to split them
it is not clear where exactly in your view you will put this code and thus it is not clear how you are going to check that this variable was initialized
it may happen that you will put there some value that will break JS syntax and will cause JS error
In my personal opinion, I would replace it with one of the mentioned options.
Option 1 - MVC + JQuery + Cookie Example
public ActionResult Index()
{
string demo = Request.QueryString["MyNameSpace.ID"]; // get value from client
Response.Cookies["MyNameSpace.ID"].Value = "server"; // change value in response
return View();
}
Then in your JS file :
$(document).ready(function() { // make sure server rendered page
var ID = $.cookie('MyNameSpace.ID'); // get cookie value from server
$.cookie('MyNameSpace.ID', 'client'); // update, on the next request server will get it
});
Option 2 - MVC + JQuery + Templates Example
public class OptionsModel // View Model
{
public string ID { get; set; }
public string User { get; set; }
}
public ActionResult Index() // Controller
{
OptionsModel options = new OptionsModel();
options.ID = "server";
return View(options);
}
Your view :
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<OptionsModel>" %>
<%=Html.HiddenFor(m => Model.ID, new { #class = "MyNameSpace:ID" })%>
<%=Html.HiddenFor(m => Model.User, new { #class = "MyNameSpace:User" })%>
Then in your JS file :
$(document).ready(function() { // make sure server rendered page
var options = $('[class^=MyNameSpace]') // get values from hidden fields
options[0] = 'client'; // update data
$.ajax({ data : options }); // create handler to send data back to server
});
Examples for Web Forms do not differ significantly.
The code you have posted will be rendered on the page as so when it hits the client (assuming you are using ASP.NET
<script>
var session = "John Smith";
</script>
This is due to the use of the server side scripting tags <%= %> (https://technet.microsoft.com/en-us/library/cc961121.aspx)
As a note its probably not the best thing in the world to fully expose the session to javascript if that is your intention. At the end of the day it depends what you are storing in there and using it for (but ASP.NET will also use it for certain things) but exposing it just opens another area for someone to attack.
http://www.owasp.org is a great place to learn more about securing your website.

MVC javascript redirect page not working

In MVC, the default views for a controller allow one to reach the edit page via selecting an item in an index and using that id to reach the specific edit page.
In this MVC edit page, I have a javascript that reacts to a change in a dropdown. The dropdown represents a subset of the potential id's available from the index page, and in general, someone will choose a different one than the currently displayed one.
The postback to the control works correctly in C#, and I can find the relevant model that goes with the id. It all appears correct on the C# controller side. However, when I try to get it to redirect back to the same edit page but with a different id (that from the dropdown), the page reverts back to the ajax call.
Is there anyway to "short-circuit" the ajax call so that it "knows" that it doesn't return but lets the C# redirect to the edit page (just like what happens when an element is chosen from the index page).
Thanks in advance,
Joseph Doggie
If you are making ajax requet, then you have to implement a way to redirect.
Depends on your ajax protocol... Are you returning json? html ...
If returning json, you could add a flag in your response telling wether this is a redirect answer and do redirect in js :
window.location = url
OK, there is at least one way to do this.
Assume editing X with Controller named YController:
JavaScript:
var MyControllerUrlSettings = {
MyControllerPrepareModifyXInfoUrl: '#Url.Action("PrepareModifyAssetInfo", "Y", new { x_txt = "param" })'
}
one then has a JavaScript to handle the dropdown change:
$('#ModelXList').change(function () {
//// alert('Change detected');
if ($("#ModelXList").val() != "") {
//// alert('Reached here');
var XNbrString = $("#ModelXList").val();
var trimmedXNbrString = $.trim(XNbrString);
//// debugger;
if (trimmedXNbrString != "") {
var url = MyControllerUrlSettings.MyControllerPrepareXInfoUrl;
window.location.href = url.replace('__param__', trimmedXNbrString);
}
}
else {
}
});
Finally, in the controller, there is a method:
public ActionResult PrepareModifyXInfo(string XNbr_txt)
{
// we cannot save anything here to cdll_cdcloanerlist;
// static variables must be used instead.
/// .... do what you have to do....
return RedirectToAction("ModifyEdit", new { XNbr_txt = XNbr_txt });
}
Note: For proprietary reasons, I changed some of the syntax so that everything would be general, therefore, you may have to work with the above code a little, but it works
Alternate answers are really welcome, also!

Programming Button OnClick Event

I'm trying to make a method run once a user clicks a button on a page. I created a sample of code to test it but it doesn't work, though it may be because I'm using MessageBox.
<input id="upload-button" type="button" ondblclick="#ModController.ShowBox("Message");" value="Upload"/><br />
Here's the method I'm invoking.
public static DialogResult ShowBox(string message)
{
return MessageBox.Show(message);
}
Any idea on how I can make this function properly?
You could do something like this if your intent is to pass a message to the client and display a dialog:
In your view, add the following:
#using (Html.BeginForm("ShowBox","Home",FormMethod.Post, new { enctype = "multipart/form-data" })){
#Html.Hidden("message", "Your file has uploaded successfully.");
<input id="upload-button" type="submit" value="Click Me" />
<input id="file" name="file" type="file" value="Browse"/>
}
Then in your controller:
[HttpPost]
public ActionResult ShowBox(string message, HttpPostedFileBase file)
{
if (file == null || file.ContentLength == 0)
{
//override the message sent from the view
message = "You did not specify a valid file to upload";
}
else
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/Uploads"));
file.SaveAs(path);
}
System.Text.StringBuilder response = new System.Text.StringBuilder();
response.Append("<script language='javascript' type='text/javascript'>");
response.Append(string.Format(" alert('{0}');", message));
response.Append(" var uploader = document.getElementById('upload-button'); ");
response.Append(" window.location.href = '/Home/Index/';");
response.Append("</script>");
return Content(response.ToString());
}
NOTE:
I think this approach is less than ideal. I'm pretty sure that returning JavaScript directly like this from the controller is probably some sort of an anti-pattern. In the least, it does not feel right, even thought it works just fine.
It looks like you're using a Razor template. If so, and you're using MVC, I don't think you're approaching this right. MVC doesn't work on an event system like ASP.NET. In MVC you make a requst to an ACtion method, usually with a URL in the form of {controller}/{action}, or something like that.
you have few options:
Setup a javascript event for the dblClick event, and perform an AJAX request to the server in the event handler.
Use #ActionLink() and style it to look like a button.
If you are using ASP.NET, there are certain POST parameters you can set before posting to the server, which will tell ASP.NET to run a certain event handler. However, if you're using ASP.NET, I'd recommend using web forms instead of Razor. I've never used Razor with ASP.NET myself, but I don't think the two technologies Jive very well.

JavaScript in C# ASP MVC issue

We have a web project that takes data from an MS SQL database and uses the Google Visualisation API to display these charts on the web view.
Recently we have added castle windsor so we can configure the application to different users with an XML file. Before we added this, the view worked fine, using the baked in parameters that were needed for this query. For some reason, when we send in the parameters from the XML files (Running with breakpoints shows that the parameters are being passed to the main controller action for the page) the data isn't being returned. here is some of the code for you.
JavaScript
<script type="text/javascript">
var csvDataUrl = '#Url.Action("TradeValuesDataCsv", "Dashboard")';
var jsonDataUrl = '#Url.Action("TradeValuesDataJson", "Dashboard")';
google.load("visualization", "1", { packages: ['table', 'corechart', 'gauge'] });
google.setOnLoadCallback(drawCharts);
drawCharts();
$("body").on({
ajaxStart: function () {
$(this).addClass("loading");
},
ajaxStop: function () {
$(this).removeClass("loading");
}
});
function drawCharts() {
var queryString = 'platform=' + $('#PlatformDropDownList').val();
queryString += '&startDate=' + $('#startDatePicker').val();
queryString += '&endDate=' + $('#endDatePicker').val();
queryString += '&model=' + $('#ModelDropDownList').val();
queryString += '&eventType=' + '#Model.EventType';
queryString += '&parameterName=' + '#Model.ParameterName';
$.ajax({
type: "POST",
url: jsonDataUrl,
data: queryString,
statusCode: {
200: function (r) {
drawToolbar(queryString);
drawTable(r);
drawChart(r);
},
400: function (r) {
},
500: function (r) {
}
}
});
}
Main controller Method for this page:
public ActionResult ActionResultName(EventTypeParameterNameEditModel model)
{
var viewModel = new EventTypeParameterNameViewModel(_queryMenuSpecific);
viewModel.EventType = model.EventType;
viewModel.ParameterName = model.ParameterName;
PopulateFilters(viewModel);
return this.View(viewModel);
}
Retrieve the JSON Data Controller Method:
public ActionResult ActionResultNameJson(EventTypeParameterNameEditModel filters)
{
List<CustomDataType> results = this.GetTradeValues(filters);
return this.Json(results, JsonRequestBehavior.AllowGet);
}
EDIT I have managed to find a solution, even if it is a rather messy one. I have some filters built into the page that allow the user to filter by device and by OS, and these were being populated on the page load with 'undefined'. I didn't spot this first time round with NHProf Running, but this wasn't happening when the page loaded before we configured the input to be from XML. I will add this as an answer and accept it and close the question. Thanks everyone for your attempts to help. Starting to really like this community. Perfect place to find help as a Graduate Developer.
Yep. I'm not a Razor syntax expert but I think these property references are probably your problem. I suspect razor is going to tend to avoid asserting itself inside strings being used in statements with properties in JS contexts. Or you could try implementing as getter functions which would probably work. Otherwise an # and a . in a string could easily lead to confusing mixups with email addresses when it's not an obvious method call:
queryString += '&eventType=' + '#Model.EventType';
queryString += '&parameterName=' + '#Model.ParameterName';
As a general rule in any server to client-side scenario, my advice is to confine JavaScript direct from the back end to JSON objects only. That way you have more granular control over what's going on on both sides of the http request wall and your client-side devs don't have to figure where stuff is getting built if there's a short-term need to quickly modify. In general, don't build behavioral code with other code if you can avoid it.
I couldn't convince my .net MVC boss at first but he slowly came around to the idea on his own months later.
We also store a URL base path along with some other context-shifting params in a standard JSON object that loads on every page so the JS devs can add these things linked JS files rather than have to work with JS in the HTML (I don't recall why but document.location wasn't always going to work).
Lastly, try to keep the JS out of the HTML. Link it. It seems like a pain from a procedural POV but trust me. It makes life much easier when you are juggling 3 major concerns as one ball each rather than all in the same jumbled HTML/template mess.
It turned out that the problem was not in my Javascript. I have some filters in there that allow the user to filter the results my model and operating system and date and what not. These were being automatically populated on page load with 'undefined' which is not an option in the database. I added something to catch that in the call to the query and it seemed to solve the problem.

reCaptcha and SSL web site

I using a reCaptcha on my web page under asp.net mvc. This web site have a SSL certificated, and I having and problem with reCaptcha.
This is my code on View:
<script type="text/javascript" src="https://api-secure.recaptcha.net/challenge?k=***Public key****"> </script>
<noscript>
<iframe src="https://api-secure.recaptcha.net/noscript?k=***Public key****" height="300" width="500" frameborder="0"></iframe><br />
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge" />
</noscript>
and this code is that I have on AccountController:
private bool PerformRecaptcha()
{
var validator = new RecaptchaValidator
{
PrivateKey = "**Private Key***",
RemoteIP = Request.UserHostAddress,
Response = Request.Form["recaptcha_response_field"],
Challenge = Request.Form["recaptcha_challenge_field"]
};
try
{
var validationResult = validator.Validate();
if (validationResult.ErrorMessage == "incorrect-captcha-sol")
ModelState.AddModelError("ReCaptcha", string.Format("Please retry the ReCaptcha portion again."));
return validationResult.IsValid;
}
catch (Exception e)
{
ModelState.AddModelError("ReCaptcha", "an error occured with ReCaptcha please consult documentation.");
return false;
}
}
and my library version is 1.0.5.0.
When I load the register form I have this alert on Opera:
The rules server certificate matches the server name. Do you want to accept?
If I accept this certificate, displays reCaptcha code, but if not, I don't view reCaptcha Code.
Can you help me with this?
If you need more information about my code, feel free to ask to me.
Regards.
I think you need to change the url you are using to include recaptcha. A number of people had the same problem in April. Recaptcha let the certificate expire for "api-secure.recaptcha.net". If you change it to use the "https://www.google.com/recaptcha/api/XXX" url instead of "https://api-secure.recaptcha.net/XXX", it should definitely fix your issue.
It looks like this one has actually been answered before: recaptcha https problem on https://api-secure.recaptcha.net/. Since you are using the .NET library, I think your answer is to upgrade your version.
Sharpening up on JasonStoltz's answer:
You are already using the latest DLL version, there's no need to update this
You can/should use RecaptchaControlMvc.GenerateCaptcha() method in your View instead of writing your own (it will use the new URL)

Categories