Populating Umbraco Contour forms from using cookie data - umbraco7

We're currently using Umbraco version 7.1.4 assembly: 1.0.5261.28127 with Contour version 3.0.26
I'm trying to populate a contour form with information pulled from a database, but dependent on a user cookie (the cookie hold the primary key for the record in the database).
To implement this I'm looking at writing a custom field type (well a bunch of them, one for each data field) which examines the cookie makes the db request and then populates the textbox with the value (users name/address/etc).
I've managed to add custom setting to a control and have it display the value that's populated at design time, but I can't seem to amend that value at run time.
I'm happy to post the code if relevant, but my question is. Am I barking up the wrong tree? is this the best way to handle this or would it even work?
Any pointers would be most welcome
Thanks
EDIT
Thanks Tim,
I've now managed to break it in such a way it's not even rendering the controls (the debug message is saying the SVT value doesn't exist).
This just (or should) just populate the form with the current date/time just to get something working.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Forms.Core;
using System.Web.UI.WebControls;
namespace Custom.FieldType
{
public class CustomTextfield : Umbraco.Forms.Core.FieldType
{
public CustomTextfield()
{
//Provider
this.Id = new Guid("b994bc8b-2c65-461d-bfba-43c4b3bd2915");
this.Name = "Custom Textfield";
this.Description = "Renders a html input fieldKey"; //FieldType
this.Icon = "textfield.png";
this.SVT = DateTime.Now.ToLongTimeString();
}
public System.Web.UI.WebControls.TextBox tb;
public List<Object> _value;
[Umbraco.Forms.Core.Attributes.Setting("SVT", description = "the SVT")]
public string SVT { get; set; }
public override WebControl Editor
{
get
{
tb.TextMode = System.Web.UI.WebControls.TextBoxMode.SingleLine;
tb.CssClass = "text gaudete";
if (_value.Count > 0)
tb.Text = _value[0].ToString();
SVT = DateTime.Now.ToLongTimeString();
tb.Text = tb.Text + SVT;
return tb;
}
set { base.Editor = value; }
}
public override List<Object> Values
{
get
{
if (tb.Text != "")
{
_value.Clear();
_value.Add(tb.Text);
}
return _value;
}
set { _value = value; }
}
public override string RenderPreview()
{
return
"<input type=\"text\" id=\"text-content\" class=\"text\" maxlength=\"500\" value=\"" + this.SVT + "\" />";
}
public override string RenderPreviewWithPrevalues(List<object> prevalues)
{
return RenderPreview();
}
public override bool SupportsRegex
{
get { return true; }
}
}
}
And the view is
#model Umbraco.Forms.Mvc.Models.FieldViewModel
#{
var widthSetting = Model.AdditionalSettings.FirstOrDefault(s => s.Key.Equals("Width"));
string width = (widthSetting == null) ? null : widthSetting.Value;
var textSetting = Model.AdditionalSettings.FirstOrDefault(s => s.Key.Equals("SVT"));
string widthTXT = (textSetting == null) ? null : textSetting.Value;
}
<input type="text" name="#Model.Name" id="#Model.Id" class="text" maxlength="500"
value="#{if(!string.IsNullOrEmpty(widthTXT)){<text>#(SVT)</text>}}"
#{if(Model.Mandatory || Model.Validate){<text>data-val="true"</text>}}
#{if (Model.Mandatory) {<text> data-val-required="#Model.RequiredErrorMessage"</text>}}
#{if (Model.Validate) {<text> data-val-regex="#Model.InvalidErrorMessage" data-regex="#Model.Regex"</text>}}
/>
The code is mostly cobbled together from online tutorials which is why the naming is abysmal but if I can get something to populate the text box on the clients side then I can start the process of refactoring (well scrapping this demo version and writing a real version)
Thanks.
EDIT2
I was able to fix the error stopping the view loading thanks to the pointer from Tim, the new view looks as follows
#model Umbraco.Forms.Mvc.Models.FieldViewModel
#{
var textSetting = Model.AdditionalSettings.FirstOrDefault(s => s.Key.Equals("SVT"));
string widthTXT = (textSetting == null) ? null : textSetting.Value;
}
<input type="text" name="#Model.Name" id="#Model.Id" class="text" maxlength="500"
value="#{if(!string.IsNullOrEmpty(widthTXT)){<text>#(widthTXT)</text>}else{<text>Unknown</text>}}"
#{if(Model.Mandatory || Model.Validate){<text>data-val="true"</text>}}
#{if (Model.Mandatory) {<text> data-val-required="#Model.RequiredErrorMessage"</text>}}
#{if (Model.Validate) {<text> data-val-regex="#Model.InvalidErrorMessage" data-regex="#Model.Regex"</text>}}
/>
And just displays "Unknown" in the text box
thanks again.

