ASP.NET Core 6 Web API: "The value string is not valid for DateTime." - asp.net

I am practicing passing value to a form in Angular, and then put it in a post url in ASP.NET Core.
Here is what I do - this is my component:
export class Demo11CreateDeleteApiComponent implements OnInit {
form: FormGroup;
file: any;
constructor(
private productApiService: ProductApiService,
private formBuilder: FormBuilder,
){}
ngOnInit() {
this.form = this.formBuilder.group({
name: '',
price: 0,
quantity: 0,
status: true,
description: '',
photo: '',
categoryId: 1
})
}
fileControl(e:any){
this.file = e.target.files[0];
}
submit(){
let product: ProductApi = this.form.value;
//=======================
//Assuming ProductApi is like this:
ProductApi{
name: string = "test";
price: number = 1;
quantity: number = 1;
status: boolean = true;
description: string = "test";
created: string = "16/02/2023" the format is "dd/MM/yyyy";
photo: string = "";
categoryId: number = 1;
}
//=======================
let formData = new FormData();
formData.append('data', this.file);
for (let k in product) {
formData.append(`product.${k}`, product[k]);
}
this.productApiService.createWithFile(formData).then(
res => {
this.result = do something;
},
err => {
console.log(err);
}
)
}
}
And the createWithFile method looks like this:
async createWithFile(file: FormData){
return await lastValueFrom(this.httpClient.post(this.baseUrl+'create-with-file', file));
}
Now in ASP.NET Core 6, my product class is:
public partial class Product
{
public int Id { get; set; }
[Required(ErrorMessage = "Invalid data, must be a non-empty string")]
public string? Name { get; set; }
[Required(ErrorMessage = "Invalid data, must be an integer")]
public int? Quantity { get; set; }
public string? Description { get; set; }
[Required(ErrorMessage = "Invalid data, must be a double")]
public double? Price { get; set; }
public bool Status { get; set; }
public string? Photo { get; set; }
public DateTime Created { get; set; }
public int CategoryId { get; set; }
}
And here is the controller:
[HttpPost("create-with-file")]
[Produces("application/json")]
public IActionResult CreateWithFile(Product product, IFormFile data)
{
try
{
if (ModelState.IsValid)
{
return Ok();
}
return BadRequest(ModelState);
}
catch
{
return BadRequest();
}
}
What I expect is, the product from ASP.NET Core will take all values from Angular with no problem, but instead, I get this error:
product.Created: ["The value '16/02/2023' is not valid for Created."]
That means ModelState returned false because the Created method field. I look for many answers in SOF but no answer solved my problem, I even do this but it doesn't work either:
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
public DateTime Created { get; set; }
I've kinda reached a dead end, please help :(

As mentioned in the comment, you should pass the date as ISO 8601 format instead of "dd/MM/yyyy" so that the API side will receive the date correctly.
With Date.prototype.toISOString()
let now = new Date();
// To remove time from date
let created = new Date(now.getFullYear(), now.getMonth(), now.getDate()).toISOString();
// 2023-02-16T16:00:00.000Z
product.created = created;
Note that the ISO String will be in the UTC offset.

Related

Missing type map configuration exception is showing in my code

