升级到MVC 3 RTM后,我得到了一个以前工作的例外.
这是场景.我有几个使用相同底层接口IActivity和IOwned的对象.
IActivity implements IOwned (another interface)
public interface IActivity:IOwned {...}
public interface IOwned
{
int? AuthorId {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
我有一个局部视图,它使用IActivity从其他具体的部分重用.
以下是Activity Partial的定义.
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IActivity>" %>
<%: Html.HiddenFor(item => item.AuthorId) %>
Run Code Online (Sandbox Code Playgroud)
但是,它会引发异常.它在ModelMetadata中找不到AuthorId.
我猜测在之前的版本中它查看了IActivity实现的接口.
任何想法,建议,到处都没有重复类似的接口?
复制下面的堆栈跟踪.
[ArgumentException: The property IActivity.AuthorId could not be found.]
System.Web.Mvc.AssociatedMetadataProvider.GetMetadataForProperty(Func`1 modelAccessor, Type containerType, String propertyName) +498313
System.Web.Mvc.ModelMetadata.GetMetadataFromProvider(Func`1 modelAccessor, Type modelType, String propertyName, Type containerType) +101
System.Web.Mvc.ModelMetadata.FromLambdaExpression(Expression`1 expression, ViewDataDictionary`1 viewData) +393
System.Web.Mvc.Html.InputExtensions.HiddenFor(HtmlHelper`1 htmlHelper, Expression`1 expression, IDictionary`2 htmlAttributes) +57
System.Web.Mvc.Html.InputExtensions.HiddenFor(HtmlHelper`1 htmlHelper, Expression`1 expression) +51
ASP.views_shared_activity_ascx.__Render__control1(HtmlTextWriter …Run Code Online (Sandbox Code Playgroud) 我很想知道是否可以覆盖模型上设置的[Required]属性.我相信这个问题最简单的解决方案,任何接受者?
我使用AutoMapper将我的域对象映射到我的视图模型.我的域层中有元数据,我希望将其转移到视图层和ModelMetadata中.(此元数据不是UI逻辑,但为我的视图提供了必要的信息).
现在,我的解决方案是使用单独的MetadataProvider(独立于ASP.NET MVC),并使用约定通过AssociatedMetadataProvider将相关元数据应用于ModelMetadata对象.这种方法的问题在于,当我使用AutoMapping绑定ModelMetadata时,我必须测试相同的约定,似乎应该有一种方法可以使这更加正交.任何人都可以推荐更好的方法来实现这一目标
automapper modelmetadata modelmetadataprovider asp.net-mvc-3 asp.net-mvc-2
说我有这样的模特
public class User
{
[Required]
[StringLength(14, ErrorMessage = "Can only be 14 characters long")]
public string UserName;
}
Run Code Online (Sandbox Code Playgroud)
我想创建一个这样的Html帮助器:
@Html.ValidatableEditorFor(m => m.UserName)
Run Code Online (Sandbox Code Playgroud)
这样它就会向jQuery Vaidation插件发出一个正确格式的文本字段,以便能够验证,如下所示:
<input type="text" class="required" maxlength="14" />
Run Code Online (Sandbox Code Playgroud)
根据我的研究,似乎没有办法迭代MetaDataModel中的所有数据注释,以便我可以检查哪一个适用于jQuery验证.
我如何设想它在伪代码中工作:
var tag = new TagBuilder("input");
tag.mergeAttribute("type", "text");
foreach(var attribute in metadata.attributes)
{
CheckForValidatableAttribute(attribute, tag);
}
...
private void CheckForValidatableAttribute(DataAnnotation attribute, TagBuilder tag)
{
switch(attribute.type)
{
case Required:
tag.addClass("required");
break;
case StringLength
tag.mergeAttribute("maxlength", attribute.value)
break;
}
}
Run Code Online (Sandbox Code Playgroud)
我怎么能去实现这样的帮助呢?我希望它能够处理数据注释,这样我就不必复制验证文字了.
例如,像TextEditorFor这样的当前Html帮助程序会将可验证的属性附加到其输出字段.它是如何做到的,我如何实现自己的实现?
干杯
编写强类型的Html助手有一个共同的问题.问题是如何检索属性名称/值对.假设我们有以下Html帮助声明:
public static string DatePickerFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, DateTime?>> expression)
Run Code Online (Sandbox Code Playgroud)
我找到了几种解决方案:1.
var value = expression.Compile()( helper.ViewData.Model );
string name = ExpressionHelper.GetExpressionText( expression );
string fullName = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName( name );
Run Code Online (Sandbox Code Playgroud)
2.
ModelMetadata metadata = ModelMetadata.FromLambdaExpression( expression, helper.ViewData );
Object value = metadata.Model;
String name = metadata.PropertyName;
Run Code Online (Sandbox Code Playgroud)
3.仅使用MemberExpression获取成员名称
string GetPropertyName<T>(Expression<Func<T>> property)
{
var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
}
return propertyInfo.Name;
}
Run Code Online (Sandbox Code Playgroud)
所有这些都有不同的实现从第一次看(使用Reflector调查),但我没有深入挖掘. …
我正在使用Entity Framework 4.1和Code First方法.我能够获取我的实体的存储模型类型和列名:
var items = context.ObjectContext.MetadataWorkspace.GetItems<EntityType>(DataSpace.SSpace);
foreach (var i in items)
{
Console.WriteLine("Table Name: {0}", i.Name);
Console.WriteLine("Keys:");
foreach (var key in i.KeyMembers)
Console.WriteLine("\t{0} ({1})", key.Name, key.TypeUsage.EdmType.FullName);
Console.WriteLine("Members:");
foreach (var member in i.Members)
Console.WriteLine("\t{0} ({1})", member.Name, member.TypeUsage.EdmType.FullName);
}
Run Code Online (Sandbox Code Playgroud)
我需要的是获取实体映射到的真实表名.有不同的方法来指定(通过使用Fluent-API .ToTable(),DataAnnotation [TableAttribute]).
有没有通用的方法来获得这些信息?
根据这篇博客文章 "ModelMetadata对象是使用从属性获取的数据构建的,主要来自System.ComponentModel和System.ComponentModel.DataAnnotations命名空间."
通过将UI辅助属性放在Model对象(DisplayFormat或UIHint)上,我们不是在耦合Model和View吗?
我有不同的人应该看到不同名称的字段.
例如,假设我有以下用户类型:
public enum UserType {Expert, Normal, Guest}
Run Code Online (Sandbox Code Playgroud)
我实现了一个IMetadataAware属性:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class DisplayForUserTypeAttribute : Attribute, IMetadataAware
{
private readonly UserType _userType;
public DisplayForUserTypeAttribute(UserType userType)
{
_userType = userType;
}
public string Name { get; set; }
public void OnMetadataCreated(ModelMetadata metadata)
{
if (CurrentContext.UserType != _userType)
return;
metadata.DisplayName = Name;
}
}
Run Code Online (Sandbox Code Playgroud)
我的想法是,我可以根据需要覆盖其他值,但是当我不这样做时,可以使用默认值.例如:
public class Model
{
[Display(Name = "Age")]
[DisplayForUserType(UserType.Guest, Name = "Age (in years, round down)")]
public string Age { get; set; }
[Display(Name …Run Code Online (Sandbox Code Playgroud) 我正在使用DataAnnotations编写MVC2应用程序.我有以下型号:
public class FooModel
{
[ScaffoldColumn("false")]
public long FooId { get; set; }
[UIHint("BarTemplate")]
public DateTime? Bar { get; set;}
}
Run Code Online (Sandbox Code Playgroud)
我想为Bar创建一个自定义显示模板.我创建了以下模板:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<DateTime?>" %>
<div class="display-label">
<span><%: Html.LabelForModel() %></span>
</div>
<div class="display-field">
<span><%: Html.DisplayForModel()%></span>
<%: Html.ActionLink("Some link", "Action", new { id = ??FooId?? }) %>
</div>
Run Code Online (Sandbox Code Playgroud)
现在,我的问题是Bar的内部模板我想从我的模型访问另一个属性.我不想为FooModel创建单独的模板,因为我将不得不对所有其他FooModel属性进行硬编码.
在使用调试器进行简短调查后,我可以看到:
this.ViewData.ModelMetadata.ContainerType
是FooModel(正如预期的那样)this.ViewData.TemplateInfo有一个非公共属性VisitedObjects
(类型
System.Collections.Generic.HashSet<object>),包含两个元素:
FooModel和DateTime?.如何访问我的FooModel?我不想破解我使用Reflection的方法.
更新:
我已经接受了mootinator的回答,因为它认为我是允许类型安全的最佳解决方案.我也赞成了Tx3的答案,因为mootinator的答案建立在它之上.尽管如此,我认为在这种场景中应该有更好的MVC支持,我认为这在现实世界中非常普遍,但在示例应用程序中却缺少.
在我的index.cshtml中,我想显示WizardStepAttributeValue
因此,用户将在每个页面的顶部看到 Step 1: Enter User Information
我有一个名为的ViewModel WizardViewModel.这个ViewModel有一个属性IList<IStepViewModel> Steps
每个"步骤"实现接口IStepViewModel,这是一个空接口.
我有一个名为Index.cshtml的视图.此视图显示EditorFor()当前步骤.
我有一个自定义的ModelBinder,它将View绑定到IStepViewModel基于该WizardViewModel.CurrentStepIndex属性实现的具体类的新实例
我创建了一个自定义属性WizardStepAttribute.
我的每个步骤类都是这样定义的.
[WizardStepAttribute(Name="Enter User Information")]
[Serializable]
public class Step1 : IStepViewModel
....
Run Code Online (Sandbox Code Playgroud)
我的视图是强类型的,WizardViewModel不是每一步.我不想为每个具体实现创建一个视图IStepViewModel
我以为我可以在界面中添加属性,但是我必须在每个类中明确地实现它.(所以这不是更好)
我想我可以在界面中使用反射来实现它,但是,你不能在接口中的方法中引用实例.
modelmetadata ×10
asp.net-mvc ×4
c# ×4
asp.net ×2
automapper ×1
entity ×1
html-helper ×1
lambda ×1
model ×1
templates ×1