C# MVC overwriting required annotation error message doesn't work - c#

I have a user class with annotations for required fields.
public class User
{
[DataMember(Name = "firstName")]
[Required(ErrorMessage="FIST_NAME_REQUIRED")]
public string FirstName { get; set; }
[DataMember(Name = "lastName")]
[Required(ErrorMessage = "LAST_NAME_REQUIRED")]
[Custom(ErrorMessage = "CUSTOM_MESSAGE")]
public string LastName { get; set; }
}
This class is the argument of a POST API call.
[HttpPost]
public HttpResponseMessage Create(User request)
{
var response = new ApiResponse();
if (request != null && ModelState.IsValid)
{
[Code here]
}
else
{
response.Success = false;
response.Message = ModelState.Values.Count() > 0 ModelState.Values.Select(value => value.Errors).Select(error => error.First().ErrorMessage).Aggregate((result, next) => result + ", " + next) : string.Empty ;
return Request.CreateResponse(HttpStatusCode.OK, response);
}
}
My problem is when I call the API controller action with no first name for example, I get the default error message "The FirsName property is required." instead of my custom error message "FIRST_NAME_REQUIRED".
The error message for the Custom validator works fine though.
Couldn't find any clue about it on Google so it might be something very specific to my code but I can't think of anything.
Any idea ?

Related

How to check null properties in AutoMapper using .NET Core