Related

MVC DisplayFormatAttribute - DataFormatString for strings

I have a string stored in my DB that is always 12 characters (digits) long. I want it to be displayed on screen as :
"###/####/####"
I like to use a DisplayFormatAttribute
[DisplayFormat(DataFormatString = "{0:##/####/#####}", ApplyFormatInEditMode = true)]
But the provided DataFormatString does not seems to be working.
EDIT
I tought solving this by creating a customer DisplayFormatAttribute, but this seems not to be that obvious.
Any suggestions ?
I had a quite similar problem, and solved it by using the UIHint attribute in my viewmodel class. In addition I then created a formatter in my EditorTemplates folder. (MVC looks for that folder by default i think).
So what happens is that the rendring engine replace the editor in my view with the formatter.
My example is for bankaccount number with 11 digits, so you have to modify it slightly for your case. The backend db only accept 11 digits with no separators, so therefore i remove these before i save.
In my view
#Html.EditorFor(m => m.BankAccount)
In folder Views/EditorTemplates
#model String
#{
Script.Require("common");
}
#{String temp = String.Empty;}
#if (!String.IsNullOrEmpty(Model))
{
if (Model.Length == 11)
{
temp = String.Format("{0: ####-##-##-###}", Convert.ToInt64(Model)).Replace("-",".");
}
else
{
temp = Model;
}
}
<input type="text" id="BankAccount" name="BankAccount" class="form-control span6" onkeypress="NumberFilter(event, '.');" value="#temp" />
ViewModel
private string _BankAccount;
[UIHint("_BankAccountFormatter")]
public string BankAccount
{
get
{
return _BankAccount;
}
set
{
if (!String.IsNullOrEmpty(value))
{
_BankAccount = value;
_BankAccount = _BankAccount.Trim();
_BankAccount = _BankAccount.Replace(".", "");
}
}
}

ASP.NET MVC 4 Want to populate dropdown list from database