I have the following code in the controller and showing exception.
[HttpGet("{id}")]
public IActionResult GetCategoryGoalsById(int id)
{
try
{
var categories = _unitOfWork.Category.GetCategoryByGoalId(id);
if (categories == null)
{
_loggerManager.LogError($"Category with id: {id}, hasn't been found in db.");
return NotFound();
}
else
{
_loggerManager.LogInfo($"Returned category with id: {id}");
var categoryResult = _mapper.Map<CategoryDetailVm>(categories);
return Ok(categoryResult);
}
}
catch (Exception ex)
{
_loggerManager.LogError($"Something went wrong inside categoryResult action: {ex.Message}");
return StatusCode(500, "Internal server error");
}
}
Where is the entity class is like this:
public class Category
{
public int Id { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public string CategoryName { get; set; }
[ForeignKey(nameof(Goals))]
public int GoalId { get; set; }
public Goals Goals { get; set; }
}
and vm class for the module class written as:
public class CategoryDetailVm
{
public int Id { get; set; }
public string CategoryName { get; set; }
}
The code is written in repository pattern with UnitofWork and the repository part is written as:
public IEnumerable<Category> GetCategoryByGoalId(int goalId)
{
return FindByCondition(g => g.Goals.Id.Equals(goalId)).ToList();
}
following exception is showing here, how can I resolve the following problem:
ex {"Missing type map configuration or unsupported mapping.\r\n\r\nMapping types:\r\nObject ->
CategoryDetailVm\r\nSystem.Object ->
EthosAPI.ViewModelEntities.CategoryDetailVm"} System.Exception
{AutoMapper.AutoMapperMappingException}
It seems like you're missing an automapper mapping, did you add it?
https://docs.automapper.org/en/stable/Getting-started.html#how-do-i-use-automapper
eg. var config = new MapperConfiguration(cfg => cfg.CreateMap<CategoryDetailVm, Categorie>());
Also you're mapping an object to an entire list, so you should also have a mapping for lists, see:
https://docs.automapper.org/en/stable/Lists-and-arrays.html
So var categoryResult = _mapper.Map<CategoryDetailVm>(categories); should be more like var categoryResult = _mapper.Map<IEnumerable<CategoryDetailVm>>(categories); or something.

Uncaught Error: Unable to convert "undefined" into a date (Angular)

In this example, I want to get all bookings data from a service and push them to an array CalendarEvent[]. But I received this error Uncaught Error: Unable to convert "undefined" into a date. I assumed that something is wrong with my service?
ng-calendar.component.ts:
export class NgCalendarComponent {
events: CalendarEvent[] = [];
bookings: any = {};
date: string;
constructor(private bookingService: BookingService) {}
ngOnInit() {
this.bookings = this.bookingService.getAllBookings();
for (let booking of this.bookings) {
var b = this.bookings[booking];
this.date = formatDate(b.bookDate, 'medium', 'en-us', 'GMT+8');
this.events.push({
start: new Date(this.date),
title: b.purpose,
});
}
}
booking.service.ts:
export class BookingService {
constructor(private http: HttpClient) { }
getAllBookings() {
return this.http.get('/api/bookings/')
.pipe(map(response => response));
}
}
BookingResource.cs:
public class BookingResource
{
public int Id { get; set; }
public RoomResource Room { get; set; }
public KeyValuePairResource Building { get; set; }
public DateTime BookDate { get; set; }
public ContactResource Contact { get; set; }
public string Purpose { get; set; }
public ICollection<TimeSlotResource> TimeSlots { get; set; }
public BookingResource()
{
TimeSlots = new Collection<TimeSlotResource>();
}
}
getAllBooking() returns an observable, you have to subscribe to it to get the result. Or convert it to a promise :
async getAllBookings() {
return this.http.get('/api/bookings/').toPromise();
}
And call it like this :
async ngOnInit() {
this.bookings = await this.bookingService.getAllBookings();
...

How skip NullReferenceException in Get API

Here create an API to get the records, in my entity relation table there are twice start date and end date. Here my compulsion is one of them need to keep Null able type.
Here is ER that is SchoolCourses:
public class SchoolCourses
{
public Guid ID { get; set; }
public DateTime StartCourseDate { get; set; }
public DateTime EndCourseDate { get; set; }
public DateTime? StartSemDate { get; set; } // Null able type
public DateTime? EndSemDate { get; set; } // Null able type
}
I creates a repository for getting the value:
public async Task<ICollection<SchoolCourses>> GetcourseBySchoolId(Guid SchoolId)
{
List<SchoolCourses> schoolCourses = null;
schoolCourses = await _GpsContext.SchoolCourses.AsNoTracking()
.Where(x => x.SchoolsID == SchoolId)
.ToListAsync();
return schoolCourses;
}
And the Controller are like this:
public async Task<IActionResult> GetforSchoolCourse(string SchoolId)
{
var result = await _schoolCoursesRepository.GetcourseBySchoolId(Guid.Parse(SchoolId));
List<GetSchoolCourseBySchoolIdVm> getSchoolCourseBySchoolIdVms = new List<GetSchoolCourseBySchoolIdVm>();
foreach (SchoolCourses schoolCourse in result)
{
getSchoolCourseBySchoolIdVms.Add(new GetSchoolCourseBySchoolIdVm
{
id = schoolCourse.ID.ToString(),
StarCoursetDate = schoolCourse.StartCourseDate.ToString(),
EndCourseDate = schoolCourse.EndCourseDate.ToString(),
StartSemDate = schoolCourse.StartSemDate.ToString(),
EndSemDate = schoolCourse.EndSemDate.ToString(),
});
}
return Ok(getSchoolCourseBySchoolIdVms);
}
Here is View Model for reference:
public class GetSchoolCourseBySchoolIdVm
{
public string id { get; set; }
public string StarCoursetDate { get; set; }
public string EndCourseDate { get; set; }
public string StartSemDate { get; set; }
public string EndSemDate { get; set; }
}
After doing all the above staff it is getting exception error in swagger is following:
System.NullReferenceException: Object reference not set to an instance of an object.;
In your SchoolCourses model StartSemDate and EndSemDate are nullable types, so it must be possible that values of those fields are null. That should have been checked before using it, unlike you have used
StartSemDate = schoolCourse.StartSemDate.ToString(),
EndSemDate = schoolCourse.EndSemDate.ToString(),
here if any of the date is null then calling .ToString() method on it will throw NullReferenceException. Use safe navigation operator to check
schoolCourse.StartSemDate?.ToString()
or
schoolCourse.StartSemDate != null ? schoolCourse.StartSemDate.ToString() : string.Empty

Add checking in controller

I have class User in my project and have model UserRow (for showing user in view)
it's UserRow
using System;
namespace Argussite.SupplierServices.ViewModels
{
public class UserRow
{
public Guid Id { get; set; }
public string FullName { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Status { get; set; }
public int Role { get; set; }
public Guid SupplierId { get; set; }
public bool ActionsAllowed { get; set; }
public bool MailResendRequired { get; set; }
}
}
and I need to add in my controller checking if ActionsAllowed
[HttpPost]
public ActionResult Unlock(Guid id)
{
var user = Context.Users.Find(id);
if (user == null)
{
return Json(CommandResult.Failure("User was not found. Please, refresh the grid and try again."));
}
var checkActionsAllowed = Context.Users.AsNoTracking()
.Select(e => new UserRow
{
Id = e.Id,
ActionsAllowed = e.ActionsAllowed
};
if (checkActionsAllowed == true)
{
user.Status = UserStatus.Active;
return Json(CommandResult.Success(string.Format("User {0} has been unlocked.", user.FullName)));
}
else return;
}
but I got error with ActionsAllowed = e.ActionsAllowed and
in else return;
Help me please to solve this problem.
You have two problems:
Context.Users.AsNoTracking()
.Select(e => new UserRow
{
ActionsAllowed = e.ActionsAllowed
};
returns a list of objects, not a single object.
You have queried the user above, so i guess you can write simply:
if (user.ActionsAllowed) {
user.Status = UserStatus.Active;
return Json(CommandResult.Success...);
}
The second problem is the return; statement.
Your method returns an action result, so you have to return something.
For example
return Json(CommandResult.Failure(
"ActionsAllowed = false"));
First error sounds like you User class doesn't provide a ActionsAllowed Boolean property, while the second error happens because you need to return something from the method that can be interpreted as an ActionResult.
EDIT:
Hmm, I didn't notice this the first time, but this:
var checkActionsAllowed = Context.Users.AsNoTracking()
.Select(e => new UserRow
{
Id = e.Id,
ActionsAllowed = e.ActionsAllowed
};
followed by this:
if (checkActionsAllowed == true)
makes no sense - you're not returning a boolean result from a Select method, but rather an IEnumerable. Perhaps you should add your User schema to your question so that it's more obvious what you're trying to accomplish.

HTTP POST to Many to Many relation using ASP.NET Web API

I am new to ASP.net (and programming in general) and I'm having trouble building a Web API. More specifically I need help in these two areas:
How to configure my DOCcontroller to post a new document (DOC table).
How to make the actual ajax post -- I am having trouble passing the EXT_GUID parameter. As it stands I get an error when I try to post. "Can't bind multiple parameters (doc and parentOwner) to the request's content."
Essentially this is for a simple document management system. I want Get/Post documents (DOC) by having the user supply an GUID from an external database (the EXT_GUID field) as a filter/parameter. Each document can have multiple EXT_GUIDs and each EXT_GUID can have multiple Documents (DOC). You can assume that the EXT_GUID fields we be populated prior to the http post.
This is the DOCcontroller code
//POST api/DOC
public HttpResponseMessage PostDOC(DOC doc, List<string> parentOwners)
{
if (ModelState.IsValid)
{
var parents = db.BIMs.Where(bx => parentOwners.Contains(bx.EXT_GUID));
foreach (var p in parents)
doc.Owners.Add(p);
db.DOCs.Add(doc);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, doc);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = doc.Id }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
This is my model setup -- EntityFramework codefirst stuff
public class EXT
{
public int Id { get; set; }
public string EXT_GUID { get; set; }
public int ProjectID { get; set; }
public virtual ICollection<DOC> DOCs { get; set; }
}
public class DOC
{
public int Id { get; set; }
public int ProjectID { get; set; }
public string Subject { get; set; }
public string Link { get; set; }
public virtual ICollection<EXT> EXTs { get; set; }
}
This is more Storage Model...
public StoreDBContext() : base("name=StoreDBContext")
{
}
public DbSet<EXT> EXTs { get; set; }
public DbSet<DOC> DOCs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Set FLUENT API config for many to many here
modelBuilder.Entity<EXT>()
.HasMany(a => a.DOCs)
.WithMany()
.Map(x =>
{
x.MapLeftKey("EXT_Id");
x.MapRightKey("DOC_Id");
x.ToTable("EXTsDOCs");
});
}
AJAX Code
function AddDOC() {
var parentOwner = "{\"" + $('#txtaddEXT').val() + "\"}";
jQuery.support.cors = true;
var DOC = {
ProjectId: ProjectID,
Subject: $('#txtaddDOCSubject').val(),
Link: $('#txtaddDOCLink').val(),
parentOwner: parentOwner
};
$.ajax({
url: "http://localhost:54171/api/DOC/",
type: 'POST',
data: JSON.stringify(DOC),
contentType: "application/json;charset=utf-8",
success: function (data) {
WriteResponse(data);
},
error: function (x, y, z) {
alert(x + '\n' + y + '\n' + z);
}
});
}
What you receive from the client and what you will save in the database is two different things.
Your doc object is ok:
var DOC = {
ProjectId: ProjectID,
Subject: $('#txtaddDOCSubject').val(),
Link: $('#txtaddDOCLink').val(),
parentOwner: parentOwner
};
Now you need to change the server logic. Make a model like this:
public class DocReceivedModel
{
public int ProjectID { get; set; }
public string Subject { get; set; }
public string Link { get; set; }
public List<string> parentOwner { get; set; }
}
Then your PostDOC method will be:
public HttpResponseMessage PostDOC(DocReceivedModel docReceived)
{
if (ModelState.IsValid)
{
Doc newDoc = new Doc();
newDoc.ProjectID = docReceived.ProjectID
newDoc.Subject = docReceived.Subject
newDoc.Link = docReceived.Link
var parents = db.BIMs.Where(bx => docReceived.parentOwners.Contains(bx.EXT_GUID));
foreach (var p in parents)
newDoc.Owners.Add(p);
// I not see in your model Owners, maybe this is EXTs but I suppose you catch the idea
db.DOCs.Add(newDoc);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, newDoc);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new {id = newDoc.Id}));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}

Resources