LINQ Select one field based on query from a different column - c#

I am trying to retrieve a field from my database based on the user.identity.name. I have tried the following but I can't seem to get a result for either UserName or CustomerId, but I do get "jmcgee" for User.Identity.Name. So dealerId ends up beging null, when I want it to return CustomerId (01d1).
What am I doing wrong? It looks like I have everything set up the same as other questions/examples here, msdn, etc.
UserProfile Table: UserName = jmcgee; CustomerId= 01d1
var dealerId = db.UserProfiles
.Where(d=>d.UserName.Equals(User.Identity.Name))
.Select (d=>d.CustomerId);
or
var dealerId = from d in db.UserProfiles
where d.UserName == User.Identity.Name
select d.CustomerId;
or
var dealerId = (from d in db.UserProfiles
where d.UserName == User.Identity.Name
select d.CustomerId).SingleOrDefault();
I've also tried FirstOrDefault to no avail, but that might be my lack of understanding how to set it up. I've even tried replacing User.Identity.Name with "jmcgee" just to see if that would work.
Here's more of the code (let me know if something else needed is missing and I'll add it):
Controller
TintagliaContext db = new TintagliaContext();
public ActionResult OpenQuotes(string searchString, string excludeString, string modelFilter, int? page)
{ // var dealerId = "01D1628";
var dealerId = (from d in db.UserProfiles
where d.UserName == User.Identity.Name
select d.CustomerId).SingleOrDefault();
string context = _customerRepository.GetContext(dealerId);
Tintaglia.Models.Filter filter;
if (context == "coverpools")
{
filter = new Tintaglia.Models.Filter { IsSubmitted = false, Order = quote => quote.Date_Created, SearchString = searchString, ExcludeString = excludeString };
}
else
{ filter = new Tintaglia.Models.Filter { IsSubmitted = false, DealerId = dealerId, Order = quote => quote.Date_Created, SearchString = searchString, ExcludeString = excludeString };
}
var quotes = _configurationRepository.GetQuotes(filter);
var model = new List<ConfigurationViewModel>();
foreach (var quote in quotes)
{
var viewModel = new ConfigurationViewModel();
viewModel = viewModel.MapModelToViewModel(quote);
model.Add(viewModel);
}
ViewData.Model = model.ToPagedList(page ?? 1, 20); ;
return View();
}
ICustomerRepository
namespace Infotech.Coverpools.Portal.Tintaglia.Repositories.Interfaces
{
public interface ICustomerRepository
{
string GetContext(string dealerId);
//bool Login(string userName, string password);
}
}
_customerRepository
namespace Infotech.Coverpools.Portal.Tintaglia.Repositories
{
public class CustomerRepository : ICustomerRepository
{
//public string GetContext(string dealerId)
public string GetContext(string dealerId)
{
using (var db = new TintagliaContext())
{
var customer = db.Customers.FirstOrDefault(x => x.No_ == dealerId);
return customer.Internal_Login == 1 ? "coverpools" : "default";
}
}
}
}
TintagliaContext
namespace Infotech.Coverpools.Portal.Tintaglia.CodeFirst.Models
{
public partial class TintagliaContext : DbContext
{
static TintagliaContext()
{
Database.SetInitializer<TintagliaContext>(null);
}
public TintagliaContext()
: base("TintagliaContext")
{
}
public DbSet<Configuration> Configurations { get; set; }
public DbSet<Customer> Customers { get; set; }
//New for Account Module
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<webpages_UsersInRoles> webpages_UsersInRole { get; set; }
// public DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ConfigurationMap());
modelBuilder.Configurations.Add(new CustomerMap());
}
}
}

Related