I am new guy in ASP.NET MVC 4. I want to populate dropdownlist from database table BO where Column name is Id, Code, Name, OrgId. I want to bind two Code & Namecolumn's data to DataTextfield and Id column Data to DataValueField of dropdown. I have created code for this which are as follows BUT ITS NOT RETURNING DATA FROM TABLE and var BOList is remain empty :
my connectionstring is
<add name="iRegDBContext"
connectionString="Data Source=****;Initial Catalog=iReg;User ID=**;Password=****;Integrated Security=True"
providerName="System.Data.SqlClient"
/>
My Controller class :
public class iRegController : Controller
{
private iRegDBContext l_oDbBO = new iRegDBContext();
// GET: /iReg/
public ActionResult PopulatejQgrid()
{
var BOList = l_oDbBO
.BO
.ToList()
.Select(d => new SelectListItem
{
Value = d.Id.ToString(),
Text = d.Name + "[ " + d.Code + " ]"
});
ViewBag.BOData = new SelectList(BOList, "Value", "Text");
return View();
}
}
My Model class :
public class BO
{
public Guid Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
public class iRegDBContext : DbContext
{
public DbSet<BO> BO { get; set; }
}
My cshtml class :
#model MvciReg.Models.BO
#{
ViewBag.Title = "PopulatejQgrid";
}
#using (Html.BeginForm())
{
<fieldset>
BO :
#Html.DropDownList("BOData")
<p>
<input type="submit" value="Go" />
</p>
</fieldset>
}
I really don't know where I am going wrong. I developed my code from reference of following link Click here . Kindly suggest correction in code ...
UPDATE: I tried following Matt Bodily's code in my controller and what I see is code is not fetching data from database and that code is
public ActionResult populatejQgrid()
{
ViewBag.BOData = GetDropDown();
return View();
}
public static List<SelectListItem> GetDropDown()
{
List<SelectListItem> ls = new List<SelectListItem>();
var lm = from m in db.BOs //fetch data from database
select m;
foreach (var temp in lm)
{
ls.Add(new SelectListItem() { Text = temp.Name, Value = temp.Id.ToString() });
}
return ls;
}
In Controller :
#Html.DropDownList("BOData", (List<SelectListItem>)ViewBag.BOData)
But when I saw value of ls through watch it always show me Count = 0 but its not giving me any error.
I found something new this problem. When I kept mouse pointer over var lm; it shows me query and in query table name in FROM clause is not that one in my SQL database. My SQL table name is BO and in query it is taking BOes. I don't know from where this name is coming. I think this is the main cause of all this problem So How I overcome this??
First Create a BO list for Dropdownlist in VIEW
#{
var Bolst= Model.BO.Select(cl => new SelectListItem
{
Value = cl.Value.ToString(),
Text = cl.Text== null ? String.Empty : cl.Text
});
}
#(Html.DropDownList("sampleDropdown", BOlst, "-----Select-----"))
In Controller:
return View(BOlst); // why use Viewbag when directly pass it to view
from what I see in your code you are creating the select list and setting the ViewBag.BOData on the controller.
So in order to render it on the view you should do this
#Html.DropDownList(ViewBag.BOData)
instead of
#Html.DropDownList("BOData")
Regarding the access to the database are you trying to use "code first" in an existing database?
If you are you need to override the context constructor like this
public class iRegDBContext : DbContext
{
  public iRegDBContext()
     :base("Name= iRegDBContext")
   {
   }
}
see this link http://msdn.microsoft.com/en-us/data/jj200620.aspx
Hope it helps.
try building your dropdown this way
#Html.DropDownList(x => x.Selected, PathToController.GetDropDown())
and then in your controller
public static List<SelectListItem> GetDropDown()
{
List<SelectListItem> ls = new List<SelectListItem>();
lm = (call database);
foreach (var temp in lm)
{
ls.Add(new SelectListItem() { Text = temp.name, Value = temp.id });
}
return ls;
}
Hopefully this helps
I recently had this issue also and managed to get it working using Viewbag. You will need to make it fit your Db tables but it works and is quite simple.
Populating Drop Down Box with Db Data

Don't understand the mechanics of writing own validation attribute

