Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checking and fixing for RequiredAttribute in model classes #3051

Merged
merged 2 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions src/Scaffolding/VS.Web.CG.EFCore/IPropertyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,16 @@ internal static IPropertyMetadata ToPropertyMetadata(this IProperty property, Ty
var propertyMetadata = new PropertyMetadata();
propertyMetadata.PropertyName = property.Name;
propertyMetadata.TypeName = property.ClrType.FullName;

propertyMetadata.IsPrimaryKey = property.IsPrimaryKey();
// The old scaffolding has some logic for this property in an edge case which is
// not clear if needed any more; see EntityFrameworkColumnProvider.DetermineIsForeignKeyComponent
propertyMetadata.IsForeignKey = property.IsForeignKey();

propertyMetadata.IsEnum = property.ClrType.GetTypeInfo().IsEnum;
propertyMetadata.IsReadOnly = property.GetBeforeSaveBehavior() != PropertySaveBehavior.Save;

propertyMetadata.IsAutoGenerated = property.ValueGenerated != ValueGenerated.Never || property.GetValueGeneratorFactory() != null;

propertyMetadata.ShortTypeName = TypeUtil.GetShortTypeName(property.ClrType);

propertyMetadata.Scaffold = true;

var declaringEntityType = property.DeclaringType as IEntityType;
var reflectionProperty = declaringEntityType?.ClrType.GetProperty(property.Name);
if (reflectionProperty != null)
Expand All @@ -45,6 +41,7 @@ internal static IPropertyMetadata ToPropertyMetadata(this IProperty property, Ty

var dataTypeAttr = reflectionProperty.GetCustomAttribute(typeof(DataTypeAttribute)) as DataTypeAttribute;
propertyMetadata.IsMultilineText = (dataTypeAttr != null) && (dataTypeAttr.DataType == DataType.MultilineText);
propertyMetadata.IsRequired = reflectionProperty.GetCustomAttribute(typeof(RequiredAttribute)) is not null;
}

propertyMetadata.IsEnumFlags = false;
Expand Down
1 change: 1 addition & 0 deletions src/Scaffolding/VS.Web.CG.EFCore/IPropertyMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public interface IPropertyMetadata
string ShortTypeName { get; set; }
string TypeName { get; set; }
bool IsMultilineText { get; set; }
bool IsRequired { get; set; }

PropertyInfo PropertyInfo { get; set; }
}
Expand Down
2 changes: 2 additions & 0 deletions src/Scaffolding/VS.Web.CG.EFCore/PropertyMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,7 @@ public PropertyMetadata(PropertyInfo property)
public bool IsMultilineText { get; set; }

public PropertyInfo PropertyInfo { get; set; }

public bool IsRequired { get; set; }
deepchoudhery marked this conversation as resolved.
Show resolved Hide resolved
}
}
7 changes: 5 additions & 2 deletions src/Scaffolding/VS.Web.CG.Mvc/Templates/Blazor/Create.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public virtual string TransformText()
this.Write("\" OnValidSubmit=\"Add");
this.Write(this.ToStringHelper.ToStringWithCulture(modelName));
this.Write("\" FormName=\"create\" Enhance>\r\n <DataAnnotationsValidator />\r\n " +
" <ValidationSummary class=\"text-danger\" />\r\n ");
" <ValidationSummary class=\"text-danger\" role=\"alert\"/>\r\n ");

