Disable username validation on edit - c#

I created my validation for unique username and now I can't edit my user. It's saying that username is already taken which makes sense since it's taken by the user that I'm trying to edit. I don't even want to edit username but because of this error I cannot edit any other field as well.
How can I disable unique username validation for my EDIT action?
Validator
public override bool IsValid(object value)
{
if (value == null) return false;
FinanceDataContext _db = new FinanceDataContext();
var user = _db.Users.ToList().Where(x => x.Username.ToLower() == value.ToString().ToLower()).SingleOrDefault();
if (user == null) return true;
return false;
}
Action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(User u)
{
// Get user we want to edit
var user = _db.Users.Where(x => x.ID == u.ID).SingleOrDefault();
if (user == null) return HttpNotFound();
// Set values and save changes
user.Address = u.Address;
if (!string.IsNullOrEmpty(u.Password)) user.Password = Infrastructure.Encryption.SHA256(u.Password);
_db.SaveChanges(); // validation error
return null;
}
Model
public class User
{
public int ID { get; set; }
[Required]
[UniqueUsername(ErrorMessage = "Username is already taken")]
public string Username { get; set; }
[Required]
public string Password { get; set; }
public string Address { get; set; }
}
Error
Validation failed for one or more entities. See
'EntityValidationErrors' property for more details.

Pass the "ID" property in "AdditionalFields" parameter of UniqueUsername Attribute so I guess your code should be like this
Class Property :
[Required]
[UniqueUsername(ErrorMessage = "Username is already taken", AdditionalFields = "ID")]
public string Username { get; set; }
Validate Action :
public ActionResult UniqueUsername(string userName, int id)
{
FinanceDataContext _db = new FinanceDataContext();
var user = _db.Users.ToList().SingleOrDefault(x => x.Username.ToLower() == value.ToString().ToLower() && x.ID != id);
return Json(user == null, JsonRequestBehavior.AllowGet);
}
Hope this will help !!

Could you pass in the user id into the IsValid method and make sure the user returned doesn't have the same user id?

One thing I would like to contribute.
This code:
var user = _db.Users.ToList().Where(x => x.Username.ToLower() == value.ToString().ToLower()).SingleOrDefault();
Is not performatic, because when you do a ToList() you execute the whole query. In this case, what you are doing is retrieving ALL USERS from the database and them doing your filter in memory.
I would sugest you to do this:
_db.Users.Where(x => x.Username.ToLower() == value.ToString().ToLower()).SingleOrDefault();
Since you just want to retrieve one record, there is no need to call the ToList() method. Just the SingleOrDefault() at the end is enough.

Fixed it by passing whole object to my validator and then checking id's as well as usernames.
public override bool IsValid(object value)
{
var user = (User)value;
if (user == null) return true;
FinanceDataContext _db = new FinanceDataContext();
var u = _db.Users.Where(x => x.Username.ToLower() == user.Username.ToLower() && x.ID != user.ID).SingleOrDefault();
if (u == null) return true;
return false;
}

Related

SQLLITE-Xamarin Form - How to check if a value already exist

I looking to check if a value already exists, if exists return true if not false. However, I may be missing something on my logic because is always returning null even if the value exists
sample
public bool ExistPref(int userid)
{
var result = prefDB.db.Table<notificationsPreferences>().Where(t => t.UserId == userid).FirstOrDefault();
Console.WriteLine("user exist "+result+userid);
return result != null;
}
and if the user exist
I would like to update his record otherwise insert the new values
public int UpdateNotifications(notificationsPreferences item)
{
if (item.UserId != 0)
{
return prefDB.db.Update(item);
}
else
{
return prefDB.db.Insert(item);
The issue is here ** the Id comes inside the object item, however for some reason doesn't save the 4 digits id, what gets saved is for example 4 which I assumed is the times I add this item?/ that's why my result is always false because it is not saving the real id .
}
}
use Any
return prefDB.db.Table<notificationsPreferences>().Any(t => t.UserId == userid);
if the user exist I would like to update his record otherwise insert the new values
If you want to insert new record or update record into sqlite, you can take a look the following code:
private void insertorupdate(User model)
{
var data = _SQLiteConnection.Table<User>();
var d1 = data.Where(x => x.userId == model.userId).FirstOrDefault();
if (d1 == null)
{
_SQLiteConnection.Insert(model);
Console.WriteLine("Sucessfully Added");
}
else
{
Console.WriteLine("Already Mail id Exist");
_SQLiteConnection.Update(model);
}
}
public class User
{
[PrimaryKey, AutoIncrement]
public int userId { get; set; }
public string userName { get; set; }
public string password { get; set; }
}