I have written an attribute before, but I I have not written a validation attribute before. I am seriously confused about how it all works together. I have read most of the tutorials online about how to go about accomplishing this. But I am left with a couple of questions to ponder.
Keep in mind that I am trying to write a requiredIf attribute that will only call a remote function if a certain Jquery variable is set... which incidentally is a variable that is pulled from view state... I guess I could make that part of my view model. But I digress
1) The C# code is slightly confusing. I know my attribute should extend the ValidationAttribute, IClientValidatable class and interface respectively. But I am a little confused about what each of the overidden methods should be doing? I am trying to write a requiredIf, how does overwriting these methods help me accomplish this goal?
2) If the variable is not there, I simply don't want the remote function to attempt to validate the field. I don't want any message to pop up on my form. Alot of the tutorials seem to revolve around that.
3) I am confused about what I need to do with the jquery to add this function to the view... What do I need to add to the JQuery to get this thing to work... It seems like a lot of extra coding when I could simply just type up a jquery function that did the same thing with just the same ore less coding... I know it also adds server side validation which is good. But still...
Here is what I have for my jquery side of this equation...
(function ($) {
$validator.unobtrusive.adapters.addSingleVal("requiredifattribute", "Dependent");
$validator.addMethod("requiredifattribute", function (value, element, params) {
if (!this.optional(element)) {
var otherProp = $('#' + params)
return (otherProp.val() != value);
}
return true;
})
}(jQuery));
Here is my Attribute (which is basically carbon copied out of one the required if tutorials... I know I need to customize it more, but once I get a better idea of what every piece is doing I will do that...
[AttributeUsage(AttributeTargets.Property)]
public class RequiredIfAttribute : ValidationAttribute, IClientValidatable {
private const string errorMessage = "The {0} is required.";
//public string
private RequiredAttribute innerAttribute = new RequiredAttribute();
public string DependentProperty { get; set; }
public object TargetValue { get; set; }
public RequiredIfAttribute(string dependentProperty, object targetValue){
this.DependentProperty = dependentProperty;
this.TargetValue = targetValue;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
var field = validationContext.ObjectInstance.GetType().GetProperty(DependentProperty);
if (field != null) {
var dependentValue = field.GetValue(validationContext.ObjectInstance, null);
if ((dependentValue == null && TargetValue == null) || (dependentValue.Equals(TargetValue))) {
if (!innerAttribute.IsValid(value))
return new ValidationResult(ErrorMessage);
}
}
return ValidationResult.Success;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
ModelClientValidationRule modelClientValidationRule = new ModelClientValidationRule {
ErrorMessage = FormatErrorMessage(metadata.DisplayName),
ValidationType = "requiredifattribute"
};
modelClientValidationRule.ValidationParameters.Add("dependent", DependentProperty);
yield return modelClientValidationRule;
}
}
UPDATE: What I have simply isn't working
Here is how a property in my model is anotated with the above attribute
[RequiredIf("isFlagSet", true)]
[Remote("ValidateHosFin", "EditEncounter", AdditionalFields = "hospitalFin, encflag", ErrorMessage = "Got Damn this is complex!")]
[MinLength(6)]
public string HostpitalFinNumber { get; set; }
The value in my view that I was trying to key this validation on is set up like so...
ViewData["ADDENCOREDITTEMP"] = encflag;
if (encflag == "AddEnc"){
isFlagSet = true;
}
I embed it into my page like so...
#Html.Hidden("isFlagSet", isFlagSet, new { id = "isFlagSet"})
I can't get my form to submit... The person who said he just tried this and got it to work, could you post the code?
Model:
public class X
{
[RequiredIf("y", "y", ErrorMessage = "y is not y")]
public string x { get; set; }
public string y { get; set; }
}
View:
#using(Html.BeginForm())
{
#Html.ValidationSummary()
#Html.TextBoxFor(m => m.x)
#Html.TextBoxFor(m => m.y)
<input type="submit"/>
}
I assume your validation fails on the server side? do you have isFlagSet property in your view model?

How can I utilise my custom DisplayTemplate with non-text fields so that it doesn't override existing values?

I've been following this guide on creating custom display attributes (specifically extra html attributes) to apply to the properties in my ViewModel. I have overridden both String and Boolean in the EditorTemplates folder. The editor template checks to see if a value has been set/the display attribute has been used - and adds the additional html attributes.
I'm getting stuck on the Boolean override when performing an edit action though. Regardless of whether or not I apply the attribute to a string, the ViewModel always maps with the correct existing data. This isn't true with any other form input type, due to the way the templates have been written by changing the type attribute inside a TextBoxFor.
I've been writing this primarily because I have been digging into knockout, and wanted an easy way to apply the data-bind attribute to strongly-typed views - if there's a better way please let me know!
Attribute Code:
public class Knockout : Attribute
{
public string DataBind { get; set; }
public string InputType { get; set; }
/*
Example:
Knockout("checked: showUploader", "checkbox")
Adds the HTML attributes data-bind="checked: showUploader" type="checkbox"
*/
public Knockout(string dataBind, string inputType)
{
this.DataBind = dataBind;
this.InputType = inputType;
}
public Dictionary<string, object> OptionalAttributes()
{
var options = new Dictionary<string, object>();
if(!string.IsNullOrWhiteSpace(DataBind))
{
options.Add("data-bind", DataBind);
}
if (!string.IsNullOrWhiteSpace(InputType))
{
options.Add("type", InputType);
}
return options;
}
}
Template Code
#using CumbriaMD.Infrastructure.ViewModels.DisplayAttributes
#{
var key = "Knockout";
}
#if (ViewData.ModelMetadata.AdditionalValues.ContainsKey(key))
{
var knockout = ViewData.ModelMetadata.AdditionalValues[key] as Knockout;
#Html.TextBoxFor(model => model, knockout.OptionalAttributes())
}
else
{
/*
When the attribute is not present, the default action is the following - which seems to
be overriding the data mapped from the database:
*/
#Html.TextBoxFor(model => model, new { type="checkbox" })
}
Found the answer nested in this beauty of a question!
My working template for boolean values now looks like:
#using CumbriaMD.Infrastructure.ViewModels.DisplayAttributes
#{
var key = "Knockout";
bool? value = null;
if(ViewData.Model != null)
{
value = Convert.ToBoolean(ViewData.Model, System.Globalization.CultureInfo.InvariantCulture);
}
}
#if (ViewData.ModelMetadata.AdditionalValues.ContainsKey(key))
{
var knockout = ViewData.ModelMetadata.AdditionalValues[key] as Knockout;
#Html.CheckBox("", value ?? false, knockout.OptionalAttributes())
}
else
{
#Html.CheckBox("", value ?? false, new { #class = "check-box" })
}

