Refer to session variable without casting it to its type everytime - asp.net

I have a session variable that is a class instance. I declared it in Global.asax:
void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
Session["SiteVariables"] = new SiteVariables();
}
Now I need to refer to some of the members of this variable in several places of my solution but, as far as I understand, I have to do it this way:
SiteVariables objSiteVariables = (SiteVariables)Session["SiteVariables"];
Label1.Text = objSiteVariables.permiss;
I wonder if there is a way, e.g. setting up somewhere a static variable or something, that allows me just to do:
Label1.Text = objSiteVariables.permiss;
in any place of my project.
Thank you!

You may create your own helper type/method.
public class Util
{
public static SiteVariables Variables
{
get
{
return HttpContext.Current.Session["SiteVariables"] as SiteVariables;
}
}
}
And assign value to
Label1.Text=Util.Variables.permiss;

You can create a wrapper for the session, which will allow type safe access like this:
public class SessionHandler
{
public static SessionHandler CurrentSession
{
get
{
SessionHandler session =
(SessionHandler)HttpContext.Current.Session["SessionId"];
if (session == null)
{
session = new SessionHandler();
HttpContext.Current.Session["SessionId"] = session;
}
return session;
}
}
public SiteVariables SiteVariables { get; set; }
}
You can use it like this:
// assign
SessionHandler.CurrentSession.SiteVariables = new SiteVariables();
// retrieve
SiteVariables objSiteVariables = SessionHandler.CurrentSession.SiteVariables;
This way you can add more sessions just by adding more property to the SessionHandler class.

Related

Accessing OutArgument value of Receive implementation child activity within custom WF4 activity

