How to write a query to check database value with session value - c#

Can anyone help me? I am taking a session value in variable like
var user = Session["UserName"];
and by this i will get username of an employee who is logged in. Now I want designation of that employee so I wrote
var data=from u in db.EmployeeTabs.Where(p=>p.EmpName==user).Select(v=>v.Designation)
Now variable data will probably contain the designation of employee who is logged in. Now I want a condition, based on the condition I want to redirect the page so I want an if condition like
if(val(data)=="Receptionist")
then it should display a Register.cshtml page, so for that what should I write?
And where to write? Means in an controller? Or i should create some method in controller?

I would recommend reading this tutorial Making some assumptions about your code, I think you want something like
public ActionResult Index()
{
var user = Session["User"];
using (var db = new YourEntity())
{
var data = from u in db.EmployeeTabs.Where(p => p.EmpName == user).Select(v => v.Designation);
if (data == null)
{
return RedirectToAction("Register");
}
Switch(data.First().Designation)
{
case "Receptionist":
return RedirectToAction(Register);
}
}
return View();
}
public public ActionResult Register()
{
return View();
}

Related

Keep data stored in Session alive

I have troubles managing data fetched by users on my app.
So far, if my understanding of ASP.NET MVC is what I think it is, I cannot put fetched data in static fields. For example, it would be a bad idea to do this:
private static List<MyObjects> listObjects = new List<MyObjects> { get; set;}
public List<MyObjects> GetMyObjects (int _objectID)
{
using(MyDatabase database = new MyDatabase())
{
listObjects = (from o in database.MyObjects
where o.MatchingID == _objectID
select o).ToList();
return listObjects;
}
}
Because that would make the list of data available to all users on the web site. So I've read a few things and I thought that I needed to put things into MVC Session dictionary so that each user would browse through their own lists.
So I have these methods:
public List<MyObjects> GetMyObjects (int _objectID)
{
using(MyDatabase database = new MyDatabase())
{
List<MyObjects> listObjects = (from o in database.MyObjects
where o.MatchingID == _objectID
select o).ToList();
return listObjects;
}
}
[HttpGet]
public ActionResult SeeItemsByID(int? _objectID)
{
// Pre-validations to make sure that the ID is valid, then:
List<MyObjects> listObjects = GetMyObjects((int)_objectID);
Session["myObjects"] = listObjects;
return RedirectToAction("SeeItems");
}
[HttpGet]
public ActionResult SeeItems()
{
List<MyObjects> listObjects = Session["myObjects"] as List<MyObjects>;
if(listObjects == null)
{
return RedirectToAction("Home");
}
return View(listObjects);
}
[HttpGet]
public ActionResult SeeItemsCompact()
{
List<MyObjects> listObjects = Session["myObjects"] as List<MyObjects>;
if(listObjects == null)
{
return RedirectToAction("Home");
}
return View(listObjects);
}
So let's resume the process:
First the user clicks on a link which calls the SeeItemsByID action, then it is redirected to the SeeItems action. In this view the user may click on a link to see the result "compacted" for any reasons. However, in my app, when the SeeItemsCompact method is called right after, all the Session data is lost.
How? And how could I keep this data alive?
Is ID specific to the user? Is the list so big that this even makes sense? (it rarely does and if it does, you'll want to implement paging at the server to reduce the time of retrieval)
If it were me, I'd serialize the data to a file based on ID then when the user comes back and the session has expired, you don't need to re-retrieve the data. You can check the timestamp on the file and reload the data if the timestamp is too old.

persisting dropdownlist between mvc post if the ModelState is Invalid

I have a simple form which saves the following entity
public class TravelInfo{
public int ID {get;set;}
public string CentreCode {get;set;}
public DateTime TravelDate {get;set;}
}
I have the standard 2 create methods in my controller - 1 get 1 post and am using this viewmodel to get stuff into the view.
public class TravelInfoVM{
public TravelInfo TravelInfo{get;set;}
public IEnumerable<SelectListItem> Centres {get;set;}
}
Controller methods...
public ActionResult Create(){
var CentresList = db.Centres.Select(c=> new SelectListItem {Text = c.Name, Value = c.Code}).ToList();
TravelInfoVM = new TravelInfoVM(){Centres = CentresList};
return View(TravelInfoVM);
}
[HttpPost]
public ActionResult Create(TravelInfoVM model){
//the Centres part of the model at this point is empty
if(ModelState.IsValid){
//save
//redirect
}
//do i **REALLY** have to get it again as below, or can I hold on to it somehow?
model.Centres = db.Centres.Select(c=> new SelectListItem {Text = c.Name, Value = c.Code}).ToList();
return View(model);
}
the question is, do I really need to do a second round trip to the DB to get the list of Centres if the ModelState comes back as invalid? or is there a better/different way to persist this list across posts, until the user correctly enters the details required to save..? or do i have completely the wrong end of the stick..
Not without adding it to the session, which is an inappropriate use of the session. Otherwise, each request is a unique snowflake, even if it seems like it's the same because you're returning the same form with errors.
I wouldn't worry about this. It's just one query, and since it's the same query already issued previously, it will very likely (or at least could be) cached, so it may not actually hit the database, anyways.
One thing I would recommend though is abstracting the query so that your GET and POST actions will simply call a function that won't change, and if you need to make a change to how the select list is created, you just do it in one place:
internal void PopulateCentreChoices(TravelInfoVM model)
{
model.Centres = db.Centres.Select(c=> new SelectListItem {Text = c.Name, Value = c.Code}).ToList();
}
...
public ActionResult Create(){
var model = new TravelInfoVM();
PopulateCentreChoices(model);
return View(model);
}
[HttpPost]
public ActionResult Create(TravelInfoVM model){
if(ModelState.IsValid){
//save
//redirect
}
PopulateCentreChoices(model);
return View(model);
}

Model binder to decrypt string and convert to int

I have a model which has a property id of type int.
I pass the id in the url like Detail/20 for fetching the data. But, now my customer says they don't want to see the id, since any one can modify and see other records.
Now, I've decided to encrypt and decrypt it, and assign it to another property: encId.
public ActionResult List()
{
foreach(Employee e in empList)
{
e.encId = MyUtil.Encrypt(id,"sessionid");
}
return View(empList);
}
Finally, I make my url like Detail/WOgV16ZKsShQY4nF3REcNQ==/.
Now, all I need is to decrypt it back to the original form and assign it to the property id of type int.
public ActionResult Detail(int id) //don't want (string id)
{
}
How can I write my model binder that decrypt and convert it to valid id? Also if any error/exception occurs, it has to redirect to 404 Error page. It might happen when user manually edits some useless text in the url (encrypted id).
First, this is not the way to go about securing your website and data. Please take a look at the issues with Security Through Obscurity. You would be better off defining sets of permissions on each employee record and who can or cannot edit them. Such an example could look like this:
public ActionResult Detail(int id)
{
if(MySecurityProvider.CanView(id, HttpContext.Current.User.Identity.Name){
return View();
}
Return RedirectToAction("PermissionIssue", "Errors");
}
With that said, to continue on the path you are on, simply do the decryption within the action result.
public ActionResult Detail(string Id)
{
int actualId;
try{
actualId = MyUtil.Decrypt(id);
}catch(Exception e){
//someone mucked with my encryption string
RedirectToAction("SomeError", "Errors");
}
var employee = MyEmployeeService.GetEmployeeById(actualId);
if(employee == null){
//This was a bad id
RedirectToAction("NotFound", "Errors");
}
Return View(employee);
}

Grabbing the ID value from a drop down list in mvc

The big picture is this: when a user logs in, they can select an "organization" to log into from a drop down list, which has a unique ID # for each organization. When the user logs in, I want to grab their ID # from my people table. The problem is, the person could be in the table twice, like this:
ID Name OrgID
1 Brandon 1
2 Brandon 2
So, to grab the appropriate person ID, I need to check against the OrgID also. Here is what I've got in my GET method:
public ActionResult Index()
{
ViewBag.Organization = new SelectList(db.Organizations, "OrgID", "OrgName");
return View();
}
Here is my POST method:
[HttpPost, ActionName("Submit")]
public ActionResult SubmitPost(string LoginNID, string LoginPassword, LoginViewModel model)
{
//Create new instance of ActiveDirectoryHelper to access its methods
ActiveDirectoryHelper login = new ActiveDirectoryHelper();
//Get Username and Password from forms
String Username = LoginNID;
String Password = LoginPassword;
int OrgID = model.Organizations.OrgID;
//ViewBag initialization for error message
ViewBag.NumTimes = 0;
ViewBag.Message = "Error logging in, please try again.";
//LDAP Authentication
bool LoginPassed = login.IsAuthenticated(Username, Password);
int Organization = organizations.OrgID;
//if Authentication Success enter site, otherwise Return error message
if (LoginPassed == true)
{
//grabs the one person from the People model whose NID is == to Username
var peopleModel = db.People.Single(g => g.NID == Username);
//grabs the peopleID for use in making a session variable
var peopleID = peopleModel.PeopleID;
//sets a session variable to be used that is the logged in person's ID
Session["peopleID"] = peopleID;
return View("LoginSuccess");
}
else
{
ViewBag.NumTimes = 1;
ViewBag.Organization = new SelectList(db.Organizations, "OrgID", "OrgName", organizations.OrgID);
return View("Index");
}
}
Here is my ViewModel:
public class LoginViewModel
{
public Music.Models.Organizations Organizations { get; set; }
}
Any ideas as to how I can get the organization's ID # and then select the unique person ID # so I can make that a session variable? Thanks much!
Edit: updated code to reflect changes I've made from answers provided.
You can create a class of something like session information with the id to capture that immediately after login. Have your login perform login verification, then route to the session info page where you select the organization based off users available organization. Pass that to your helper class that stores it in session information.
Edit
After re-reading your question you can provide a list of organizations at the login page and do a verification against whatever you are doing currently and ensuring it matches organization too so it is only one screen.
public class LoginCredential
{
public string UserName { get; set; }
public string Password { get; set; }
public int OrganizationId { get; set; }
}
public ActionResult Index()
{
ViewBag.Organizations = new SelectList(db.Organizations, "OrgID", "OrgName");
return View();
}
Make the model for your login page a login credential
#model MyProject.Models.LoginCredential
Then when you do a submit from your form it will pass in the selected options.
[HttpPost, ActionName("Submit")]
public ActionResult Login(LoginCredential credentials)
{
String Username = credentials.UserName ;
String Password = credentials.Password ;
Int OrganizationId = credentials.OrganizationId;
/// Rest of your code goes here
}
After creating a ViewModel based on kadumel's answer, I was still getting the same error as before. Since the username and password were both getting posted back from the view, I only needed 1 model to be used by the view to get the OrgID. What I did was change the #model directive in my view to this:
#model Music.Models.Organizations
and then changed the parameters in my POST to:
public ActionResult SubmitPost(Organizations model, string LoginNID, string LoginPassword)
From there, I was able to get the OrgID by doing this:
int OrgID = model.OrgID;
From debugging, OrgID is finally getting the correct value, and it says that the value of "model" is no longer null. While this works, I'm not completely sure why, since I would think that using a ViewModel would do just the same thing because my ViewModel contained the Organizations model.
EDIT: I figured out why this was working and using a ViewModel didn't seem to: in my view I had
#Html.DropDownList("Organization", ViewData["Organizations"] as SelectList, "--Select Organization--")
The first parameter, "Organization" is nothing in my model, so of course the model was going to return null and not give me the ID. When I changed it to:
#Html.DropDownList("OrgID", ViewData["Organizations"] as SelectList, "--Select Organization--")
It passed back the ID and I was good to go.

ASP.NET MVC: Ignore field(s) when editing

As I'm in the progress of learning ASP.NET MVC, I ran into a question and into some trouble
I'm trying to create a simple blog, just to test out what I have learned so far. But when it comes to editing and leaving a field i run into a problem.
I'm trying to edit an already submitted post on my blog, the post contains few fields: Id, Headline, Message, Author and Date for the submission which should not be edited, just left as it is.
Here is some code:
My post model:
namespace MyBlock.Models
{
public class Post
{
public int Id { get; set; }
[Required]
public string Author { get; set; }
[Required]
public string Headline { get; set; }
[Required]
public string Message { get; set; }
public DateTime Date { get; set; }
}
}
My edit:
[HttpGet]
public ActionResult Edit(int id = 0)
{
Post post = db.Posts.Find(id);
if (post != null) {
return View(post);
}
return HttpNotFound();
}
[HttpPost]
public ActionResult Edit(Post post)
{
if (ModelState.IsValid) {
db.Entry(post).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View(post);
}
And my view for edit:
#model MyBlock.Models.Post
#{
ViewBag.Title = "Edit";
}
<h2>Rediger "#Model.Headline"</h2>
#using (Html.BeginForm()) {
#Html.LabelFor(u => u.Author)
#Html.TextBoxFor(u => u.Author)
#Html.LabelFor(u => u.Headline)
#Html.TextBoxFor(u => u.Headline)
#Html.LabelFor(u => u.Message)
#Html.TextAreaFor(u => u.Message)
<input type="submit" value="Gem" />
}
I know I could throw in a #HiddenFor(u => u.Date) and the same date would be submitted. But I bet there is another way than having it as a hidden field in the source code? I mean this isn't that secure in another example? So I want something else than hidden field here. Can you guys help me out?
If I try to run this as it is. I'm getting an error which is my Date isn't set, which is logic because it want to update that one aswell. But I dont want it to. I want to leave it optional if you could say that.
Don't take candy from strangers
In other words, don't take the information from the client and directly update the DB. You should enforce your business rules on the server side and not trust the client to do it for you.
[HttpPost]
public ActionResult Edit(Post post)
{
if (ModelState.IsValid) {
var dbPost = db.Posts.FirstOrDefault(p => p.Id == post.Id);
if (dbPost == null)
{
return HttpNotFound();
}
dbPost.Author = post.Author;
dbPost.Message = post.Message;
dbPost.Headline = post.Headline;
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View(post);
}
[HttpPost]
public ActionResult Add(Post post)
{
if (ModelState.IsValid) {
var dbPost = db.Create<Post>();
dbPost.Author = post.Author;
dbPost.Message = post.Message;
dbPost.Headline = post.Headline;
dbPost.Date = DateTime.Now(); // Don't trust client to send current date
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View(post);
}
In my own project I enforce rules like this at the domain layer by adding custom validation rules to the ValidateEntity method.
DateTime is a value type, and cannot be null. Thus, it can never be optional.
You need to make a it a nullable type. ie.
public DateTime? Date {get;set;}
In general, most value types in a ViewModel should be nullable, then you use Required attributes to enforce that they contain a value. This allows you to tell whether they failed to enter a value, or whether it's a default value.
In your controller, you can then check if the Date has a value with Date.HasValue and if so, then save the date.
In regards to security, in this case it's not raelly an issue. Assuming someone has access to the page (they pass authorization) and they have the right to update the date, then it doesn't matter if the user can bypass it. All they can do is submit a valid date format. Unless you want to add logic to ensure that the date is within a specific time period, then you don't have to worry. The ModelBinder will not bind to a non-valid date format.
If you want to control whether the user can update the date, say based on role, then you could add logic to your controller to check if the date has a value and the user is in the correct role, otherwise issue an error.
UPDATE:
I think the easiest solution here is to do two things. The first is to make Date nullable, as I mention above. Although this is not strictly necessary if you do not have a form field for Date in your view, if you were to add a form field later then you would get a validation error if you left the textbox empty. I like to prevent future errors from occurring if possible. Also, should someone be posting values to your Edit action manually, and they include a blank Date field, it will fail to validate, rather than simply ignore it. Making the value nullable allows the value to be completely ignored regardless of its value.
Second, is do what #p.s.w.g suggests, and only update the fields that you want updated. Retrieve the post from the database, then update all fields except Id and Date. Then call SaveChanges().
Just my 2cents here. I know this is a simple situation and the answer given is nice and straightforward. But as that list of attributes grows then it could get difficult.
So a different approuch would be along these lines
var t = _db.Blog.Where(x => x.ID == id).FirstOrDefault();
var info = typeof(Blog).GetProperties();
//properties you don't want to update
var properties = info.Where(x => x.Name != "xxx" && x.Name != "xxxx").ToList();
foreach(var p in properties)
{
p.SetValue(t, p.GetValue(temp.Volunteer));
}
_db.Entry(t).State = EntityState.Modified;
_db.SaveChanges();
But if you are just doing a few fields then the above makes sense.
Just use your noggin!

Categories

Resources