I have a new .NET 9 Razor page Blazor server-side project.
I used EF Core Power Tools to import my database schema and generate the DbContext
and model classes.
I created a MetaData
class for one of my model classes and I'm using a call to TypeDescriptor.AddProviderTransparent
to attach the metadata class to the class that was generated by EF Core Power Tools.
I'm attempting to do the same thing shown here: /add-dataannotations-metadata-to-ef-core-in-a-partial-class
But, the metadata appears to be not getting used at all.
Generated model code:
[Table("AsphaltIndexPrice")]
public partial class AsphaltIndexPrice
{
[Key]
public int AsphaltIndexPriceId { get; set; }
[Column(TypeName = "datetime")]
public DateTime EffectiveDate { get; set; }
[Column(TypeName = "money")]
public decimal IndexPrice { get; set; }
}
Metadata class:
public class AsphaltIndexPriceMetaData
{
[Display(Name = "Asphalt Index Price Id")]
public int AsphaltIndexPriceId { get; set; }
[Required(ErrorMessage="An Effective Date is required")]
[Display(Name = "Effective Date")]
public DateTime EffectiveDate { get; set; }
[Required(ErrorMessage = "An Index Price is required")]
[DataType(DataType.Currency)]
[Display(Name = "Price")]
public decimal IndexPrice { get; set; }
}
Code for attaching the metadata class to the model class:
public static void HMADBMetaDataInit()
{
AddMetaData(typeof(AsphaltIndexPrice), typeof(AsphaltIndexPriceMetaData));
}
private static void AddMetaData(Type baseClass, Type metaDataClass)
{
TypeDescriptor.AddProviderTransparent(
new AssociatedMetadataTypeTypeDescriptionProvider(
baseClass,
metaDataClass),
baseClass);
}
The call to setup the metadata, in Program.cs
:
HMADBHelper.HMADBMetaDataInit();
app.Run();
I also put the same call to HMADBMetaDataInit()
in the OnInitialize
of a page, when just having it in Program.cs
didn't work. That made no difference.
Ways that tell me the metadata is being ignored:
On the screen where EffectiveDate
and IndexPrice
are shown, the labels generated are "EffectiveDate" and "IndexPrice", instead of "Effective Date" (with a space) and "Price" (no word "Index").
Also, on the Edit
screen, if I blank out the EffectiveDate
and the IndexPrice
fields and click to save them, I get error messages that the values are not valid or not in the right range, but I do not get the specific text from above, e.g. "An Index Price is required".
I've stepped over the calls to AddProviderTransparent
in the debugger and I don't see any errors or other information in the output window to explain why it doesn't seem to be working.
What am I doing wrong?
Update
Per Simon's comment, I changed Program.cs
to call my metadata initialization before calling builder.Build()
. No change in application behavior.
HMADBHelper.HMADBMetaDataInit();
var app = builder.Build();
I have a new .NET 9 Razor page Blazor server-side project.
I used EF Core Power Tools to import my database schema and generate the DbContext
and model classes.
I created a MetaData
class for one of my model classes and I'm using a call to TypeDescriptor.AddProviderTransparent
to attach the metadata class to the class that was generated by EF Core Power Tools.
I'm attempting to do the same thing shown here: https://simonholman.dev/add-dataannotations-metadata-to-ef-core-in-a-partial-class
But, the metadata appears to be not getting used at all.
Generated model code:
[Table("AsphaltIndexPrice")]
public partial class AsphaltIndexPrice
{
[Key]
public int AsphaltIndexPriceId { get; set; }
[Column(TypeName = "datetime")]
public DateTime EffectiveDate { get; set; }
[Column(TypeName = "money")]
public decimal IndexPrice { get; set; }
}
Metadata class:
public class AsphaltIndexPriceMetaData
{
[Display(Name = "Asphalt Index Price Id")]
public int AsphaltIndexPriceId { get; set; }
[Required(ErrorMessage="An Effective Date is required")]
[Display(Name = "Effective Date")]
public DateTime EffectiveDate { get; set; }
[Required(ErrorMessage = "An Index Price is required")]
[DataType(DataType.Currency)]
[Display(Name = "Price")]
public decimal IndexPrice { get; set; }
}
Code for attaching the metadata class to the model class:
public static void HMADBMetaDataInit()
{
AddMetaData(typeof(AsphaltIndexPrice), typeof(AsphaltIndexPriceMetaData));
}
private static void AddMetaData(Type baseClass, Type metaDataClass)
{
TypeDescriptor.AddProviderTransparent(
new AssociatedMetadataTypeTypeDescriptionProvider(
baseClass,
metaDataClass),
baseClass);
}
The call to setup the metadata, in Program.cs
:
HMADBHelper.HMADBMetaDataInit();
app.Run();
I also put the same call to HMADBMetaDataInit()
in the OnInitialize
of a page, when just having it in Program.cs
didn't work. That made no difference.
Ways that tell me the metadata is being ignored:
On the screen where EffectiveDate
and IndexPrice
are shown, the labels generated are "EffectiveDate" and "IndexPrice", instead of "Effective Date" (with a space) and "Price" (no word "Index").
Also, on the Edit
screen, if I blank out the EffectiveDate
and the IndexPrice
fields and click to save them, I get error messages that the values are not valid or not in the right range, but I do not get the specific text from above, e.g. "An Index Price is required".
I've stepped over the calls to AddProviderTransparent
in the debugger and I don't see any errors or other information in the output window to explain why it doesn't seem to be working.
What am I doing wrong?
Update
Per Simon's comment, I changed Program.cs
to call my metadata initialization before calling builder.Build()
. No change in application behavior.
HMADBHelper.HMADBMetaDataInit();
var app = builder.Build();
Share
Improve this question
edited Mar 27 at 4:58
marc_s
756k184 gold badges1.4k silver badges1.5k bronze badges
asked Mar 27 at 3:13
StuartVStuartV
1352 silver badges10 bronze badges
2 Answers
Reset to default 0Check the create/edit pages/components. Normally, we use a label
to display the property name by directly writing it. If you want to display the Display Name
based on the property name, you can achieve this through reflection.
Refer to the following sample code:
Classes:
[MetadataType(typeof(MyModelMetadata))]
public class MyModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class MyModelMetadata
{
public int Id { get; set; }
[Required(ErrorMessage ="User Name is required, please enter a name")]
[Display(Name= "User Name")]
public string Name { get; set; }
}
Razor component:
@page "/metadata"
@using BlazorServerWithoutIdentity.Data
@using System.ComponentModel
@using System.ComponentModel.DataAnnotations
<EditForm Model="@model" OnValidSubmit="HandleValidSubmit" FormName="metadatatest">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label for="name">@GetDisplayName(nameof(model.Name))</label>
<InputText id="name" @bind-Value="model.Name" />
</div>
<button type="submit">Submit</button>
</EditForm>
@code {
[SupplyParameterFromForm]
private MyModel model { get; set; } = new();
protected override void OnInitialized()
{
TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(MyModel), typeof(MyModelMetadata)), typeof(MyModel));
}
private void HandleValidSubmit()
{
// Handle the valid form submission here
Console.WriteLine("Form submitted!");
}
private string GetDisplayName(string propertyName)
{
var propInfo = typeof(MyModelMetadata).GetProperty(propertyName);
var displayName = propInfo?.GetCustomAttributes(typeof(DisplayAttribute), false)
.OfType<DisplayAttribute>()
.FirstOrDefault()?.Name;
return displayName ?? propertyName;
}
}
The output as below:
The only difference I can see from your code to what I'm using (which was the basis of my blog post) is that I have my TypeDescriptor
calls before my builder.Build()
call, not before my app.Run()
I hope that helps.