I have an Employee Model and Profile Picture. I need to Upload Profile Picture and Model Date both in one POST method. I just need to save Image File Name in Database and Uploading image in a WebRoot Directory.
Here is my Model:
public partial class Employers
{
public int EmployerId { get; set; }
public string Companyname { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public string Password { get; set; }
public string DisplayImage { get; set; }
public bool? IsActive { get; set; }
public DateTime StateDate { get; set; }
}
Here is my Controller Code:
[HttpPost]
public async Task<ActionResult<Employees>> PostEmployees([FromForm] FileUploadAPI Image, [FromBody]Employees employees)
{
try
{
_context.Employees.Add(employees);
await _context.SaveChangesAsync();
await UploadImage(Image, 2, employees.EmployeeId);
var returnInfo = CreatedAtAction("GetEmployees", new { id = employees.EmployeeId }, employees);
return returnInfo;
}
catch(Exception ex)
{
return NoContent();
}
}
public class FileUploadAPI
{
public IFormFile files { get; set; }
}
public async Task<string> UploadImage(FileUploadAPI files, int UserType, int UserId)
{
if (files.files.Length > 0)
{
try
{
if (!Directory.Exists(_hostingEnvironment.WebRootPath + "\\Employees\\"))
{
Directory.CreateDirectory(_hostingEnvironment.WebRootPath + "\\Employees\\");
}
Guid guid = Guid.NewGuid();
string filename = _hostingEnvironment.WebRootPath + "\\Employees\\" + $"EM-{UserType}-UserId-{guid}";
using (FileStream filestream = System.IO.File.Create(filename))
{
await files.files.CopyToAsync(filestream);
filestream.Flush();
return filename;
}
}
catch (Exception ex)
{
return ex.ToString();
}
}
else
{
return "Not Found";
}
}
If i just upload File in POSTMAN without Employee Model, its working fine. But when i pass both File EMployee Data both then FILE is returning null.
Any Suggestion, Solution ?
Thanks
It's impossible to use [FromForm] and [FromBody] simultaneously as is mentioned here. But I think You have 2 choices:
You can either put your JSON body into a form and send Employee data besides the File or use 2 separate endpoints for form upload. An endpoint for uploading user picture using [FromFile] and obtaining a pictureId and another for sending Employee in the body with populated pictureId key.
Firstly change FromBody to FromForm.Then,because you want to save filename to the database,change your code like below:
[HttpPost]
public async Task<ActionResult<Employers>> PostEmployees([FromForm] FileUploadAPI Image, [FromForm]Employers employees)
{
try
{
var filename = await UploadImage(Image, 2, employees.EmployerId);
employees.DisplayImage = filename;
_context.Employers.Add(employees);
await _context.SaveChangesAsync();
var returnInfo = CreatedAtAction("GetEmployees", new { id = employees.EmployerId }, employees);
return returnInfo;
}
catch (Exception ex)
{
return NoContent();
}
}
Your postman should be like below:
Result:
Related
I get data from my database, but the swagger throws a 500 error.
This is my code - model of user
public class User
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(30)]
public string Pseudo { get; set; }
[EmailAddress]
public string Mail { get; set; }
[Required]
public string Pwd { get; set; }
[Required]
public bool IsAdmin { get; set; }
public ICollection<Project> UsersProjects { get; set; }
}
DAL code to interact with database:
public TEntity? GetById(params object[] Id)
{
return _Context.Set<TEntity>().Find(Id);
}
public ICollection<Project> GetProjectList(int id)
{
return _Context.projects
.Where(u => u.ProjectManager.Id == id)
.ToList();
}
BLL
public UserBLL GetUser(int id)
{
try
{
UserBLL user = _Repo.GetById(id).ToBLL();
user.UsersProjects = _Repo.GetProjectList(id);
return user;
}
catch
{
throw new Exception("Utilisateur introuvable");
}
}
Controller
public IActionResult GetUser(int id)
{
try
{
return Ok(_userService.GetUser(id));
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
ERROR
Error: response status is 500
When I run the code step by step my object is good nothing is empty so I don't know what is the problem with Swagger
Please help
I'm struggling with net core returning truncated response. I have already defined no reference loop in my startup services, and also tried to set compatibility version for the version i'm currently using 2.1 as follows:
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
I also tried to serialize the array using JsonConvert and it did not throw any reference loop exception. Here's the action in the controller and the serializedArray text:
public IActionResult GetProductItems(int productId)
{
try
{
var productItems = _productsMethods.GetProductItems(productId);
// for testing the object for ref loops
string serialized = Newtonsoft.Json.JsonConvert.SerializeObject(productItems);
return Ok(productItems);
}
catch (ClientException ex)
{
return BadRequest(new { message = ex.Message });
}
catch (Exception ex)
{
return StatusCode(500, new { message = ex.Message });
}
}
// serialized string
//[{"ID":2,"ProductId":6,"ItemId":4,"Product":null,"Item":null,"Orders":[]},{"ID":3,"ProductId":":6,"ItemId":1,"Product":null,"Item":null,"Orders":[]},{"ID":5,"ProductId":":6,"ItemId":2,"Product":null,"Item":null,"Orders":[]}]
Here's the actual response
[{"id":2,"productId":6,"itemId":4,"product":null,"item":null,"orders":
Method:
public List<ProductItem> GetProductItems(int productId)
{
IQueryable<DataSets.ProductItem> query = db.ProductItems
.AsNoTracking()
.Include(k => k.Orders)
.Where(k => k.ProductId == productId);
// result truncated (when array orders is empty)
//return query.Select(_mapper.Map<ProductItem>).ToList();
// without automapper, also truncated
//return query.Select(k => new ProductItem()
//{
// ID = k.ID,
// ItemId = k.ItemId,
// ProductId = k.ProductId,
// Orders = k.Orders.Select(a => new Order() { ID = a.ID })
// .ToList()
//}).ToList();
// WORKS, not getting truncated
// order not included
return query.Select(k => new ProductItem()
{
ID = k.ID,
ItemId = k.ItemId,
ProductId = k.ProductId,
}).ToList();
}
Entities (renamed and removed props for simplification):
public class Product
{
public int ID { get; set; }
// some props
public string UserId { get; set; }
public User User { get; set; }
public List<ProductItem> Items { get; set; }
}
public class ProductItem
{
public int ID { get; set; }
// some props
public int ProductId { get; set; }
public int ItemId { get; set; }
public Product Product { get; set; }
public Item Item { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int ID { get; set; }
// some props
public int ItemId { get; set; }
public ProductItemOrder Item { get; set; }
}
Since there is no reference loop in orders and also the reference loop is ignored. Why is this still truncating?
I think the problem is public Product Product { get; set; } part here. You should define your Product entity virtually.
Here is an example below,
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public string Tags { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
Here is source.
For someone who might have this issue in the future. While I think the API should throw that error instead of just truncating the response.
I had 2 properties with the same letters but different letter case IPAddress and IpAddress.
SerializeObject alone wasn't throwing an exception, then I did this (CamelCase Resolver) to point out the issue:
Newtonsoft.Json.JsonConvert.DefaultSettings = () => new Newtonsoft.Json.JsonSerializerSettings
{
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
};
string serialized = Newtonsoft.Json.JsonConvert.SerializeObject(productItems);
So it threw: A member with the name 'ipAddress' already exists on ...
I am having a silly problem trying to deserialize asp.net core model state errors to an object. My code is like this
For backend register method
[HttpPost("register-user")]
[ValidateModel]
public async Task<IActionResult> Index(RegisterDto registerDto)
{
try
{
Data.Models.User user = mapper.Map<RegisterDto, Data.Models.User>(registerDto);
user.LockoutEnd = DateTimeOffset.Now;
user.Warehouse = configuration["Config:Warehouse"];
user.SiteId = Convert.ToInt32(configuration["Config:SiteId"]);
IdentityResult result = await userManager.CreateAsync(user, registerDto.Password);
if (result.Succeeded)
{
AddLogInformation(logger, "User created a new account with password.");
string token = await userManager.GenerateEmailConfirmationTokenAsync(user);
token = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(token));
string confirmationUrl = Url.Action("Index", "EmailConfirmation",
new {userId = user.Id, code = token}, Request.Scheme);
emailSender.SendEmailAsync(registerDto.Email, "Confirm your email",
GetEmailConfirmationTemplate(registerDto.FirstName, registerDto.LastName,
confirmationUrl));
ApplicationRole retailPersonRole =
await roleManager.FindByNameAsync(RoleHelper.GetRetailUserRoleName());
if (retailPersonRole != null) await userManager.AddToRoleAsync(user, retailPersonRole.Name);
if (userManager.Options.SignIn.RequireConfirmedAccount)
{
AddLogInformation(logger, "Sent email confirmation email to user");
return Ok(SuccessResult(null));
}
//If confirm account is set to false
await signInManager.SignInAsync(user, false);
return Ok(SuccessResult(null));
}
// If we got this far, something failed, redisplay form
return Ok(FailedMessage(logger, "Cannot register user at this time. Please try again later."));
}
catch (Exception e)
{
return ServerErrorJsonResult(logger, "Error while trying to register user. Error message is: " + e.Message);
}
}
And I am catching the model state error in action filter and returning a response as below.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var modelState = context.ModelState;
if (!modelState.IsValid)
context.Result = new BadRequestObjectResult(new JsonResult(new {modelError = true, Errors = modelState}));
}
}
Now in the front-end (xamarin), I have a model to where the error should be deserialised so that I can display a proper error to user.
My register model in the front end is like this
public class RegisterDto: BaseDto
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public AddressDto BillingAddress { get; set; }
public RegisterDto Errors { get; set; }
}
My Address Dto is like this
public class AddressDto
{
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string PostCode { get; set; }
public string State { get; set; }
}
I am creating the post request in xamarin like this.
public async Task<TResult> PostAsync<TResult>(string uri, TResult data, string token = "", string header = "")
{
try
{
HttpClient httpClient = CreateHttpClient(token);
if (!string.IsNullOrEmpty(header))
{
AddHeaderParameter(httpClient, header);
}
var content = new StringContent(JsonConvert.SerializeObject(data));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = await httpClient.PostAsync(uri, content);
await HandleResponse(response);
string serialized = await response.Content.ReadAsStringAsync();
TResult result = await Task.Run(() =>
JsonConvert.DeserializeObject<TResult>(serialized, serializerSettings));
return result;
}
catch (Exception e)
{
return default;
}
}
And finally, in the view model, I am doing this
--
userToBeRegistered is an instance of RegisterDto
await something.PostAsync(UrlHelper.RegisterUrl, userToBeRegistered);
The serialized string output is like this
{
"errors":{
"Email":[
"Email is required"
],
"LastName":[
"Last name is required"
],
"Password":[
"Password is required"
],
"FirstName":[
"First name is required"
],
"PhoneNumber":[
"Phone number is required"
],
"BillingAddress.City":[
"Suburb is required"
],
"BillingAddress.State":[
"State is required"
],
"BillingAddress.Address1":[
"Street address is required"
],
"BillingAddress.PostCode":[
"Postcode is required"
]
},
"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title":"One or more validation errors occurred.",
"status":400,
"traceId":"|3c2d7d70-49a6eceecbeedab8."
}
My question is how can I deserialise it to an errors object. If I keep running the above code, then I get this error.
"Unexpected character encountered while parsing value: [. Path 'errors.Email', line 1, position 20."
Can anyone help me with this?
Try the below method.
Create ErrorInfor class:
class ErrorInfor
{
public MyError errors { get; set; }
public string type { get; set; }
public string title { get; set; }
public int status { get; set; }
public string traceId { get; set; }
public class MyError
{
public List<string> FirstName { get; set; }
public List<string> LastName { get; set; }
public List<string> PhoneNumber { get; set; }
public List<string> Email { get; set; }
public List<string> Password { get; set; }
[JsonProperty("BillingAddress.City")]
public List<string> Citiy { get; set; }
[JsonProperty("BillingAddress.State")]
public List<string> State { get; set; }
[JsonProperty("BillingAddress.Address1")]
public List<string> Address1 { get; set; }
[JsonProperty("BillingAddress.PostCode")]
public List<string> PostCode { get; set; }
}
}
then you could get the data from your above json string.
ErrorInfor errorInfor = JsonConvert.DeserializeObject<ErrorInfo>(json);
Tried to update a Cosmos DB record in ASP.NET core 3.1. But the update fails with the following message: "Unable to cast object of type 'System.Func'2[Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry,System.Guid]' to type 'System.Func'2[Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry,System.String]'
The error occurs on the saveCangesAsync();
Simplified, the code looks like:
// The service
public async Task<Todo> UpdateAsync(Todo entity)
{
var response = ctx.Todos.Update(entity);
await ctx.SaveChangesAsync(); // Error here
return response.Entity;
}
// The entity Todo
public class Todo
{
public Guid id { get; set; }
[Required(ErrorMessage = "Description is required")]
public string description { get; set; }
...
}
// The context
public class TodoDbContext : DbContext
{
public DbSet<Todo> Todos { get; set; }
public TodoDbContext(DbContextOptions<TodoDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultContainer("Todos");
}
}
// The controller
[HttpPut]
public async Task<IActionResult> Put(Todo todo)
{
try
{
if (ModelState.IsValid)
{
Todo td = await service.GetAsync(todo.id.ToString());
if (td != null)
{
td.description = todo.description;
var response = await service.UpdateAsync(td);
return Ok(response);
}
return BadRequest("Not found.");
}
else
{
return BadRequest(ModelState);
}
}
catch (Exception ex)
{
return BadRequest(ex.Message); // Exception here
}
}
I can insert, read, but not update, so following code runs fine (with a Guid as well)
public async Task<Todo> CreateAsync(Todo entity)
{
entity.id = Guid.NewGuid();
var response = await ctx.Todos.AddAsync(entity);
await ctx.SaveChangesAsync();
return response.Entity;
}
Thanks for any help!
Don't use "id", that will collide with the automatically generated id. Use another property or use "Id" (with a capital I) in stead, to solve the problem.
Is there any reason you're using Guid as your id type? In your Todo class you could write it like so:
public class Todo
{
[JsonProperty("id")
public string Id { get; set; }
[JsonProperty("description")
[Required(ErrorMessage = "Description is required")]
public string description { get; set; }
}
I'm assuming that you're using v3 of the Cosmos DB SDK. You would then just use Guid.NewGuid().ToString() to set the id as a Guid (but as a string type).
Its keep a week that I'm trying to figure this out. I hope to get help from community. Here is a scenario:
I have a entity class called "Company". One company has many users (One-To-Many)
public class User : IdentityUser<int>
{
public User()
{
Company = new Company();
}
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime CreatedDate { get; set; } = DateTime.Now;
public virtual ICollection<UserRole> UserRoles { get; set; }
public virtual Company Company { get; set; }
public int CompanyId { get; set; }
}
I also have a company entity like so.
public class Company
{
public Company()
{
Users = new List<User>();
}
public int CompanyId { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Company Name")]
public string CompanyName { get; set; }
public virtual List<User> Users { get; set; }
}
Now, I can add new company but I cannot add users.
Here is my Controller/Create
[HttpGet]
public IActionResult Create(int companyId)
{
ViewData["UserList"] = new SelectList(_context.Companies, "CompanyId", "CompanyName", companyId);
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(RegisterViewModel viewModel)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(viewModel.UserName);
if (user == null)
{
user = new User
{
UserName = viewModel.UserName,
FirstName = viewModel.FirstName,
LastName = viewModel.LastName,
Email = viewModel.UserName,
PhoneNumber = viewModel.PhoneNumber
};
var result = await _userManager.CreateAsync(user, viewModel.Password);
if (result.Succeeded)
{
RedirectToAction(nameof(Index));
}
else
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
return View();
}
}
return View("Success");
}
ViewData["CompanyId"] = new SelectList(_context.Companies, "Id", "Id", viewModel.CompanyId);
return View();
}
When i run the program and enter data in a POST/Form,
if (ModelState.IsValid)
{
Model.IsValid is always return false. and it ask to enter Company information which i don't want it because i already have company data. I all was trying to do is have Foreign Id linked with user.
Since Identity already have built in function like
var users = await _userManager.GetUserAsync(viewModel.UserName);
How to i also query like Include in GetUserAsync method?