Why is EF core one-to-one relationship not working as expected?

I have a User and a RefreshToken. I need to create a one-to-one relationship between those two objects. My RefreshToken object looks like this
`public class RefreshToken
{
[ForeignKey("User")]
public string RefreshTokenID { get; set; }
public string UserId { get; set; }
public User User { get; set; }
public string Token { get; set; }
}`
My User object looks like this
`public class User : IdentityUser
{
public RefreshToken RefreshToken { get; set; }
}`
Here is how I am persisting the RefreshToken for a user using _refreshTokenRepository:
`public async Task<bool> SaveAsync(User user, string newRefreshToken, CancellationToken ct = default(CancellationToken))
{
if(user.RefreshToken != null) return false;
RefreshToken rt = new RefreshToken(newRefreshToken, DateTime.Now.AddDays(5), user.Id);
await _dbContext.RefreshTokens.AddAsync(rt);
await _dbContext.SaveChangesAsync(ct);
return true;
}`
The issue happens when, user is redirected to the '/refresh' route, and when I need to check the User's refresh token against the one coming back from the client. This property check is always null:
`var user = _userManager.Users.SingleOrDefault(u => u.UserName == username);
if(user == null || user.RefreshToken.Token != refreshToken) return BadRequest();`
The user is in fact the right user and is found, but the RefreshToken property is null.
I have tried using fluent API to create this relationship. Same outcome. The refresh tokens are successfully persisted to the database with the right user ID in the table, but the navigational property is not working. Any ideas why?
You should modify this line:
var user = _userManager.Users.SingleOrDefault(u => u.UserName == username);
By adding .Include(u => u.RefreshToken), So, the line should look like this:
var user = _userManager.Users.Include(u => u.RefreshToken).SingleOrDefault(u => u.UserName == username);
This will tell the store to also load the related RefreshToken entities.

Can I return different razor views on .NET controller?

