locked
Blazor wasm : Metadatatype not working in shared project library! RRS feed

  • Question

  • User-79977429 posted

    Hi

    i have 3 project types to handle my layers as follow :

    • MyBlazorProject.Shared (Class Library) -> To hold my models
    • MyBlazorProject.Api (Web api) -> To represent a service layer (& also hold myDbContext)
    • MyBlazorProject.Client (Blazor wasm) -> To represent UI

    Now, i want to add some extra validation attributes in my models. To do this, ive created s separate class file & extend my models with additional attribute like this :

     public partial class PatientMetadata
        {
            [Required]
            public string FirstName { get; set; }
            [Required]
            public string LastName { get; set; }
        }

        [MetadataType(typeof(PatientMetadata))]
        public partial class Patient
        { 
        }

    But this code does not working & validation attributes not trigged!

    I also add Microsoft.Aspnetcore.Mvc in my shared project class library & using 'ModelMetadataType' instead of 'MetadataType' but i'm facing error message in my Blazor client at runTime which demonstrate could not load type or assembly Microsoft.Aspnetcode.mvc ...

    Can anybody help me how to solve this problem?

    Thanks in advance

    Wednesday, March 31, 2021 10:39 AM

All replies

  • User475983607 posted

    The namespace is Microsoft.AspNetCore.Mvc not Microsoft.Aspnetcode.mvc.  But this library is not required for Blazor.

    Reference; https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.metadatatypeattribute?view=net-5.0

    Library

    using System;
    using System.ComponentModel.DataAnnotations;
    using System.Security.Cryptography.Xml;
    using System.Text;
    using System.Xml;
    
    namespace ClassLibraryDemo
    {
        [MetadataType(typeof(CustomerMetaData))]
        public partial class Customer
        {
        }
    
        public class CustomerMetaData
        {
            // Apply RequiredAttribute
            [Required(ErrorMessage = "Title is required.")]
            public object Title;
        }
    }

    Blazor _Imports.razor

    @using System.Net.Http
    @using System.Net.Http.Json
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.AspNetCore.Components.Web.Virtualization
    @using Microsoft.AspNetCore.Components.WebAssembly.Http
    @using Microsoft.JSInterop
    @using BlazorWasm
    @using BlazorWasm.Shared
    @using ClassLibraryDemo

    Wednesday, March 31, 2021 11:09 AM
  • User-79977429 posted

    Thanks

    I do this, but not working.

    If i ignore my blazor project & call my api via Postman, i'm facing the same result (dataAnnotaions not working)!

    If you need more info, Please se my sample project

    Thanks

    Wednesday, March 31, 2021 11:33 AM
  • User475983607 posted

    hamed_1983

    If i ignore my blazor project & call my api via Postman, i'm facing the same result (dataAnnotaions not working)!

    The data annotations are used in the UI not Web API.  Web API does not have a UI.  Typically, the UI project contains ViewModel with the validation and the shared library has POCOs that are sent between the Blazor and Web API.   

    Wednesday, March 31, 2021 11:42 AM
  • User-79977429 posted

    Thanks

    Please see my new project from this link. (I've removed my blazor project from solution to demonstrate my problem clearly).

    If you see in my shared project (Blazor02.Shared.Models), I have a Patient model & If you see inside Metadata folder, I have a PatientMetadata class.

    Inside PatientMetadata class file, I have a partial class of Patient with Metadatatype attribute. This Validation does not works in my webApi. But, If you pickup [Required] attribute from PatientMetadata & Place on Patient class itself, it works! See this codes :

    This code does not works :

    public partial class PatientMetadata
        {
            [Required]
            public string FirstName { get; set; }
            [Required]
            public string LastName { get; set; }
        }

        [MetadataType(typeof(PatientMetadata))]
        public partial class Patient
        { 
        }

    But this code works :

    public partial class Patient
        {
            [Key]
            public int PatientID { get; set; }
            [StringLength(50)]
            [Required]
            public string FirstName { get; set; }
            [StringLength(50)]
            [Required]
            public string LastName { get; set; }
        }

    Where is the problem? I just want to set validation attribute in another class file.

    Thanks in advance

    Wednesday, March 31, 2021 2:26 PM
  • User475983607 posted

    The action input parameter must be the metadata type if you want the model validation to fire.  Frankly, I do not understand the design.  Typically, MVC and Razor Pages implement model validation.   Also, it is unusual to pass entities to Web API.

    Anyway, the following fires a validation error if the name is missing.

        public partial class PatientMetadata
        {
            [Required]
            public string FirstName { get; set; }
            [Required]
            public string LastName { get; set; }
        }
    
        [MetadataType(typeof(Patient))]
        public partial class Patient
        {
            [Key]
            public int PatientID { get; set; }
            [StringLength(50)]
            public string FirstName { get; set; }
            [StringLength(50)]
            public string LastName { get; set; }
        }
            // GET: api/HttpPost
            [HttpPost]
            public ActionResult<Patient> Post(PatientMetadata model)
            {
                if(ModelState.IsValid)
                {
                    return Ok(model);
                }
    
                return BadRequest("Oops there was a validation error");
            }

    Wednesday, March 31, 2021 3:19 PM
  • User-79977429 posted

    Thanks mgebhard

    but i think your code does not make sense, Because i should define my Metadata type & declare all variable(s) of my main model & convert to/from together during runtime!

    Would you plz tell me how to validate your models in blazor wasm project in nLayer architecture mode?

    Thanks

    Wednesday, March 31, 2021 3:57 PM
  • User475983607 posted

    hamed_1983

    but i think your code does not make sense, Because i should define my Metadata type & declare all variable(s) of my main model & convert to/from together during runtime!

    Would you plz tell me how to validate your models in blazor wasm project in nLayer architecture mode?

    This is NOT my design.  This is your design.  For the third time, I design POCOs to pass data and ViewModels for use in the UI.  I'm not sure how to help you as you are not following the advice. 

    Wednesday, March 31, 2021 4:07 PM
  • User-79977429 posted

    Sorry mgebhard

    Would u plz give me an example how to accomplish this in your nLayer project(s)?

    Wednesday, March 31, 2021 4:58 PM
  • User475983607 posted

    hamed_1983

    Would u plz give me an example how to accomplish this in your nLayer project(s)?

    Pretty simple.  The shared library contains the data the moves between the Blazor and Web API projects; POCOs.  The Blazor application contains the ViewModels used in the Blazor application.  Entities and LINQ are used in your data services and injected into the Web API constructor.  Use a mapper to projects to convert between POCO, Entities, and ViewModels.

    You should be able to test each project separately. 

    Wednesday, March 31, 2021 5:07 PM
  • User-79977429 posted

    Thanks mgebhard

    As i understand my architecture design is almost correct except some different(s) : I have to use ViewModels in my blazor wasm client project & map viewModel(s) to main pocos during runtime. If this true, I have some questions :

    1. Should i decorate my viewModel's fields with validationAttributes in my blazor wasm project (instead of shared class library)?
    2. Can u provide me an example (in my situation is 'Patient' model) how to map between viewModels & pocos & where should i do this (blazor or api service or shared class library)?
    3. Is this architecture design is best practice?

    Thanks in advance

    Wednesday, March 31, 2021 5:28 PM
  • User-79977429 posted

    Any help?

    Monday, April 5, 2021 3:46 PM
  • User475983607 posted

    hamed_1983

    Should i decorate my viewModel's fields with validationAttributes in my blazor wasm project (instead of shared class library)?

    User input validations are only relevant to the UI layer.  DB constraints are only relevant to the DB.  

    hamed_1983

    Can u provide me an example (in my situation is 'Patient' model) how to map between viewModels & pocos & where should i do this (blazor or api service or shared class library)?

    A characteristic of a "good design" is each layer can be tested independently. 

    Keep in mind, that sharing a library between a service and UI is only possible when both applications are owned by the same entity, are written in the same language, running on the same platform.  Design your web service with the understanding that the service will be used by unknown clients and use REST standards. 

    hamed_1983

    Is this architecture design is best practice?

    I do not understand the question.  What is "this"?

    Monday, April 5, 2021 4:25 PM