Я создал пользовательский HtmlHelper для отображения адреса на веб-странице. Адрес должен быть динамическим в зависимости от страны, в которой находится адрес. Для этого у меня есть простой интерфейс с несколькими реализациями. Мой контроллер передает конкретную реализацию в представление, которое строго типизировано для интерфейса. При отладке в представлении отображается правильный тип реализации, и я передаю эту модель в свой пользовательский HtmlHelper в качестве типичного параметра типа. Этот пользовательский HtmlHelper принимает только модели типа IAddress или его реализации, но TModel всегда является IAddress независимо от того, какой тип передается в него. Это проблема из-за атрибутов отдельных реализаций, поскольку я использую существующие HtmlHelpers, такие как Html.EditorFor и Html.LabelFor в моем собственном помощнике, чтобы отображать поля и метки для адреса, включая правильную проверку при отправке.Выражение <Func <TModel, string >> где TModel - это интерфейс, тип никогда не передается.
Я считаю, что проблемы в том, что представление строго типизировано для IAddress, а HtmlHelper игнорирует фактический тип модели и подходит прямо к типу вида, как я могу обойти это?
интерфейса и исполнители Классы:
public interface IAddress
{
// Dumbed down to one property to save space
String City { get; set; }
String State { get; set; }
}
public class AddressUS : IAddress
{
// Required and displayed on page.
[DisplayName("City")]
[Required(ErrorMessage = "City is required!")]
public String City { get; set; }
// Required and displayed on page.
[DisplayName("State")]
[Required(ErrorMessage = "State is required!")]
public String State { get; set; }
}
public class AddressJP : IAddress
{
// Required and displayed on page.
[DisplayName("Prefecture")]
[Required(ErrorMessage = "Prefecture is required!")]
public String City { get; set; }
// Not required and not displayed on page.
[DisplayName("State")]
public String State { get; set; }
}
Действие
Контроллер:
public ActionResult DisplayAddress()
{
// Returning a specific type for testing.
AddressJP address = new AddressJP() { City = "Test" };
}
Вид:
@*
Set to the interface to accept all implementations, but possibly also the cause of the issue.
Setting to AddressJP, but I need it dynamic.
*@
@model IAddress
@using Custom.HtmlExtensions
<div id="address">
@Html.AddressEditorForModel(true)
</div>
HtmlHelper:
public static MvcHtmlString AddressEditorForModel<TModel>(this HtmlHelper<TModel> helper, Boolean showLabels) where TModel : IAddress
{
// TModel is always IAddress unless I change the view to be a specific implementation.
StringBuilder sb = new StringBuilder();
PropertyInfo pInfo = typeof(TModel).GetProperty("City");
ParameterExpression paramExpr = Expression.Parameter(typeof(TModel));
MemberExpression propertyAccess = Expression.MakeMemberAccess(paramExpr, pInfo);
var lambdaExpr = Expression.Lambda<Func<TModel, string>>(propertyAccess, paramExpr);
if (showLabels)
sb.AppendLine(helper.LabelFor(lambdaExpr).ToString());
sb.AppendLine(helper.EditorFor(lambdaExpr).ToString());
return MvcHtmlString.Create(sb.ToString());
}
Использование helper.ViewData.Model.City прекрасно работает для получения значений этого свойства, но то, что мне нужно, это атрибуты этих свойств, которые будут использоваться. Например, DisplayName для метки и проверки в редакторе. Я не понимаю, как это могло бы это сделать? – WebDevNewbie
@WebDevNewbie Не работает ли это просто при использовании 'helper.Label'? В любом случае, посмотрите на «ModelMetadataProviders.Current.GetMetadataForType» - он дает вам все эти атрибуты на основе типа автоматически, не нужно связываться с атрибутами самостоятельно. – Luaan
helper.Label (helper.ViewData.Model.City) устанавливает значение метки в значение свойства City, а не значение атрибута в свойстве City. helper.LabelFor делает, но для этого требуется выражение, которое потребует TModel.Я буду экспериментировать с ModelMetadataProviders для немного здесь и посмотреть, где он идет :) – WebDevNewbie