Entity Framework not saving jsonb property - c#

I have an update method:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
[Column(TypeName = "jsonb")]
}
public async Task<bool> Update(int id, UserRequest user)
{
var result = await _context.Users.Where(x => x.Id == id).FirstOrDefaultAsync();
var cities = new List<string>();
cities.Add("New York");
cities.Add("London");
result = new Users()
{
Id = result.Id,
FirstName = user.FirstName,
LastName = user.LastName,
City = JsonSerializer.Serialize(cities)
};
// _context.Entry(result).Property(x => x.City).IsModified = true;
await _context.SaveChangesAsync();
return true;
}
FirstName and LastName change is reflected in db but not in City db.
_context.Entry(result).Property(x => x.City).IsModified = true;
As a solution, generally used the Entry feature, but the Entry property throws an error for me:
An exception occurred while calculating the database error page content.
Skipping display of the database error page.
System.InvalidOperationException:
StatusCode cannot be set because the response has already started.

I don't understand the cause of the issue but the following change solved my issue.
result = new Users()
{
Id = result.Id,
FirstName = user.FirstName,
LastName = user.LastName,
City = JsonSerializer.Serialize(cities)
};
to
result.FirstName = user.FirstName;
result.LastName = user.LastName ;
result.City = JsonSerializer.Serialize(cities);

Related

How to update user details using ASP. NET Core MVC? ConcurrencyFailure

I am trying to update user details from a SQL database using ASP.NET Core MVC and Angular. I want to update the user without sending the UserID to the API so i have to get the UserId in the PUT method.
I used Entity and Identity to create the database.
With the following code I am getting this error:
Code: "ConcurrencyFailure"
Description: "Optimistic concurrency failure, object has been modified."
How can i make this works?
PUT Method
[HttpPut]
[Route("Update")]
//api/ApplicationUser/Update
public async Task<Object> PutApplicationUser(UserAccountModel model)
{
var user = _userManager.GetUserId(HttpContext.User);
var applicationUser = new UserAccount()
{
UserName = model.UserName,
FirstName = model.FirstName,
LastName = model.LastName,
Email = model.Email,
PhoneNumber = model.PhoneNumber,
VerificationCode = "",
ExpCode = new DateTime(2020, 8, 18),
SecurityStamp = Guid.NewGuid().ToString()
};
try
{
var result = await _userManager.UpdateAsync(applicationUser);
return result;
}
catch (Exception ex)
{
throw ex;
}
}
UserAccount model
public class UserAccount : IdentityUser
{
[Column(TypeName = "nvarchar(30)")]
public string FirstName { get; set; }
[Column(TypeName = "nvarchar(30)")]
public string LastName { get; set; }
[Column(TypeName = "nvarchar(30)")]
public string VerificationCode { get; set; }
[Column(TypeName = "smalldatetime")]
public DateTime ExpCode { get; set; }
public virtual ICollection<File> File { get; set; }
public virtual ICollection<Folder> Folder { get; set; }
}
Try getting ConcurrencyStamp for this user and set it to your update model:
var user = _userManager.GetUserId(HttpContext.User);
var currStamp = ... // somehow get current stamp
var applicationUser = new UserAccount()
{
...
ConcurrencyStamp = currStamp
};
Or just use UserManager<TUser>.GetUserAsync and update fields on returned user:
var user = await _userManager.GetUserAsync(HttpContext.User);
user.UserName = model.UserName;
.....
var result = await _userManager.UpdateAsync(user);
I think you should update the record that exist. This works:
string user = User.Claims.First(c => c.Type == "UserID").Value;
var userModel = await _userManager.FindByIdAsync(user);
userModel.model.UserName;
userModel.FirstName = model.FirstName;
userModel.LastName = model.LastName;
userModel.Email = model.Email;
userModel.PhoneNumber = model.PhoneNumber;
userModel.VerificationCode = "";
userModel.ExpCode = new DateTime(2020, 8, 18);

How can I get latest employee ID (string) from the list of employees using .net web api Get call

