Link to home
Start Free TrialLog in
Avatar of SamCash
SamCashFlag for United States of America

asked on

How to reference objects of the calling class without passing them as parameters

EE,

I want to be able to call this method in my CodeBehind
Utl.LogDebug_Add(StatusLogStringToAdd, hdnLogDebugChild, Session["skPost"]);

Open in new window

.  Like this
Utl.LogDebug_Add(StatusLogStringToAdd);

Open in new window


There must be a way to get the HiddenField and Session Variable within this Method and not have to pass them all the time.  The Session Variable and HiddenField have the same Key "skPost" and ID hdnLogDebugChild on EVERY page in this project.

Thank You
Sam

using System;
using System.Web;
using System.Web.UI.WebControls;

namespace templateT01.Site.Utilities
{
    public class Utl : System.Web.UI.Page
    {
        internal static void LogDebug_Add(string StatusLogStringToAdd, HiddenField hdnLogDebugChild, object Session)
        {
            string UrlAbsolute = HttpContext.Current.Request.Url.AbsolutePath;
            DateTimeOffset dt = DateTimeOffset.Now;

                hdnLogDebugChild.Value = dt.ToString("HH:mm:ss")
                //+ "-->" + Session["skPost"].ToString()
                + "-->" + Session.ToString()
                + ">" + UrlAbsolute
                + "-->" + StatusLogStringToAdd
                + "\r\n"
                + hdnLogDebugChild.Value;
            ;
        }
    }
}

Open in new window

Avatar of sarabande
sarabande
Flag of Luxembourg image

you could make the two variables static members of class Utl. the members needed to be initialized but then can be used by the logging function.

Sara
As you said it is on every page, I have to ask you: Why don't you use a derived page? And implement the wiring in the base class?
Using static variables is a bad idea. ASP.NET is a multi-threaded environment, and each request that comes in gets served by a thread. Static variables would hold the same value across all threads. If you have two different users using your application, then they would each see the values that you have in static variables.
Using static variables is a bad idea.
in a static member function you very well can use static member variables. if the function was used in a multi-threaded environment, you would use a static mutex or semaphore to make it thread-safe. of course, if you want to have  a different log for each thread - what is rarely a requirement - you can't do it that way but have to pass arguments.

