Luke
Luke

Reputation: 23690

Can access Session variables from @Page but not from underlying Class

When a user logs in, my code sets a Session variable using System.Web.HttpContext.Current.Session["customer_ref"], within HandleUserLogin().

I'm doing this in the following class, SessionManager:

SessionManager.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for Session
/// </summary>
public class SessionManager
{
    public string customer_ref;
    public bool logged_in = false;

    public SessionManager()
    {

        //
        // NULL REFERENCE EXCEPTION CAUSED HERE
        //
        //
        // Check to see if the user is logged in (is a customer reference set?)
        if (System.Web.HttpContext.Current.Session["customer_ref"] != null)
        {

            // The user is logged in
            logged_in = true;
        }

    }

    public bool HandleUserLogin(string username, string password)
    {
        if ((!string.IsNullOrEmpty(username)) && (!string.IsNullOrEmpty(password)))
        {
            // Check that the username and password are valid
            if ((!string.IsNullOrEmpty(username)) && (password == "password"))
            {
                // Generate a new session ID
                // TODO: Find out how to.

                // Set the session variables
                System.Web.HttpContext.Current.Session["customer_ref"] = username;

                // Set the variables of this Session object for future use
                this.customer_ref = username;

                // Set the logged in status to true
                this.logged_in = true;

                return true;
            }
            else
            {
                // Username and password are incorrect
                return false;
            }
        }

        // The username or password was not entered
        return false;
    }

    public void HandleUserLogout()
    {
        System.Web.HttpContext.Current.Session["customer_ref"] = null;

        // Unset the variables in the SessionManager object
         this.customer_ref = string.Empty;

         // Set the logged in status to false
         this.logged_in = false;
    }
}

Once this Session variable is set, I am happily able to show it on the page using the following code and the value that I set it to appears nicely.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" EnableSessionState="True" %>

<!DOCTYPE html>

<html>

<head>
</head>
<body>
            <%
                // 
                // WRITE THE CUSTOMER REFERENCE FROM THE SESSION
                //
                Response.Write(System.Web.HttpContext.Current.Session["customer_ref"]);
             %>

</body>
</html>

However, I am not able to access it from another page called dashboard.aspx as it throws a NullReferenceException when I call my SessionManager() class which tries to access the Session variable upon construction.

Here's the code for dashboard.aspx, dashboard.aspx.cs:

dashboard.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="dashboard.aspx.cs" Inherits="dashboard" MasterPageFile="~/Design.master" EnableSessionState="True" %>

<asp:Content ID="customer" ContentPlaceHolderID="CustomerInfo" runat="server">              
    <div class="customer_name"><% Response.Write(customer.customer_name); %></div>
    <div class="customer_account_number">Account number: <% Response.Write(customer.customer_ref); %></div>
</asp:Content>


<asp:Content ID="outstanding_orders" ContentPlaceHolderID="Content" runat="server">

    <div class="content_left_title_wrapper">
        <h2 class="content_left_title">Your Outstanding Orders</h2>
    </div>

    <table id="outstanding_orders" cellpadding="0" cellspacing="0">
    <colgroup span="4"></colgroup>
    <colgroup span="1" class="view_link_col"></colgroup>
        <tr>
            <th><div>Order Number</div></th>
            <th><div>Date Placed</div></th>
            <th><div>Total Cost</div></th>
            <th><div>Order Status</div></th>
            <th></th>
        </tr>

        <% 
            // Loop through all of the outstanding orders for the customer
            foreach (OrderSummary order_item in outstanding_orders)
            {
        %>

        <tr>
            <td><div><% Response.Write(order_item.order_number); %></div></td>
            <td><div><% Response.Write(order_item.uk_order_date); %></div></td>
            <td><div>£<% Response.Write(order_item.order_total); %></div></td>
            <td><div>Incomplete</div></td>
            <td><div><a href="orderlines.aspx?orderno=<% Response.Write(order_item.order_number); %>" class="order_detail_link">Detail<br /><img src="images/design/view_order_arrow.png" /></a></div></td>
        </tr>   

        <%
            }
        %>                  

    </table>

