I have a controller
public ActionResult UsersInRoles()
{
using (var ctx1 = new UsersModel())
{
var model = new UsersInRolesViewModel();
model.UserProfiles = ctx1.UserProfiles.ToList();
model.UserRoles = ctx1.UserRoles.ToList();
return View(model);
}
}
I am Passing both of those models through to my View:
UserRoles Contains all of my possible roles in the system. Now I need to get an array in my controller of all the roles that a User Is registered for, and pass that through to me view as well, So that I can know not to display roles in a box of available roles which the user is already registered for.
How can I do this?
I see two options:
Some how using linq statement to try and get the data in one go,
or
To pass the full model of roles through and and array of roles that the user is registered for and then I am able to display either or etc in the view?
AUX Classes related to the Usermodel:
public class UsersModel : DbContext
{
public UsersModel()
: base("name=UsersConnection")
{}
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Roles> UserRoles { get; set; }
public DbSet<UsersInRoles> UsersInUserRoles { get; set; }
}
and
public class UsersInRolesViewModel
{
public IList<UserProfile> UserProfiles { get; set; }
public IList<Roles> UserRoles { get; set; }
public IList<ut_GMUTempData> GMUTempData { get; set; }
}
This is a recurring question.
Look at my answer to this SO question: Getting values of check-box from formcollection in asp.net mvc
If that's not clear enough, please, leave a comment.
If you just need roles of the logged in user and you use the default simple membership of Internet Application template, you doesn't need model binding at all. You can retrieve roles of the logged in user in your view like the following:
#{
// r will be a string[] array that contains all roles of the current user.
var r = Roles.GetRolesForUser();
}
and if you want to retrieve roles of any other user, just put the username into that method:
#{
// r will be a string[] array that contains all roles of the entered username.
var r = Roles.GetRolesForUser("username");
}
in this case, you just need to send the username to your model.
Update:
And if you have UserID, you can retrieve username as the following:
#{
SimpleMembershipProvider provider = new SimpleMembershipProvider();
string uname = provider.GetUserNameFromId(id);
// r will be a string[] array that contains all roles of the entered username.
var r = Roles.GetRolesForUser(uname);
}
Related
I know this is an old question, but could not find an answer for ASP.Net Core. I have ASP.Net Core web api application with role-based membership. Suppose we have an enitity from database with such fields:
public class Transaction
{
public int Id { get; set;}
public string UserId { get; set; }
public string ManagerId { get; set; }
public decimal Amount { get; set; }
}
And controller action:
[Authorize(Roles = "Admin,Manager,RegularUser")]
public async Task<IActionResult> Transactions(TransactionsRequest request)
{
var response = await _repository.Find(request, User);
return Ok(response);
}
My goal is to query and return partial result based on a role:
For Admin role I need to return all transations with all fields
For Manager role I need to return trasactions for current manager (based on managerId) without UserId field
For RegularUser role I need to return trasactions for current user (based on userId) without ManagerId field
I think it is simple to make three different actions, each one for specific role. But what if my role number will grow?
I know I can validate a model object by implementing IValidateObject but unfortunately this doesn't give you the nice errors that state the line and the type that has failed json validation when converting the json request to the object when your controller is decorated with the FromBody attribute.
My question is, is it possible to validate an objects properties conditionally in an ApiController and get the nice error format you get for free? As an arbitrary example, say the Account class below needed to validate Roles had more than one item if IsAdmin was true?
public class Account
{
[JsonRequired]
public bool IsAdmin { get; set; }
public IList<string> Roles { get; set; }
}
is it possible to validate an objects properties conditionally in an ApiController and get the nice error format you get for free? As an arbitrary example, say the Account class below needed to validate Roles had more than one item if IsAdmin was true?
Try this:
1.Controller(be sure to add [ApiController] otherwise you need to judge the ModelState):
[Route("api/[controller]")]
[ApiController]
public class ValuesController : Controller
{
[HttpPost]
public IActionResult Post([FromBody]Account account)
{
return Ok(account);
}
}
2.Model:
public class Account: IValidatableObject
{
[JsonRequired]
public bool IsAdmin { get; set; }
public IList<string> Roles { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var count = 0;
if (IsAdmin == true)
{
if (Roles != null)
{
foreach (var role in Roles)
{
count++;
}
}
}
if (count <= 1)
{
yield return new ValidationResult(
$"Roles had more than one item", new[] { "Roles" });
}
}
}
I've got a model that represents a joint table (with payload) in my database:
public class UserHasCar
{
// Foreign keys
[Key, Column(Order = 0)]
public string ApplicationUserId { get; set; }
[Key, Column(Order = 1)]
public int CarId { get; set; }
// Navigation properties
[Required]
public virtual ApplicationUser ApplicationUser { get; set; }
[Required]
public virtual Car Car{ get; set; }
// Additional fields
public int YearsRidden { get; set; }
}
public class Car
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<UserHasCar> UserHasCars { get; set; }
}
public class ApplicationUser : IdentityUser
{
public int BirthYear{ get; set; }
public virtual ICollection<UserHasCar> UserHasCars { get; set; }
}
I have a form that includes multiple select boxes, and upon submitting I want to clear out all records related to that user who submitted the form in the UserHasCar table and replace them with the new updated information. I'm getting a An entity object cannot be referenced by multiple instances of IEntityChangeTracker. because I am doing something wrong, but I don't see where I am using more than one context. This code happens in my controller:
public ApplicationUser GetCurrentUser()
{
return UserManager.FindById(User.Identity.GetUserId());
}
public string GetUserId()
{
string id = User.Identity.GetUserId();
var user = UserManager.FindById(id);
return user.Id;
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ManageCars(FormCollection form)
{
string id = GetUserId();
// Remove cars records with my id from database
var queryCars = (from m in db.UserHasCars where m.ApplicationUserId == id select m).ToList();
foreach (var record in queryCars )
{
// Could the problem be here?
db.UserHasCars.Remove(record)
}
// Add user-submitted cars to the database
string carval = form["Cars[0]"];
Car car = (from m in db.Cars where m.Name == carval select m).First();
int carid = car.ID;
// I get the abovementioned title error here
db.UserHasCars.Add(
new UserHasCar()
{
ApplicationUser = GetCurrentUser(),
ApplicationUserId = id,
Car = car,
CarId = carid,
YearsRidden = 0
}
);
db.SaveChanges();
}
I've seen many SO posts, but can't seem the problem as why my code doesn't want to save the new database entries.
EDIT
The solution was to remove the call to get the user and replace it with a query. Why? I was making database conflict errors by having both types of calls (database and DataManager calls in the same controller action). I ended up using a modified GetUser() function instead of GetCurrentUser()
Code:
public ApplicationUser GetUser()
{
// As opposed to:
// UserManager.FindById(User.Identity.GetUserId())
// We make a database call to grab our user instead
// So we don't get database context conflicts by using UserManager
string id = GetUserId();
return db.Users.Where(m => m.Id == id).First();
}
public string GetUserId()
{
return User.Identity.GetUserId();
}
// snip
// in ManageCars(FormCollection form)
ApplicationUser user = GetUser();
// snip
var newRow = db.UserHasCars.Create();
newRow.ApplicationUser = user;
// snip
db.UserHasCars.Add(newRow);
Try removing this line:
ApplicationUser = GetCurrentUser(),
from your object instantiation when adding.
Entity populates this object automatically once you set the foreign key ApplicationUserId. If UserManager.FindById(User.Identity.GetUserId()) uses a different db context that's where your exception is coming from.
Also to save yourself further trouble down the line, you should always call db.SaveChanges() in between the two operations. If you're worried about the atomicity of the db operation, just wrap the whole thing in a Transaction.
And when adding new rows to a table, I usually prefer to use something like:
var newRow = db.SomeTable.Create();
newRow.SomeColumn1 = "something";
newRow.SomeColumn2 = 5;
db.SomeTable.Add(newRow);
db.SaveChanges();
In order to delete entries from UserHasCars you need to change their EntityState to Deleted.
Example:
foreach (var record in queryCars )
{
db.ObjectStateManager.ChangeObjectState(record, EntityState.Deleted);
}
Hope this will fix your issue.
I have a razor .cshtml view in MVC4 and I want to print a field of my userprofile class. I understand I can get the Username from User.Identity.Name but I don't know how to access the other properties of the currently logged in user in the partial. Do I need to do this in my controller and reference it in my view? If so is there a controller that is available to all views so I am not setting this variable in every controller? Is there a simple way to access the current users properties as defined in the UserProfile model class right in the view? To give some context. I have my model as...
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
//Added to round out requirements for site user profile
public string FirstName { get; set; }
public string LastName { get; set; }
public string Site { get; set; }
}
I need to access the FirstName in the view. If I get it in the controller then I will need to do it in all controllers since this is a page partial for all pages.
I decided to put it in a session variable since it is not critical, sensitive, or effects the stability of the application. In my controller on login or registration I set the session variable with...
var context = new UsersContext();
var curuser = context.UserProfiles.First(p => p.UserName == model.UserName);
Session["FName"] = curuser.FirstName;
I got this from Pro ASP.NET MVC and from this post. And in my Razor view I use this derived from this post.
#HttpContext.Current.Session["FName"].ToString()
In the controller action that is serving the partial view put FirstName in the ViewBag.
If there are more properties that you would like to return then create a ViewModel for them and make the controller action return that.
I would like to have a reference between two entities stored in the RavenDB document database. Since this is not a relational db I know that I am supposed to use the Denormalized Reference technique described on RavenDBs documentation. Whilst at first this seems fine, once I start to create a real-world domain ‘hierarchy’ including bidirectional references the effort of keeping all those references up to date feels disproportionate. I feel I may be going wrong somewhere.
Can you explain the best / simplest way to model a reasonably complex domain hierarchy using RavenDB?
Thanks
I am not sure whether this will go far enough to answer your question but here is how I go about creating a Denormalized Reference in RavenDB (this is taken from real code with non-essentials removed for clarity)
Domain
public class User : IUserIdentity
{
public string UserName { get; set; }
public IEnumerable<string> Claims { get; set; }
public string Id { get; set; }
public Guid FormsAuthenticationGuid { get; set; }
}
public class Assessment
{
public string Id { get; set; }
public UserReference User { get; set; }
public AssessmentState State { get; set; }
}
You can see that I have a Assessment class that references a User. This user reference are managed using the UserReference class below.
Denormalized Reference
public class UserReference
{
public string Id { get; set; }
public string UserName { get; set; }
public static implicit operator UserReference(User user)
{
return new UserReference
{
Id = user.Id,
UserName = user.UserName
};
}
}
Note how the reference class also carries the UserName. This value will not change very often but it may change so we need a way to update the UserName property in the UserReference property held in the Assessment class. To make the change we must first find the correct Assessment instances from RavenDB and for that we need an index.
Raven Index
public class Assessment_ByUserId : AbstractIndexCreationTask<Assessment>
{
public Assessment_ByUserId()
{
Map = assessments => from assessment in assessments
select new
{
User_Id = assessment.User.Id
};
}
}
This index needs to be invoked whenever a User's UserName value is updated. I have a UserService class that helps me co-ordinate all my User related functions, so that is where I put this code.
I reuse this code for other references so it has been abstracted out a little. This may help you create the more complex hierarchies (or perhaps 'domain graph' is a better description) you want.
UserService
public static void SetUserName(IDocumentSession db, string userId, string userName)
{
var user = db.Load<User>(userId);
user.UserName = userName;
db.Save(user);
UpdateDenormalizedReferences(db, user, userName);
}
private static void UpdateDenormalizedReferences(IDocumentSession db, User user, string userName)
{
db.Advanced.DatabaseCommands.UpdateByIndex(
RavenIndexes.IndexAssessmentByUserId,
GetQuery(user.Id),
GetUserNamePatch(userName),
allowStale: true);
}
private static IndexQuery GetQuery(string propertyValue, string propertyName = "User_Id")
{
return new IndexQuery {Query = string.Format("{0}:{1}", propertyName, propertyValue)};
}
private static PatchRequest[] GetUserNamePatch(string referenceValue, string referenceName = "User")
{
return new[]
{
new PatchRequest
{
Type = PatchCommandType.Modify,
Name = referenceName,
Nested = new[]
{
new PatchRequest
{
Type = PatchCommandType.Set,
Name = "UserName",
Value = referenceValue
}
}
}
};
}
That is it. And you know, now that I lay it all out I can see what you mean. It is a lot of work just to update a reference. Perhaps the Service code can be made more DRY and reused for different relationship types, but I don't see how to get away from writing lots of indexes, one per referenced type.