HomeController (String[]) Method is not Valid in Given Context (ASP.Net MVC C#)

I'm currently building a program that processes tickets (agile) in different stages. For some reason I'm having a hard time resolving an error with my home controller and model references. I am being told that model.DueFilter = Filter.DueFilterValue is a method (Filter) which is not valid in the given context.
Below is my Home Controller:
public class HomeController : Controller
{
private TicketContext context;
public HomeController(TicketContext ctx) => context = ctx;
public IActionResult Index(string ID)
{
AgileViewModel model = new AgileViewModel();
var filter = new Filter(ID);
model.Filter = new Filter(ID);
model.Sprints = context.Sprints.ToList();
model.TicketStatuses = context.TicketStatuses.ToList();
model.DueFilter = Filter.DueFilterValue;
IQueryable<Ticket> query = context.Tickets.Include(t => t.Sprint).Include(t => t.TicketStatus);
if (filter.HasSprint)
{
query = query.Where(t => t.SprintID == filter.SprintID);
}
if (filter.HasTicketStatus)
{
query = query.Where(t => t.TicketStatusID == filter.TicketStatusID);
}
if (filter.HasDue)
{
var currentDate = DateTime.Today;
if (filter.isPast)
query = query.Where(t => t.Deadline < currentDate);
else if (filter.isFuture)
query = query.Where(t => t.Deadline > currentDate);
else if (filter.isToday)
query = query.Where(t => t.Deadline == currentDate);
}
var tasks = query.OrderBy(t => t.Deadline).ToList();
model.Tasks = tasks;
return View(model);
}
}
Here is my Filter model:
public class Filter
{
public Filter(string filterstring)
{
FilterString = filterstring ?? "all-all-all";
string[] filter = FilterString.Split('-');
SprintID = filter[0];
Due = filter[1];
TicketStatusID = filter[2];
}
public string FilterString { get; }
public string SprintID { get; }
public string Due { get; }
public string TicketStatusID { get; }
public bool HasSprint => SprintID.ToLower() != "all";
public bool HasDue => Due.ToLower() != "all";
public bool HasTicketStatus => TicketStatusID.ToLower() != "all";
public static Dictionary<string, string> DueFilterValue =>
new Dictionary<string, string>
{
{"future", "Future" },
{"past", "Past" },
{"today", "Today" }
};
public bool isPast => Due.ToLower() == "past";
public bool isFuture => Due.ToLower() == "future";
public bool isToday => Due.ToLower() == "today";
}
Add lastly my ModelView:
public class AgileViewModel
{
public AgileViewModel()
{
CurrentTask = new Ticket();
}
public Filter Filter { get; set; }
public List<TicketStatus> TicketStatuses { get; set; }
public List<Sprint> Sprints { get; set; }
public Dictionary<string, string> DueFilter { get; set; }
public List<Ticket> Tasks { get; set; }
public Ticket CurrentTask { get; set; }
}

restricting access to a dropdownlist in C#

Hello I have a 'RestrictAccessController' That looks like this
public class RestrictAccessController : Controller
{
private PIC_Program_1_0Context db = new PIC_Program_1_0Context();
public ActionResult Index()
{
return View ();
}
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple=true)]
public class RestrictAccessAttribute : ActionFilterAttribute
{
private PIC_Program_1_0Context db = new PIC_Program_1_0Context();
public AccessRestrictions restriction { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
// here's where we check that the current action is allowed by the current user
if (!IGT.canAccess(IGT.userId, restriction, false))
{
string url = IGT.baseUrl+"/Home/NotAllowed";
string msg = "This page requires " + IGT.DisplayEnum(restriction) + " access";
filterContext.Result = new RedirectResult("~/Home/NotAllowed?msg="+HttpUtility.HtmlEncode(msg));
}
}
And a Config model that looks like this
public enum AccessRestrictions
{
[Display(Name = "Disposal Orders")]
ModifyDisposalOrder,
[Display(Name = "Admin")]
Admin
}
public class userAccess
{
[Key]
public int ID { get; set; }
public AccessRestrictions restriction { get; set; }
public bool allow { get; set; }
public int userID { get; set; }
}
public class configDetails
{
public int ID {get; set;}
public string Name {get; set;}
public string Value {get;set;}
public bool deleted {get;set;}
public DateTime updateTime { get; set; }
}
public class Config
{
public int ID { get; set; }
[Display(Name = "Configuration Date")]
public DateTime TargetDate { get; set; }
[Display(Name = "Enable Access Restrictions")]
public bool restrictAccess { get; set; }
}
What I want to do is edit what my 'ChangeStatus' dropdown looks like based on whether they have the Admin access restriction or not. Here is the controller method that I want to edit
[RestrictAccess(restriction = AccessRestrictions.ModifyDisposalOrder)]
public ActionResult ChangeStatus(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
DisposalOrder disposalOrder = db.disposalOrders.Find(id);
if (disposalOrder == null)
{
return HttpNotFound();
}
switch (disposalOrder.Status)
{
case DOStatus.Pending:
ViewBag.statusList = new List<Object>
{
new {value = DOStatus.Pending, text = "Pending"},
new {value = DOStatus.Disposed, text = "Disposed" }
};
break;
case DOStatus.Disposed:
// if(restriction = AccessRestrictions.ModifyDisposalOrder)
ViewBag.statusList = new List<Object>
{
new {value = DOStatus.Pending, text = "Pending"},
new {value = DOStatus.Disposed, text = "Disposed" }
};
//else
//{
// new { value = DOStatus.Disposed, text = "Disposed" }
// };
break;
};
return View(disposalOrder);
}
Here is my Startup file
public class LdapAuthentication
{
private string _adUser = ConfigurationManager.AppSettings["ADUserName"];
private string _adPW = ConfigurationManager.AppSettings["ADPassword"];
private string _domain = ConfigurationManager.AppSettings["ADDomain"];
public LdapAuthentication() {
}
public string authenticate(string username, string pwd)
{
using (var context = new PrincipalContext(ContextType.Domain, _domain, _adUser, _adPW)) {
//Username and password for authentication.
if (context.ValidateCredentials(username, pwd)) {
UserPrincipal user = UserPrincipal.FindByIdentity(context, username);
Internal internalUser = new Internal {
UserName = user.SamAccountName,
ContactName = user.DisplayName,
Email = user.UserPrincipalName
};
//Search if the user account already exists in the database
PIC_Program_1_0Context db = new PIC_Program_1_0Context();
Internal existing = db.Internals.Where(x => x.UserName == user.SamAccountName).FirstOrDefault();
// If it does not, create a new user account
if (existing == null) {
// add a new Internal entry for this user
existing = new Internal {
UserName = user.SamAccountName,
ContactName = user.DisplayName,
Email = user.UserPrincipalName
};
db.Internals.Add(existing);
db.SaveChanges();
// If it does exist, but some of the data does not match, update the data
} else if(existing != internalUser) {
existing.ContactName = internalUser.ContactName;
existing.Email = internalUser.Email;
db.SaveChanges();
}
return user.SamAccountName;
} else {
return null;
}
}
}
public UserPrincipal getUserPrincipal(string username)
{
using (var context = new PrincipalContext(ContextType.Domain, _domain, _adUser, _adPW))
{
return UserPrincipal.FindByIdentity(context, username);
}
}
Is it possible for me to accomplish this?
Ok, I think I understand your question now. You need to access the User's claims. MVC Controllers have this, half way, built in.
if (User.HasClaim("ClaimNameHere", "Admin"))
{
}
Solved by adding
if (IGT.canAccess(IGT.userId, AccessRestrictions.Admin, false))

ModelState Error c# mvc5

In an Action Result that does a HttpPost i get an error from EF
"ModelState.Errors Internal error in the expression evaluator"
My model in View is OrdineOmaggio
public partial class OrdineOmaggio
{
public int Id { get; set; }
public string Id_Gioielleria { get; set; }
public System.DateTime Data_Ordine { get; set; }
public virtual Consumatore MD_CONSUMATORE { get; set; }
public virtual Omaggio MD_OMAGGIO { get; set; }
public virtual CodiceRandomConsumatore MD_RANDOM_CONSUMATORE { get; set; }
}
My Action is so
public async Task<ActionResult> ChooseGift(
[Bind(Include ="Data_Ordine,MD_RANDOM_CONSUMATORE,MD_OMAGGIO,Id_Gioielleria")]
OrdineOmaggio ordineOmaggio,
string codiceOmaggio, string codice)
{
var randomConsumatore = _context.CodiciRandomConsumatori
.SingleOrDefault(c => c.Codice == codice) ??
new CodiceRandomConsumatore
{
Id = -1,
Codice = "",
Assegnato = null,
Distinzione = ""
};
var consumatore = _context.CodiciRandomConsumatori
.Where(c => c.Codice == codice)
.Select(c => c.MD_CONSUMATORE)
.SingleOrDefault();
var omaggio = _context.Omaggi
.SingleOrDefault(c => c.CodiceOmaggio == codiceOmaggio);
if (ModelState.IsValid)
{
ordineOmaggio.Data_Ordine = DateTime.Now;
ordineOmaggio.Id_Gioielleria = ordineOmaggio.Id_Gioielleria;
ordineOmaggio.MD_CONSUMATORE = consumatore; // FK
ordineOmaggio.MD_OMAGGIO = omaggio; // FK
ordineOmaggio.MD_RANDOM_CONSUMATORE = randomConsumatore; // FK
_context.OrdiniOmaggio.Add(ordineOmaggio);
randomConsumatore.Assegnato = true;
_context.SaveChanges();
return RedirectToAction("Success");
}
return View(ordineOmaggio);
}
The error is about dataAnnotation: it say that not all field all filled
The metadata is
public class OrdineOmaggioMetadata
{
[Required(ErrorMessage = "Scegli la gioiellereia.")]
public string Id_Gioielleria;
[Required(ErrorMessage = "Seleziona una foto.")]
public Omaggio MD_OMAGGIO;
...
}
In my view i placed
#Html.HiddenFor(m=> m.MD_OMAGGIO.CodiceOmaggio)
#Html.ValidationMessageFor(m => m.MD_OMAGGIO.CodiceOmaggio)
but this helper pass null to ActionResult
MD_OMAGGIO is a table foreign key for product codes.
what i wrong ?

Mapping string rules to LINQ expressions, including expressions containing own methods for authorisation

In an MVC app, I want to implement a set of rules, which super users can create, read, update and delete.
Each rule explicitly allows/forbids a user to perform an action in the format:
<Allow || Deny> userId <action_key> <condition>
The action key would be something like "DoSomeAction" as a string.
I then intend to use those rules for authorisation inside controllers for
authorisation. For example:
//GET ViewProduct/id
public ActionResult ViewProduct(string productId)
{
var product = // get product from repository;
if(RulesAuthorizer.Authorise("ViewProduct", User.Identity.GetUserId(), product){
//proceed to product... JSON or partial view, etc.
}
return new HttpStatusCodeResult(403);
}
ViewProduct is an example action_key above.
In the Authorise(string action_key, string userId, object ruleArg = null) method, I would load all the user relevant rules from the DB for this action key and decide if the user should be allowed.
However, and this is really the question, how could I use a condition for a rule as a string. For example, a condition would be:
a user must be a member of the group "Customers" and the product must not be of type "cheese" or
a custom method result such as if the product was added by group X, and group Y must not see it, I could have my method Product.GetAddedBy() and include this method in the LINQ expression.
How could I store such conditions as strings for each rule and then build LINQ expressions from them?
I intend to pass the object in question (Product in the example) in the optional ruleArg parameter.
Any ideas are much appreciated for a convenient way to store strings, which can be made into LINQ expressions at run time or any alternative approach such as perhaps map conditions to delegates with parameters?
Here is an example of user access via Attributes using strings to determine what they have access to. This is using Action/Controller to determine access but you can modify it for any string(s) you want.
Decorate the controller(s) with [AuthoriseByRole]
First the Attribute
namespace PubManager.Authorisation
{
public class AuthoriseByRoleAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized && httpContext.Request.IsAjaxRequest())
{
httpContext.Response.StatusCode = 401;
httpContext.Response.End();
}
if (isAuthorized)
{
var request = httpContext.Request;
var r = request.RequestContext.RouteData.Values["r"]
?? request["r"];
var currentUser = (UserModel) HttpContext.Current.Session["user"];
if (currentUser == null)
{
currentUser = HttpContext.Current.User.GetWebUser();
}
var rd = httpContext.Request.RequestContext.RouteData;
string currentAction = rd.GetRequiredString("action");
string currentController = rd.GetRequiredString("controller");
if (currentUser.HasAccess(currentController, currentAction))
return true;
}
httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return false;
}
}
}
Then the UserModel that is used to determine access:
namespace PubManager.Domain.Users
{
public class UserModel
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Title { get; set; }
[Required]
[DisplayName("Forename")]
public string FirstName { get; set; }
[Required]
public string Surname { get; set; }
[Required]
[DisplayName("Company name")]
public DateTime? LastLogin { get; set; }
public bool LockedOut { get; set; }
public DateTime? LockedOutUntil { get; set; }
public bool IsGlobalAdmin { get; set; }
public bool? IsSystemUser { get; set; }
public IEnumerable<RoleModel> Roles { get; set; }
public bool HasAccess(string controller, string view)
{
if (IsGlobalAdmin || IsSystemUser.Value)
{
return true;
}
var isAuthorized = false;
if (!Roles.Any())
return false;
foreach (var role in Roles)
{
if (role.PageToRoles == null)
return false;
foreach (var pg in role.PageToRoles)
{
if (pg.RolePage.Controller.Equals(controller, StringComparison.InvariantCultureIgnoreCase) && (pg.RolePage.View.Equals(view, StringComparison.InvariantCultureIgnoreCase) || pg.RolePage.View.Equals("*")))
isAuthorized = true;
}
}
return isAuthorized;
}
}
}
Finally the GetWebUser class to get the user
namespace PubManager.Domain.Users
{
public static class SecurityExtensions
{
public static string Name(this IPrincipal user)
{
return user.Identity.Name;
}
public static UserModel GetWebUser(this IPrincipal principal)
{
if (principal == null)
return new UserModel();
var db = new DataContext();
var user = (from usr in db.Users
where usr.UserName == principal.Identity.Name
select new UserModel
{
Title = usr.Person.Title,
UserName = usr.UserName,
FirstName = usr.Person.FirstName,
Surname = usr.Person.LastName,
Email = usr.Person.Email,
LockedOut = usr.LockedOut,
UserId = usr.UserId,
IsSystemUser = usr.IsSystemUser,
IsGlobalAdmin = usr.IsGlobalAdmin.Value,
PersonId = usr.PersonId,
Roles = from r in usr.UserToRoles
select new RoleModel
{
RoleId = r.RoleId,
PageToRoles = from ptr in r.Role.PageToRoles
select new PageToRoleModel
{
RolePage = new RolePageModel
{
Controller = ptr.RolePage.Controller,
View = ptr.RolePage.View
}
}
}
}).FirstOrDefault();
if (user != null)
{
HttpContext.Current.Session["user"] = user;
}
return user;
}
}
}

