An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll
In page_load event i am calling
if (mySession.Current._isCustomer)
{
Response.Redirect("Products.aspx");
}
mySession class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ShoppingCartWebApp
{
public class mySession
{
// private constructor
private mySession() {}
// Gets the current session.
public static mySession Current
{
get
{
mySession session =
(mySession)HttpContext.Current.Session["__MySession__"];
if (session == null)
{
session = new mySession();
HttpContext.Current.Session["__MySession__"] = session;
}
return session;
}
}
// **** add your session properties here, e.g like this:
public string _Property1 { get; set; }
public DateTime _date { get; set; }
public String _loginId { get; set; }
public string _firstName { get; set; }
public string _userName { get; set; }
public string _role { get; set; }
public Boolean _isCustomer = false;
public Boolean _isAuth = false;
public Boolean _isGuest = true;
public ShoppingCart _cart = new ShoppingCart();
public ShoppingCart instance
{
get
{
return _cart;
}
set
{
_cart = value;
}
}
public void abandonSession()
{
// _date =
_loginId = null;
_firstName = null;
_cart = null;
_userName = null;
_role = null;
_isCustomer = false;
_isAuth = false;
}
}
}
it gives a stackoverflow exception. why?
ShoppingCart Class:
public class ShoppingCart
{
#region ListCart
public List<CartItem> Items { get; private set; }
public static SqlConnection conn = new SqlConnection(connStr.connString);
#endregion
#region CartSession
public ShoppingCart cart;
public ShoppingCart()
{
if (mySession.Current._cart == null)
{
cart = new ShoppingCart();
cart.Items = new List<CartItem>();
if (mySession.Current._isCustomer)
cart.Items = ShoppingCart.loadCart(mySession.Current._loginId);
mySession.Current._cart = cart;
}
else
{
cart = mySession.Current._cart;
}
}
}
This line of code causes infinite loop and stack overflow :
if (mySession.Current._isCustomer)
cart.Items = ShoppingCart.loadCart(mySession.Current._loginId);
it is initialized by each instance of mysession class. and its using its parent class.
even using singleton mySession can not solve the problem.
when this code is executing :
session = new mySession();
it tries to initialize new ShoppingCard. shopping card asks for singleton instance of mysession. this line of code is not executed yet :
HttpContext.Current.Session["__MySession__"] = session;
so goes to create a new instance of my session and ...
this means stack overflow !
you can correct it like this :
public static mySession Current
{
get
{
mySession session =
(mySession)HttpContext.Current.Session["__MySession__"];
if (session == null)
{
session = new mySession();
HttpContext.Current.Session["__MySession__"] = session;
session._cart = new ShoppingCart(); //initialize your shoppoing car after adding variable to session !
}
return session;
}
}
public ShoppingCart _cart;// = new ShoppingCart(); remove initialization
look at my comments in code.
The problem comes because of the relationship between mySession and ShoppingCart.
mySession has a member variable defined like so:
public ShoppingCart _cart = new ShoppingCart();
When the constructor of mySession is called, an instance of ShoppingCart is instantiated. When the constructor of ShoppingCart executes, it calls the mySession.Current static property. Because the constructor of ShoppingCart was called from within this same property (remember, we are still creating an instance of mySession in the original static call), it continues to recurse in this way until a StackOverflowException is raised.
To fix this, I suggest you take a look at your ShoppingCart class. Firstly, why does it need an instance of itself as a member variable? Secondly, if ShoppingCart needs to know information about the contents of mySession, your encapsulation is not correct. I suggest you pass the information needed into the constructor of ShoppingCart to avoid making a call back to mySession.Current.
Given your updated question, I think if you properly followed .Net naming guidelines (as outlined in my comment on your question), you should be able to easily figure out where the problem is. I suspect your calling code is similar, and not following the guidelines is obscuring what is actually happening from what you think is happening.
As a first step I would recommend doing this cleanup; it will likely make it clear where you're causing the overflow.
Related
I want to fetch first record from AboutUs table and display as a content label.
I have created 4 classes in MVVM pattern.
First is Model class AboutUs.cs
[Table("tblAboutUs")]
public class AboutUs
{
[PrimaryKey, AutoIncrement, NotNull]
public int IDP { get; set; }
public string Content { get; set; }
}
Second is Data Access class
SQLiteAboutUs.cs
public class SQLiteAboutUs
{
private static readonly AsyncLock Mutex = new AsyncLock();
private SQLiteAsyncConnection dbConn;
public int StatusCode { get; set; }
public SQLiteAboutUs(ISQLitePlatform sqlitePlatform, string dbPath)
{
if (dbConn == null)
{
var connectionFunc = new Func<SQLiteConnectionWithLock>(() =>
new SQLiteConnectionWithLock
(
sqlitePlatform,
new SQLiteConnectionString(dbPath, storeDateTimeAsTicks: false)
));
dbConn = new SQLiteAsyncConnection(connectionFunc);
dbConn.CreateTableAsync<Model.AboutUs>();
}
}
public SQLiteAboutUs()
{
}
public async Task Save(Model.AboutUs content)
{
using (await Mutex.LockAsync().ConfigureAwait(false))
{
StatusCode = 0;
await dbConn.InsertAsync(new Model.AboutUs { Content = content.Content });
StatusCode = 1;
}
//For Get first Row from Table
public async Task<Model.AboutUs> GetAllData()
{
return await dbConn.Table<Model.AboutUs>().Where(x => x.IDP == 1).FirstOrDefaultAsync();
}
}
Third class ViewModel Class
AboutUsViewModel.cs
public class AboutUsViewModel
{
readonly SQLiteAboutUs _db;
public string AboutUsContent { get; set; }
//public string AboutUs;
public AboutUsViewModel()
{
_db = new SQLiteAboutUs();
}
public async void FirstRecord()
{
Model.AboutUs obj = await _db.GetAllData();
this.AboutUsContent = obj.Content;
}
}
Forth one is Code behind file of my xaml pages.
AboutUs.xaml.cs
public partial class AboutUs : ContentPage
{
readonly AboutUsViewModel aboutUsViewModel;
public AboutUs()
{
InitializeComponent();
aboutUsViewModel = new AboutUsViewModel();
aboutUsViewModel.FirstRecord();
lblContent.Text = aboutUsViewModel.AboutUsContent;
}
}
I have debug code but problem is In AboutUsViewModel.cs class in FirstRecord Method object can not be set that's why AboutUsContent string property is also not set.
I can't figure out why my debugger directly jump from GetAllData() method in SQLiteAboutUs.cs to label.text in code behind file of view?
Welcome in the wonderfull world of asynchronicity. I encourage you to read carefully about how await is working: How and When to use `async` and `await`
It is not a blocking call. Thus you create the view AboutUs. It creates the ViewModel AboutUsViewModel. It calls
aboutUsViewModel.FirstRecord();
But does not wait for the call to be complete (dont't forget you marked your FirstRecord function as async...)
So it calls
Model.AboutUs obj = await _db.GetAllData();
And directly return to the caller because of the await operator.
That's why it directly jump to
lblContent.Text = aboutUsViewModel.AboutUsContent;
What you would like is Something like
await aboutUsViewModel.FirstRecord();
To wait the call to be complete before going to the next line. But of course you can't do that, because you are in a constructor and you can't have an async constructor. And calling a database (or actually anything that could likely failed) in a constructor is a bad practice anyway.
I would advise you to let only InitializeComponent() in the constructor, and then use Something like the OnDataLoaded() event of your view to perform your async call with a await.
Hope it helps.
I know I shouldn't have to ask this but whatever it is I am missing is driving me nuts! I have done this many times before and I can only put it down to old age and slight senility.
I have a class with two objects that get initialized in the constructor...
public class EbayFunctions
{
private static ApiContext apiContext = null;
private static List<StoreCategoriesFlattened> storeCategories = new List<StoreCategoriesFlattened>();
public EbayFunctions()
{
ApiContext apiContext = GetApiContext();
List<StoreCategoriesFlattened> storeCategories = GetFlattenedStoreCategories();
}
public string GetStoreCategoryIdForItem(string category)
{
var result = storeCategories.Find(x => x.CCDatabaseMatch == category);
return ""; //Ignore will return a value
}
}
then I have a forms app (test harness) that makes use of the class and on button click I call a method...
namespace EbayTestHarness
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void cmdGetEbayStoreCatID_Click(object sender, EventArgs e)
{
EbayFunctions ebf = new EbayFunctions();
string ddd = ebf.GetStoreCategoryIdForItem("Motors > Bikes");
}
}
}
However apiContext persists between calls but storeCategories gets populated on EbayFunctions ebf = new EbayFunctions(); and is null when string ddd = ebf.GetStoreCategoryIdForItem("Motors > Bikes"); is called.
I know its something stupid but what am I missing?
Your problem is here:
private static ApiContext apiContext = null;
private static List<StoreCategoriesFlattened> storeCategories = new List<StoreCategoriesFlattened>();
public EbayFunctions()
{
ApiContext apiContext = GetApiContext(); // local!!
List<StoreCategoriesFlattened> storeCategories = GetFlattenedStoreCategories(); // local!!
}
You're not setting the static fields - you're introducing local variables that then go out of scope and are (eventually) garbage collected. Take out the type indicators to set the static fields:
public EbayFunctions()
{
apiContext = GetApiContext();
storeCategories = GetFlattenedStoreCategories();
}
Also, as #PatrickHofman points out, the initialization of static members should be done once - preferably in a static constructor:
static EbayFunctions()
{
apiContext = GetApiContext();
storeCategories = GetFlattenedStoreCategories();
}
I am thinking to implement something like a static SessionHelper class where I would like to keep some data in Session.
But it seems like is impossible to use Session object out of the Controller class. Right?
Or may be I am wrong... I.e. is this link a solution ASP.NET MVC - How to access Session data in places other than Controller and Views
Let me know, please!
Anyway for now I cannot refer to Session object in that class which lives in Models folder.
public static class SessionHelper
{
public static bool ShowSuccessPopup
{
get
{
if (Session["ShowSuccessPopup"] == null)
{
Session["ShowSuccessPopup"] = false;
return false;
}
else
{
var result = (bool)Session["ShowSuccessPopup"].ToString();
return result;
}
}
set {Session["ShowSuccessPopup"] = value; }
}
}
The Session object is only set in the request-cycle, so anything outside the request-cycle won't have access to it (i.e. Controllers and Views are fine, but models no). If you need to work with the session in something outside of the request-cycle, then you must inject the Session object as a dependency. However, you're not going to be able to accomplish that with a static class. So you might instead try something like:
public class SessionHelper
{
private HttpSessionState session;
public SessionHelper (HttpSessionState session)
{
this.session = session;
}
public bool ShowSuccessPopup { ... }
}
Alternatively, you may be able to get by with merely injecting the session into your actual methods individually, but you wouldn't be able to continue using a property:
public static bool ShowSuccessPopup (HttpSessionState session)
{
// do something with session
}
Thanks to Chris Pratt!
Just like an alternative I am gonna share my approach.
public partial class BaseController : Controller
{
public SessionBox SessionBox;
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
SessionBox = new SessionBox(filterContext.HttpContext);
base.OnActionExecuting(filterContext);
}
}
public class SessionBox
{
private HttpContextBase context { get; set; }
public SessionBox(HttpContextBase context)
{
this.context = context;
}
public bool ShowSuccessPopup
{
get
{
if (context.Session["ShowSuccessPopup"] == null)
{
context.Session["ShowSuccessPopup"] = false;
return false;
}
else
{
var result = Convert.ToBoolean(context.Session["ShowSuccessPopup"].ToString());
return result;
}
}
set { context.Session["ShowSuccessPopup"] = value; }
}
}
Notice that you should inheritine Controller class on BaseController class
and later in the Controller class you can do like
if (SessionBox.ShowSuccessPopup)
{
SessionBox.ShowSuccessPopup = false;
Here are extra links that demonstrate difference between
http://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.aspx
and
http://msdn.microsoft.com/en-us/library/system.web.httpcontextbase.aspx
I'm using the Singleton design pattern and I must return the object if it hasn't been used before.
I get an exception in the following code :
namespace app.Models
{
public class Conexion:DbContext
{
private static Conexion Instance = null;
private Conexion(string con) : base(con) { }
public static Conexion MainConexion
{
get {//error here
if (Instance == null)
{
Instance = new Conexion(#"Server=*****; User Id=***;Password=****; Database=****");
}
return Instance;
}
}
public DbSet<label> Labels { get; set; }
public DbSet<checke_status> CheckStatus { get; set; }
public void SaveChanges()
{
MainConexion.SaveChanges();
}
}
}
How can I solve this?
Remove the override of the SaveChanges method:
namespace app.Models
{
public class Conexion : DbContext
{
private static Conexion Instance = null;
private Conexion(string con) : base(con) { }
public static Conexion MainConexion
{
get
{ //error here
if (Instance == null)
{
Instance = new Conexion(
#"Server=*****; User Id=***;Password=****; Database=****");
}
return Instance;
}
}
public DbSet<label> Labels { get; set; }
public DbSet<checke_status> CheckStatus { get; set; }
}
}
Since you have a private constructor, the only instance of this class that can be used is the one exposed in the MainConexion property. It looks like you were trying to make sure that when any instance's SaveChanges method was called that the SaveChanges method on the MainConnection property's instance was called. This is not necessary, because you can only ever have one instance of the Conexion class, and it's the instance that you want to call SaveChanges on. The usage is still the same:
Conexion.MainConexion.SaveChanges();
That being said, I think you would have better luck if you were to not implement it this way. It would probably be better to open and close connections as they were needed, rather than rely on a single connection instance. What happens if the connection is interrupted? Rather than getting a single error, your application will be broken.
I'm calling my custom factory that I created (PhotoServiceFactory), which is a singleton that allows me to get at a specific custom service type back (in this case FacebookService). FacebookService is also a singleton. In FacebookService I've exposed an instance of FacebookAlbumPhoto through a property. I did this because then I don't have to have a ton of the same code over and over again creating a new instance of FacebookAlbumPhoto...I can get an instance using the FacebookService's property.
PhotoServiceFactory service = PhotoServiceFactory.CurrentPhotoServiceFactory;
FacebookService facebookService = (FacebookService)service.GetAPIService(APIType.Facebook);
FacebookAlbumPhoto facebookPhoto = facebookService.FacebookAlbumPhoto.GetFacebookAlbumPhoto(selectedPhotoID);
So this is all set up now, I created all this and just testing it now.
What's happening is my code is bombing out at this line:
FacebookAlbumPhoto facebookPhoto = facebookService.FacebookAlbumPhoto.GetFacebookAlbumPhoto(selectedPhotoID);
The error I get is when I try to reference the facebookService.FacebookAlbumPhoto instance:
CurrentSession = '_singletonInstance.CurrentSession' threw an exception of type 'System.Threading.ThreadAbortException'
So I don't know if it's because the service singleton is on one thread and then it tries to reference another singleton that's on a completely different thread and that's just not possible? That it's not possible to nest singletons like this? Or could this be another issue altogether? Cause I can't see it.
Here's my ServiceFactory:
public class PhotoServiceFactory
{
private static PhotoServiceFactory _singletonInstance;
private PhotoServiceFactory(){}
public static PhotoServiceFactory CurrentPhotoServiceFactory
{
get
{
_singletonInstance = _singletonInstance ?? (_singletonInstance = new PhotoServiceFactory());
return _singletonInstance;
}
}
public object GetAPIService(APIType apiType)
{
object apiService = null;
switch (apiType)
{
case APIType.Facebook:
apiService = FacebookService.CurrentService;
break;
// rest of code
}
return apiService;
}
So the main singleton here Service has a property to get its related Session:
Here's the FacebookServiceClass:
public class FacebookService
{
private static FacebookService _singletonInstance;
private FacebookService(){}
public FacebookSession CurrentSession
{
get
{
return FacebookSession.GetCurrentSession();
}
}
/// <summary>
/// Gets the current facebook service singleton instance.
/// </summary>
/// <value>The current facebook service.</value>
public static FacebookService CurrentService
{
get
{
_singletonInstance = _singletonInstance ?? (_singletonInstance = new FacebookService());
return _singletonInstance;
}
}
public FacebookAlbumPhoto FacebookAlbumPhoto
{
get
{
return new FacebookAlbumPhoto(); // create an instance automatically so we can start working with this object
}
}
}
Here's the session class:
public class FacebookSession
{
const string loginCallbackUrl = "http://localhost/PhotoUpload/FacebookOauth.aspx";
private FacebookSession()
{
}
public string UserID { get; private set; }
public static FacebookSession GetCurrentSession()
{
//....bunch of other logic is here
FacebookSession facebookSession = CreateNewSession();
return facebookSession;
}
public FacebookSession CreateNewSession()
{
//...some code here
FacebookSession newFacebookSession = new FacebookSession
//... rest of code...
return newFacebookSession;
}
// ... rest of code
}
UPDATED:
As requested here's my FacebookAlbumPhoto class that I created:
public class FacebookAlbumPhoto : FacebookPhotoBase
{
private FacebookSession currentSession;
public FacebookAlbumPhoto()
{
currentSession = FacebookService.CurrentService.CurrentSession;
}
#region Methods
public FacebookAlbumPhoto GetFacebookAlbumPhoto(string photoID)
{
...more code
FacebookPhotoRequest request = new FacebookPhotoRequest(currentSession.UserID, photoID);
...more code
FacebookAlbumPhoto facebookPhoto = ParseFacebookPhoto(json);
return facebookPhoto;
}
...rest of code
}
Two things. First, remember to read over Skeet's catalogue of singleton implementations.
Second, try breaking your code just before the spot where the exception occurs, and then bring up your "Exception" dialogue (ctrl-alt-e). Click the "throw" checkbox next to the CLR (second row of dialogue) and hit ok. Continue debugging your code. The results may tell you where the real problem is.
Don't forgot to go back to the Exception dialogue and remove that check from the check box, after you are done. :)
separate instance creation from initialization