</asp:Content>

dashboard.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using IBMU2.UODOTNET;
using System.Xml.Linq;

public partial class dashboard : System.Web.UI.Page
{
    // Get the users session
    SessionManager session = new SessionManager();

    // Create a new connection to the database
    ReflexDatabase db_con = new ReflexDatabase();

    // Blank list to hold the orders
    public List<OrderSummary> outstanding_orders = new List<OrderSummary>();

    public XDocument test { get; set; }

    public Customer customer;

    // OnInit is called before the page loads (See internet for ASP.NET Page Lifecycle)
    protected override void OnInit(EventArgs e)
    {

        if (session.logged_in == false)
        {

            // I've tried it here, and it won't redirect
            Response.Redirect("default.aspx");
        }

    }

    protected void Page_Load(object sender, EventArgs e)
    {

            try
            {

                // Create the customer as a Customer object
                customer = new Customer(session.customer_ref);

                // Query the TOELINE database
                XDocument customer_orders = db_con.Query(String.Format("LIST TOEHEAD BY.DSND ORDERNO WITH CUSREF = \"{0}\" AND ORDERSTATUS < 50 ORDERNO DATEONFILE T.VAL.TO.INV ORDERSTATUS TOXML ELEMENTS", customer.customer_ref));

                test = customer_orders;

                // Use LINQ to pipe the data in to OrderSummary objects
                var linqQuery = from n in customer_orders.Element("ROOT").Descendants("TOEHEAD")
                                select new OrderSummary
                                {
                                    //order_number = n.Element("ORDERNO").Nodes()..ToString(),
                                    order_number = n.Descendants("ORDERNO").First().Value,
                                    us_order_date = n.Descendants("DATEONFILE").First().Value,
                                    order_total = n.Descendants("T.VAL.TO.INV").First().Value
                                };

                // Add all of the items to the list of orders outstanding for the customer
                foreach (OrderSummary linqItem in linqQuery)
                {
                    outstanding_orders.Add(linqItem);
                }

            }
            finally
            {
                // Close the session to prevent hogging of sessions
                db_con.CloseSession();
            }

    }
}

Upvotes: 0

Views: 2731

Answers (2)

fowlermatthewd
fowlermatthewd

Reputation: 173

The instance of SessionManager is be created as soon as your dashboard (page) object is created. You can change it to :

// Get the users session
    SessionManager session = null;

...

protected override void OnInit(EventArgs e)
    {
        session = new SessionManager();

..
}

or you can take this logic, and put it in it's own method instead o the constructor

    public bool IsLoggedIn()
    {
    if (System.Web.HttpContext.Current.Session["customer_ref"] != null)
    {

        // The user is logged in
        logged_in = true;
    }
    }

there are a few options, but the issue is because the the contructor of the SessionManager class is calling the Session, and its not created yet.

Upvotes: 0

user1429080
user1429080

Reputation: 9166

You have made the SessionManager an instance member of the Page. That means the initializer will run (I think) just before the Page constructor is run by the Page handler.

And that happens before the Session has been added to the HttpContext object.

Try changing this line:

SessionManager session = new SessionManager();

to

SessionManager session = null;

And then new it up in (for instance) the OnInit method (also, don't forget to call base.OnInit()):

protected override void OnInit(EventArgs e)   
{   
    session = new SessionManager();
    if (session.logged_in == false)   
    {   
        Response.Redirect("default.aspx");   
    }   
    base.OnInit(e);
}

If this is going to be your authentication scheme, you might wan't to create custom BasePage type which your other pages could derive from. That way you don't have to copy the same pieces of code to all pages that require the user to be logged in.

Or (as I already wrote in an answer to a previous quetion of yours) you could just go ahead and implement the authentication using a custom MembershipProvider and let the framework handle all the plumbing.

Upvotes: 2

Related Questions