I'm basically trying to create a class that holds all the session information, then set and get it at will.
here is my call Session["SessionInformation"] = new SessionVar.UserSession();
and here is that class
public static class SessionVar
{
public class UserSession
{
public string FullName
{
get;
set;
}
public string HomeURL
{
get;
set;
}
public bool ValidUser
{
get;
set;
}
public int CountID
{
get;
set;
}
}
}
Lets say in this example I have a comboBox called CountID_ComboBox and on SelectedIndexChanged I want to set the users specific Session["SessionInformation"] CountID to the value of the combobox. How is that done?
protected void CountID_ComboBox_SelectedIndexChanged(object sender, Telerik.Web.UI.RadComboBoxSelectedIndexChangedEventArgs e)
{
//set the session variable here
}
Also, is there a way to foreach loop the strings in the class. Basically I want to see if any of those variables in that class is null.
So you've created this strongly typed UserSession class to handle your session variables. That's nice, specially if you have a big project, with lots of forms and (junior) developers.
You already know the most important part: for each new session, we'll have one, and only one UserSession object.
Now, let's move on to the part where you actually use it. You can retrieve the object's reference using ((SessionVar.UserSession)Session["SessionInformation"]). Let's dive into it:
Session["something"] returns an object
You want your UserSession object
We cast it using ((SessionVar.UserSession)Session["SessionInformation"]) and your done!
Now, let's say that, later on, you decide to move that object from the session to the viewstate (I'm not saying that this is a good idea, mind you). If you have that code scattered around your project, then it'll be a pain to manage that change.
So, the idea is to have a base page, from which all your pages will inherit. Something like:
public class BasePage : System.Web.UI.Page
{
...
}
And you place the code to retrieve your UserSession there, like:
public class BasePage : System.Web.UI.Page
{
public UserSession CurrentUserSession
{
get
{
UserSession userSession = null;
if (Session["UserSession"] == null)
{
userSession = new UserSession();
Session["UserSession"] = userSession;
}
else
userSession = (UserSession)Session["UserSession"];
return userSession;
}
private set { }
}
}
Bonus: note that, on the code above, I'm suggesting a way to ensure that you get one and only one object for the current user.
Finally, in order to get a list of the string properties that are empty, you can use the following method (place it inside UserSession):
public List<string> GetEmptyStringAttributes()
{
List<string> emptyStringAttributes = new List<string>();
Type type = this.GetType();
foreach (System.Reflection.PropertyInfo property in type.GetProperties())
{
if (property.PropertyType == typeof(String))
{
string value = property.GetValue(this) as string;
if (string.IsNullOrWhiteSpace(value))
emptyStringAttributes.Add(property.Name);
}
}
return emptyStringAttributes;
}
}
In case you can't find the combo box from your code behind, I'll use sender just to be sure we have the correct control.
var cBox = (RadComboBox)sender;
(SessionVar.UserSession)Session["SessionInformation"].CountID = cBox.SelectedValue;
It seems like the root of your question is actually about casting.
Related
I'm working with C#. I have a Employee class and I'm getting employee data from a URL then I created a list named EmpList in another class which is being populated with that information. I'm not getting the location of each employee so I want to hard code the location by making a set location function in Employee class.
The name 'EmpList' does not exist in the current context.
I've tried to make setLocation function in CreateEmpList function and I got no error but location was empty.
I know I'm probably doing something silly but I really need some help here. I really appreciate that.
Thankyou.
This is my employee class.
public class Employee
{
public string Name { get; set; }
public string Email { get; set; }
public Guid ID { get; set; }
public string Location { get; set; }
public void SetLocation()
{
foreach (var item in EmpList) // I'm getting error here
{
if (item.Email == "abc#gmail.com")
{
item.Location = "US";
}
}
And here I'm populating the list in another class.
private List<Employee> EmpList = null;
private void CreateEmpList(SPHttpClient client)
{
List<Employee> SortedList = new List<Employee>();
JObject jsondata = client.ExecuteJson(UriResources);
string strjsondata = jsondata.First.First.First.First.ToString();
JArray jsonArray = JArray.Parse(strjsondata);
foreach (var item in jsonArray) // Creating master resources list
{
ResourcesExcemptList.ForEach(i => i.ToLower());
if(!ResourcesExcemptList.Contains(item["ResourceEmailAddress"].
ToString().ToLower()))
{
if (Boolean.Parse(item["ResourceIsActive"].ToString()))
{
Employee emp = new Employee();
emp.ID = (Guid)item["ResourceId"];
emp.Email = item["ResourceEmailAddress"].ToString();
emp.Name = item["ResourceName"].ToString();
emp.Practice = item["ResourceGroup"].ToString();
emp.ApproverID =
(Guid)item["ResourceTimesheetManageId"];
SortedList.Add(emp);
}
}
}
EmpList= SortedList.OrderBy(o => o.Name).ToList();
//private void setLocation(){ }
}
The direct answer to your question
The main issue here is that you're not understanding how object oriented code works. You're not using this, and you seem to be confused when the class method will be executed and what that means.
Oddly, when in a class method, you still expect that you need to look through the list to find the correct object. That's the opposite of how you should approach it.
When an object's class method is being executed, you obviously already have found the object whose method you want to call. Because otherwise you wouldn't have been able to call that object's class method.
So what you need to do here is to iterate over the list before you call the object's class method, not after. Your Employee class:
public void SetLocation()
{
this.Location = "US";
}
And then:
private void CreateEmpList(SPHttpClient client)
{
// the rest of the code
EmpList = SortedList.OrderBy(o => o.Name).ToList();
foreach(var employee in EmpList)
{
employee.SetLocation();
}
}
Footnote
Your question shows a basic confusion on OOP principles, but the code itself shows a different level of grasp on OOP principles. I suspect that you didn't write this code yourself, but a colleague did.
I'm mentioning this because I noticed the comment in your example code:
//private void setLocation(){ }
Notice how its signature is that of a method definition, not that of a method call!
What I think has happened is that your colleague annotated the code and placed a reminder for you to create a method, and you've ended up implementing this method in the Employee class instead of in the other class (the one with the CreateEmpList method in it).
Creating the method in the other class makes a lot more sense than putting it in the Employee class. Something along the lines of:
public void SetLocation(Employee employee)
{
employee.Location = "US";
}
One possible solution, based on my comments:
Declare EmpList as:
public List<Employee> EmpList { get; private set;}
Then in your Employee class:
public void SetLocation()
{
var otherClassObj = new otherClassObj(); // Or perhaps some other way of getting the object of the other class.
otherClassObj.CreateEmpList(client); // You may have to change this.
foreach (var item in otherClassObj.EmpList)
{
if (item.Email == "abc#gmail.com")
{
item.Location = "US";
}
}
}
If your main concern is set location value and if empty then set hardcode value then consider this solution:
private string _location;
public string Location
{
get { return _location; }
set
{
if (string.IsNullOrEmpty(value))
{
_location = "US";
}
else
{
_location = value;
}
}
}
To answer your question: public void SetLocation(List<Employee> EmpList) allows the code inside SetLocation() to access the list object (passed by reference) but I doubt this is what you really want to do. (No offense;-)
Your logic isn't clear but surely within CreateEmpList(),
emp.Email = ...
if (emp.Email...) emp.Location = "..."
or within Employee, something like
public string Email { get {} set { Email = value; if (value...) Location = "..."; } }
I been search but have no luck with this, im trying to call a method in a class from a table in a DB this method call another that find a entry and fill the object however i want to pass this object to my instance of the class
public class ProductCategory
{
public int ProductCategoryID { get; set; }
public string Name { get; set; }
public Guid rowguid { get; set; }
public DateTime ModifiedDate { get; set; }
public void FindItem<T1>(T1 id)
{
try
{
var obj = Activator.CreateInstance(this.GetType());
obj = Dal.ObjFind(obj, id); //this fill the object
//i want something like
foreach properties in obj
this.propertie = obj.propertie
}
catch (Exception e)
{
throw e;
}
}
}
in a way that i can call that method like
ProductCategory test = new ProductCategory();
test.Find(1);
and after that my object is loaded, i would really appreciate any help with this and sorry for the bad English or if i not explain clearly
Regards
Ok i found a way to achieve as Pac0 say with reflection you can do this
public void FindItem<T1>(T1 id)
{
try
{
var obj = this;
// fill the object with the DB data
obj = Dal.ObjFind(new Production.ProductCategory(), id);
PropertyDescriptorCollection PropertyObj =
TypeDescriptor.GetProperties(this);
//iterating the properties in the instance of the class
foreach (PropertyDescriptor prop in PropertyObj)
{
//Get the value for each properties in the filled Obj
//and set that value for each properites in "this"
prop.SetValue (this,prop.GetValue(obj));
}
}
catch (Exception e)
{
throw e;
}
}
in that way you can call your instalce like "test.FindItem(1)" and the object will be load, thanks!
To get information at runtime about the some class durig runtime is called *reflection** (this term should help you in your searches)
To get all the properties of a Type, you can use Type.GetProperties() .
have a look at GetProperty as well.
With this, you should be able to achieve what you want.
However, I'm not convinced it's the simplest way to go. Probably someone will come up with a better way to solve your underlying issue.
I know this has been asked in several different ways, but I am not sure my specific problem has been asked. Due to Business rules, I can not use a db for temp storage of data between views. Static Variables are out (multi-user). I'm trying to avoid session and tempdata. I'll be storing about 9-12 models worth of data that will slow page load if I use Viewstate. I have multi-paged forms that will need to be refilled if the user returns to a form. I know this isn't the ideal way, but can anyone suggest a way to persist this data for multiple models other than session variables? Tempdata would need to be re-written per view I assume. I can't supply code and I know this is not a favorable design, but the rules are constricting.
Thank you.
I don't think there is anything wrong with using Session, even for MVC. It's a tool, use it when you need it. I find that most people tend to avoid Session because the code is usually pretty ugly. I like to use a Generic Wrapper around objects I need to store in session which provide a Strongly-Typed and Re-usable Class (example):
public abstract class SessionBase<T> where T : new()
{
private static string Key
{
get { return typeof(SessionBase<T>).FullName; }
}
public static T Current
{
get
{
var instance = HttpContext.Current.Session[Key] as T;
// if you never want to return a null value
if (instance == null)
{
HttpContext.Current.Session[Key] = instance = new T();
}
return instance;
}
set
{
HttpContext.Current.Session[Key] = value;
}
}
public static void Clear()
{
var instance = HttpContext.Current.Session[Key] as T;
if (instance != null)
{
HttpContext.Current.Session[Key] = null;
}
}
}
Create your class that needs to be stored:
[Serializable] // The only requirement
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Create your Concrete type: (Really really easy?)
public class PersonSession : SessionBase<Person> { }
Use it whenever you want, with whatever you want (as long as it's serializable)
public ActionResult Test()
{
var Person = db.GetPerson();
PersonSession.Current = Person;
this.View();
}
[HttpPost]
public ActionResult Test(Person)
{
if (Person.FirstName != PersonSession.Current.FirstName)
{
// etc, etc
PersonSession.Clear();
}
}
I have just recently got involved in a classic ASP.NET project which contains lots of storing and reading values from the session and query strings. This could look something like the following:
Session["someKey"]=someValue;
And somewhere else in the code the value in the session is read. Clearly this violates the DRY principle since you'll have the literal string key spread out all over the code. One way to avoid this could be to store all keys as constants that could be referenced everywhere there is a need to read and write to the session. But I'm not sure that's the best way to do it. How would you recommend I best handle this so that I don't violate the DRY principle?
Create a separate public class where you can define your constants, e.g
public class SessionVars
{
public const string SOME_KEY = "someKey";
public const string SOME_OTHER_KEY = "someOtherKey";
}
and then anywhere in your code you can access session variables like this:
Session[SessionVars.SOME_KEY]=someValue;
This way you can get IntelliSence and other bells and whistles.
I think you're reading too much into DRY. I pertains more to things that could be wrapped up in a function. I.e. instead of repeating the same fives lines all over the place wrap those 5 lines in a function and call the function everywhere you need it.
What you have as an example is just setting a value in a dictionary (the session object in this case), and that is the simplest way to store and retrieve objects in it.
I can't remember for the life of me where I humbly re-purposed this code from, but it's pretty nice:
using System;
using System.Web;
namespace Project.Web.UI.Domain
{
public abstract class SessionBase<T> where T : class, new()
{
private static readonly Object _padlock = new Object();
private static string Key
{
get { return typeof(SessionBase<T>).FullName; }
}
public static T Current
{
get
{
var instance = HttpContext.Current.Session[Key] as T;
lock (SessionBase<T>._padlock)
{
if (instance == null)
{
HttpContext.Current.Session[Key]
= instance
= new T();
}
}
return instance;
}
}
public static void Clear()
{
var instance = HttpContext.Current.Session[Key] as T;
if (instance != null)
{
lock (SessionBase<T>._padlock)
{
HttpContext.Current.Session[Key] = null;
}
}
}
}
}
The idea behind it two fold. The type created should be the only type you need. It's basically a big strongly-typed wrapper. So you have some object you want to keep extending information in:
public class MyClass
{
public MyClass()
public string Blah1 { get; set; }
}
Then down the road you extend MyClass and you don't want to have to remember all the Key Values, store them in AppSettings or Const variables in Static Classes. You simply define what you want to store:
public class MyClassSession : SessionBase<MyClass>
{
}
And anywhere in your program you simply use the class.
// Any Asp.Net method (webforms or mvc)
public void SetValueMethod()
{
MyClassSesssion.Current.Blah1 = "asdf";
}
public string GetValueMethod()
{
return MyClassSession.Current.Blah1;
}
Optionally you could place the access to this session object in a base page and wrap it in a property:
class BasePage : Page
{
...
public string MySessionObject
{
get
{
if(Session["myKey"] == null)
return string.Empty;
return Session["myKey"].ToString();
}
set
{
Session["myKey"] = value;
}
}
...
}
Here you are repeating the myKey string but it is encapsulated into the property. If you want to go to the extreme of avoiding this, create a constant with the key and replace the string.
I have a type SearchBag that holds a bunch of strings and nullable integers to use for passing on search values. I need a way to check if the search bag contains any values.
I'm currently trying to do it like this:
public bool HasValues()
{
return GetType().GetProperties().Any(p => p.GetValue(this, null) != null);
}
But was wondering if there's a better way.
Without modifying the SearchBag type, there isn't a better way.
EDIT: You could change the type to set a boolean flag in every property setter, then check the flag instead of using Reflection.
You could use Post Sharp to intercept the request to change a property value. You could have all search classes inherit from a common class with a List<string>. Then create an aspect attribute to add a property name to that dictionary whenever the value changes. The following is just a sample, and has bugs:
[Serializable]
public class PropertyChangeAwareAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionEventArgs eventArgs)
{
if (eventArgs.Method.Name.StartsWith("set_"))
((SearchBagBase)eventArgs.Instance).PropertiesChanged.Add(eventArgs.Method.Name);
base.OnEntry(eventArgs);
}
}
abstract class SearchBagBase
{
public List<string> PropertiesChanged = new List<String>();
}
[PropertyChangeAware]
class RegularSearch : SearchBagBase
{
public String Key { get; set; }
}
with usage:
RegularSearch regularSearch = new RegularSearch();
regularSearch.Key = "toys";
regularSearch.PropertiesChanged.ForEach(Console.WriteLine);