How to read property data annotation value in .NET MVC

I Just starting out w/ ASP.NET MVC 3 and I am trying to render out the following HTML for the string properties on a ViewModel on the create/edit view.
<input id="PatientID" name="PatientID" placeholder="Patient ID" type="text" value="" maxlength="30" />
Each value ties back to the property on the ViewModel, id & name are the property name, placeholder is the Display attribute, value is the value of the property, and maxlength is the StringLength attribute.
Instead of typing out the above HTML w/ the correct values for each of my string properties I thought I would try to create an EditorTemplate by the name of SingleLineTextBox and use UIHint on my string properties or pass the name of the view when I call EditFor. So far so good, except I can't figure out how to get the maxlength value off the StringLength attribute.
Here is the code I have so far:
<input id="#ViewData.ModelMetadata.PropertyName" name="#ViewData.ModelMetadata.PropertyName" placeholder="#ViewData.ModelMetadata.DisplayName" type="text" value="#ViewData.Model" maxlength="??" />
As you can see, not sure how to set maxlength value. Anyone know how?
Also, am I going about this the best way? As I said before I could just write out the plain HTML myself for each property on the page. I've looked at using TextBoxFor it wasn't setting the maxlength and was adding a bunch of validation markup to the HTML output because of the StringLength attribute which I do not want. Another option I saw was extensions/helpers off the HTML class.
A full code sample for tvanfosson's answer:
Model:
public class Product
{
public int Id { get; set; }
[MaxLength(200)]
public string Name { get; set; }
EditorTemplates\String.cshtml
#model System.String
#{
var metadata = ViewData.ModelMetadata;
var prop = metadata.ContainerType.GetProperty(metadata.PropertyName);
var attrs = prop.GetCustomAttributes(false);
var maxLength = attrs.OfType<System.ComponentModel.DataAnnotations.MaxLengthAttribute>().FirstOrDefault();
}
<input id=#Html.IdForModel()#(metadata.IsRequired ? " required" : "")#(maxLength == null ? "" : " maxlength=" + maxLength.Length) />
HTML output:
<input id=Name maxlength=200 />
Ugly but it works. Now let's abstract it and clean it up a bit. Helper class:
public static class EditorTemplateHelper
{
public static PropertyInfo GetPropertyInfo(ViewDataDictionary viewData)
{
var metadata = viewData.ModelMetadata;
var prop = metadata.ContainerType.GetProperty(metadata.PropertyName);
return prop;
}
public static object[] GetAttributes(ViewDataDictionary viewData)
{
var prop = GetPropertyInfo(viewData);
var attrs = prop.GetCustomAttributes(false);
return attrs;
}
public static string GenerateAttributeHtml(ViewDataDictionary viewData, IEnumerable<Delegate> attributeTemplates)
{
var attributeMap = attributeTemplates.ToDictionary(t => t.Method.GetParameters()[0].ParameterType, t => t);
var attrs = GetAttributes(viewData);
var htmlAttrs = attrs.Where(a => attributeMap.ContainsKey(a.GetType()))
.Select(a => attributeMap[a.GetType()].DynamicInvoke(a));
string s = String.Join(" ", htmlAttrs);
return s;
}
}
Editor Template:
#model System.String
#using System.ComponentModel.DataAnnotations;
#using Brass9.Web.Mvc.EditorTemplateHelpers;
#{
var metadata = ViewData.ModelMetadata;
var attrs = EditorTemplateHelper.GenerateAttributes(ViewData, new Delegate[] {
new Func<StringLengthAttribute, string>(len => "maxlength=" + len.MaximumLength),
new Func<MaxLengthAttribute, string>(max => "maxlength=" + max.Length)
});
if (metadata.IsRequired)
{
attrs.Add("required");
}
string attrsHtml = String.Join(" ", attrs);
}
<input type=text id=#Html.IdForModel() #attrsHtml />
So you pass in an array of Delegates, and for each entry use a Func<AttributeTypeGoesHere, string>, and then return whatever HTML string you wanted for each attribute.
This actually decouples well - you can map only the attributes you care about, you can map different sets for different parts of the same HTML, and the final usage (like #attrsHtml) doesn't harm readability of the template.
Instead of the StringLength attribute (because it's a validator attribute not a metadata provider) you can use the AdditionalMetadata attribute. Sample usage:
public class ViewModel
{
[AdditionalMetadata("maxLength", 30)]
public string Property { get; set; }
}
Basically it puts the value 30 under the key maxLength in the ViewData.ModelMetadata.AdditionalValues dictionary. So you can use it your EditorTemplate:
<input maxlength="#ViewData.ModelMetadata.AdditionalValues["maxLength"]" id="#ViewData.ModelMetadata.PropertyName" name="#ViewData.ModelMetadata.PropertyName" placeholder="#ViewData.ModelMetadata.DisplayName" type="text" value="#ViewData.Model" />
To do this you'll need to create your own HtmlHelper extension and use reflection to get at the attributes on the model property. Look at the source code at http://codeplex.com/aspnet for the existing ...For() HtmlHelper extensions. You'll need to get the PropertyInfo object for the model property using the expression that is passed in as the argument. They have several helper classes that should serve as templates for this. Once you have that, use the GetCustomAttributes method on the PropertyInfo to find the StringLength attribute and extract it's value. Since you'll be using a TagBuilder to create the input, add the length as an attribute via the TagBuilder.
...
var attribute = propInfo.GetCustomAttributes(typeof(StringLengthAttribute),false)
.OfType<StringLengthAttribute>()
.FirstOrDefault();
var length = attribute != null ? attribute.MaximumLength : 20; //provide a default
builder.Attributes.Add("maxlength",length);
...
return new MvcHtmlString( builder.ToString( TagRenderMode.SelfClosing ) );
}
See my comment on why I think this is a bad idea.
An much simpler solution is to implement a custom DataAnnotationsModelMetadataProvider like this:
internal class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
ModelMetadata modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
var maxLengthAttribute = attributes.OfType<MaxLengthAttribute>().SingleOrDefault();
if (maxLengthAttribute != null)
{
modelMetadata.AdditionalValues.Add("maxLength", maxLengthAttribute.Length);
}
return modelMetadata;
}
}
In the template you can simply use:
object maxLength;
ViewData.ModelMetadata.AdditionalValues.TryGetValue("maxLength", out maxLength);
You can get the StringLength Validator from within an Editor Template, here are some examples:
https://jefferytay.wordpress.com/2011/12/20/asp-net-mvc-string-editor-template-which-handles-the-stringlength-attribute/
What I used and tested, as a result from the article above can be seen in my answer below (tested with MVC 5, EF 6) :
ASP.NET MVC 3 - Data Annoation and Max Length/Size for Textbox Rendering
Without being specific, I've personally had some mixed results with attempts to implement some other approaches, and I don't find either claimed method particular long; however, I did think some of the other approached looked a little "prettier".
#using System.ComponentModel.DataAnnotations
#model string
#{
var htmlAttributes = ViewData["htmlAttributes"] ?? new { #class = "checkbox-inline" };
var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
if (!attributes.ContainsKey("maxlength"))
{
var metadata = ViewData.ModelMetadata;
var prop = metadata.ContainerType.GetProperty(metadata.PropertyName);
var attrs = prop.GetCustomAttributes(false);
var maxLength = attrs.OfType<MaxLengthAttribute>().FirstOrDefault();
if (maxLength != null)
{
attributes.Add("maxlength", maxLength.Length.ToString());
}
else
{
var stringLength = attrs.OfType<StringLengthAttribute>().FirstOrDefault();
if (stringLength != null)
{
attributes.Add("maxlength", stringLength.MaximumLength.ToString());
}
}
}
}
#Html.TextBoxFor(m => m, attributes)

Resources