foreach (var property in entityProperties)
{
Expand All @@ -68,6 +68,7 @@ public virtual string TransformText()
string propertyShortTypeName = property.ShortTypeName.Replace("?", string.Empty);
var inputTypeName = Model.GetInputType(propertyShortTypeName);
var inputClass = Model.GetInputClassType(propertyShortTypeName);
var requiredAttributeHtml = property.IsRequired ? "aria-required=\"true\"" : string.Empty;

this.Write("<div class=\"mb-3\">\r\n <label for=\"");
this.Write(this.ToStringHelper.ToStringWithCulture(modelPropertyNameLowercase));
Expand All @@ -83,7 +84,9 @@ public virtual string TransformText()
this.Write(this.ToStringHelper.ToStringWithCulture(modelPropertyName));
this.Write("\" class=\"");
this.Write(this.ToStringHelper.ToStringWithCulture(inputClass));
this.Write("\" /> \r\n <ValidationMessage For=\"() => ");
this.Write("\" ");
this.Write(this.ToStringHelper.ToStringWithCulture(requiredAttributeHtml));
this.Write("/> \r\n <ValidationMessage For=\"() => ");
this.Write(this.ToStringHelper.ToStringWithCulture(modelName));
this.Write(".");
this.Write(this.ToStringHelper.ToStringWithCulture(modelPropertyName));
Expand Down
5 changes: 3 additions & 2 deletions src/Scaffolding/VS.Web.CG.Mvc/Templates/Blazor/Create.tt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<div class="col-md-4">
<EditForm method="post" Model="<#= modelName #>" OnValidSubmit="Add<#= modelName #>" FormName="create" Enhance>
<DataAnnotationsValidator />
<ValidationSummary class="text-danger" />
<ValidationSummary class="text-danger" role="alert"/>
<#
foreach (var property in entityProperties)
{
Expand All @@ -44,10 +44,11 @@
string propertyShortTypeName = property.ShortTypeName.Replace("?", string.Empty);
var inputTypeName = Model.GetInputType(propertyShortTypeName);
var inputClass = Model.GetInputClassType(propertyShortTypeName);
var requiredAttributeHtml = property.IsRequired ? "aria-required=\"true\"" : string.Empty;
#>
<div class="mb-3">
<label for="<#= modelPropertyNameLowercase #>" class="form-label"><#= modelPropertyName #>:</label>
<<#= inputTypeName #> id="<#= modelPropertyNameLowercase #>" @bind-Value="<#= modelName #>.<#= modelPropertyName #>" class="<#= inputClass #>" />
<<#= inputTypeName #> id="<#= modelPropertyNameLowercase #>" @bind-Value="<#= modelName #>.<#= modelPropertyName #>" class="<#= inputClass #>" <#= requiredAttributeHtml #>/>
<ValidationMessage For="() => <#= modelName #>.<#= modelPropertyName #>" class="text-danger" />
</div>
<# } #>
Expand Down
8 changes: 6 additions & 2 deletions src/Scaffolding/VS.Web.CG.Mvc/Templates/Blazor/Edit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public virtual string TransformText()
this.Write("\" OnValidSubmit=\"Update");
this.Write(this.ToStringHelper.ToStringWithCulture(modelName));
this.Write("\" FormName=\"edit\" Enhance>\r\n <DataAnnotationsValidator />\r\n " +
" <ValidationSummary />\r\n <input type=\"hidden\" name=\"");
" <ValidationSummary role=\"alert\"/>\r\n <input type=\"hidden\"" +
" name=\"");
this.Write(this.ToStringHelper.ToStringWithCulture(modelName));
this.Write(".");
this.Write(this.ToStringHelper.ToStringWithCulture(primaryKeyName));
Expand All @@ -82,6 +83,7 @@ public virtual string TransformText()
string propertyShortTypeName = property.ShortTypeName.Replace("?", string.Empty);
var inputTypeName = Model.GetInputType(propertyShortTypeName);
var inputClass = Model.GetInputClassType(propertyShortTypeName);
var requiredHtml = property.IsRequired ? "aria-required=\"true\"" : string.Empty;

this.Write(" <div class=\"mb-3\">\r\n <label for=\"");
this.Write(this.ToStringHelper.ToStringWithCulture(modelPropertyNameLowercase));
Expand All @@ -97,7 +99,9 @@ public virtual string TransformText()
this.Write(this.ToStringHelper.ToStringWithCulture(modelPropertyName));
this.Write("\" class=\"");
this.Write(this.ToStringHelper.ToStringWithCulture(inputClass));
this.Write("\" />\r\n <ValidationMessage For=\"() => ");
this.Write("\" ");
this.Write(this.ToStringHelper.ToStringWithCulture(requiredHtml));
this.Write("/>\r\n <ValidationMessage For=\"() => ");
this.Write(this.ToStringHelper.ToStringWithCulture(modelName));
this.Write(".");
this.Write(this.ToStringHelper.ToStringWithCulture(modelPropertyName));
Expand Down
5 changes: 3 additions & 2 deletions src/Scaffolding/VS.Web.CG.Mvc/Templates/Blazor/Edit.tt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ else
<div class="col-md-4">
<EditForm method="post" Model="<#= modelName #>" OnValidSubmit="Update<#= modelName #>" FormName="edit" Enhance>
<DataAnnotationsValidator />
<ValidationSummary />
<ValidationSummary role="alert"/>
<input type="hidden" name="<#= modelName #>.<#= primaryKeyName #>" value="@<#= modelName #>.<#= primaryKeyName #>" />
<#
foreach (var property in entityProperties)
Expand All @@ -55,10 +55,11 @@ else
string propertyShortTypeName = property.ShortTypeName.Replace("?", string.Empty);
var inputTypeName = Model.GetInputType(propertyShortTypeName);
var inputClass = Model.GetInputClassType(propertyShortTypeName);
var requiredHtml = property.IsRequired ? "aria-required=\"true\"" : string.Empty;
#>
<div class="mb-3">
<label for="<#= modelPropertyNameLowercase #>" class="form-label"><#= modelPropertyName #>:</label>
<<#= inputTypeName #> id="<#= modelPropertyNameLowercase #>" @bind-Value="<#= modelName #>.<#= modelPropertyName #>" class="<#= inputClass #>" />
<<#= inputTypeName #> id="<#= modelPropertyNameLowercase #>" @bind-Value="<#= modelName #>.<#= modelPropertyName #>" class="<#= inputClass #>" <#= requiredHtml #>/>
<ValidationMessage For="() => <#= modelName #>.<#= modelPropertyName #>" class="text-danger" />
</div>
<# } #>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
@using Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore
@using System.Collections.Generic
@using System.Linq
Expand All @@ -11,47 +11,49 @@
}
else if (Model.IsLayoutPageSelected)
{
@:@@{
@:ViewData["Title"] = "@Model.RazorPageName";
@:@@{
@:ViewData["Title"] = "@Model.RazorPageName";
if (!string.IsNullOrEmpty(Model.LayoutPageFile))
{
@:Layout = "@Model.LayoutPageFile";
@:Layout = "@Model.LayoutPageFile";
}
@:}
@:
@:<h1>@Model.RazorPageName</h1>
@:
@:}
@:
@:<h1>@Model.RazorPageName</h1>
@:
}
else
{
@:@@{
@:Layout = null;
@:}
@:
@:<!DOCTYPE html>
@:
@:<html>
@:<head>
@:<meta name="viewport" content="width=device-width" />
@:<title>@Model.RazorPageName</title>
@:</head>
@:<body>
@:
@:@@{
@:Layout = null;
@:}
@:
@:<!DOCTYPE html>
@:
@:<html>
@:<head>
@:<meta name="viewport" content="width=device-width" />
@:<title>@Model.RazorPageName</title>
@:</head>
@:<body>
@:
// PushIndent(" ");
}
@:<h4>@Model.ViewDataTypeShortName</h4>
@:<hr />
@:<div class="row">
@:<h4>@Model.ViewDataTypeShortName</h4>
@:<hr />
@:<div class="row">
@:<div class="col-md-4">
@:<form method="post">
@:<div asp-validation-summary="ModelOnly" class="text-danger"></div>
foreach (var property in Model.ModelMetadata.Properties)
{
if (property.Scaffold && !property.IsAutoGenerated && !property.IsReadOnly)
@:<form method="post">
@:<div asp-validation-summary="ModelOnly" class="text-danger"></div>
foreach (var property in Model.ModelMetadata.Properties)
{
var sixteenWhitespace = new string(' ', 16);
var propertyRequiredText = property.IsRequired ? $"\n{sixteenWhitespace}<span class=\"text-danger\">*</span>" : string.Empty;
if (property.Scaffold && !property.IsAutoGenerated && !property.IsReadOnly)
{
if (property.IsForeignKey)
{
@:<div class="form-group">
@:<div class="form-group">@propertyRequiredText
@:<label asp-for="@(Model.ModelTypeName).@property.PropertyName" class="control-label"></label>
@:<select asp-for="@(Model.ModelTypeName).@property.PropertyName" class ="form-control" asp-items="ViewBag.@property.PropertyName"></select>
@:</div>
Expand All @@ -61,31 +63,31 @@
bool isCheckbox = property.TypeName.Equals("System.Boolean");
if (isCheckbox)
{
@:<div class="form-group form-check">
@:<div class="form-group form-check">@propertyRequiredText
@:<label class="form-check-label">
@:<input class="form-check-input" asp-for="@(Model.ModelTypeName).@property.PropertyName" /> @@Html.DisplayNameFor(model => model.@(Model.ModelTypeName).@GetValueExpression(property))
@:</label>
@:</div>
}
else if (property.IsEnum && !property.IsEnumFlags)
{
@:<div class="form-group">
@:<div class="form-group">@propertyRequiredText
@:<label asp-for="@(Model.ModelTypeName).@property.PropertyName" class="control-label"></label>
@:<select asp-for="@(Model.ModelTypeName).@property.PropertyName" class="form-control"></select>
@:<span asp-validation-for="@(Model.ModelTypeName).@property.PropertyName" class="text-danger"></span>
@:</div>
}
else if (property.IsMultilineText)
{
@:<div class="form-group">
@:<div class="form-group">@propertyRequiredText
@:<label asp-for="@(Model.ModelTypeName).@property.PropertyName" class="control-label"></label>
@:<textarea asp-for="@(Model.ModelTypeName).@property.PropertyName" class="form-control"></textarea>
@:<span asp-validation-for="@(Model.ModelTypeName).@property.PropertyName" class="text-danger"></span>
@:</div>
}
else
{
@:<div class="form-group">
@:<div class="form-group">@propertyRequiredText
@:<label asp-for="@(Model.ModelTypeName).@property.PropertyName" class="control-label"></label>
@:<input asp-for="@(Model.ModelTypeName).@property.PropertyName" class="form-control" />
@:<span asp-validation-for="@(Model.ModelTypeName).@property.PropertyName" class="text-danger"></span>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
@using Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore
@using System.Collections.Generic
@using System.Linq
Expand Down Expand Up @@ -47,6 +47,7 @@
@:<div asp-validation-summary="ModelOnly" class="text-danger"></div>
foreach (PropertyMetadata property in Model.ModelMetadata.Properties)
{
var propertyRequiredText = property.IsRequired ? "<span class=\"text-danger\">*</span>" : string.Empty;
if (property.IsPrimaryKey)
{
@:<input type="hidden" asp-for="@(Model.ModelTypeName).@property.PropertyName" />
Expand All @@ -63,6 +64,7 @@
if (property.IsForeignKey)
{
@:<div class="form-group">
@:@propertyRequiredText
@:<label asp-for="@(Model.ModelTypeName).@property.PropertyName" class="control-label"></label>
@:<select asp-for="@(Model.ModelTypeName).@property.PropertyName" class="form-control" asp-items="ViewBag.@property.PropertyName"></select>
@:<span asp-validation-for="@(Model.ModelTypeName).@property.PropertyName" class="text-danger"></span>
Expand All @@ -74,6 +76,7 @@
if (isCheckbox)
{
@:<div class="form-group form-check">
@:@propertyRequiredText
@:<label class="form-check-label">
@:<input class="form-check-input" asp-for="@(Model.ModelTypeName).@property.PropertyName" /> @@Html.DisplayNameFor(model => model.@(Model.ModelTypeName).@GetValueExpression(property))
@:</label>
Expand All @@ -82,6 +85,7 @@
else if (property.IsEnum && !property.IsEnumFlags)
{
@:<div class="form-group">
@:@propertyRequiredText
@:<label asp-for="@(Model.ModelTypeName).@property.PropertyName" class="control-label"></label>
@:<select asp-for="@(Model.ModelTypeName).@property.PropertyName" class="form-control"></select>
@:<span asp-validation-for="@(Model.ModelTypeName).@property.PropertyName" class="text-danger"></span>
Expand All @@ -90,6 +94,7 @@
else if (property.IsMultilineText)
{
@:<div class="form-group">
@:@propertyRequiredText
@:<label asp-for="@(Model.ModelTypeName).@property.PropertyName" class="control-label"></label>
@:<textarea asp-for="@(Model.ModelTypeName).@property.PropertyName" class="form-control"></textarea>
@:<span asp-validation-for="@(Model.ModelTypeName).@property.PropertyName" class="text-danger"></span>
Expand All @@ -98,6 +103,7 @@
else
{
@:<div class="form-group">
@:@propertyRequiredText
@:<label asp-for="@(Model.ModelTypeName).@property.PropertyName" class="control-label"></label>
@:<input asp-for="@(Model.ModelTypeName).@property.PropertyName" class="form-control" />
@:<span asp-validation-for="@(Model.ModelTypeName).@property.PropertyName" class="text-danger"></span>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel.DataAnnotations;
using Microsoft.CodeAnalysis;

namespace Microsoft.DotNet.Tools.Scaffold.AspNet.Extensions;

internal static class PropertySymbolExtensions
{
public static bool HasRequiredAttribute(this IPropertySymbol propertySymbol)
{
return propertySymbol.GetAttributes().Any(
x => x.AttributeClass is not null &&
x.AttributeClass.Name.Equals(nameof(RequiredAttribute), StringComparison.OrdinalIgnoreCase));
}
}
Loading