I have 2 classes SMSModel, SMSRequest . I created AutoMapper and initiated in Azure Function HTTP Trigger.
Step1: Installed below NuGet Package.
AutoMapper.Extensions.Microsoft.DependencyInjection
Step2:
Initiated AutoMapper Profile which is from different assembly in azure function startup.
services.AddAutoMapper(Assembly.GetAssembly(typeof(AutoMapperProfile)));
Step3: Created 2 Classes with few properties.
public class SMSModel
{
public string MobileNumber { get; set; }
public string UserId { get; set; }
public string Code { get; set; }
.
.
.
.
}
public class SMSRequest
{
[Required(AllowEmptyStrings = false, ErrorMessage = "The 'MobileNumber' field is required.")]
[JsonProperty("MobileNumber")]
public string MobileNumber { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "The 'UserId' field is required.")]
[JsonProperty("UserId ")]
public string UserId { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "The 'Code' field is required.")]
[JsonProperty("Code ")]
public string Code { get; set; }
.
.
.
.
}
Step4: Mapped Request and Model classes to mapper in automapper profile class.
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<SMSRequest, SMSModel>();
// .ForMember(dest => dest.MobileNumber, act => act.Condition(src => src.MobileNumber != null ));
}
}
Step5: Injected Automapper in HTTP Trigger Function c#. Sharing partial code.
private readonly IMapper _mapper;
public SMSHTTPTrigger(
ILogger<SMS> logger,
IMapper mapper)
{
this._logger = logger;
this._mapper = mapper;
}
public async Task<IActionResult> SendSMS(
[HttpTrigger(
AuthorizationLevel.Function, "post", Route = null)]
HttpRequest req)
{
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
SMSRequest data = JsonConvert.DeserializeObject<SMSRequest>(requestBody);
var smsModelData = _mapper.Map<SMSModel>(data);
// Here I want to list all properties (fields) which are having null or empty string without checking each property manually like as below ..
if(string.IsNullOrEmpty(smsModelData.MobileNumber)
{
}
}
I tried .ForMember with condition but in vain.
Is there any possibility to check the fields with null or empty string using AutoMapper?
The goal is to find out only Null properties. Hence used extension as an alternative and it worked for me without Automapper.
Extension Class:
public static class HttpRequestValidationExtension
{
public static bool IsValid(this object o, out ICollection<ValidationResult> validationResults)
{
validationResults = new List<ValidationResult>();
return Validator.TryValidateObject(o, new ValidationContext(o, null, null), validationResults, true);
}
}
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
SMSRequest data = JsonConvert.DeserializeObject<SMSRequest>(requestBody);
if (!data.IsValid(validationResults: out var validationResults))
{
//Incase if want to loop for each property
foreach (var failure in validationResults)
{
string message = failure.MemberNames.FirstOrDefault() + " Message" + failure.ErrorMessage;
//Console.WriteLine("Property " + memberName + " failed validation. Error was: " + failure.ErrorMessage);
}
//Single line code statement to fetch all null properties
string invalidrequestErrorMessage = $" Invalid Request body. Please check these errors. {string.Join(" ", validationResults.Select(s => s.ErrorMessage))}";
var badrequestObject = new
{
StatusCode = 400,
ErrorDetails = new
{
FunctionName = nameof(SendSMS),
ErrorMessage = invalidrequestErrorMessage
}
};
return new BadRequestObjectResult(badrequestObject);
}

Customize returning JSON from ASP.NET Core API , Values with Statuscode

I'm trying to return back JSON with customization , anyone can help to return the result like this :
{
status: 200,
message: "success",
data: {
var1: {
},
var2: {
}
}
}
with this code :
return Ok(new
{
var1,
var2
});
Why do you need to use the OkResult object?
A simple way of returning what you'd like is to use dynamic objets, or a class with properties matching the Json you'd like to get, and a JsonResult object.
dynamic json = new ExpandoObject();
json.Result = 200;
json.Message = "success";
json.Data.var1 = "whatever";
json.Data.var2 = "something else";
Response.StatusCode = json.Result; //matches the HTTP Status Code with the one from your json
return new JsonResult(json);
I used this for taking profile information from google id token , and then generate JWT token from my backend server and retuen back JWT and Profile info for client apps so this is the solution :
var profile = (new RetrnedUserProfile
{
Email = payload.Email,
FirstName = payload.GivenName,
FamilyName = payload.FamilyName,
PictureUrl = payload.Picture
});
return Ok(new ResponseModel
{
StatusCode = HttpStatusCode.OK,
Message = "success",
Data = new
{
profile,
accessToken
}
});
public class RetrnedUserProfile
{
public string FirstName { get; set; }
public string FamilyName { get; set; }
public string Email { get; set; }
public string PictureUrl { get; set; }
}
public class ResponseModel
{
public HttpStatusCode StatusCode { get; set; }
public string Message { get; set; }
public object Data { get; set; }
}

How to return BadRequest if payload contains unexpected fields

I'm trying to make PATCH operation, that should fail if request body contains fields that are not specified in contract. For example, if I call this method:
[HttpPatch("{id}")]
public async Task<ActionResult> PatchResource(
[FromRoute][Required] Guid id,
[FromBody][Required] PatchRequest request) {/* whatever */}
where PatchRequest is
public class PatchRequest
{
public string Name { get; }
public string Address { get; }
public PatchRequest(string name, string address) { Name = name; Address = address; }
}
I would like to return 400 (Bad Request), possibly with explanation, if I get request body like this
{
"name": "Adam",
"address" "NY City",
"additional": true
}
I want to return
400 (Bad Request) - Didn't expect property 'additional'
I know that if I set custom serializer on PatchRequest with MissingMemberHandling set to Error I can easily get 500 (Internal Server Error) in this case by throwing exception, but it wouldn't make sense, because it's request that is at fault here, not server.
In your PatchRequest model, add a JsonExtensionsData property
public class PatchRequest
{
public string Name { get; }
public string Address { get; }
public PatchRequest(string name, string address) { Name = name; Address = address; }
// extra fields
[JsonExtensionData]
private IDictionary<string, JToken> _extraStuff;
}
Then in your controller if _extraStuff is not empty you have received additional fields.
The following functionality will return you exactly which properties are different from the defined object in FromBody
Create a class, e.g. ValidationBase
In the class, create a method to validate your object, e.g. ValidateModel()
ValidateModel() - contains the entire logic of your validation
Controller: (Endpoint)
[HttpPatch("{id}")]
public async Task<ActionResult> PatchResource([FromRoute][Required] Guid id,
[FromBody][Required] PatchRequest request)
{
string body;
using (var reader = new StreamReader(Request.Body))
{
body = reader.ReadToEnd();
}
validator = new ValidationBase();
string resultValidation = validator.ValidateObject(body, new PatchRequest());
if (resultValidation.Length != 0)
{
return BadRequest(new { error_message = resultValidation });
}
// Content endpoint
return Json(response);
}
ValidationBase:
public class ValidationBase
{
public string ValidateObject(string json, object obj)
{
var dictJSON = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
var listParameterInJSON = dictJSON.Keys.ToHashSet<string>();
listParameterInJSON.ToList().ForEach(x => x = x.ToLower());
var jsonObj = JsonConvert.SerializeObject(obj);
var dictObj = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonObj);
var listParameterInObj = dictObj.Keys.ToList();
listParameterInObj = listParameterInObj.ConvertAll(d => d.ToLower());
listParameterInObj.ToHashSet<string>();
var fields = listParameterInJSON.Except(listParameterInObj);
if (fields.ToList().Count == 0) return "";
var result = "Didn't expect property ";
foreach (var item in fields)
{
result += "'" + item + "'" + " ";
}
return result;
}
}

Multiple return type from API

