Access ViewState from Static method in aspx page - asp.net

suppose i have one static method and i need to access viewstate from that method...how could i do so...i know it is not possible but there must be some way out.
[WebMethod]
public static string GetData(int CustomerID)
{
string outputToReturn = "";
ViewState["MyVal"]="Hello";
return outputToReturn;
}

You can get the reference to the page via HttpContext.CurrentHandler. But since Control.ViewState is protected you can't access it (without using reflection) as opposed to the Session which is accessible via HttpContext.Current.Session.
So either don't use a static method, use the Session or use this reflection approach:
public static string CustomerId
{
get { return (string)GetCurrentPageViewState()["CustomerId"]; }
set { GetCurrentPageViewState()["CustomerId"] = value; }
}
public static System.Web.UI.StateBag GetCurrentPageViewState()
{
Page page = HttpContext.Current.Handler as Page;
var viewStateProp = page?.GetType().GetProperty("ViewState",
BindingFlags.FlattenHierarchy |
BindingFlags.Instance |
BindingFlags.NonPublic);
return (System.Web.UI.StateBag) viewStateProp?.GetValue(page);
}
However, this won't work if called via WebService, because then it's outside of Page-Lifecycle.

You might be able use [WebMethod(EnableSession=true)] for your PageMethod, and use Session instead of ViewState. Remember, with a static PageMethod no instance of the Page class is ever created, so nice things like ViewState simply are not there and there is no way to make them be there.

I tried this and worked for me:
Create a class conteining the properties of the viewState you want to access to
In the constructor pass the real ViewState
Create a static instance of the class but not initialize it
In the PageLoad initialize Not static class and the static one
Access the ViewState using static class properties
public class Repository
{
public int a
{
get
{
if (_viewState["a"] == null)
{
return null;
}
return (int)_viewState["a"];
}
set
{
_viewState["a"] = value;
}
}
public StateBag _viewState;
public Repository(StateBag viewState)
{
_viewState = viewState;
}
}
static Repository staticRepo;
protected void Page_Load(object sender, EventArgs e)
{
Repository repo = new Repository(ViewState);
staticRepo = repo;
}
public static void testMethod()
{
int b = staticRepo.a;
}

Related

Change default session provider in ASP.NET