Using VS2012/.NET 4.5 I am creating a custom activity which implements a Receive child activity (as an implementation child). The parameters are in the example below fixed to just one: OutValue of type Guid.
I really would love to access the value of incoming parameter value in ReceiveDone, because I need to work with it and transform it before returning it from the activity. Please ignore that I am currently using a Guid, it still fails to access the value with and InvalidOperationException:
An Activity can only get the location of arguments which it owns. Activity 'TestActivity' is trying to get the location of argument 'OutValue' which is owned by activity 'Wait for
workflow start request [Internal for TestActivity]'
I have tried everything I could think of, but am stupefied. There must be a way to do this very simple thing?
public class TestActivity : NativeActivity<Guid>
{
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
var content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>()
{
// How to access the runtime value of this inside TestActivity?
{"OutValue", new OutArgument<Guid>()}
});
startReceiver = new Receive()
{
DisplayName = string.Format("Wait for workflow start request [Internal for {0}]", this.DisplayName),
CanCreateInstance = true,
ServiceContractName = XName.Get("IStartService", Namespace),
OperationName = "Start",
Content = content
};
foreach (KeyValuePair<string, OutArgument> keyValuePair in content.Parameters)
{
metadata.AddImportedChild(keyValuePair.Value.Expression);
}
metadata.AddImplementationChild(startReceiver);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(startReceiver, ReceiveDone);
}
private void ReceiveDone(NativeActivityContext context, ActivityInstance completedInstance)
{
var receive = completedInstance.Activity as Receive;
ReceiveParametersContent content = receive.Content as ReceiveParametersContent;
try
{
// This causes InvalidOperationException.
// An Activity can only get the location of arguments which it owns.
// Activity 'TestActivity' is trying to get the location of argument 'OutValue'
// which is owned by activity 'Wait for workflow start request [Internal for TestActivity]'
var parmValue = content.Parameters["OutValue"].Get(context);
}
catch (Exception)
{ }
}
private Receive startReceiver;
private const string Namespace = "http://company.namespace";
}
Use internal variables to pass values between internal activities.
Although not directly related to your code, see the example below which should give you the idea:
public sealed class CustomNativeActivity : NativeActivity<int>
{
private Variable<int> internalVar;
private Assign<int> internalAssign;
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
internalVar = new Variable<int>("intInternalVar", 10);
metadata.AddImplementationVariable(internalVar);
internalAssign = new Assign<int>
{
To = internalVar,
Value = 12345
};
metadata.AddImplementationChild(internalAssign);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(internalAssign, (activityContext, instance) =>
{
// Use internalVar value, which was seted by previous activity
var value = internalVar.Get(activityContext);
Result.Set(activityContext, value);
});
}
}
Calling the above activity:
WorkflowInvoker.Invoke<int>(new CustomNativeActivity());
Will output:
12345
Edit:
In your case your OutArgument will be the internalVar
new OutArgument<int>(internalVar);
You need to use OutArgument and them to variables. See the code example with the documentation.
I may have tried everything I thought of, but I am stubborn and refuse to give up, so I kept on thinking ;)
I here have changed my example to use a Data class as a parameter instead (it does not change anything in itself, but I needed that in my real world example).
This code below is now a working example on how to access the incoming data. The use of an implementation Variable is the key:
runtimeVariable = new Variable<Data>();
metadata.AddImplementationVariable(runtimeVariable);
And the OutArgument:
new OutArgument<Data>(runtimeVariable)
I can then access the value with:
// Here dataValue will get the incoming value.
var dataValue = runtimeVariable.Get(context);
I haven't seen an example elsewhere, which does exactly this. Hope it will be of use to any one but me.
The code:
[DataContract]
public class Data
{
[DataMember]
Guid Property1 { get; set; }
[DataMember]
int Property2 { get; set; }
}
public class TestActivity : NativeActivity<Guid>
{
public ReceiveContent Content { get; set; }
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
runtimeVariable = new Variable<Data>();
metadata.AddImplementationVariable(runtimeVariable);
Content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>()
{
{"OutValue", new OutArgument<Data> (runtimeVariable)}
});
startReceiver = new Receive()
{
DisplayName = string.Format("Wait for workflow start request [Internal for {0}]", this.DisplayName),
CanCreateInstance = true,
ServiceContractName = XName.Get("IStartService", Namespace),
OperationName = "Start",
Content = Content
};
metadata.AddImplementationChild(startReceiver);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(startReceiver, ReceiveDone);
}
private void ReceiveDone(NativeActivityContext context, ActivityInstance completedInstance)
{
// Here dataValue will get the incoming value.
var dataValue = runtimeVariable.Get(context);
}
private Receive startReceiver;
private Variable<Data> runtimeVariable;
private const string Namespace = "http://company.namespace";
}

Strangeness with DataContext and GridView / ListView

