views:

522

answers:

6

Hi, I come from a C/C++ background and am having trouble doing some things in C#. My problem right now is that I need a static keyword that works like in C++. So that the property is global to all instances of the class, which is what C#'s does. But what I don't want is the persistence in C#(/ASP.NET). I want the static property global to all instances of a class on the currently executing page only.

How can it be possible to do this?

Basically what I'm using this for is unique naming which must only be unique on the currently executing page. If the static property is persistent, then there is a much higher chance of integer rollover in periods of high traffic, which could lead to the same value being used twice.

Like if someone went to a page with

static int i=0;
page_load...{
  lbl.Text=i;
  i++;
}

then they would get 0. and if someone else went to the same page they would also get 0. But also having the static property so that it's the same in all instances of the class.

A: 

Where are you referencing the "static" from? If it is just child controls, I would add a regular instance property to your page class, then reference that variable through the page property on the child controls.

public class DefaultPage : Page {
    public string MyProperty { get; set; }
} 

public class DefaultControl : UserControl {
    //...
    ((DefaultPage)this.Page).MyProperty
    //...
}

Honestly though, if I saw this code, I would think the design is a little backwards. Page should be supplying the user control with all of the data it needs.

Bob
+4  A: 

Unfortunately you're not going to be able to get what you want in this case because you're trying to combine two incompatible concepts

  • static is a modifier in C# which frees a member (method, property, field, etc ...) from being bound to an instance. It's instance more accurately bound to a type within an AppDomain.
  • A counter specific to the current executing page is necessarily associated with an instance

I think your best bet is to create an instance level property and do what is needed to pass down the instance and update the counter.

But I'm still a bit unclear about your scenario. It seems like you could want any of the following ...

  • A property specific to the currently instance of the executing page
  • A property specific to all instances of the executing page
  • A property specific to the all uses of the page within the current session

Could you clarify which of these is the problem?

JaredPar
I don't think he can do this with any specific keyword but I believe I provided the correct solution.
Chris Marisic
+1  A: 

I'm not really sure I understand your question 100% however...

I believe what your really looking for is to store an object in the Session.

What I would do is something like this

public class PageBase : Page
{

    public MyObject Foo 
    {
        get { return (MyObject)Session["myobject"]; }
        set { Session["myobject"] = value; }
    }
}

And change your pages to inherit from PageBase

Edit: After looking up the implications on [ThreadStatic] inside ASP.NET I came across this blog post by Scott Hanselmen saying, no no no! A tale of two techniques: The [ThreadStatic] Attribute and System.Web.HttpContext.Current.Items. He also pointed out the existence of the HttpContext having a builtin dictionary that you can store objects in. I forgot entirely about this mostly because so far I've never once found anything useful for it.

Chris Marisic
`Session` persists across different requests (for the same user).
LukeH
@Luke: That's true, but reading between the lines... that may be what the original poster wants.
R. Bemrose
No, it's not.. though per-user it should never overflow(for surely someone can't generate a over 10,000 page requests in an 8 hour day(assuming they are active enough to keep session from dying)
Earlz
+3  A: 

There's no really clean way to do this, but if your object will always live in the context of a HTTP page/request, you could use the Items collection of the current HttpContext:

public class YourClass
{
    private static readonly string _itemKey = "Key Goes Here";
    private readonly HttpContext _context;

    public YourClass()
    {
        _context = HttpContext.Current;
        if (_context == null) throw new InvalidOperationException("Boom!");

        // set a default value here if you like...
        if (_context.Items[_itemKey] == null)
        {
            _context.Items[_itemKey] = new YourType("Default Value");
        }
    }

    public YourType NonPersistentStatic
    {
        get { return (YourType)(_context.Items[_itemKey]); }
        set { _context.Items[_itemKey] = value; }
    }
}
LukeH
I think we both got this nailed down as the answer and it's just the poster's preference if he wants to exist per session or per request. I think session makes more sense since why would it need to be static only for a request since that could be handled by an instance object passed around or dependency injected.
Chris Marisic
A: 

What you are asking for is a ThreadStatic variable, however that is not a good solution. It would work, but it's not a robust way to handle it. A ThreadStatic variable is for example only initialized for the first thread, so you need to handle the initialization for each thread yourself.

First of all you should look into the built in capabilities for providing a unique id for each element. If you for example have a repeater so that the same control is repeated, each iteration gets a unique id which is prepended to the control id. You can use the ClientID property to get this unique id.

If you need to handle the naming yourself, you should use a member variable in the Page class to keep track of the naming. You can easily initialize the variable in the constructor of the class, and as the variable doesn't exist before that, you are sure that you can't accidentally use it before it's initialized.

Guffa
A: 

Not sure why you would need that. You can store stuff unique to a session in the HTTPContext.Current.Session. You can store stuff that is unique to a request in HTTPContext.Current.ViewState.

To do what you want to do, you would need to declare an application scopped variable of an object that that is threadsafe.The example below example would give you a unique number across all pages.

1) Create a thread-safe counter class since the Application scopped variables are not thread safe by defaut

public class ThreadSafeCounter
{
  private object _padlock = new object;
  private int _counterValue = 0;

  public int GetNextValue()
  {
     int temp;
     lock(_padlock)
     {
       _counter++;
       temp = _counter;
     }
     return temp;
  }

}

2) Create the application variable in the Global.asax Application_Start event

HttpContext.Current.Application["MyCounter"] = new ThreadSafeCounter();

3) Access this in your page's code behind

var counter = HttpContext.Current.Application["MyCounter"] as ThreadSafeCounter;
if (counter != null)
{
  var uniqueValue = counter.GetNextValue();
  // DO SOME WORK HERE
}
else
{
  //throw some exception here
}

A potential gotcha: If you deploy this across a server farm or you have more than 1 worker process, make sure that your session mode is either a state server or SQL Server based because if it is InProc the each server/process that handles the request will have its own counter.

Gus