I am using:
if (string.IsNullOrEmpty(myHttpContext.Request.QueryString["code"]))
{
if (myHttpContext.Session == null || myHttpContext.Session["code"] == null)
{
OutputError("Code", "Invalid code.");
}
else
{
code = myHttpContext.Session["code"].ToString();
}
}
else
{
code = myHttpContext.Request.QueryString["code"];
myHttpContext.Session.Add("code", code);
}
However I keep getting the error:
Object reference not set to an instance of an object.
For:
myHttpContext.Session.Add("code", code);
All I want to do is set a simple session, someone please help this is driving me crazy.
Has your IHttpHandler (ashx) class implemented IRequireSessionState? Otherwise the Session object will not be accessible.
public class MyHandler : IHttpHandler, IRequireSessionState
{
public bool IsReusable { get { return false; } }
public void ProcessRequest(HttpContext ctx)
{
// your code here
}
}
You forgot if (myHttpContext != null)
However you might want to use the always-present context instead: HttpContext.Current
// if querystring parameter has a value
if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["code"]))
// then use its value
Same for Session (if it's present - see #davisleeps answer for that)
https://stackoverflow.com/a/8598088/179972
I believe you might want to try
myHttpContext.Session["code"] = code;
Related
Our MVC web app is load balanced and makes use of the session to persist data out of proc in SQL server. Web config is set up like so:
<sessionState mode="SQLServer" allowCustomSqlDatabase="true" sqlConnectionString="Data Source..."/>
Using dependency injection we pass a class wrapping our session to the various controllers
public class MyWebSession : IWebSession
{
private const MyModelKey = "MyModelKey"
public MyModel MyModel
{
get { return (MyModel ) HttpContext.Current.Session[MyModelKey]; }
set { HttpContext.Current.Session[MyModelKey] = value; }
}
}
My question is if in our controllers we do things like this:
var id = MyWebSession.MyModel.Id;
var description = MyModel.Id.Description;
Would that incur multiple trips to the database? Or has that hit already occurred when the http request is made and I can treat the session data as in-memory variables?
Current refers to ContextBase, which refers to HostContext, which looks like this:
public static Object HostContext
{
[System.Security.SecurityCritical] // auto-generated
get
{
ExecutionContext.Reader ec = Thread.CurrentThread.GetExecutionContextReader();
Object hC = ec.IllogicalCallContext.HostContext;
if (hC == null)
hC = ec.LogicalCallContext.HostContext;
return hC;
}
IllogicalCallContext looks like this:
internal class IllogicalCallContext
{
private Hashtable m_Datastore;
private Object m_HostContext;
internal struct Reader
{
IllogicalCallContext m_ctx;
public Reader(IllogicalCallContext ctx) { m_ctx = ctx; }
public bool IsNull { get { return m_ctx == null; } }
[System.Security.SecurityCritical]
public Object GetData(String name) { return IsNull ? null : m_ctx.GetData(name); }
public Object HostContext { get { return IsNull ? null : m_ctx.HostContext; } }
}
private Hashtable Datastore
{
get
{
if (null == m_Datastore)
{
// The local store has not yet been created for this thread.
m_Datastore = new Hashtable();
}
return m_Datastore;
}
}
internal Object HostContext
{
get
{
return m_HostContext;
}
set
{
m_HostContext = value;
}
}
public Object HostContext { get { return IsNull ? null : m_ctx.HostContext; } }
}
..etc.
Eventually you wind up in CallContext.HostContext, which looks like this:
internal Object HostContext
{
get
{
return m_HostContext;
}
set
{
m_HostContext = value;
}
}
So whatever behavior occurs is going to depend on what someone puts in that HostContext property. This is where the Reference Source ends, so presumably someone or something is putting a dictionary or caching object in there, though I suppose it could be a database endpoint.
By the way, somewhere in this labyrinth should be a SessionState object that looks like this:
https://github.com/microsoft/referencesource/blob/master/System.Web/State/SessionState.cs
Our MvcSitemap has some DynamicNodeProviders implemented.
We want these to be unique per session. But it appears they are unique per user.
So if a user logs into two different browsers, or computers, they currently share the same sitemap.
We do not want this.
But I can't seem to figure out how to get it to use the User/Session combination for uniqueness.
Is there a way to make this work?
Option 1:
Implement your own ICacheProvider based on session state and inject it using DI.
using System;
using System.Collections.Generic;
using MvcSiteMapProvider.Web.Mvc;
using MvcSiteMapProvider.Caching;
using System.Web;
public class SessionStateCacheProvider<T>
: ICacheProvider<T>
{
public SessionStateCacheProvider(
IMvcContextFactory mvcContextFactory
)
{
if (mvcContextFactory == null)
throw new ArgumentNullException("mvcContextFactory");
this.mvcContextFactory = mvcContextFactory;
}
private readonly IMvcContextFactory mvcContextFactory;
protected HttpContextBase Context
{
get
{
return this.mvcContextFactory.CreateHttpContext();
}
}
#region ICacheProvider<ISiteMap> Members
public bool Contains(string key)
{
return (Context.Session[key] != null);
}
public Caching.LazyLock Get(string key)
{
return (LazyLock)Context.Session[key];
}
public bool TryGetValue(string key, out Caching.LazyLock value)
{
value = this.Get(key);
if (value != null)
{
return true;
}
return false;
}
public void Add(string key, LazyLock item, ICacheDetails cacheDetails)
{
// NOTE: cacheDetails is normally used to set the timeout - you might
// need to roll your own method for doing that.
Context.Session[key] = item;
}
public void Remove(string key)
{
Context.Session.Remove(key);
}
public event EventHandler<MicroCacheItemRemovedEventArgs<T>> ItemRemoved;
#endregion
// NOTE: Normally this is called by a callback from the cache when an item exprires.
// It is required to ensure there is no memory leak because a sitemap has circular references
// that need to be broken explicitly. You need to work out how to call this when the user's session
// expires.
protected virtual void OnCacheItemRemoved(MicroCacheItemRemovedEventArgs<T> e)
{
if (this.ItemRemoved != null)
{
ItemRemoved(this, e);
}
}
}
Then inject it like this (StructureMap example shown):
// Setup cache
SmartInstance<CacheDetails> cacheDetails;
this.For<ICacheProvider<ISiteMap>>().Use<SessionStateCacheProvider<ISiteMap>>();
var cacheDependency =
this.For<ICacheDependency>().Use<NullCacheDependency>();
cacheDetails =
this.For<ICacheDetails>().Use<CacheDetails>()
.Ctor<TimeSpan>("absoluteCacheExpiration").Is(absoluteCacheExpiration)
.Ctor<TimeSpan>("slidingCacheExpiration").Is(TimeSpan.MinValue)
.Ctor<ICacheDependency>().Is(cacheDependency);
Option 2:
Append the user name to the siteMapCacheKey in a custom ISiteMapCacheKeyGenerator, and inject it via DI:
public class SessionBasedSiteMapCacheKeyGenerator
: ISiteMapCacheKeyGenerator
{
public UserBasedSiteMapCacheKeyGenerator(
IMvcContextFactory mvcContextFactory
)
{
if (mvcContextFactory == null)
throw new ArgumentNullException("mvcContextFactory");
this.mvcContextFactory = mvcContextFactory;
}
protected readonly IMvcContextFactory mvcContextFactory;
#region ISiteMapCacheKeyGenerator Members
public virtual string GenerateKey()
{
var context = mvcContextFactory.CreateHttpContext();
var builder = new StringBuilder();
builder.Append("sitemap://");
builder.Append(context.Request.Url.DnsSafeHost);
builder.Append("/?sessionId=");
builder.Append(context.Session.SessionID);
return builder.ToString();
}
#endregion
}
Inject it like this (StructureMap example):
this.For<ISiteMapCacheKeyGenerator>().Use<SessionBasedSiteMapCacheKeyGenerator>();
Note that using an external DI container is required.
Please see my open question here and explain to me why you would want to do this on GitHub, as it renders most of the features useless: https://github.com/maartenba/MvcSiteMapProvider/issues/16#issuecomment-22229604
This is my property on my code :
public KPage Padre
{
get
{
if (k_oPagina.father != null)
{
this.Padre = new KPage((int)k_oPagina.father);
}
else
{
this.Padre = null;
}
return this.Padre;
}
set { }
}
but it says :
An unhandled exception of type 'System.StackOverflowException' occurred in App_Code.rhj3qeaw.dll
Why? How can I fix it?
EDIT
After correct the code, this is my actual code :
private KPage PadreInterno;
public KPage Padre
{
get
{
if (PadreInterno == null)
{
if (paginaDB.father != null)
{
PadreInterno = new KPage((int)paginaDB.father);
}
else
{
PadreInterno= null;
}
}
return PadreInterno;
}
}
What do you think about?
The property is calling itself... usually properties call underlying fields:
public KPage Padre
{
get
{
if (k_oPagina.father != null)
{
_padre = new KPage((int)k_oPagina.father);
}
else
{
_padre = null;
}
return _padre;
}
set { }
}
private KPage _padre;
Your old code was recursively calling the get of the Padre property, hence the exception.
If your code only "gets" and doesn't need to store the value, you could also get rid of the backing field entirely:
public KPage Padre
{
get
{
return k_oPagina.father != null
? new KPage((int)k_oPagina.father)
: (KPage)null;
}
}
That said, I'd put this in a method.
This is also the same issue as the one you asked a couple of days ago:
An unhandled exception of type 'System.StackOverflowException' occurred
I would like to implement lazy loading on properties with PostSharp.
To make it short, instead of writing
SomeType _field = null;
private SomeType Field
{
get
{
if (_field == null)
{
_field = LongOperation();
}
return _field;
}
}
I would like to write
[LazyLoadAspect]
private object Field
{
get
{
return LongOperation();
}
}
So, I identify that I need to emit some code in the class to generate the backing field, as well as inside the getter method in order to implement the test.
With PostSharp, I was considering overriding CompileTimeInitialize, but I am missing the knowledge to get a handle over the compiled code.
EDIT:
The question can be extended to any parameterless method like:
SomeType _lazyLoadedField = null;
SomeType LazyLoadableMethod ()
{
if(_lazyLoadedField ==null)
{
// Long operations code...
_lazyLoadedField = someType;
}
return _lazyLoadedField ;
}
would become
[LazyLoad]
SomeType LazyLoadableMethod ()
{
// Long operations code...
return someType;
}
After our comments, I think I know what you want now.
[Serializable]
public class LazyLoadGetter : LocationInterceptionAspect, IInstanceScopedAspect
{
private object backing;
public override void OnGetValue(LocationInterceptionArgs args)
{
if (backing == null)
{
args.ProceedGetValue();
backing = args.Value;
}
args.Value = backing;
}
public object CreateInstance(AdviceArgs adviceArgs)
{
return this.MemberwiseClone();
}
public void RuntimeInitializeInstance()
{
}
}
Test code
public class test
{
[LazyLoadGetter]
public int MyProperty { get { return LongOperation(); } }
}
Thanks to DustinDavis's answer and comments, I could work on my own implementation, and I just wanted here to share it to help other people.
The main differences from the original answer are:
Implement the suggested "only run the operation once" (purpose of the lock)
Made the initialization status of the backing field more reliable by passing this responsibility to a boolean.
Here is the code:
[Serializable]
public class LazyLoadAttribute : LocationInterceptionAspect, IInstanceScopedAspect
{
// Concurrent accesses management
private readonly object _locker = new object();
// the backing field where the loaded value is stored the first time.
private object _backingField;
// More reliable than checking _backingField for null as the result of the loading could be null.
private bool _hasBeenLoaded = false;
public override void OnGetValue(LocationInterceptionArgs args)
{
if (_hasBeenLoaded)
{
// Job already done
args.Value = _backingField;
return;
}
lock (_locker)
{
// Once the lock passed, we must check if the aspect has been loaded meanwhile or not.
if (_hasBeenLoaded)
{
args.Value = _backingField;
return;
}
// First call to the getter => need to load it.
args.ProceedGetValue();
// Indicate that we Loaded it
_hasBeenLoaded = true;
// store the result.
_backingField = args.Value;
}
}
public object CreateInstance(AdviceArgs adviceArgs)
{
return MemberwiseClone();
}
public void RuntimeInitializeInstance() { }
}
I think the requirement cannot be accurately described as 'lazy loading', but is a special case of a more general caching aspect with in-AppDomain storage but without eviction. A general caching aspect would be able to handle method parameters.
I hope to phrase my question correctly (if not please help me to entitle it better)
,to make it clear,please take a look at my code.
class Factory
{
public string Name { get; set; }
private Person _manager;
public Person Manager
{
get
{
return (_manager );
}
set
{
_manager = value;
if (_manager.WorkPlace!=this)
{
_manager.WorkPlace = this;
}
}
}
public Factory(string name, Person manager)
{
Name = name;
Manager = manager;
if (Manager.WorkPlace ==null)
{
Manager.WorkPlace = this;
}
}
public Factory(string name, string managerFullName, int managerAge)
{
Name = name;
Manager = new Person(managerFullName, managerAge);
if (Manager.WorkPlace != this)
{
Manager.WorkPlace = this;
}
}
public void ShowInfo()
{...}
}
my problem appears when using first constructor of factory class
class Program
{
static void Main(string[] args)
{
Person oPerson1=new Person("Jon",30);
factory oFactory1=new Factory("f1",oPerson1);
factory oFactory2=new Factory("f2",oPerson1);
factory oFactory3=new Factory("f3",oPerson1);
factory oFactory4=new Factory("f4",oPerson1);
...
}
}
as you can see in this constructor I can use one person object(as a manger) more than one time
,in fact so many times it could be used , and there is nothing to prevent me . that
means one person could manage many factories,I dont want it.I want a person could
mange only one factory,how is that possible?
to handle this issue some workarounds came to my mind.
1- deleting that constructor and using only another one .(but I am looking for a better solution,I would like to have that constructor.)
2- throwing an exception in Run time that i hate it
as i know the c# compiler has nothing to prevent passing an object more than one time.
should I change something in design of the class?
what is your recommendation? what is the best solution ?thank u so much for any advices.
EDIT:Our business Logic
each factory has a manager ,its meaningless to have a factory without a manger.
and a person could be a manager.
person(1..1)-------------(0..1)factory
Relationships are better modeled with static code relationships than with imperative checks. That would enable the compiler to help you enforce the relationship.
Remove the manager from the factory and add the factory to the manager:
public class Manager : Person
{
public Manager(Factory factory)
}
In this way a Manager can manage only one Factory...
The answer is in your code:
set
{
_manager = value;
if (_manager.WorkPlace!=this)
{
_manager.WorkPlace = this;
}
}
Replace this with
set
{
if (value == null) // Edit: Add manager release capability to change factories
{
if(_manager != null)
_manager.WorkPlace = null;
_manager = null;
}
else if (value.WorkPlace == null)
{
_manager = value;
_manager.WorkPlace = this;
}
else
throw new ArgumentException();
}
I use the following "micropattern" for setters:
public Person Manager
{
get
{
return (_manager );
}
set
{
if (_manager != null)
{
_manager.WorkPlace = null;
}
_manager = value;
if (_manager != null)
{
_manager.WorkPlace = this;
}
}
Now, whenever you associate a manager with a factory, it's old manager is automatically de-associated with the factory.
Now, this does not prevent you reassigning a manager to a factory. But it will make sure that pointers are always in sync with each other.
I learned this trick from Martin Fowlers Refactoring. An online reference to the technique can be found here.
Despite that you hate it, throwing an exception in the constructor will notify you early that you have an error. You also need to make sure that the Person isn't already a manager.
public Factory(string name, Person manager)
{ if (Manager.WorkPlace != null && Manager.WorkPlace.Manager==manager)
{
var errmsg = "Cannot pass an existing manager to Factory constructor.";
throw new ArgumentException("manager",errmsg);
}
Name = name;
Manager = manager;
Manager.WorkPlace = this;
}
A "Cell" has an "Item"; and an "Item" has a "Cell". If you update one of them; the other should be updated as well. So In Cell we have a property like:
public Item CurrentItem
{
get { return _currentItem; }
set
{
if (_currentItem == value) return;
var oldItem = _currentItem;
_currentItem = value;
if (oldItem != null && oldItem.CurrentCell == this)
{
oldItem.CurrentCell = null;
}
if (value != null)
{
value.CurrentCell = this;
}
}
}
In the opposite site (In Item) we have following property:
public Cell CurrentCell
{
get { return _currentCell; }
set
{
if (_currentCell == value) return;
var oldCell = _currentCell;
_currentCell = value;
if (oldCell != null && oldCell.CurrentItem == this)
{
oldCell.CurrentItem = null;
}
if (value != null)
{
value.CurrentItem = this;
}
}
}