I am using Entity Framework
My EmployeeDto class is :
public class EmployeeDto
{
[DataMember]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int SerialNumber { get; set; }
[DataMember]
[Key]
[Required]
public string ID { get; set; }
[DataMember]
[Required]
public string FirstName { get; set; }
[DataMember]
public string MiddleName { get; set; }
[DataMember]
[Required]
public string LastName { get; set; }
}
My Dto class is EmployeeDto and Dal class is named as Employee. I want to get the maximum value of EmployeeID from the database and provide it to frontend through Get call .
My Get call to get the list of all employees is :
public List<EmployeeDto> GetAllEmployees()
{
var employeeDto = new List<EmployeeDto>();
using (EmployeeDataEntities entities = new EmployeeDataEntities())
{
var employeeData = entities.Employees.ToList().Where(e => e.IsActive == true);
List<Employee> emp = employeeData.ToList();
//emp.FindLastIndex(e => e.)
employeeDto = Mapper.Map<List<Employee>,List<EmployeeDto>>(emp);
};
return employeeDto;
}
This is my GetLatestEmployeeByID code :
public int GetEmployeeLatestID(EmployeeDto employeeDto)
{
using (EmployeeDataEntities entities = new EmployeeDataEntities())
{
var employeeData = entities.Employees.ToList().Where(e => e.IsActive == true);
List<Employee> emp = employeeData.ToList();
emp.FindLastIndex(e => e.ID);
}
}
I have tried a couple of solutions and i end up with this one:
var a = new List<EmployeeDto>()
{
new EmployeeDto()
{
SerialNumber = 1,
ID = "AB01",
FirstName = "Ala",
MiddleName = "b",
LastName = "ala"
},
new EmployeeDto()
{
SerialNumber = 2,
ID = "AB02",
FirstName = "Ala",
MiddleName = "b",
LastName = "ala"
},new EmployeeDto()
{
SerialNumber = 3,
ID = "AB03",
FirstName = "Ala",
MiddleName = "b",
LastName = "ala"
}
};
// biggestIdAsInt = 230 a.max returns the max value after the calculations
var biggestIdAsInt = a.Max(employee => Encoding.ASCII.GetBytes(employee.ID) // get Employee Id as byte array
.Sum(b => b)); // summ the bytes for each employee
// 230
var substractedNumberFromBiggestId = Regex.Match(a.FirstOrDefault(x => x.ID.ToCharArray().Sum(y => y) == biggestIdAsInt).ID, #"\d+").Value;
Console.WriteLine(substractedNumberFromBiggestId);
I have put comments to make the code a little bit clearer.

My Web Api action return all data instead of one

One way to fix this problem is to turn lazy loading off ..... if i do not want to turn off lazy loading, is there other solution?
my action is look like this
[ResponseType(typeof(AspNetUsers))]
public IHttpActionResult Get(string id)
{
var user = db.AspNetUsers.FirstOrDefault(s => s.UserName == id);
if (user == null)
return null; //":کاربر نامعتبر";
JsonResult js = new JsonResult();
js.Data = user;
js.ContentEncoding = Encoding.UTF8;
js.ContentType = "Application/json";
js.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
//var returnUser = user.UserName + user.Email + user.FirstName + user.LastName +
// user.AspNetRoles.Select(s => s.Name);
return Ok(js);/// or return ok(user)
}
You are mixing MVC and Web Api concepts and object.
JsonResult is an MVC derived ActionResult object while IHttpActionResult is associated with Web API.
Also, if you don't want to return all the data then don't. Construct a new object result model and return only what is needed.
[ResponseType(typeof(UserModel))]
public IHttpActionResult Get(string id) {
var user = db.AspNetUsers.FirstOrDefault(s => s.UserName == id);
if (user == null)
return NotFound();
var data = new UserModel {
UserName = user.UserName,
Email = user.Email,
FirstName = user.FirstName,
LastName = user.LastName,
Roles = user.AspNetRoles.Select(s => s.Name).ToArray()
//...other properties you want to return
};
return Ok(data);
}
public class UserModel {
public string UserName { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string[] Roles { get; set; }
}
i fix my Problem whit little change in Nkosi answer .....
[ResponseType(typeof(UserModel))]
public IHttpActionResult Get(string id)
{
var user = db.AspNetUsers.Include(a=>a.AspNetRoles).Where(s => s.UserName == id).FirstOrDefault();
if (user == null)
return NotFound();
var data = new UserModel
{
UserName = user.UserName,
Email = user.Email,
FirstName = user.FirstName,
LastName = user.LastName,
Roles = user.AspNetRoles.Select(s => s.Name).ToArray()
//...other properties you want to return
};
return Ok(data);
}
public class UserModel
{
public string UserName { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string[] Roles { get; set; }
}
thanks alot

Merging 2 lists of different objects into a third list of a different type?

I'm building an API wrapper for a third party API that translates their objects into business domain objects that can be used for other processing. In this case, I need to take 2 different objects Contact and User and merge them into a single list of objects called UserContacts. I'm matching these objects based on their Email property, and if there is no matching elements, a new one is inserted.
Here are my current objects and methods, I'm just trying to figure out if there's a better/faster method.
public class ContactUser : IUser
{
public string SalesForceUserId { get; set; }
public string SalesForceContactId { get; set; }
public string ZendeskId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
private List<IUser> MergeContactsAndUsers()
{
var sfContacts = SalesForceCache.Contacts.Data;
var sfUsers = SalesForceCache.Users.Data;
var newUsers = sfUsers.Select(user => new ContactUser
{
SalesForceUserId = user.Id,
Name = user.Name,
FirstName = user.FirstName,
LastName = user.LastName,
Email = user.Email
}).Cast<IUser>().ToList();
foreach (var contact in sfContacts)
{
var tmp = newUsers.FirstOrDefault(n => n.Email == contact.Email);
if (tmp != null)
{
tmp.SalesForceContactId = contact.Id;
}
else
{
var newUser = new ContactUser
{
SalesForceContactId = contact.Id,
Name = contact.Name,
FirstName = contact.FirstName,
LastName = contact.LastName,
Email = contact.Email
};
newUsers.Add(newUser);
}
}
return newUsers;
}
If you want to replace your current implementation with Join you can have something like this:
private List<IUser> MergeContactsAndUsers()
{
var sfContacts = SalesForceCache.Contacts.Data;
var sfUsers = SalesForceCache.Users.Data;
var leftJoinResults =
sfUsers.Join(
sfContacts,
u => u.Email,
c => c.Email,
(u, c) => new ContactUser()
{
SalesForceContactId = c.SalesForceContactId,
SalesForceUserId = u.Id,
Name = u.Name,
FirstName = u.FirstName,
LastName = u.LastName,
Email = u.Email
}).Cast<IUser>().ToList();
var rightJoinResults =
sfContacts
.Where(c => !leftJoinResults.Select(nu => nu.SalesForceContactId).Contains(c.Id))
.Select(c => new ContactUser
{
SalesForceContactId = c.Id,
Name = c.Name,
FirstName = c.FirstName,
LastName = c.LastName,
Email = c.Email
});
leftJoinResults.AddRange(rightJoinResults);
return leftJoinResults;
}
But because Join is only a left join (and you need right join as well) it still requires an additional query to get missing contacts (the query to get rightJoinResults).
It's more of an alternative implementation with use of Join. Without proper measurements it's hard to tell whether it's faster.

WebSecurity.CreateUserAndAccount propertyValues

I'm writing an mvc 4 c# .net 4.5 website
I want to create a new company object and register a new user that is linked to that company.
My account model is:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string PhoneNumber { get; set; }
public bool MarketingEmailOptin { get; set; }
public bool isDisabled { get; set; }
public virtual Company CompanyICanEdit { get; set; }
}
If i call the following it adds the user fine but has null for the CompanyICanEdit field:
WebSecurity.CreateUserAndAccount(addCompanyViewModel.User.UserName,
addCompanyViewModel.User.Password,
propertyValues: new
{
FirstName = addCompanyViewModel.User.FirstName,
LastName = addCompanyViewModel.User.LastName,
EmailAddress = addCompanyViewModel.User.EmailAddress,
PhoneNumber = addCompanyViewModel.User.PhoneNumber,
MarketingEmailOptin = addCompanyViewModel.User.MarketingEmailOptin,
isDisabled = false
});
which i would expect as i am not assigning it anything.
i have tried adding (mycompany is a company object):
WebSecurity.CreateUserAndAccount(addCompanyViewModel.User.UserName,
addCompanyViewModel.User.Password,
propertyValues: new
{
FirstName = addCompanyViewModel.User.FirstName,
LastName = addCompanyViewModel.User.LastName,
EmailAddress = addCompanyViewModel.User.EmailAddress,
PhoneNumber = addCompanyViewModel.User.PhoneNumber,
MarketingEmailOptin = addCompanyViewModel.User.MarketingEmailOptin,
isDisabled = false,
CompanyICanEdit = mycompany
});
But i get an error saying it can't match the type.
How do i go about registering the user so that the CompanyICanEdit contains the CompanyId value of mycompany?
Any help will be appreciated. thanks
Never worked out how to do it in 1 go, got round it by the following in the end if anyone has the same problem.
//
// POST: /BusinessManager/ManageCompanies/Add
[HttpPost]
public ActionResult Add(AddCompanyViewModel addCompanyViewModel)
{
if (ModelState.IsValid)
{
// Create company and attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(addCompanyViewModel.User.UserName,
addCompanyViewModel.User.Password,
propertyValues: new
{
FirstName = addCompanyViewModel.User.FirstName,
LastName = addCompanyViewModel.User.LastName,
EmailAddress = addCompanyViewModel.User.EmailAddress,
PhoneNumber = addCompanyViewModel.User.PhoneNumber,
MarketingEmailOptin = addCompanyViewModel.User.MarketingEmailOptin,
isDisabled = false
});
db.Companies.Add(addCompanyViewModel.Company);
var newuser = db.UserProfiles.FirstOrDefault(u => u.UserName == addCompanyViewModel.User.UserName);
if (newuser != null)
{
newuser.CompanyICanEdit = addCompanyViewModel.Company;
db.Entry(newuser).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
ModelState.AddModelError("", "New user wasn't added");
}
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", Mywebsite.Controllers.AccountController.ErrorCodeToString(e.StatusCode));
}
}
return View(addCompanyViewModel);
}

Categories

Resources