Input and API definition :
I'm consuming the following API, that responde either with a Data object of an Error object
FooBar Method: Ids is a list of string separated by commas
GET: /FooBar/v1{?ids}
GET: /FooBar/v1/{ids}
Request Header:
X-FooBar-Key: ## My key ##
Response : 200
// if there is multiple IDs, response is an array of Data and Error
[{
"data": { }
}, {
"data": { }
}, {
"error": { }
}]
//If there is only one ID, response is the content of the data object
{
"code": "",
"date": "",
"status": "",
"message": "",
"link": "",
"type": ""
}
Response : 400/404/etc , Return the content of an Error object
{
"code": "",
"message": ""
}
Output and Expected results:
I want to be able to check [1, N] IDs and with only one object return type Response with either Data or Error initialised the other at null...
public class Response
{
[JsonProperty("data")]
public Data Data { get; set; }
[JsonProperty("error")]
public Error Error { get; set; }
public string Id{ get; set; }
}
public class Error
{
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("code")]
[JsonConverter(typeof(StringEnumConverter))]
public ErrorCode Code { get; set; }
}
public class Data
{
[JsonProperty("status")]
[JsonConverter(typeof(StringEnumConverter))]
public Status Status { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("code")]
public string Code { get; set; }
[JsonProperty("date")]
public string Date { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("link")]
public string Link { get; set; }
}
Attempt:
In order to simply the problem For now I work only on 1 Id at a time.
Using ServiceStack Client to consume the REST API.
public class FooBarAPI : IFooBarAPI
{
Dictionary<string, string> DefaultHeader;
string BasePath; // https://foofoo.bar/FooBar/v1
public FooBarAPI(Dictionary<string, string> defaultHeader, string basePath)
{
DefaultHeader = defaultHeader;
BasePath = basePath;
}
public Response GetFooBar(string id)
{
JsonServiceClient client = new JsonServiceClient(BasePath);
client.RequestFilter = httpReq => httpReq.Headers.Add("X-FooBar-Key", DefaultHeader["X-FooBar-Key"]);
var response =
client.GetAsync<Response>($"/{id}"); // Null as for one ID the result is type Data not Response
// client.GetAsync<Data>($"/{id}"); // Working If not Error
var toto = response.Result;
toto.Id = id;
return toto;
}
public Response[] GetFooBar(string[] ids)
{ //
throw new NotImplementedException();
}
}
This question is not tagged with ServiceStack as I'm open to solution using :
HttpWebRequest/Response Class,
WebClient Class,
HttpClient Class,
RestSharp NuGet Package,
ServiceStack Http Utils, Or Anything that make my life easier.
I am using ServiceStack because of documentation saying that I could use something like :
client.GetAsync(new Hello { Name = "World!" })
.Success(r => r => r.Result.Print())
.Error(ex => { throw ex; });
Using Success and Error to map single return type to my Response type.
If you are using ServiceStack, then you should use it the way you found in the doc, but this would mean that you actually throw (a custom) exception when ever the id does not exist. Your custom exception would then include the code and message. So you would actually just throw an exception when ever you want to return an error.
However, I don't think that is what you should do, because exceptions should only be used if an exceptional case happens, but as far as I understand, errors is a common and normal behavior that happens often (like the client does try and error with ids). Therefore, I recommend using HttpWebResponse Class as your return type. There you can basically set the HTTP return state (e.g. 400, 404) and json (or actually any) data.
ServiceStack C#/.NET Service Clients supports both Sync and Async APIs, since your method is synchronous you should only be using the synchronous APIs, e.g:
public Response GetFooBar(string id)
{
var client = new JsonServiceClient(BasePath) {
RequestFilter = req => req.Headers.Add(
"X-FooBar-Key", DefaultHeader["X-FooBar-Key"])
}
try
{
var response = client.Get<Response>($"/{id}");
response.Id = id; // Why isn't this already in the response?
return response;
}
catch (WebServiceException ex)
{
//Error Details
//ex.StatusCode;
//ex.ErrorCode;
//ex.ErrorMessage;
}
}
You should only use the async APIs if your method is also async, e.g:
public async Task<Response> GetFooBar(string id)
{
var client = new JsonServiceClient(BasePath) {
RequestFilter = req => req.Headers.Add(
"X-FooBar-Key", DefaultHeader["X-FooBar-Key"])
}
try
{
var response = await client.GetAsync<Response>($"/{id}");
response.Id = id; // Why isn't this already in the response?
return response;
}
catch (WebServiceException ex)
{
//Error Details
//ex.StatusCode;
//ex.ErrorCode;
//ex.ErrorMessage;
}
}

Mvc Remote Attribute is sending "undefined" in query string

I'm trying to remote validate some code and for the parameter, its passing undefined in as a parameters. Here is my validation code:
[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public class ValidationController : Controller
{
public JsonResult IsUserNameAvailable(string userName, int? UserId)
{
var users = new BusinessLayer.BdsAdmin.Users();
if (UserId == null || UserId == 0)
// Do something
else // Do something else
if (users.Count == 0)
{
return Json(true, JsonRequestBehavior.AllowGet);
}
string msg = string.Format("{0} is already taken and is not available.", userName);
return Json(msg, JsonRequestBehavior.AllowGet);
}
}
Here is my model:
public class EditUserAdministrationViewModel
{
public int UserId { get; set; }
[Required(ErrorMessage = "You must enter a user name.")]
[Display(Name = "User Name")]
[Remote("IsUserNameAvailable", "Validation", AdditionalFields = "UserId")]
public string UserName { get; set; }
// More properties
}
Looking at the request in Fiddler, here is what I see:
GET /Validation/IsUserNameAvailable?UserName=sara&UserId=undefined
Why is MVC injecting the string undefined into the request instead of the actual UserId?
You need to add
#Html.HiddenFor(m=>m.UserId)
at the view so that the binder will bind it to the remote validation controller or otherwise there is no value to bind

Categories

Resources