so i was able to make my recaptcha thing working but my problem is though, i want to have it appear only after 3 tries. one option that i have is to redirect the user to a View that will have the captcha already (duplicate of the login but with captcha) and then have him log in through that page. is there any other option? i feel like partial views would cause problems on Post of the page. what do you think is the best way to generate the captcha?
<% using(Html.BeginForm()) {%>
<%: Html.AntiForgeryToken() %>
<%: Html.ValidationSummary() %>
<label>Username:</label>
<%: Html.TextBoxFor(m => m.Username) %>
<br /><br />
<label>Password:</label>
<%: Html.PasswordFor(m => m.Password) %>
<br /><br />
<input type="submit" value="Login" />
<%: Html.ActionLink("Register", "Register", "") %>
<%: Html.ActionLink("Forgot Password", "Password", "") %>
<%: Html.ActionLink("Forgot Username", "Username", "") %>
<%: ReCaptcha.GetHtml(publicKey: "thisismykey", theme: "red") %>
<% } %>
THanks,
G
You are passing in a model (hopefully a ViewModel). Why not add NumberOfFailedLogins to it?
Then you could just put a bit of code around the Recaptcha saying
<%: if (Model.NumberofFailedLogins > 3) { %>
<%: ReCaptcha.GetHtml(publicKey: "thisismykey", theme: "red") %>
<% } %>
NOTE: I am used to Razor syntax, so apologies if the above is not perfect. I'm sure you get the idea!
Obviously you would need to update NumberOfFailedLogins behind the scenes!
EDIT: Just to clarify, the number of failed login attempts ought to be recorded in the membership database behind the scenes automatically (the act of attempting to login would do this; note that the ASP.NET Membership Provider automatically records the number of consecutive failed login attempts out of the box) and it is from there that the ViewModel obtains this information. So it doesn't matter if you are using a bot to attempt to brute-force your way in, it can still be presented with the ReCaptcha after three attempts (and of course can be locked out too if desired).
Related
I have an ASP.NET MVC2 application. On one of my pages I have a textbox defined in the following manner:
<%: Html.TextBoxFor(model => model.PostCode) %>
Which is working perfectly.
However, for specific countries (model.Country) I do not want to show this TextBox.
What is the best way of implementing this?
This is an .aspx file, not .cshtml
Thanks
Create a property in your model class, and try this:
#if (!Model.IsSpecificCountry) {
#Html.TextBoxFor(model => model.PostCode)
}
Update:
<%if (!Model.IsSpecificCountry) { %>
<%= Html.TextBoxFor(model => model.PostCode) %>
<% } %>
As part of my current project I've blundered into an enormous MVC web form that I know relatively little about, and am having to do some fairly serious debugging on it. I have plenty of WebForms experience but little with MVC so please forgive me if the following isn't clear, or is asking silly questions.
Part of the form is a custom .ascx control which gets information from another URL and limits what the user can put into that section of the form based on that information. All the form elements can be turned on and off. If you turn this particular form element on, fill it in and submit then the ModelState fails its validation check, complaining that its missing a required value. The form is returned with the problematic element switched on, but no values in the boxes. If you don't switch on this particular element, the ModelState validates properly.
I know enough about MVC to understand that the mapping between form elements and the model occurs under the hood. However this makes it very difficult to debug. I really have no idea what the problem is or, worse, how to go about investigating what the cause is. Any suggestions on either front would be greatly appreciated.
EDIT: Some code
//start to deal with specialist form user controls
case "ViewData.Customer.CustomFieldTypes.BlackWhiteListConfigViewData ":
if (Model.Visible)
{ %>
<div class="formItem">
<label>
<% Html.RenderPartial("~/Views/Shared/EditorTemplates/BlackWhiteListConfigViewData.ascx"); %>
</div>
<% }
else
{ %>
<%= Html.HiddenFor(m => Model.Value) %>
<% }
b break;
And the binding code:
switch (fieldType)
{
case FeatureFieldFactory.BlackWhiteListConfigElTypeName:
{
// create a new default model binder, and tell it which type we actually want it to bind.
BlackWhiteListConfigViewData model = new BlackWhiteListConfigViewData();
bindingContext.ModelMetadata =
ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(BlackWhiteListConfigViewData));
return base.BindModel(controllerContext, bindingContext);
}
EDIT: BlackWhiteListConfigViewData.ascx code
if (Model.Visible)
{ %>
<script type="text/javascript">
$(cpContext.CurrentService()).bind('onServiceAttributesReady', function (context) {
$(document).ready(function () {
$("#js-hook-BlackWhiteListLoading").hide();
if (context.target.AttributeNames().length === 0) {
$("#js-hook-AddBlackWhiteListEntry").hide();
$("#js-hook-BlackWhiteListConfigTable").hide();
$("#js-hook-BlackWhiteListMessage").html('There are no attribute types present in the catalogue. The Black and White lists can be configured once the catalogue is loaded.');
$("#js-hook-BlackWhiteListMessage").show();
}
else {
$("#js-hook-BlackWhiteListMessage").hide();
$("#js-hook-AddBlackWhiteListEntry").show();
$("#js-hook-BlackWhiteListConfigTable").show();
}
});
});
$(cpContext.CurrentService()).bind('onServiceAttributesError', function (context) {
$(document).ready(function () {
$("#js-hook-BlackWhiteListLoading").hide();
$("#js-hook-AddBlackWhiteListEntry").hide();
$("#js-hook-BlackWhiteListConfigTable").hide();
$("#js-hook-BlackWhiteListMessage").html('No attribute types retrieved from service API. The Black and White lists can be configured when a Build has been completed and service API is accessible.');
$("#js-hook-BlackWhiteListMessage").show();
});
});
cpContext.CurrentService().getAttributes();
</script>
<div class="formItem narrow blackWhiteListConfig">
<% using (Html.BeginCollectionItem("fields"))
{
Model.Value = "n/a";
%>
<%= Html.HiddenFor(m => Model.Id) %>
<%= Html.HiddenFor(m => Model.Type) %>
<%= Html.HiddenFor(m => Model.Name) %>
<%= Html.HiddenFor(m => Model.Visible) %>
<%= Html.HiddenFor(m => Model.DisplayName) %>
<%= Html.HiddenFor(m => Model.Value) %>
<table id="js-hook-BlackWhiteListConfigTable" class="configTable" style="display:none">
<thead>
<tr><th class="configTableColumn">Key Attribute Type</th><th class="configTableColumn">Key Value</th><th class="transparent"></th><th class="configTableColumn">Related Attribute Type</th><th class="configTableColumn">Related Attribute Value</th><th class="configTableColumn narrow">Black</th><th class="configTableColumn narrow">White</th><th class="transparent" style="width:20px"></th></tr>
</thead>
<tbody class="blackWhiteListRows">
<% foreach (BlackWhiteListEntryViewData entry in Model.Entries)
{ %>
<%= Html.EditorForNested(e => entry) %>
<% } %>
</tbody>
</table>
<hr />
<p id="js-hook-AddBlackWhiteListEntry" class="clear" style="display:none">Add another entry</p>
<p id="js-hook-BlackWhiteListMessage" class="clear" style="display:none">There are no attribute types present in the catalogue. The Black and White lists can be configured once the catalogue is loaded.</p>
<img id="js-hook-BlackWhiteListLoading" src="<%=Links.Content.images.content_loading_gif %>" alt="Loading Black and White list configuration..."
style="" class="clear" />
<%= Html.ValidationMessageFor(m => Model) %>
<% } %>
Model.Value) %>
Cheers,
Matt
Try replacing:
<% Html.RenderPartial("~/Views/Shared/EditorTemplates/BlackWhiteListConfigViewData.ascx"); %>
with:
<%= Html.EditorForModel() %>
or if your model type is not BlackWhiteListConfigViewData you could specify it:
<%= Html.EditorForModel("BlackWhiteListConfigViewData") %>
Also inside your editor template you seem to be using some custom helpers such as Html.EditorForNested. Make sure your input field names respect the conventions for binding to a list.
Having trouble grasping this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Movie movieToEdit)
{
var originalMovie = (from m in _db.MovieSet
where m.Id == movieToEdit.Id
select m).First();
In this case you've posted your form, and it gets the movie you're going to edit by checking movieToEdit.Id
However I don't understand how it knows what the Id is. I thought that movieToEdit was created by examining the View. The fields on the View are only:
<fieldset>
<legend>Fields</legend>
<p>
<label for="Title">Title:</label>
<%= Html.TextBox("Title", Model.Title) %>
<%= Html.ValidationMessage("Title", "*") %>
</p>
<p>
<label for="Director">Director:</label>
<%= Html.TextBox("Director", Model.Director) %>
<%= Html.ValidationMessage("Director", "*") %>
</p>
<p>
<label for="DateReleased">DateReleased:</label>
<%= Html.TextBox("DateReleased", String.Format("{0:g}", Model.DateReleased)) %>
<%= Html.ValidationMessage("DateReleased", "*") %>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
Presumably when you hit save it will construct the movieToEdit based on the textboxes on the page automatically. But Id isn't one of the fields on the page, so how does it know what it is? Does it create hidden fields for properties such as Id automatically?
ID is most likely in your URL since default MVC route definition is:
{controller}/{action}/{id}
Your <form> in the view most likely posts back to something like:
http://www.yourappaddress.com/movies/edit/N
where N is movie ID. All other movie property values are sent via form POST values.
The ViewUserControl below results in the following error at runtime:
The Collection template was used with an object of type 'System.Data.Entity.DynamicProxies.Collection_1D9779ACB92AE24E3428C288EA7B1480A6477CF8861FB7582692E775613EFB3A', which does not implement System.IEnumerable.
The error occures on this line: <%: Html.EditorFor(model => model) %>
If I change the name of the model object to Collection2 it works. Does it gets confused because Collection is also the name of an object in the .net framework?
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CollectionManager.Models.Collection>" %>
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) { %>
<%: Html.ValidationSummary(true) %>
<%: Html.EditorFor(model => model) %>
<input type="submit" value="Save" />
<% } %>
remco - yes, i think that would definately be a reserved word. not sure about it getting confused but definately you should take care with naming when potential clashes could occur. the same thing is true of variable names, tho you can prefix them with # to override that i.e. string #absract would be allowable, whereas string abstract wouldn't.
go with the 'reserved' flow :)
jim
I am working on an ASP.NET MVC RC2 app using Entity Framework.
This is my Entity diagram.
In my repository I get the entity like this:
public Product GetProduct(int id)
{
return (from c in _entities.ProductSet.Include("User")
where c.Id == id
select c).FirstOrDefault();
}
My view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<SampleApp.Models.Product>" %>
Edit product
<h2>Edit product</h2>
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<p>
<label for="Id">Id:</label>
<%= Model.Id %>
</p>
<p>
<label for="Title">Title:</label>
<%= Html.TextBox("Title", Model.Title) %>
<%= Html.ValidationMessage("Title", "*") %>
</p>
<p>
<label for="Body">Body:</label>
<%= Html.TextBox("Body", Model.Body) %>
<%= Html.ValidationMessage("Body", "*") %>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
Problem and my question is: When the "Product" entity is returned from the view on post, the linked entity "User" is null. Why is that and is there any way to get around this?
Because the productToEdit is a new product object populated from the form fields and if you don't have fields for the user how would you populate the User entity
For a "workaround", first get the product from the db, edit this with the edited fields in the productToEdit and save to db
You can also choose to use a custom ModelBinder that understands your model & persistence strategy to fully load the graph back into memory.