Asp.Net Mvc - Setting Required attribute error message from property - asp.net

I pass in a string through a constructor that i want to use as my error message in my model class like this:
public class ContactForm
{
public string NameError { get; set; }
public ContactForm(string nameError)
{
NameError = nameError;
}
[Required(ErrorMessage = NameError)]
public string Name { get; set; }
//More properties
}
Here i get the exception:
An object reference is required for the non-static field, method, or property 'UmbracoSport.Models.ContactForm.NameError.get' D:\Umbraco\Websites\UmbracoSport\UmbracoSport\Models\Custom\ContactForm.cs 19 34 UmbracoSport
If i make NameError static i get this error:
An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type D:\Umbraco\Websites\UmbracoSport\UmbracoSport\Models\Custom\ContactForm.cs 19 34 UmbracoSport
Is this in any way possible ?

Related

.NET 5.0 Web API won't work with record featuring required properties

I'm using a C# 9.0 record type as a binding model for a .NET 5.0 Web API project. Some of the properties are required.
I'm using the record positional syntax, but am receiving errors.
public record Mail(
System.Guid? Id,
[property: Required]
string From,
[property: Required]
string[] Tos,
[property: Required]
string Subject,
string[]? Ccs,
string[]? Bccs,
[property: Required]
Content[] Contents,
Attachment[]? Attachments
);
This is then exposed as the binding model for my Index action:
public async Task<ActionResult> Index(Service.Models.Mail mailRequest)
{
…
}
Whenever I try to make a request, however, I receive the following error:
Record type 'Service.Models.Mail' has validation metadata defined on property 'Contents' that will be ignored. 'Contents' is a parameter in the record primary constructor and validation metadata must be associated with the constructor parameter.
I tried removing the attribute on the Contents property, but it then fails for the next (prior) property. I tried using [param: …] instead of [property: …], as well as mixing them, but keep getting the same kind of error.
I looked around the web, and haven't found any suggestion of handling annotations differently for C# 9 records. I did my best, but I'm out of ideas—outside of converting my records to POCOs.
I gave up using Positional constructor, and with the verbose full declaration of the properties, it works.
public record Mail
{
public System.Guid? Id { get; init; }
[Required]
public string From { get; init; }
[Required]
public string[] Tos { get; init; }
[Required]
public string Subject { get; init; }
public string[]? Ccs { get; init; }
public string[]? Bccs { get; init; }
[Required]
public Content[] Contents { get; init; }
public Attachment[]? Attachments { get; init; }
public Status? Status { get; init; }
public Mail(Guid? id, string #from, string[] tos, string subject, string[]? ccs, string[]? bccs, Content[] contents, Attachment[]? attachments, Status status)
{
Id = id;
From = #from;
Tos = tos;
Subject = subject;
Ccs = ccs;
Bccs = bccs;
Contents = contents;
Attachments = attachments;
Status = status;
}
}
Try using only [Required] (instead of [property: Required]), for some reason worked for me
For me it started to work by adding the [ApiController] attribute to the controller.
I found something similar on ASP.NET Core Razor pages getting:
InvalidOperationException: Record type 'WebApplication1.Pages.LoginModelNRTB+InputModel' has validation metadata defined on property 'PasswordB' that will be ignored. 'PasswordB' is a parameter in the record primary constructor and validation metadata must be associated with the constructor parameter.
from
Microsoft.AspNetCore.Mvc.ModelBinding.ModelMetadata.ThrowIfRecordTypeHasValidationOnProperties()
After some digging, I found: https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/ModelBinding/Validation/DefaultComplexObjectValidationStrategy.cs
So maybe as you've done, the verbose declaration is the way forward.
Positional record attributes in ASP.NET Core background
How do I target attributes for a record class? more background
Using FluentValidation and keeping properties with the full declaration seems to work perfectly in my case. I highly recommend trying this highly polished alternative validation library instead of using the pretty old standard data annotations
public record LoginViewModel
{
public string Mail { get; init; }
public string Password { get; init; }
public bool IsPersistent { get; init; }
}
public class LoginValidator : AbstractValidator<LoginViewModel>
{
public LoginValidator()
{
RuleFor(l => l.Mail).NotEmpty().EmailAddress();
RuleFor(l => l.Password).NotEmpty();
}
}

I have one entity, i need to add property of entity type

**public class Ticket : BaseEntity
{
public TicketType TicketType { get; set; }
}
public class TicketType : AuxiliaryInfoBaseEntity
{
public string Description { get; set; }
}**
In Ticket Entity i need one property of TicketType and type of column should be byte in Ticket.
Resulting table will look like.Table-Ticket:column TicketType(tinyint,not null).
When i trying to migrate, i am getting this exception.
System.InvalidOperationException: 'The property 'Ticket.TicketType' is of type 'TicketType' which is not supported by current database provider. Either change the property CLR type or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Please help me with some soluntion thanks.

Issue while passing null values to nullable properties in web api call in .netcore web api project

I am facing issue while passing null parameter values to properties of my model in HttpGet verb.
I am using .Net Core 2.1 for my web API project. Below is my action method in controller:
[HttpGet("get")]
public ActionResult GetData([FromQuery]MyTestModel model)
{
var result = new MyTestModel();
return new JsonResult(result);
}
And my MyTestModel.cs is like :
[Serializable]
public class MyTestModel
{
public MyTestModel()
{
PageNo = 1;
PageSize = 10;
}
public int ClientId { get; set; }
public int? CandidateId { get; set; }
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
public int PageNo { get; set; }
public int PageSize { get; set; }
}
When I call the API like :
api/controller/get?clientId=7583&candidateId=null&fromDate=null&toDate=null
I am getting 400 response. Below is the response message:
{"toDate":["The value 'null' is not valid for ToDate."],
"fromDate":["The value 'null' is not valid for FromDate."],
"candidateId":["The value 'null' is not valid for CandidateId."]
}
When I don't send nullable properties at all(candidateId, fromDate,toDate), this hits my action and uses default values as null.
What's the problem if I am trying to explicitly setting null values?
Do I need to set some configuration in my Startup.cs to handle null values for nullable properties?
Any help will be appreciated .
Thanks in advance.
Everything sent in the query string is just a string. So, when you do something like toDate=null, you're actually saying "set toDate to "null"", i.e. the string "null". The modelbinder attempts to convert all the strings to the actual types you're binding to, but there's no conversion available that can turn "null" into a null DateTime.
To set the value to null, you need to either pass no value toDate= or just omit the key entirely from the query string.

Unable to find a default constructor to use for type Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.DynamicViewData

I am getting this error when trying to Deserialize the string from the redis cache using Newtonsoft.Json.
where HeaderTopViewComponent is model class of one of my view component ""
like: JsonConvert.DeserializeObject<HeaderTopViewComponent>(cacheValue.Result.ToString());
Unable to find a default constructor to use for type Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.DynamicViewData. Path 'ViewBag', line 1, position 340.
Output string :
{"ShowTopheaderSection":true,"PageHeader":"MSHSL","FriendlyURL":"/MSHSL","leagueList":[{"leagueId":0,"FriendlyURL":"/","leaguename":"--Select--"},{"leagueId":3,"FriendlyURL":"/MSHSL","leaguename":"MSHSL"},{"leagueId":4,"FriendlyURL":"/CHSAA","leaguename":"CHSAA"}],"HttpContext":null,"Request":null,"User":null,"RouteData":null,"ViewBag":{},"ModelState":{},"Url":null,"ViewComponentContext":{"Arguments":null,"HtmlEncoder":null,"ViewComponentDescriptor":{"DisplayName":null,"FullName":null,"Id":"9882d08a-1c50-4c59-8a30-2d9c843957e9","ShortName":null,"TypeInfo":null,"MethodInfo":null},"ViewContext":{"FormContext":null,"ClientValidationEnabled":false,"Html5DateRenderingMode":0,"ValidationSummaryMessageElement":null,"ValidationMessageElement":null,"ViewBag":{},"View":null,"ViewData":{},"TempData":null,"Writer":null,"ExecutingFilePath":null,"ActionDescriptor":null,"HttpContext":null,"ModelState":{},"RouteData":null},"ViewData":{},"Writer":null},"ViewContext":{"FormContext":null,"ClientValidationEnabled":false,"Html5DateRenderingMode":0,"ValidationSummaryMessageElement":null,"ValidationMessageElement":null,"ViewBag":{},"View":null,"ViewData":{},"TempData":null,"Writer":null,"ExecutingFilePath":null,"ActionDescriptor":null,"HttpContext":null,"ModelState":{},"RouteData":null},"ViewData":{},"ViewEngine":null}
I have fix it by adding some tag in my viewcomponent modal class and get set property like
[JsonObject(MemberSerialization.OptIn)] and [JsonProperty]
//Tag to add only selected property when Deserialize or Serialize using Newtonsoft
[JsonObject(MemberSerialization.OptIn)]
public class HeaderTopViewComponent:ViewComponent
{
#region //Property//
[JsonProperty]
public bool ShowTopheaderSection { get; set; }
[JsonProperty]
public string PageHeader { get; set; }
[JsonProperty]
public string FriendlyURL { get; set; }
[JsonProperty]
And now its working

Mandatory and valid parameter in WebAPI request

can I somehow mark property in my "input object" that goes to action as being mandatory and that it needs to be valid. I.e. if I have:
public class MyInput
{
//[SuperNeeded]
public int FooBar { get; set; }
public string Other { get; set; }
}
I'd like to ASP.NET stack throw an exception when request without FooBar or when FooBar isn't number comes. These are valid:
FooBar=1&Other=abc
FooBar=3
But these are not (don't want FooBar to be 0):
FooBar=abc&Other=abc //FooBar is not number
Other=abc //FooBar is missing
Any ideas how to easily do it?
Have you tried using RequiredAttribute?
In which case, you'd want:
[Required]
public int? FooBar { get; set; }
That way you won't simply get 0, you'll get null if it was missing, and 0 if a 0 was passed in.

Resources