The background is this. I have a controller that shows the details of an story object (which you can think of as a blog post).
I would like anyone to be able to read the details of a story without being logged in to the application. However, in my StoryDetailsViewModel I have an ApplicationUser field. I do this because if someone wants to comment on the story, I need to know who the author is and therefore, I want to force them to log-in to write a comment.
I have [AllowAnonymous] as an attribute on my controller action. When I try to get the identity of the user who's signed in, if the person is not signed in, the call returns null, sticks null in my ApplicationUser field in the viewmodel and consequently breaks the view. My controller action is below.
This whole thing is because in the view, I want this textarea if someone is logged in:
I don't know whether or not I should have some kind of boolean that if User.Identity.GetUserId() returns null I can act on that, or, as the controller action below has, try to create two separate viewmodels depending on if the user is anonymous or logged in.
Any thoughts on the best (most efficient) way to tackle this?
[HttpGet]
[AllowAnonymous]
public ActionResult Details(int id)
{
var FoundStory = _dbContext.Stories.SingleOrDefault(x => x.Id == id);
if (FoundStory == null)
{
return HttpNotFound();
}
//get the logged in userId
string signedInUserId = User.Identity.GetUserId();
//if the person reading the article isn't signed in, the userId will come back null
//need to create a viewmodel and view that doesn't have a signed in user associated with it
if (signedInUserId == null)
{
var viewModel = new StoryDetailsViewModelAnonymousUser
{
StoryId = FoundStory.Id,
AuthorId = FoundStory.AuthorId,
Story = FoundStory,
Comments = _dbContext.Comments.Where(x => x.StoryId == FoundStory.Id).ToList()
};
return View(viewModel);
} else
{
var viewModel = new StoryDetailsViewModelSignedInUser
{
StoryId = FoundStory.Id,
AuthorId = FoundStory.AuthorId,
Story = FoundStory,
User = _dbContext.Users.SingleOrDefault(x => x.Id == signedInUserId),
Comments = _dbContext.Comments.Where(x => x.StoryId == FoundStory.Id).ToList()
};
return View(viewModel);
}
}
My viewModel:
public class StoryDetailsViewModelSignedInUser
{
public ApplicationUser User { get; set; }
public int StoryId { get; set; }
public Story Story { get; set; }
public string AuthorId { get; set; }
[Required]
public string Content { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
In this case you probably don't need to use different views.
You can add a bool property such as IsAnonymous to StoryDetailsViewModelSignedInUser to indicate if a user is logged in or not, or check if property User is set (model.User != null). Finally, in your view, show or hide the Comments section/partial view using these properties.
ViewModel:
public class StoryDetailsViewModelSignedInUser
{
public bool IsAnonymous
{
get
{
return User != null;
}
}
public ApplicationUser User { get; set; }
// other properties here
}
Using a partial view for your comments section will probably make your life easier, given that all you have to do is to add an if statement checking if the user is logged in or not.
I'd also refactor the controller method in order to reduce code duplication. Instead of:
if (signedInUserId == null)
{
var viewModel = new StoryDetailsViewModelAnonymousUser
{
StoryId = FoundStory.Id,
AuthorId = FoundStory.AuthorId,
Story = FoundStory,
Comments = _dbContext.Comments.Where(x => x.StoryId == FoundStory.Id).ToList()
};
return View(viewModel);
} else
{
var viewModel = new StoryDetailsViewModelSignedInUser
{
StoryId = FoundStory.Id,
AuthorId = FoundStory.AuthorId,
Story = FoundStory,
User = _dbContext.Users.SingleOrDefault(x => x.Id == signedInUserId),
Comments = _dbContext.Comments.Where(x => x.StoryId == FoundStory.Id).ToList()
};
return View(viewModel);
}
You can do:
var viewModel = new StoryDetailsViewModelAnonymousUser
{
StoryId = FoundStory.Id,
AuthorId = FoundStory.AuthorId,
Story = FoundStory,
Comments = _dbContext.Comments.Where(x => x.StoryId == FoundStory.Id).ToList()
};
if (signedInUserId != null)
{
viewModel.User = _dbContext.Users.SingleOrDefault(x => x.Id == signedInUserId);
}
return View(viewModel);

PUT does not insert object in SQL Server

I'm having a problem with Web API where I want to create a new object in SQL Server.
The PUT method is used to update an expensenote. An expensenote contains dailyexpensenotes. A dailyexpensenote contains individualexpenses.
In the GUI, a user that edits his expensenote can:
Fill in an empty individualexpense with value > 0 (Creates a new individualexpense)
Change an existing individualexpense (Updates the existing individualexpense)
Clear an individualexpense/change value to 0 (Deletes the existing individualexpense)
After this the user clicks save and the entire expensenote is sent by ajax call to the web service. Nr 2 and Nr 3 are working as desired but the Nr 1 doesn't work and gives no error.
PUT method
// PUT api/expenses/5
public void Put(int id, [FromBody]Expensenote exUpdate)
{
expensenote ex = (from e in db.expensenotes
where e.ID == id
select e).FirstOrDefault();
if (ex == null)
{
//return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Request was not found.");
}
else
{
foreach (Expensenotedaily d in exUpdate.dailyExpenses)
{
var daily = ex.expensenotedailies.SingleOrDefault(da => da.ID == d.ID);
daily.city = d.city;
daily.dailyallowance = d.dailyallowance;
foreach (Expenseindividual i in d.individualExpenses)
{
expenseindividual individual = daily.expenseindividuals.SingleOrDefault(ind => ind.ID == i.ID);
if (i.value == 0)
{
if (!(individual == null))
{
db.expenseindividuals.Remove(individual);
}
}
else
{
if (!(individual == null))
{
individual.value = i.value;
}
else
{
expenseindividual newInd = db.expenseindividuals.Create();
newInd.typecode_ID = i.expensetypeID;
newInd.daily_ID = daily.ID;
newInd.typecode = db.typecodes.SingleOrDefault(t => t.ID == i.expensetypeID);
newInd.expensenotedaily = daily;
newInd.value = i.value;
newInd.creditcard = false;
db.expenseindividuals.Add(newInd);
//SOLUTION: db.SaveChanges();
}
}
}
}
db.SaveChanges();
}
}
expenseindividual datamodel class
public partial class expenseindividual
{
public expenseindividual()
{
this.supplementalinfoes = new HashSet<supplementalinfo>();
}
public int ID { get; set; }
public double value { get; set; }
public bool creditcard { get; set; }
public int daily_ID { get; set; }
public int typecode_ID { get; set; }
public virtual expensenotedaily expensenotedaily { get; set; }
public virtual typecode typecode { get; set; }
public virtual ICollection<supplementalinfo> supplementalinfoes { get; set; }
}
When I debug I see that all attributes are passed correctly.
Using newInd = new expenseindividual() instead of Create() doesn't fix the problem.
I tried setting the expenseindividual.ID manually and this makes the insert work but it must auto increment and auto increment is enabled.
So I'm really wondering what causes the problem here and how I can fix it?
If I understand you correctly, you are trying to insert a new expense note into the database when one does not already exist?
Firstly... this code currently ignores expense notes that do not already exist in the database...
expensenote ex = (from e in db.expensenotes
where e.ID == id
select e).FirstOrDefault();
if (ex == null)
{
//return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Request was not found.");
}
else
{
ex will always be null when you pass an id of an expense note that does not already exist inside of the database, therefore no code will be run.
The convention is that typically PUT is always used to update a record, POST is used instead when trying to create one but thats up to you.
You need to implement your logic to create a new record within the if statement, replacing the commented out return statement.

C# Entity Framework with linq returns null reference

I have a problem with entity framework in C#.
I have 2 entities, User and UserRole. They are bond by relationships User *->1 UserRole
Whenever I use this query in a function:
User user = context.User.Where(i => i.id == id).FirstOrDefault();
return user.UserRole.accessLevel;
The query returns user, but UserRole is null. The User table has roleId which is related to id of UserRole, and the value of roleId when debugging is correct, although UserRole entity is null. This is strange as it never happened before...
I already made sure that my relationships in model and database are correct. I have correct rows added to database.
EDIT:
Sorry, I should've mentioned I use custom testable database controller:
public class DBController : IUnitOfWork
{
readonly ObjectContext context;
const string ConnectionStringName = "MarketPlaceDBEntities";
public DBController()
{
var connectionString =
ConfigurationManager
.ConnectionStrings[ConnectionStringName]
.ConnectionString;
context = new ObjectContext(connectionString);
}
public void Commit()
{
context.SaveChanges();
}
public IObjectSet<Category> Category
{
get { return context.CreateObjectSet<Category>(); }
}
public IObjectSet<ItemComment> ItemComment
{
get { return context.CreateObjectSet<ItemComment>(); }
}
public IObjectSet<ItemRating> ItemRating
{
get { return context.CreateObjectSet<ItemRating>(); }
}
public IObjectSet<Item> Item
{
get { return context.CreateObjectSet<Item>(); }
}
public IObjectSet<ItemSale> ItemSale
{
get { return context.CreateObjectSet<ItemSale>(); }
}
public IObjectSet<ItemScreenshot> ItemScreenshot
{
get { return context.CreateObjectSet<ItemScreenshot>(); }
}
public IObjectSet<UserRole> UserRole
{
get { return context.CreateObjectSet<UserRole>(); }
}
public IObjectSet<User> User
{
get { return context.CreateObjectSet<User>(); }
}
}
And I do operations via it. Maybe it has to do something with my prob.
interface IUnitOfWork
{
IObjectSet<Category> Category { get; }
IObjectSet<ItemComment> ItemComment { get; }
IObjectSet<ItemRating> ItemRating { get; }
IObjectSet<Item> Item { get; }
IObjectSet<ItemSale> ItemSale { get; }
IObjectSet<ItemScreenshot> ItemScreenshot { get; }
IObjectSet<UserRole> UserRole { get; }
IObjectSet<User> User { get; }
void Commit();
}
I had this whole thing working before, but don't know why it went wrong..
EDIT2:
Solved! Thanks RicoSuter.
Enabling lazy loading in constructor of my db controller solved the problem. I thought it was already enabled, because it was set to true in database model, but it looks like that when creating a new context, you have to enable it manually again.
public DBController()
{
var connectionString =
ConfigurationManager
.ConnectionStrings[ConnectionStringName]
.ConnectionString;
context = new ObjectContext(connectionString);
context.ContextOptions.LazyLoadingEnabled = true;
}
try to eagerly load UserRole (join):
context.User.Include("UserRole").Where(i => i.id == id).FirstOrDefault();
or enable lazy loading first:
context.ContextOptions.LazyLoadingEnabled = true;
context.User.Where(i => i.id == id).FirstOrDefault();
otherwise there is no relation to a UserRole in your database...
Try this
User user = context.User.Where(i => i.id == id).FirstOrDefault();
return user==null?null:user.UserRole.accessLevel;
Most simply u can do this:
UserRole user = context.User.Where(i => i.id == id).Select(i => i.UserRole);
return user.accessLevel;
Edit:
Assuming you already have a relation between User and UserRole
User user = context.User.Where(i => i.id == id).FirstOrDefault();
UserRole role = context.UserRole.Where(i => user.Contains(i.id)).FirstOrDefault();
return role.accessLevel;
Assuming you dont have a relation between User and UserRole
int roleid = Convert.ToInt32(context.User.Where(i => i.id == id).Select(i => i.roleid));
UserRole role = context.UserRole.Where(i => i.id == roleid).FirstOrDefault();
return role.accessLevel;
Also if you have relation but cant see UserRole under User than try adding this to your model
public IDisposable User()
{
YourDataContext context = new YourDataContext();
Type ct = context.User.GetType();
return (IDisposable)(ct);
}

Categories