I have a Windows 8 store app based off of the grouped template project, with some renames etc. However, I'm having a hard time getting the ItemsSource databinding to work for both non-snapped and snapped visual states.
I have a property, that, when set, changes the ItemsSource property, but I can only get one of the controls to bind at a time (either the GridView for non-snapped, or the ListView for snapped).
When I use the following, only the non-snapped binding works and the snapped binding shows no items:
protected PickLeafModel ListViewModel
{
get
{
return (PickLeafModel)m_itemGridView.ItemsSource;
}
set
{
m_itemGridView.ItemsSource = value;
m_snappedListView.ItemsSource = value;
}
}
If I comment out one of the setters, the snapped view shows items but the non-snapped view shows nothing:
protected PickLeafModel ListViewModel
{
get
{
return (PickLeafModel)m_itemGridView.ItemsSource;
}
set
{
//m_itemGridView.ItemsSource = value;
m_snappedListView.ItemsSource = value;
}
}
It's as if I can bind my view model only to one property at a time. What am I doing wrong?
Since I am generating my data model on another thread (yes, using the thread pool), I cannot make it inherit from DependencyObject. If I do, I get a WrongThreadException.
So to make it work I have done the following:
public class PickLeafModel : IEnumerable
{
public PickLeafModel()
{
}
public IEnumerator GetEnumerator()
{
if (m_enumerator == null)
{
m_enumerator = new PickLeafModelViewDataEnumerator(m_data, m_parentLeaf);
}
return m_enumerator;
}
private SerializableLinkedList<PickLeaf> m_data =
new SerializableLinkedList<PickLeaf>();
}
and then my items look like this:
// Augments pick leafs by returning them wrapped with PickLeafViewData.
class PickLeafModelViewDataEnumerator : IEnumerator
{
public PickLeafModelViewDataEnumerator(
SerializableLinkedList<PickLeaf> data, PickLeaf parentLeaf)
{
m_viewDataList =
new System.Collections.Generic.LinkedList<PickLeafViewData>();
foreach (PickLeaf leaf in data)
{
PickLeafViewData viewData = new PickLeafViewData();
viewData.copyFromPickLeaf(leaf, parentLeaf);
m_viewDataList.AddLast(viewData);
}
m_enumerator = m_viewDataList.GetEnumerator();
}
public void Dispose()
{
m_viewDataList = null;
m_enumerator = null;
}
public object Current
{
get
{
return m_enumerator.Current;
}
}
public bool MoveNext()
{
return m_enumerator.MoveNext();
}
public void Reset()
{
m_enumerator.Reset();
}
private IEnumerator<PickLeafViewData> m_enumerator = null;
private System.Collections.Generic.LinkedList<PickLeafViewData>
m_viewDataList;
}
}
Is there something I'm doing fundamentally wrong?
Help appreciated.
Thanks!
Thankfully there is a much easier way to do what you are trying!
Create a class called your ViewModel as shown below:
public class DataViewModel
{
public DataViewModel()
{
Data = new ObservableCollection<PickLeafViewData>(new PickLeafModelViewDataEnumerator(m_data, m_parentLeaf));
}
public ObservableCollection<PickLeafViewData> Data
{
get;
set;
}
}
Now on the code behind set the Page.DataConected to equal an instance of the above class.
And finally on both your snapped listview, and the grid view set the item source to this:-
ItemsSource="{Binding Data}"
That should work nicely for you.
Thanks to Ross for pointing me in the right direction.
I'm not 100% happy with this solution, but it does work. Basically the idea is that after I get back the PickLeafModel from the worker threads, I transplant its internal data into a derived version of the class which is data binding aware.
public class PickLeafViewModel : PickLeafModel, IEnumerable
{
public PickLeafViewModel()
{
}
public PickLeafViewModel(PickLeafModel model)
{
SetData(model);
}
public void SetData(PickLeafModel model)
{
model.swap(this);
}
public IEnumerator GetEnumerator()
{
if (m_observableData == null)
{
m_observableData = new ObservableCollection<PickLeafViewData>();
var data = getData();
PickLeaf parentLeaf = getParentLeaf();
foreach (PickLeaf leaf in data)
{
PickLeafViewData viewData = new PickLeafViewData();
viewData.copyFromPickLeaf(leaf, parentLeaf);
m_observableData.Add(viewData);
}
}
return m_observableData.GetEnumerator();
}
and the page code is as follows:
protected PickLeafViewModel ListViewModel
{
get
{
return DataContext as PickLeafViewModel;
}
set
{
DataContext = value;
}
}
whenever I want to set ListViewModel, I can do this:
ListViewModel = new PickLeafViewModel(model);
and swap looks like:
private static void swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
// Swaps internals with the other model.
public void swap(PickLeafModel other)
{
swap(ref m_data, ref other.m_data);
...
Also, PickLeafModelViewDataEnumerator can be deleted altogether.

User Control's child controls not getting instantiated

public partial class ChatUserControl : System.Web.UI.UserControl
{
UserChatClass ucc = new UserChatClass();
public ChatUserControl()
{
lblChatFriend = new Label();
txtChatMessage = new TextBox();
imgFriend = new Image();
rpChatMessages = new Repeater();
}
public string ChatFriend { get { return this.lblChatFriend.Text; } set { this.lblChatFriend.Text = value; } }
public string imgFriendUrl { get { return this.imgFriend.ImageUrl; } set { this.imgFriend.ImageUrl = value; } }
public object rpChatDataSource { get { return this.rpChatMessages.DataSource; } set { this.rpChatMessages.DataSource = value; } }
public Repeater rpChatMessagesToBind { get { return this.rpChatMessages; } set { this.rpChatMessages = value; } }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ChatUserControl user1 = new ChatUserControl();
divChatUserControlCover.Controls.Add(user1);
}
}
private void BindUserControls()
{ ChatUserControl user1 = divChatUserControlCover.Controls[1] as ChatUserControl;
user1.ChatFriend = row["username"].ToString();
user1.imgFriendUrl = "../../HttpImageHandler.jpg?username=" + row["username"].ToString();
DataSet dsCM = ucc.GetChatMessages(Session["username"].ToString(), row["username"].ToString());
user1.rpChatDataSource = dsCM;
user1.DataBindForRpChatMessagesToBind();
user1.Visible = true;
}
Master.aspx
<div id="divChatUserControlCover" runat="server">
</div>
Ok I have edited the code and now I have created properties. How do I call the DataBind method for rpChatMessages? I also cant see my usercontrol on page. Why
I'm not sure if your trying to reference the first label or second label. If its the second lable you can't just do chatMessage. you would have to do
((Label)rpChatMessages.FindControl("chatMessage")) due to scope of controls.
When you reference a component inside another component (ie Repeater) the child component no longer belongs to the document (implied this) but rather belongs to the control, ie
this.rpChatMessages { chatMessage }
I think you are just trying to pass a value to one control inside a UserControl if this is correct, declare a public property like this:
ASCX code behind
public string MyProperty
{
get
{
return this.lbl.Text;
}
set
{
this.lbl.Text = value;
}
}
Setting the value to the UserControl
private void BindUserControls()
{
ChatUserControl user1 = divChatUserControlCover.Controls[1] as ChatUserControl;
user1.MyProperty = row["username"].ToString();
Setting the value in the page markup
<uc1:ChatUserControl MyProperty='<%# Eval("some field") %>' ...
Edit 1
Remove that line
public object rpChatDataSource { get { return this.rpChatMessages.DataSource; } set { this.rpChatMessages.DataSource = value; }
And instead add a method
public void BindMyRepeaterOrWhatever(IEnumerable<Yourentity> data)
{
this.myDataBoundControl.DataSource = data;
this.myDataBoundControl.DataBind();
}
You can change the IEnumerable<Yourentity> data for object data but if you can pass a strongly typed enumeration would be better
To my surprise I found why my user control's child controls dont get instantiated. Its because ChatUserControl user1 = new ChatUserControl() doesnt get its child controls initialized.
The proper way to create a new intance of user control is this way....
ChatUserControl user1 = (ChatUserControl)Page.LoadControl("~/ChatUserControl.ascx");

ASP.NET custom controls - custom property doesn't hold the assigned value on postaback

I have a custom asp-net control that inherits from another one and its works as expected, though the properties are only set properly if i code them in the markup directly, so for instance if i need set a property at runtime that is some dynamic value, this value is never set or somehow lost.
Here's the markup code:
<!--related form-->
<fw:advancedformdisplay id="formDisp" runat="server" captchaenabled="true" EmailEnabled="true" EnableViewState="true" captchaprivatekey="xxxxxxxxxxxxxxxxxxxx" captchapublickey="xxxxxxxxxxxxx" captchatheme="white" SourceType="MenuItem" SourceMainId="Auto">
</fw:advancedformdisplay>
This is the code of the control:
[DefaultProperty("CaptchaEnabled"),ToolboxData("<{0}:AdvancedFormDisplay runat=server></{0}:AdvancedFormDisplay>"), Description("This is an enhanced FormDisplay control that inlcudes Googles Captcha control is enabled")]
public class AdvancedFormDisplay :SiteBuilder.WebControls.FormDisplay
{
bool _CaptchaEnabled = false, sendEmail = false;
string captchaErrorMessage = "The verification code entered is not valid. Please try again!";
RecaptchaControl captchaControl = null;
string captchaPrivateKey = "", captchaPublicKey = "", captchaTheme = "clean";
string originalFormHtml = string.Empty;
string afterText = string.Empty, beforeText = string.Empty;
Literal litHtmlForm = null;
string captchaErrorClass = "errorCaptcha";
public string EmailBeforeText
{
get { return beforeText; }
set { beforeText = value; }
}
public string EmailAfterText
{
get { return afterText; }
set { afterText = value; }
}
public string CaptchaErrorClass
{
get { return captchaErrorClass; }
set { captchaErrorClass = value; }
}
public bool CaptchaEnabled
{
get { return _CaptchaEnabled; }
set { _CaptchaEnabled = value; }
}
public bool EmailEnabled
{
get { return sendEmail; }
set { sendEmail = value; }
}
public string CaptchaErrorMessage
{
get { return captchaErrorMessage; }
set { captchaErrorMessage = value; }
}
/// <summary>
/// red,white,blackglass,clean
/// </summary>
public string CaptchaTheme
{
get { return captchaTheme; }
set { captchaTheme = value; }
}
public string CaptchaPrivateKey
{
get { return captchaPrivateKey; }
set { captchaPrivateKey = value; }
}
public string CaptchaPublicKey
{
get { return captchaPublicKey; }
set { captchaPublicKey = value; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
}
public override void OnSaved(FormDisplayEventArgs e)
{
//If captcha control is enabled we need to adda bit of code to redirect form properly
if (CaptchaEnabled && e.Redirect && !e.SendMail)
{
//Do Stuff
}
if(sendEmail)
{
//Send email
}
base.OnSaved(e);
}
public override void OnSaving(FormDisplayEventArgs e)
{
if (CaptchaEnabled)
{
//Validate and do stuff
}
base.OnSaving(e);
}
}
And then in my asp.net page that is using control, created by markup code, in the Page_Load() i try to assign some values to some properties and and the values aren't set properly, meaning that if i have set for isntance, the property EmailBeforeText = "somthing" this value will not be assigned..
protected void Page_Load(object sender, EventArgs e)
{
//2: Get the language of menuitem - Based on current culture setting (for by dropdownbox - change logic)
try
{
currentCulture = Thread.CurrentThread.CurrentCulture.ToString();
// Redirect if domain does not match rootnode.
DomainChecker.CheckURL(this.Request, this.Response, currentCulture);
if (footerArticle != null)
footerArticle.SourceMenuId = Digimaker.Config.Custom.Get("FooterID_" + currentCulture).ToString();
}
catch
{
currentCulture = "en-GB";
if( footerArticle != null )
footerArticle.SourceMenuId = Digimaker.Config.Custom.Get("FooterID_" + currentCulture).ToString();
}
Any ideas what i'm missing here?
Thanks a lot for your reading!
Regards,
byte_slave
short answer: use viewstate to persist your custom values!
Understanding ASP.NET ViewState whitepaper (see example with NavigateUrl)
edit: as reading the white-paper is obviously a really hard thing:
Each control is responsible for storing its own state, which is
accomplished by adding its changed state to its ViewState property.
The ViewState property is defined in the System.Web.UI.Control class,
meaning that all ASP.NET server controls have this property available.
(When talking about view state in general I'll use lower case letters
with a space between view and state; when discussing the ViewState
property, I'll use the correct casing and code-formatted text.)
If you examine the simple properties of any ASP.NET server control
you'll see that the properties read and write directly to the view
state. (You can view the decompiled source code for a .NET assembly by
using a tool like Reflector.) For example, consider the HyperLink Web
control's NavigateUrl property. The code for this property looks like
so:
public string NavigateUrl
{
get
{
string text = (string) ViewState["NavigateUrl"];
if (text != null)
return text;
else
return string.Empty;
}
set
{
ViewState["NavigateUrl"] = value;
}
}
As this code sample illustrates, whenever a control's property is
read, the control's ViewState is consulted. If there is not an entry
in the ViewState, then the default value for the property is returned.
When the property is assigned, the assigned value is written directly
to the ViewState.

Why am I losing object references on the postback?

I am developing an asp.net (3.5) application and I am puzzled with the behavior of the postbacks.
Consider the following scenario: I have a web user control that is basically a form. However each form field is a web user control in itself.
In the click event of the save button I iterate through all controls in my form and I retrieve the field value and the field name that refers to the database field that I am saving the value to.
The click event triggers a postback and it is during the postback that I visit the controls and here is the funny thing: the property value for the database field has become null! Could anyone shed a light here?
Here is some basic code:
[Serializable]
public partial class UserProfileForm : CustomIntranetWebappUserControl
{
protected override void OnInit(EventArgs e)
{
//AutoEventWireup is set to false
Load += Page_Load;
CancelLinkButton.Click += CancelButtonClickEvent;
SaveLinkButton.Click += SaveButtonClickEvent;
base.OnInit(e);
}
private void SaveButtonClickEvent(object sender, EventArgs e)
{
VisitFormFields();
}
private void VisitFormFields()
{
var userProfileVisitor = new UserProfileVisitor();
foreach (var control in Controls)
{
if (control is FormFieldUserControl)
{
var formField = (FormFieldUserControl) control;
formField.Visit(userProfileVisitor);
}
}
userProfileVisitor.Save();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindText();
}
}
private void BindText()
{
LastNameFormLine.LabelText = string.Format("{0}:", HomePage.Localize("Last Name"));
LastNameFormLine.InputValue = UserProfile.LastName;
LastNameFormLine.IsMandatoryField = true;
LastNameFormLine.IsMultilineField = false;
LastNameFormLine.ProfileField = "UserProfile.LastName";
//... the rest of this method is exactly like the 4 lines above.
}
}
[Serializable]
public abstract class FormFieldUserControl : CustomIntranetWebappUserControl
{
public string ProfileField { get; set; }
public abstract void Visit(UserProfileVisitor userProfileVisitor);
}
[Serializable]
public partial class FormLineTextBox : FormFieldUserControl
{
//... irrelevant code removed...
public override void Visit(UserProfileVisitor userProfileVisitor)
{
if (userProfileVisitor == null)
{
Log.Error("UserProfileVisitor not defined for the field: " + ProfileField);
return;
}
userProfileVisitor.Visit(this);
}
}
[Serializable]
public class UserProfileVisitor
{
public void Visit(FormLineTextBox formLine)
{
// The value of formLine.ProfileField is null!!!
Log.Debug(string.Format("Saving form field type {1} with profile field [{0}] and value {2}", formLine.ProfileField, formLine.GetType().Name, formLine.InputValue));
}
// ... removing irrelevant code...
public void Save()
{
Log.Debug("Triggering the save operation...");
}
}
Remember ASP.NET is stateless. Any properties created are destroyed after the page has been render to the browser. So you have to recreate objects on each post back or store them in View, Session, or Application State.
When you do a property you have to tell it to save the view state it does not do it automatically. Here is a sample of a view state property.
public string SomePropertyAsString
{
get
{
if (this.ViewState["SomePropertyAsString"] == null)
return string.Empty;
return (string)this.ViewState["SomePropertyAsString"];
}
set { this.ViewState["SomePropertyAsString"] = value; }
}
public MyCustomType ObjectProperty
{
get
{
if (this.ViewState["ObjectProperty"] == null)
return null;
return (MyCustomType)this.ViewState["ObjectProperty"];
}
set { this.ViewState["ObjectProperty"] = value; }
}
First guess would be that BindText() shouldn't be in Page_Load, but in Page_Init, so the control state will be saved.
#David Basarab, this is not true afaik, and was only the case in .Net 1.1, in .Net2 and up this is all handled by the framework if you do all the magic stuff in the Init.
Your problem is that 'ProfileField' isn't available on the Postback, right?
The solution is to store the value for that in ViewState (instead of an auto-implemented property). Without that, it won't be available on the postback.

Resources