1

I am currently using the @Html.EditorFor HTML helper for the password field. I want to use the @Html.PasswordFor HTML helper instead.

I copied the current code and replaced @Html.EditorFor with @Html.PasswordFor.

CSHTML

This is the code:

@Html.EditorFor(x => x.Password, new { htmlAttributes = new { @class = "form-control k-textbox large", placeholder = "password", @id = "password", @autocomplete = "off" } })

@Html.PasswordFor(x => x.Pwd, new { htmlAttributes = new { @class = "form-control k-textbox large", placeholder = "password", @id = "password", @autocomplete = "off" } })

Rendered Output

The parameters are 100% the same, but these produce different style textboxes:

enter image description here

Note that @Html.EditorFor has validation and a placeholder as well, but @Html.PasswordFor doesn't; the later also has a different style. The validation spam element is also not a part of the textbox.

Generated HTML

Here is generated HTML code for @Html.EditorFor:

<input autocomplete="off" class="form-control k-textbox large text-box single-line password k-invalid" data-val="true" data-val-required=" " id="password" name="Password" placeholder="password" type="password" value="" aria-invalid="true"> 

Here is generated HTML code for @Html.PasswordFor:

<input data-val="true" data-val-required=" " htmlattributes="{ class = form-control k-textbox large, placeholder = password, id = password, autocomplete = off }" id="Pwd" name="Pwd" type="password" aria-invalid="true" class="k-invalid">

Model Definition

This is how I define those two fields in the model:

[Required(ErrorMessage = " ")]
[DataType(DataType.Password)]
public string Password { get; set; }

[Required(ErrorMessage = " ")]
[DataType(DataType.Password)]
public string Pwd { get; set; }

What am I doing wrong here?

blackgreen
  • 34,072
  • 23
  • 111
  • 129
gene
  • 2,098
  • 7
  • 40
  • 98

2 Answers2

2

The method signatures are slightly different.

public static System.Web.Mvc.MvcHtmlString PasswordFor<TModel,TProperty> (this System.Web.Mvc.HtmlHelper<TModel> htmlHelper,
     System.Linq.Expressions.Expression<Func<TModel,TProperty>> expression,
     object htmlAttributes);

public static System.Web.Mvc.MvcHtmlString EditorFor<TModel,TValue> (this System.Web.Mvc.HtmlHelper<TModel> html,
    System.Linq.Expressions.Expression<Func<TModel,TValue>> expression,
    object additionalViewData);

You don't need to wrap the PasswordFor attribute object in another object. What you have is:

@Html.EditorFor(m => m.Password, additionalViewData: new { htmlAttributes = new { ... } })
@Html.PasswordFor(m => m.Pwd, htmlAttributes: new { htmlAttributes = new { ... } })

It is simply:

@Html.PasswordFor(m => m.Pwd, new { @class = "..." })
Jasen
  • 14,030
  • 3
  • 51
  • 68
2

I can't tell you why the decision was made to treat these differently, but while the second parameter for these particular overloads of EditorFor() and PasswordFor() both accept an anonymous object, those objects actually represent different concepts.

Documentation

For EditorFor(), the second parameter is titled additionalViewData:

An anonymous object that can contain additional view data that will be merged into the ViewDataDictionary<TModel> instance that is created for the template.

For PasswordFor(), the second parameter is titled htmlAttributes:

An object that contains the HTML attributes to set for the element.

Explanation

In other words, you're operating at different levels here. When you set a property called htmlAttributes on your anonymous object for EditorFor() (i.e., additionalViewData), that's being parsed out as HTML attributes on your rendered element:

<input autocomplete="off" class="…" id="password" placeholder="password" … > 

But when you set htmlAttributes on your anonymous object for PasswordFor() (i.e., htmlAttributes), that's being seen as an HTML attribute itself, as you can see in your HTML output:

<input htmlattributes="{ class = …, placeholder = password, id = password, autocomplete = off }" … >

Resolution

As a result, what you should be doing in elevating the htmlAttributes one level for your PasswordFor() call:

@Html.PasswordFor(x => x.Pwd, new { @class = "form-control k-textbox large", placeholder = "password", @id = "password", @autocomplete = "off" })

Which should render something like:

<input class="form-control k-textbox large" placeholder="password" id="password" autocomplete="off" … >

And with the CSS classes correctly set, you should also find that the presentation aligned.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
  • Thank you, it fixed the problem with the textbox style. However, the validation sign, is still displayed outside of the box ;( – gene Jun 27 '22 at 19:23
  • 1
    I got it. I had to change the style of the Password class – gene Jun 27 '22 at 19:28
  • @gene: What style did you alter for the `Password` class? If you let me know, I'll update my answer so it is complete. (I'll obviously credit you for discovering that.) – Jeremy Caney Jun 27 '22 at 19:30
  • span#Password_validationMessage – gene Jun 27 '22 at 19:31
  • may be you know the answer to the following question I posted the other day regarding that Password property? This is the link to the question: https://stackoverflow.com/questions/72759111/how-to-mitigate-cwe-316-cleartext-storage-of-sensitive-information-in-memory-in?noredirect=1#comment128516152_72759111 – gene Jun 27 '22 at 19:46
  • @gene: Unfortunately, I don't know the answer to that question. As an aside, please be sure to mark my answer (or @Jasen's) as accepted if one of them helped solve your problem. – Jeremy Caney Jun 27 '22 at 23:31