I have a crystal report in my asp.net web application which has a lot of report parameters (about 15). Previously I was using querystring to pass them but it was being unsecure.
Now I am mapping all parameters to a Hashtable, storing them in session & passing to the report viewer. Now If user opens multiple instance of reports in different browser tabs, the session values get messed up. When I navigate pages, wrong reports are displayed.
Please advise me a good method to pass my parameters to report.
Damien.
How about creating a simple DTO for storing all report parameters. Save this DTO in session and access in report viewer page where your viewer control resides.
To cross over the session issue when user opens multiple instances in browser, you can do a simple trick. When user provides parameter, and clicks on "Show Report", at that point create a guid, store value inside the session using key as this guid, and pass this guid as query string parameter to your report viewer page. This way each instance of report viewer page is aware which session value to be brought out.
Something like this
public class AttendanceDTO
{
public int EmployeeId {get;set;}
public string Month {get;set;}
}
And then in your "Report parameter page"
/* JUST NOTEPAD CODE, SYNTAX MIGHT VARY */
protected override ShowReport_Click(object sender, EventArgs e)
{
string guid = new Guid();
AttendanceDTO dto = new AttendanceDTO()
{ EmployeeId = txtEmployee.Text;
Month = txtMonth.text
};
session[guid] = dto;
Response.Redirect("ReportViewer.aspx?Guid=" + guid);
}
And then inside your Report Viewer Page
string guid = Request.QueryString["Guid"]; //Null check etc..
AttendanceDTO dto = (AttendanceDTO) session[guid];
//Provide dto values as parameters to your report viewer control and then clean the session
[You would need to make sure that you clear out the respective session value after you get it used.]
[Above code is just from notepad to give you an idea. On top of this you can bring more innovation]
Session Objects are shared among multiple tabs of same browser since server stores only one session cookie for a browser. So it is pretty obvious for the values to messup in several tabs on single browser.
One of the possible solution:
Use ViewStates instead of session to store HashTable.
Refer the code below for a demo, I have used ArrayList instead is HashTable for the sake of simplicity.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ViewState["ht"] = new ArrayList();
//initialize viewstate with arraylist on first pageload.
}
}
protected void btnAddElement_Click(object sender, EventArgs e)
{//adding new elements to the arraylist
if (ViewState["ht"] != null)
{
ArrayList ht = (ArrayList)ViewState["ht"];
ht.Add(TextBox1.Text);
ViewState["ht"] = ht;
}
}
protected void Button2_Click(object sender, EventArgs e)
{
if (ViewState["ht"] != null)
{
ArrayList ht=(ArrayList)ViewState["ht"];
foreach (object a in ht)
{//write code to pass parameters to the crystal report
Response.Write(a);
}
}
}
}
Since Viewstates work at page level, therefor the values in the collection will not mess up this time.
Hope this helps.
Related
Since I'm a newbie for asp, I'm trying to take a name as input,trying to put that name in list, then check the list to find a match. I'm doing this as basics keeping the log in procedure in mind, which I will try to implement later. I have the following code:
I have made a class like this:
public class Login
{
public string name { get; set; }
}
The two button events are as follows:
List<Login> list;
protected void Button1_Click(object sender, EventArgs e)
{
list = new List<Login>(){
new Login { name = TextBox1.Text },
new Login { name = "Badhon"}
};
Label1.Text = "Inserted";
}
protected void btnLogIn_Click(object sender, EventArgs e)
{
foreach (var s in list)
{
if (s.name == TextBox1.Text)
{
Label1.Text = "Found";
break;
}
else
Label1.Text = "Not Found";
}
}
when I'm trying to insert,its working fine, but when clicking on the login button showing any error message like "Object reference not set to an instance of an object."
When you press the login button you're in a different scope to when you pressed the first button, so the list is not initialised (Each time you press an ASP button you get a new state: The web is designed to be stateless).
Why not use the asp:login control?
You code is not exactly what it is supposed to be. You'd better go searching for some (of the various) examples on how to hanle logins in ASP.NET.
Each click is a new HTTP request. The list initialized in the first request is not the same with the list in the other request because each request will use its own instance of the Page object.
You need to read & understand the life cycle of a ASP.net page: http://msdn.microsoft.com/en-us/library/ms178472.aspx
make protected properties to store list of logins
It should looks like this:
protected List<Login> LoginStore
{
get{ return ViewState["store"] =! null ? (List<Login>)ViewState["store"] : new List<Login>; }
set{ ViewState["store"]=value; }
}
You can use Session as well as ViewState. It will make your list doesn't disapear every time you make PostBack.
then in event btnLogIn
create List<Login> list = LoginStore;
then make the rest of your code.
click on here
why do go forloop, use session variables in Global.asax, try googlin you can find many example..
What i am doing is whenever users logs in I store his username in Session Object
Now what i want on the Admin Page is the List of ACTIVE USERS (i.e No of Users which are presently working with the Application (usernames in Session Objects)
Is there any way of doing that..
???
Thanks
Based on your comment to Davide Piras, if you are storing Session["user"] =username then you are only storing one element since you are always using the same key.
I would put everything in a List<string>, for example.
Something like this in your login page:
List<string> activeUsers = Cache["ActiveUsers"] as List<string>;
if(activeUsers==null)
activeUsers = new List<string>();
activeUsers.Add(username_of_person_logged_in);
Cache["active_users"]=activeUsers;
Then in your "Admin" page...
List<string> activeUsers = Cache["ActiveUsers"] as List<string>;
if(activeUsers!=null)
{
foreach(var item in activeUsers)
{
//do something with them
}
}
Note: I changed it to Cache since Cache is shared across all users. Session will not work since it will be only valid on a per-user basis. Thanks to #CheckRaise for his comment.
The Session object cannot be accessed outside of its own session. If you need an administrator to be able to see all the active sessions, you need to use the Application object. For example, in global.asax:
protected void Application_Start(object sender, EventArgs e) {
Application["Users"] = new List<string>;
}
Then, to add a user (possibly when they click 'Log in'):
Application.Lock();
((List<string>)Application["Users"]).Add(username);
Application.UnLock();
You should also remove the user in Session_End:
protected void Session_End(object sender, EventArgs e) {
Application.Lock();
((List<string>)Application["Users"]).Remove(username);
Application.UnLock();
}
I have more than one user control on my aspx page, and each user control call it's own service or method to display content retrieved from SQL DB. I want to reduce these round trips, and get the job done in one call. Any idea what's the best practice.
You can put your all select statements in one stored procedure that mean you will hit your database just one time and load the result into a DataSet using SqlAdapter.Fill(MyDataSet) and pass the each table in your dataset to corresponding user control by creating public property with DataTable type
public class UserControl_1
{
private DataTable _dbTable;
public DataTable dbTable;
{
get
{
return _dbTable;
}
set
{
_dbTable = value
}
}
}
in your page
Private DataSet myDataSet;
public void Page_Load(Object sender,EventArgs e)
{
myDataSet = PopulateData(); // call your stored procedure inside it
UserControl_1.dbTable = myDataSet.Tables[0];
UserControl_2.dbTable = myDataSet.Tables[1];
//... and so on
}
I wish that give you a good idea
I have configured an asp.NET web application to use forms authentication and store the session in a custom table. So far so good, when I log in the authentication persists across browser sessions. I am trying to get to grip with the possibilities of storing the session like so but I come up against a problem early on.
If I add variable/value pairs to the session object, and output the session variables to the page, the variable/value pairs are displayed as expected, but when I close and reopen the browser the correct session reloads as expected (which I confirm by outputting the sessionid) but the variable/value pairs are gone.
Is there something very simple I am missing here as from what I understand the session variables should also be available across browser sessions(strings are serializable right?).
List<SessionVar> sessionVars = new List<SessionVar>();
protected void Page_Load(object sender, EventArgs e)
{
Session[Session.SessionID] = Session.SessionID;
LoadSessionData();
}
protected void btnSessionVariable_Click(object sender, EventArgs e)
{
Session[txtVariableName.Text.Trim()] = txtVariableValue.Text.Trim();
txtVariableName.Text = string.Empty;
txtVariableValue.Text = string.Empty;
LoadSessionData();
}
private void LoadSessionData()
{
sessionVars.Clear();
foreach (string key in Session.Keys)
{
sessionVars.Add(new SessionVar(key, (string)Session[key]));
}
gridView.DataSource = sessionVars;
gridView.DataBind();
}
Session state is NOT maintained when a browser (or browser tab) closes and is restarted.
The session cookie is no longer available for the new browser window so a new session will start. That ASP.NET assigns the same id again is just a coincedence.
What would be the best practice to persist property values of an aspx-page?
I have done the following, is there some neater way?
public string DataTable
{
get
{
return _DataTable;
}
set
{
_DataTable = value;
ViewState["DataTable"] = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataTable = Request["dataTable"].ToString();
}
else
{
DataTable = ViewState["DataTable"].ToString();
}
}
You have multiple places where you can persist data,each with it's own pros and cons, and with it' own lifespan:
ViewState - stored individually on each page as a hidden (somewhat encrypted) item on the client. Remember that the data has to make a round trip to the client and back on each postback, so generally it's not a good ideea to store large ammounts of data
HiddenItem - a hidden input control. Works the same as ViewState, except it's not enrypted and you can use the values in the JS from the client
QueryString - same as hiddenitem, but seriously, use it only for small ammounts of data. I think some browsers have a limit on the URL length
Session - has the advantage of being able to store larger ammounts of data, as this is stored on the server end, not on the client. You can get into trouble if the client is using the back/next buttons on the browser, and you need to be carefull about maintaining session data accross server farms(ie. multiple servers running the same webapp)
Cache - almost identical to Session, except you can access it from other sessions. This is better to use for "globally" accesable data (ie. stuff everyone uses in you app)
Static Properties - works the same as cache, but you cannot share it across webfarms, so each member of the webfarm will have it's own static value in it's loaded assembly.
I would do it like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
TableName = Request.QueryString["tableName"];
}
public string TableName
{
get { return ViewState["tableName"] as string; }
set { ViewState["tableName"] = value; }
}
I don't like using Request["tableName"] alone since it has to search in more places. Usually I know where I'm sending the parameter.
Also DataTable is a type, so it's best to not use it as a property name.