I want to change my session proviced to statically typed - I just hate typing strings because of many many errors I do.
What technology am I using? ASP.NET MVC via EXT.NET MVC
I was trying to do that using web.config but the problem is that after add session state to it visual is not going to compile my code because of that session should be using strings as keys.
I want to use session by enums such as :
public enum SessionEnum{Model}
public class Bar{
void foo(){
Session[SessionEnum.Model] = "blah";
}
}
I am aware that I can create wrapper converting enums to strings but it's not very satisfying solution for me.
public class StorageWrapper{
public object this[SessionEnum enum]{ get{return Session[enum.toString()]}; //+set
}
What I did was create static object for base class for all of my controllers and then I was able to use it across them but after closing and opening the page again I wasn't able to get values from it. I guess I should serialize them somehow but I have no idea how.
Is there any way to do that?
EDIT
My session now looks like this :
[Serializable]
public abstract class DataWrapper<T> : HttpSessionStateBase
{
Dictionary<T, object> Dictionary { get; set; } = new Dictionary<T, object>();
public object this[T a]
{
get
{
try
{
return Dictionary[a];
}
catch
{
return null;
}
}
set { Dictionary[a] = value; }
}
}
[Serializable]
public class SessionWrapper : DataWrapper<SessionNames>
{}
public enum SessionNames { Model, Login, LastOpenedFile }
It's very simple.
Create a UserSession object which does everything you want (holds your values as enum etc), instantiate it, then put it in the session.
var US = new UserSession();
US.stuff = somestuff;
Session["UserSess"] = US
Then you can just always use Session["UserSess"].stuff;
Mmmm, wouldn't you use static const string instead of an enum?
using System.Web;
public static class SessionEnum
{
public static const string Model = "_Session_Model";
public static const string Login = "_Session_Login";
public static const string LastOpenedFile = "_Session_LastOpenedFile ";
}
class test
{
void test()
{
Session[SessionEnum.Model] = "blah";
}
}

ASP.NET is System.Web.UI.Page thread safe

I am wondering if the following code is thread safe?
Can i be be sure that UniqueFoo will indeed be the Unique Foo and will not be override?
public partial class Dummy : System.Web.UI.Page
{
public string UniqueFoo{ get; set; }
protected void Page_Load(object sender, EventArgs e)
{
var id = int.Parse(Request["Id"]);
UniqueFoo = SomeThreadSafeWCF.GetUniqueFoo(id);
}
}
what about the following (static)
public partial class Dummy : System.Web.UI.Page
{
public static string UniqueFoo{ get; set; }
protected void Page_Load(object sender, EventArgs e)
{
var id = int.Parse(Request["Id"]);
UniqueFoo = SomeThreadSafeWCF.GetUniqueFoo(id);
}
}
i later want to use UniqueFoo in a [WebMethod]
[WebMethod]
public static void SetSomeObject(SetSomeObject obj)
{
SomeThreadSafeWCF service = new SomeThreadSafeWCF ();
service.SetSomeObject(UniqueFoo, obj);
}
EDIT:
I am getting SetSomeObject from JS and UniqueFoo is coming from ASP.NET
will i have any issues when NOT using the static in my Dummy class according to your answers?
Surely your first sample is thread safe because when a request of a page post to the Web Server asp.net make new instance of your page and call page_load so if your SomeThreadSafeWCF.GetUniqueFoo() always make a unique Foo everything is thread save
Your second code snippet is not thread safe because you are modifying the value of a static field. So for example if later in this page you attempt to read the value of this UniqueFoo field you might not get the value you expect.
The first code snippet is fine because the field is not static.
If you want to use the UniqueFoo in a WebMethod then I would recommend you to pass it to this web method when calling it.
[WebMethod]
public static void SetSomeObject(SetSomeObject obj, string uniqueFoo)
{
SomeThreadSafeWCF service = new SomeThreadSafeWCF ();
service.SetSomeObject(uniqueFoo, obj);
}

Using castle windsor with interceptors and asp.net

I'm trying to add logging with aspect orientated programming using castle windsor in plain asp.net, i.e. not MVC
I've added a class that implements the IInterceptor interface and an attribute that inherits from Attribute.
public class LogAttribute : Attribute
{
public Level LogLevel { get; set; }
public LogAttribute(Level level)
{
LogLevel = level;
}
}
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
MethodInfo mi = invocation.Method;
LogAttribute[] atts = (LogAttribute[])mi.GetCustomAttributes(typeof(LogAttribute), true);
// if method not marked with InternalUseRestricted attribute, then pass on call
if (atts.Length == 0)
{
invocation.Proceed();
}
else
{
ISeiLogger log = LoggerFactory.GetLogger(mi.DeclaringType.ToString());
//assume only one logging attribute
//log on entry
log.LogEnter(atts[0].LogLevel);
//allow code to continue
invocation.Proceed();
//log on exit
log.LogExit(atts[0].LogLevel);
}
}
}
Now in the global.asax.cs I've added the following:
public partial class Global : System.Web.HttpApplication, IoCProvider
{
private void InitializeIoC()
{
container = new WindsorContainer();
container.Install(new Sei.Aspect.AspectInstaller());
}
public IWindsorContainer Container
{
get { return container; }
}
private static Sei.Logging.ISeiLogger log;
private IWindsorContainer container;
public override void Init()
{
base.Init();
InitializeIoC();
}
and I've created an installer class:
public class AspectInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
//container.Register(AllTypes.FromAssembly(Assembly.GetExecutingAssembly()).BasedOn<IInterceptor>().Configure(component => component.LifeStyle.PerWebRequest));
container.Register(Component.For<IInterceptor>().ImplementedBy<LoggingInterceptor>().LifeStyle.PerWebRequest);
container.Register(Component.For<IInterceptor>().ImplementedBy<InternalUseRestrictedInterceptor>().LifeStyle.PerWebRequest);
container.Register(Component.For<IInterceptor>().ImplementedBy<CachingInterceptor>().LifeStyle.PerWebRequest);
}
}
I now want to add the attribute to some arbitary page's code behind class and some arbitary virtual method, as in
[Log(Level.Info)]
protected string Login(string username, string password)
{
DoSomething();
}
This obviously doesn't work. Do I need to change the way I'm instantiating the page (its a page's code-behind class) to use a container? Or is it the way I'm registering the interceptors? I want to be able to use the interceptors on any class going forward and not have to tell the container about each and every class that I have in my application.
Short answer: it's not possible.
Long answer: due to the way ASP.NET Web Forms works, it doesn't let anyone interfere with the page instantiation. Some claim that using a custom PageHandlerFactory lets you do IoC, but this only lets you set properties after the page has been instantiated, which is simply not enough for proxying.
So runtime proxy libraries such as DynamicProxy or LinFu can't do anything about this. But you may be able to use compile-time aspect weavers, such as PostSharp.
Alternatively, make your code-behind as slim as possible, deferring actual logic to Windsor-managed components.

Call Public Property Declared in a ASPX Page from a Different ASPX Page

How can I call a public property declared on a ASPX page from a different ASPX Page? Is that possible? It is a website project. How can I get/call this property from a different aspx page? I have attempted this from the other page, but it is not recognizing the partial class: private Test_Default _test; It does not recognize the "Test_Default"
I.E.
public partial class Test_Default : System.Web.UI.Page
{
private string myAge = string.empty;
public string Name
{
get
{
return myName;
}
set
{
myName = value;
}
}
If you need a piece of shared code, create a class for it in the APP_CODE folder.
See MSDN documentation here and here.
I would create a separate class exposing the property you are wanting to work with, and store the value in Session :
public class MyClass
{
public static string MyName
{
get
{
if (Session["MY_NAME"] != null)
{
return Session["MY_NAME"].ToString();
}
return String.Empty;
}
set { Session["MY_NAME"] = value; }
}
}
You should be able to call that from either Page. If it's a complex object, then change the type from string to your object.
Hope that helps!!

asp.net store object class in viewstate (or other ideas)

I've build a class like this:
private class TestResults
{
public bool IsAdmitted { get; set; }
public bool IsDuplicate { get; set; }
public bool IsVerified { get; set; }
}
The values of this class are set at postback by clicking a radiobutton list. Problem however is I don't know how to save this values across multiple postbacks. I thought of using viewstate but I'm not quite sure how to do it with this class.
Maybe I'm missing some important thing here.
Hope someone can point me in the right direction
thanks for your time!
Kind regards,
Mark
Just sticking this class in viewstate is pretty simple:
ViewState["SomeUniqueKey"] = myTestResults;
var testResults = (TestResults)ViewState["SomeUniqueKey"];
Your class will need to be marked with the [Serializable] attribute though.
try using the Session cache instead
var testResults = new TestResults();
//set values
Session["TestResults"] = testResults;
Retrieving them later on:
var testResults = Session["TestResults"] as TestResults;
if (testResults != null)
{
//use it
}
You can use
Session.Add("TestResults", Your_Test_Result_Object)
Session Object Explanation
If you don't need this value on other pages or in other places throughout the app, you can use viewstate.
Use the Page.ViewState object bag to store it:
public partial class Page1 : Page {
protected void button1_click(object sender, EventArgs e) {
ViewState["myObject"] = testResultsObject;
}
}
You could also wrap the access to it in a property on the page:
public partial class Page1 : Page {
public TestResults TestResults {
get{ return ViewState["TestResults"] as TestResults; }
set{ ViewState["TestResults"] = value; }
}
}

Resources