static members is not a good idea if the class was used in different executables (dll's or applications). then, all static members are duplicated per executable unit what is error-prone and can lead to crash.

Sara
Avatar of SamCash

ASKER

Experts,

Thank you for your Expert Comments.

The page(s) and structure for each User/Session are:
--One Parent with multiple Child iFrames
--The Parent has the one <asp:TextBox ID="txtLogDebug"... which displays the log for this Session.
--The Child iFrames, in their code behind, append new text to the variable LogDebug
      and saves LogDebug in <asp:HiddenField ID="hdnLogDebugChild"
--Then Child iFrame, javaScript, appends to Parent <asp:TextBox ID="txtDebugLog" from hdnLogDebugChild

--So the Parent <asp:TextBox ID="txtLogDebug"... displays logging text from all Parent's Child(s) for this User/Session and not from other User/Session.
*************

The objective is for logging on the Child(s) code behind is to:
Utl.LogDebug_Add(string s);

Open in new window

or better
Utl.LogDebug_Add = s;

Open in new window


*************
After reading the expert comments, I am not sure weather to use static or not.

If someone could just answer the static question I will build a simple working sample to further clarify my issue.

Kind Regards
Sam
The Session Variable and HiddenField have the same Key "skPost" and ID hdnLogDebugChild on EVERY page in this project.
if multiple requests must be served simultanously and should have separate debug logs - as stated by käµfm³d 👽 - you can't use single static variables but would need variables for each thread (request). this could be solved by a static dictionary where the thread id is the key and the pair of (hdnLogDebugChild, Session["skPost"]) could be retrieved from dictionary by using the thread id. if the values don't change between threads you could use static members as suggested above. however, logging must run exclusively by using a mutex or critical section.

Sara
ASKER CERTIFIED SOLUTION
Avatar of kaufmed
kaufmed
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of SamCash

ASKER

Experts,

Thank you very much, I think I am learning a lot about OOP.  So much more to learn, having fun...

I haven't found how to attach a solution or project on EE.  So I zipped the project excluding the folder/files that error.  If there are destructions on sending a solution/project please link me up.

I am pasting the class below also.

Kind Regards
Sam

using System;
using System.Web;
using System.Web.SessionState;
using System.Web.UI.WebControls;

namespace prjLogDebug.Utilities
{
    public class LogDebug
    {
        string _StringToAdd;
        HiddenField _hdnLogDebugChild;
        string _SessionItem;

        public LogDebug(HiddenField hdnLogDebugChild, HttpSessionState Session)
        {
            _hdnLogDebugChild = hdnLogDebugChild;
            _SessionItem = Session["skPost"].ToString();
        }
        public string LogDebugAdd
        {
            set
            {
                _StringToAdd = value;
                AppendString();
            }
        }
        private void AppendString()
        {
            string UrlAbsolute = HttpContext.Current.Request.Url.AbsolutePath;
            DateTimeOffset dt = DateTimeOffset.Now;

            _hdnLogDebugChild.Value = dt.ToString("HH:mm:ss")
                + "-->" + _SessionItem
                + "-->" + UrlAbsolute
                + "-->" + _StringToAdd
                + "<"
                +"\r\n"
                + _hdnLogDebugChild.Value;
        }
    }
}

Open in new window

-prjLogDebug.zip
in case of debug logging of the server or service side of  a client-server, it is often necessary to view concurrent processing and threading into one output. if that is a requirement static functions will do the technical part. however, you need to synchronize the output by running the output statements exclusively. the synchronization part for the above is not more than a lock at the beginning of the output function and a (an automatic) release at end.

it costs some more programming efforts to have a suitable output like

1: output from thread 1
2: output from thread 2
1: more output from thread 1
...

but obviously you could find out concurrency issues by doing so, where separate log outputs for each thread won't help. and the efforts are not tremendous but could be made with a few lines of code.

so, if you need output for each thread, you may make the function non-static and create a new LogDebug object for each new request as suggested in the previous comment. pass the two (?) variables once when you create the object. nevertheless you will need a reference to the LogDebug object per thread and have some management to handle this. don't know whether the "interface" technique mentioned can manage this.

Sara
Avatar of SamCash

ASKER

Sara, käµfm³d 👽,

I trust you had a merry Christmas and Happy New Year.  I am back after an extended Christmas break.  

Sara, This is a web site.  Each client (or session) has a log, saved in Session, and only persists during the session, so there is a log for each session, entries are made by one client, (or session), how does that effect your above comment?

I am very interested in understanding käµfm³d 👽 's EDIT to his answer...
 
** Edit:  Actually, I see now that you are indeed deriving from Page. I do not, however, understand why you made that method static. I would remove the static modifier, and create a new interface that exposes your HiddenField control. By implementing that interface, your LogDebug_Add method can know that each page that inherits from this base page will have a HiddenField. You should not have to explicitly pass Session either (i.e. remove it as a parameter).
I have re-coded, refactored and attached the whole running sample in my last post.  

How do I get rid of, not have to pass the HiddenField or Session, I as you can see I am passing them in the constructor?  I am still learning OOP.

Kind Regards
Sam
How do I get rid of, not have to pass the HiddenField or Session, I as you can see I am passing them in the constructor?
if you passed the parametes in the constructor all subsequent calls using the LogDebug object don't need the parameters but can use the members.

but i don't really understand members _hdnLogDebugChild and _StringToAdd. every second debug string would replace the previous string. fro logging you need some kind of a stream (for example a file stream or a list) where you could add strings rather than to update them. and of course you need only string member (if at all).

Sara
Avatar of SamCash

ASKER

Sara,

Thanks for the comment.  First, staying on the narrow question...

How do I reference " HiddenField hdnLogDebugChild, HttpSessionState Session " without passing them in the Constructor, as käµfm³d 👽 commented?

I may have comments or questions on your comments but I need this first.

Thank You Very Much
Sam
without passing them in the Constructor, as käµfm³d 👽 commented?
no, käµfm³d didn't want you to use static members as those static members would need a management for all user web pages currently accessing your server. but if you create a LogDebug object for each session, you can pass the parameters which won't change for that session to the constructor of the LogDebug object and store them as members. for all subsequent log messages you then use the one LogDebug object of your session and call LogDebugAdd member function to add more text to the debug log output. you would only pass the message text as argument.

of course you should not overwrite a previous output string but 'add' the messages for example by appending the texts in a debug output window.

Sara
Avatar of SamCash

ASKER

Sara,

Thanks for the prompt response.

käµfm³d 👽 ==
** Edit:  Actually, I see now that you are indeed deriving from Page. I do not, however, understand why you made that method static. I would remove the static modifier, and create a new interface that exposes your HiddenField control. By implementing that interface, your LogDebug_Add method can know that each page that inherits from this base page will have a HiddenField. You should not have to explicitly pass Session either (i.e. remove it as a parameter).

It is no longer static (and it think I understand why to not use static).  Each web page instantiates its own object, I am getting a separate log for each page (as desired).

What I have not figured out is how to not pass HiddenField and Session in the constructor.  It seems the new instantiated object, LogDebug,  should be able to access the objects and properties of the instantiating object, wfChild_1 or wfChild_2?  I think the
this.
keyword is what I should be using?  

Thanks Again
Sam
I think the 'this' keyword is what I should be using?  

no, the 'this' is a self-reference to the class object. it can be used if you have to pass a reference to the current object itself as Argument or if you want to return a reference to self from a call.

as far as i understand (sorry if i am wrong  but i am not a web programmer) you have multiple page classes derived from System.Web.UI.Page. and you want all those pages to have a common debug logging. if i am right, you have a further class which creates those pages. this class should create a LogDebug object and should pass the Session-ID and the HiddenField to the constructor of the LogDebug member, given that those members will not change. when you create the pages you could pass a reference or pointer to the LogDebug object to the page objects and store the reference (or pointer) as a member - say named _logDebug. that allows to call in the pages _logDebug->LogDebugAdd("some debug message"); using the common and session singleton LogDebug object which you created before for all pages.

when you derive all pages from a common baseclass, you could have the reference/pointer as a member of the baseclass. this baseclass then can be used to implement all member functions and methods which are used by all pages.

Sara
Avatar of SamCash

ASKER

Sara,

and you want all those pages to have a common debug logging.
 No each page has its own log.  See the code.  It works correctly.  I am just trying to not have to pass HiddenField and Session in the constructor.

Thanks Much
Sam
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of SamCash

ASKER

Sara,

Thank you for the comment.  I attempted to follow them.  Below is the code I think you wanted me to change.  The Session Variable builds, but the control hdnLogDebugChild would not build, The name does not exist in the current context.

I changed
//public class LogDebug
    public class LogDebug : System.Web.UI.Page

Open in new window

And
//public LogDebug(HiddenField hdnLogDebugChild, HttpSessionState Session)
        public LogDebug()

Open in new window

We got one of two, now how do we get a reference to hdnLogDebugChild, without passing it in the constructor.

Kindest Regards
Sam

Full snipit
using System;
using System.Web;
using System.Web.SessionState;
using System.Web.UI.WebControls;

namespace prjLogDebug.Utilities
{
    //public class LogDebug
    public class LogDebug : System.Web.UI.Page
    {
        string _StringToAdd;
        HiddenField _hdnLogDebugChild;
        string _SessionItem;

        //public LogDebug(HiddenField hdnLogDebugChild, HttpSessionState Session)
        public LogDebug()
        {
            _hdnLogDebugChild = hdnLogDebugChild;
            _SessionItem = Session["skPost"].ToString();
        }
        public string LogDebugAdd
        {
            set
            {
                _StringToAdd = value;
                AppendString();
            }
        }
        private void AppendString()
        {
            string UrlAbsolute = HttpContext.Current.Request.Url.AbsolutePath;
            DateTimeOffset dt = DateTimeOffset.Now;

            _hdnLogDebugChild.Value = dt.ToString("HH:mm:ss")
                + "-->" + _SessionItem
                + "-->" + UrlAbsolute
                + "-->" + _StringToAdd
                + "<"
                +"\r\n"
                + _hdnLogDebugChild.Value;
        }
    }
}

Open in new window

public class LogDebug : System.Web.UI.Page
no, the LogDebug must not be derived from System.Web.UI.Page. a public derivation means that an object of the derived class "is a" baseclass object what obviously is not the case for a log debug utility object.

your web pages should be derived from System.Web.UI.Page. when you create one of those you would pass the HiddenField and the SessionState to their constructor. then you can have a debug_log member function of those classes and could use them for those pages without having to pass the two variables for each logging.

Sara
Avatar of SamCash

ASKER

Sara,

Thank you for the prompt comment.

Isn't that what I have in the code before these last two changes?

Regards
Sam
Avatar of SamCash

ASKER

This question was not answered.  The thread got too long...  I will post another simpler question.

Regards
Sam
Isn't that what I have in the code before these last two changes?
no. you derived class LogDebug from System.Web.UI.Page. but log debug object isn't a web.ui.page.

i assumed that you have classes for your web page(s) which were derived from System.Web.UI.Page. then, it would make sense to do all debug logs by using your page class. that means the class provides a log function where you only have to pass a message and where the page class would add the two members as arguments which you have passed to the class' constructor when creating the page.

Sara
Avatar of SamCash

ASKER

Sara,

Thanks very much for the comment.  I think I may actually get this before we are done.  Thanks for your patience.
i assumed that you have classes for your web page(s) which were derived from System.Web.UI.Page.
True
then, it would make sense to do all debug logs by using your page class.
How? One line+ code snippet or link to example?
Best Regards
Sam
it would be like

mypage.log("some message");

and MyPage::log would do like

public void log(string message)
{            
            string UrlAbsolute = HttpContext.Current.Request.Url.AbsolutePath;
            DateTimeOffset dt = DateTimeOffset.Now;

                hdnLogDebugChild.Value = dt.ToString("HH:mm:ss")
                //+ "-->" + _SessionItem.ToString()
                + "-->" + _SessionItem.ToString()
                + ">" + UrlAbsolute
                + "-->" + message
                + "\r\n"
                + _hdnLogDebugChild.Value;
...

Open in new window


where i used the snippet you posted in your original post. you would only have to pass the message string while session and hidden log were added from members stored in your  page object.

Sara
Avatar of SamCash

ASKER

Sara,

Thanks again.

You got it, this is what I want, to make the call like...  
mypage.log("some message");
.  So I can put it on all the many pages and be able to change the class without having to change every page.

Your comment
and MyPage::log
I do not know how to use :: , I did read MSDN about :: namespace alias qualifier, it is new to me.  Where does it go?  I will post the refactored code below.

Kind regards
Sam
The Class: Line 13, I am still passing the control and session in the constructor, and added the underscore to line 25. I did this just to get it to build.
using System;
using System.Web;
using System.Web.SessionState;
using System.Web.UI.WebControls;

namespace prjLogDebug.Utilities
{
    public class Log
    {
        HiddenField _hdnLogDebugChild;
        string _SessionItem;

        public Log(HiddenField hdnLogDebugChild, HttpSessionState Session)
        {
            _hdnLogDebugChild = hdnLogDebugChild;
            _SessionItem = Session["skPost"].ToString();
        }

        public void log(string message)
        {
            string UrlAbsolute = HttpContext.Current.Request.Url.AbsolutePath;
            DateTimeOffset dt = DateTimeOffset.Now;

            //hdnLogDebugChild.Value = dt.ToString("HH:mm:ss")
            _hdnLogDebugChild.Value = dt.ToString("HH:mm:ss")
            + "-->" + _SessionItem.ToString()
            + ">" + UrlAbsolute
            + "-->" + message
            + "\r\n"
            + _hdnLogDebugChild.Value;
        }
    }
}

Open in new window

One of many webform(s): (does not build)
using prjLogDebug.Utilities;
using System;

namespace prjLogDebug.Site
{
    public partial class wfChild_1 : System.Web.UI.Page
    {
        Log Log;
        
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Session["skPost"] != null)
            {
                Session["skPost"] = (int)Session["skPost"] + 1;
            }
            else
            {
                //Throw err
            }

            hdnLogDebugChild.Value = ""; //clear persisted data from prior post
            Log = new Log(hdnLogDebugChild, Session);
            wfChild_1.Log("Child_1 PageLoad()");
        }

        protected void btnLog_Click(object sender, EventArgs e)
        {
            string s = "Text to add from wfChild_1";
            Log.Log(s);

            string result = hdnLogDebugChild.Value; // to view with debugger
        }
    }
}

Open in new window

MyPage::log

that only means that log is a member function of MyPage (and so can use data members of MyClass) . sorry for confusing but i am neither a c# nor an asp programmer.

Sara
Avatar of SamCash

ASKER

Sara,

Thanks, I think this is a OOP question, or referencing or scoping??

I see two problems (mine).
1.  On the class Log I want to eliminate lines 15 and 16.
2.  On the class wfChild_1 I need 22 and 23 to work.  This is my mis-implementation of your prior post.

Getting Closer
Sam
Avatar of SamCash

ASKER

Sara,

Please look at https://www.experts-exchange.com/questions/29001529/Object-Oriented-Programming-C-referencing-scoping.html?anchor=a42002110¬ificationFollowed=183948705&anchorAnswerId=42002110#a42002110 

I would like to see how your answer fits here.

mypage.log("some message");

and MyPage::log would do like:

session and hidden log were added from members stored in your  page object.

Kind Regards
Sam