How can i get the correct information to display in my listbox?

I have two Listboxes where you can move exercises from an available list of exercises to a list of selected exercises for a specific user. My current problem is that my selected list (aka RegimeItems) shows the exercises for all of the users.
I believe the problem lies in ChosenExercises(at the bottom of controller) i am also getting a null reference exception at:
var regimeIDs = model.SavedRequested.Split(',').Select(x => int.Parse(x));
Controller.cs
[HttpGet]
public ActionResult ExerciseIndex(int? id, UserExerciseViewModel vmodel)
{
User user = db.Users.Find(id);
user.RegimeItems = ChosenExercises();
UserExerciseViewModel model = new UserExerciseViewModel { AvailableExercises = GetAllExercises(), RequestedExercises = ChosenExercises(user, vmodel) };
user.RegimeItems = model.RequestedExercises;
return View(model);
}
[HttpPost]
public ActionResult ExerciseIndex(UserExerciseViewModel model, string add, string remove, string send, int id)
{
User user = db.Users.Find(id);
user.RegimeItems = model.RequestedExercises;;
RestoreSavedState(model);
if (!string.IsNullOrEmpty(add))
AddExercises(model, id);
else if (!string.IsNullOrEmpty(remove))
RemoveExercises(model, id);
SaveState(model);
return View(model);
}
void SaveState(UserExerciseViewModel model)
{
model.SavedRequested = string.Join(",", model.RequestedExercises.Select(p => p.RegimeItemID.ToString()).ToArray());
model.AvailableExercises = GetAllExercises().ToList();
}
void RestoreSavedState(UserExerciseViewModel model)
{
model.RequestedExercises = new List<RegimeItem>();
//get the previously stored items
if (!string.IsNullOrEmpty(model.SavedRequested))
{
string[] exIds = model.SavedRequested.Split(',');
var exercises = GetAllExercises().Where(p => exIds.Contains(p.ExerciseID.ToString()));
model.AvailableExercises.AddRange(exercises);
}
}
private List<Exercise> GetAllExercises()
{
return db.Exercises.ToList();
}
private List<RegimeItem> ChosenExercises(User user, UserExerciseViewModel model)//RegimeItem regimeItem)
{
var regimeIDs = model.SavedRequested.Split(',').Select(x => int.Parse(x));
return db.RegimeItems.Where(e => regimeIDs.Contains(e.RegimeItemID)).ToList();
//return db.Users.Where(r => r.RegimeItems = user.UserID);
//return db.Users.Where(r => r.RegimeItems.RegimeItemID == user.UserID);
}
Models
public class User
{
public int UserID { get; set; }
public ICollection<RegimeItem> RegimeItems { get; set; }
public User()
{
this.RegimeItems = new List<RegimeItem>();
}
}
public class RegimeItem
{
public int RegimeItemID { get; set; }
public Exercise RegimeExercise { get; set; }
}
ViewModel
public class UserExerciseViewModel
{
public List<Exercise> AvailableExercises { get; set; }
public List<RegimeItem> RequestedExercises { get; set; }
public int? SelectedExercise { get; set; }
public int[] AvailableSelected { get; set; }
public int[] RequestedSelected { get; set; }
public string SavedRequested { get; set; }
}
Try changing
return db.Users.Where(r => r.RegimeItems = user.UserID);
to
return db.Users.Where(r => r.RegimeItems.RegimeItemID == user.UserID);
Because the way I read it you're currently trying to match an int with an object.
edit: Another error was resulted which the OP found himself.
"It seems that RegimeItems is a collection of RegimeItem - it does not have a have a single ID. So it needed to be .Where(u => u.UserID == user.UserID) and then to select the regimeItems associated with the user .SelectMany(u => u.RegimeItems).ToList(); Thanks for your help, if you update your answer with that i will mark yours as the correct answer." -Nilmag
Firstly, you're going to want to update the calls to ChosenExercises() in ExcerciseIndex(int? id) to pass in the user like this: ChosenExercises(user).
Secondly, the conversion error is because you are comparing r.RegimeItems to the User ID, which is an int. In order to return a list of regime items for the user you'll need to query the Excercises table, rather than the users table:
private List<RegimeItem> ChosenExercises(User user)//RegimeItem regimeItem)//User user, RegimeItem regimeItem)
{
var regimeIDs = user.SavedRequested.Split(',').Select(x=>int.Parse(x));
return db.RegimeItem.Where(e=> regimeIDs.Contains(e.RegimeItemID)).ToList();
}

Categories