MetadataType not working to merge metadata having followed Microsoft tutorial for data first approach

P Williams 6 Reputation points
2022-04-04T20:09:03.043+00:00

I have tried to simplify this problem as much as possible and cannot find a solution or fix.

I have followed the second approach ("Add metadata class") in this Microsoft tutorial enhancing-data-validation

I am using data first with a Razor project. The database scaffolds without problem to create the dbContext. I want to annotate columns eg with Display(Name=""). This cannot go in the scaffolding generated files because they may get overwritten so the tutorial says to create metadata classes in a separate file and then a partial class in another separate file to merge the metadata into the scaffold generated classes. I understand all of this but it doesn't work.

To make it extremely simply I created a table Customer and after running scaffolding I edited the scaffold generated file so that everything was in the one file (so no potential problems with namespace - even though everything was in the same namespace anyway...).

So here is all of the code:

CREATE TABLE [dbo].[Customers] (  
      [Id] INT NOT NULL,  
      [Name] VARCHAR (30) NOT NULL,  
      [Details] VARCHAR (MAX) NOT NULL,  
      PRIMARY KEY CLUSTERED ([Id] ASC)  
    );  

I then edited the Customer.cs class generated by scaffolding to include the metadata class and MetadataType property. The file is:

using System;  
using System.Collections.Generic;  
using System.ComponentModel.DataAnnotations;  
namespace MyProject.Models  
{  
public partial class Customer  
{  
public int Id { get; set; }  
// [Display(Name ="Customer name")]  
// if I put the annotation here it works. If I comment this out and put it in the metadata class it doesn't work  
public string Name { get; set; } = null!;  
public string Details { get; set; } = null!;  
}  
  
[MetadataType(typeof(CustomerMetaData))]  
public partial class Customer  
{  
}  
  
public class CustomerMetaData  
{  
[Display(Name ="Customer name")]  
public string Name";  
}  
}  

So once I've done that I simply created a folder in the Pages folder and right clicked and Add > Razor Page > Razor Pages with EF (CRUD) to generate the default CRUD pages for the Customer class in the dbContext.

So that's it. Nothing complicated. Back in the Customer.cs class file if I put the [Display(Name="Customer Name"] in the Scaffolding generated class it works and the pages display "Customer name" instead of the column name "Name". However, comment out the annotation in the Customer class and put the MetaDataType attribute on a second partial class Customer and have a CustomerMetaData class that includes the annotation and it doesn't work.

I can not get it to work.

The problem is compounded because you cannot see the annotations if you "watch" a data object during debug

Developer technologies .NET Other
0 comments No comments
{count} vote

3 answers

Sort by: Most helpful
  1. Jack J Jun 25,296 Reputation points
    2022-04-05T07:13:41.857+00:00

    @P Williams , Welcome to Microsoft Q&A, based on your description, I make a test. I also reproduced your problem.

    After my attempt, I find that the problem is the namespace.

    As usual, If we use database first in asp.net mvc appp, the customer class should be generated like the following:

        //------------------------------------------------------------------------------  
        // <auto-generated>  
        //     This code was generated from a template.  
        //  
        //     Manual changes to this file may cause unexpected behavior in your application.  
        //     Manual changes to this file will be overwritten if the code is regenerated.  
        // </auto-generated>  
        //------------------------------------------------------------------------------  
          
        namespace WebApplication1  
        {  
            using System;  
            using System.Collections.Generic;  
            using System.ComponentModel.DataAnnotations;  
          
            public partial class Customer  
            {  
                public int Id { get; set; }  
                //[Display(Name = "Customer name")]  
                public string Name { get; set; }  
                public string Details { get; set; }  
            }  
          
        }  
    

    Then, We could add the CustomerMetaData class and partial Customer class to the namespace directly.

    //------------------------------------------------------------------------------  
    // <auto-generated>  
    //     This code was generated from a template.  
    //  
    //     Manual changes to this file may cause unexpected behavior in your application.  
    //     Manual changes to this file will be overwritten if the code is regenerated.  
    // </auto-generated>  
    //------------------------------------------------------------------------------  
      
    namespace WebApplication1  
    {  
        using System;  
        using System.Collections.Generic;  
        using System.ComponentModel.DataAnnotations;  
      
        public partial class Customer  
        {  
            public int Id { get; set; }  
            //[Display(Name = "Customer name")]  
            public string Name { get; set; }  
            public string Details { get; set; }  
        }  
      
      
        [MetadataType(typeof(CustomerMetaData))]  
        public partial class Customer  
        {  
      
        }  
        public class CustomerMetaData  
        {  
            [StringLength(50)]  
            [Display(Name = "Customername")]  
            public string Name;  
      
            [StringLength(50)]  
            [Display(Name = "DetailName")]  
            public string Details;  
      
      
      
        }  
      
    }  
    

    Note: I also noted that you used the same namespace, but we need to use the default namespace(WebApplication1) instead of the model namespace (WebApplication1.Models).

    Tested result:

    190054-image.png

    Best regards,
    Jack


    If the answer is the right solution, please click "Accept Answer" and upvote it.If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Felaray 1 Reputation point
    2022-04-07T08:15:29.383+00:00

    it's not work on .net core project also.

    0 comments No comments

  3. Felaray 1 Reputation point
    2022-04-07T09:02:43.17+00:00

    I find how it's worked.

    the example has two models, "WeatherForecast_Success" is worked with dataAnnotation.

    using Microsoft.AspNetCore.Mvc;
    using System.ComponentModel.DataAnnotations;
    
    namespace Net6.Issue.MetadataType
    {
        [ModelMetadataType(typeof(MetaData))]
        public partial class WeatherForecast_Success: MetaData
        {
            public string Summary { get; set; }
        }
    
        [ModelMetadataType(typeof(MetaData))]
        public partial class WeatherForecast_Failed 
        {
            public string Summary { get; set; }
        }
    
        public interface MetaData
        {
            [StringLength(50, MinimumLength = 10)]
            public string Summary { get; set; }
        }
    }
    

    you can see this example : Full project

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.