Variable Goes Out Of Scope When Used In Remoted Class

N

Not Available

On the host server:

namespace JCart.Common
public class JCartConfiguration : IConfigurationSectionHandler
private static String dbConnectionString;
public static String ConnectionString
{
get
{
return dbConnectionString;
}
}
//Initialze it:
dbConnectionString = "My Database Connection String";


On remote server:

namespace JCart.DataAccess
public class CustomerSystem : MarshalByRefObject
String testVar;
testVar = JCartConfiguration.ConnectionString;

testVar comes back as "". However when this exact code is used without being remoted testVar = "My Database Connection String";

This is basically the Duwamish .Net sample cloned minus the shopping cart that I useed as a way to learn c#. No enterprise template but the same seperate projects structure within the solution only containg the stuff needed to implement the account setup/modify system part.

I'm not sure if I'm overlooking some basic concept, but I can post more details if necessary.

Here is the remote config file when used:

<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="http client" clientConnectionLimit="200">
<clientProviders>
<formatter ref="soap"/>
</clientProviders>
</channel>
</channels>
<client url="HTTP://192.168.1.13:80/JCart_Facade">
<wellknown type="JCart.BusinessFacade.CustomerSystem, JCart.BusinessFacade" url="HTTP://192.168.1.13:80/JCart_Facade/CustomerSystem.rem"/>
</client>
</application>
</system.runtime.remoting>
</configuration>
 
N

Not Available

Just switched from Verizon DSL to RR and forgot to put my email address, it's (e-mail address removed)
On the host server:

namespace JCart.Common
public class JCartConfiguration : IConfigurationSectionHandler
private static String dbConnectionString;
public static String ConnectionString
{
get
{
return dbConnectionString;
}
}
//Initialze it:
dbConnectionString = "My Database Connection String";


On remote server:

namespace JCart.DataAccess
public class CustomerSystem : MarshalByRefObject
String testVar;
testVar = JCartConfiguration.ConnectionString;

testVar comes back as "". However when this exact code is used without being remoted testVar = "My Database Connection String";

This is basically the Duwamish .Net sample cloned minus the shopping cart that I useed as a way to learn c#. No enterprise template but the same seperate projects structure within the solution only containg the stuff needed to implement the account setup/modify system part.

I'm not sure if I'm overlooking some basic concept, but I can post more details if necessary.

Here is the remote config file when used:

<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="http client" clientConnectionLimit="200">
<clientProviders>
<formatter ref="soap"/>
</clientProviders>
</channel>
</channels>
<client url="HTTP://192.168.1.13:80/JCart_Facade">
<wellknown type="JCart.BusinessFacade.CustomerSystem, JCart.BusinessFacade" url="HTTP://192.168.1.13:80/JCart_Facade/CustomerSystem.rem"/>
</client>
</application>
</system.runtime.remoting>
</configuration>
 
J

Jon Skeet

Not Available said:
On the host server:

namespace JCart.Common
public class JCartConfiguration : IConfigurationSectionHandler
private static String dbConnectionString;
public static String ConnectionString
{
get
{
return dbConnectionString;
}
}
//Initialze it:
dbConnectionString = "My Database Connection String";

Where is that connection string being initialised though? You haven't
shown that.
 
N

Not Available

The connection string is initialized from a web.config file. I've included the complete modules JCartConfiguration, ApplicationConfiguration and the Web.config files below. Here are the lines:

JCartConfiguration:
dbConnectionString = ApplicationConfiguration.ReadSetting(settings, DATAACCESS_CONNECTIONSTRING, DATAACCESS_CONNECTIONSTRING_DEFAULT);

ApplicationConfiguration:
System.Configuration.ConfigurationSettings.GetConfig("JCartConfiguration");

Web.config:

<JCartConfiguration>
<!-- Settings specific to the Duwamish application -->
<add key="JCart.DataAccess.ConnectionString" value="server=EMPIRE2;User ID=sa;Password=;database=JCart;Connection Reset=FALSE" />


Here's the global.asx.cs file
protected void Application_Start(Object sender, EventArgs e)
{
ApplicationConfiguration.OnApplicationStart(Context.Server.MapPath( Context.Request.ApplicationPath ));
AppStartDateTime = dt.ToString();
string configPath = Path.Combine(Context.Server.MapPath( Context.Request.ApplicationPath ),"remotingclient.cfg");
if(File.Exists(configPath))
RemotingConfiguration.Configure(configPath);
}








Jon Skeet said:
Where is that connection string being initialised though? You haven't
shown that.


JCARTCONFIGURATION.cs
namespace JCart.Common
{
using System;
using System.Collections;
using System.Configuration;
using System.Xml;
using System.Collections.Specialized;
using JCart.SystemFramework;


public class JCartConfiguration : IConfigurationSectionHandler

// public class JCartConfiguration
{
//
// Constant values for all expected entries in the DuwamishConfiguration section
//
private const String WEB_ENABLEPAGECACHE = "JCart.Web.EnablePageCache";
private const String WEB_PAGECACHEEXPIRESINSECONDS = "JCart.Web.PageCacheExpiresInSeconds";
private const String DATAACCESS_CONNECTIONSTRING = "JCart.DataAccess.ConnectionString";
private const String WEB_ENABLESSL = "JCart.Web.EnableSsl";

private static String dbConnectionString;
// public static int test1p;

// private static bool enablePageCache;
// private static int pageCacheExpiresInSeconds;
// private static bool enableSsl;


//
// Constant values for all of the default settings.
//
private const bool WEB_ENABLEPAGECACHE_DEFAULT = true;
private const int WEB_PAGECACHEEXPIRESINSECONDS_DEFAULT = 3600;
private const String DATAACCESS_CONNECTIONSTRING_DEFAULT =
"server=EMPIRE2;User ID=sa;Password=;database=JCart;Connection Reset=FALSE";
private const bool WEB_ENABLESSL_DEFAULT = false;


public Object Create(Object parent, object configContext, XmlNode section)
{

NameValueCollection settings;

try
{
NameValueSectionHandler baseHandler = new NameValueSectionHandler();
settings = (NameValueCollection)baseHandler.Create(parent, configContext, section);
}
catch
{
settings = null;
}

if ( settings == null )
{
dbConnectionString = DATAACCESS_CONNECTIONSTRING_DEFAULT;
// pageCacheExpiresInSeconds = WEB_PAGECACHEEXPIRESINSECONDS_DEFAULT;
// enablePageCache = WEB_ENABLEPAGECACHE_DEFAULT;
// enableSsl = WEB_ENABLESSL_DEFAULT;
}
else
{
dbConnectionString = ApplicationConfiguration.ReadSetting(settings, DATAACCESS_CONNECTIONSTRING, DATAACCESS_CONNECTIONSTRING_DEFAULT);
// pageCacheExpiresInSeconds = ApplicationConfiguration.ReadSetting(settings, WEB_PAGECACHEEXPIRESINSECONDS, WEB_PAGECACHEEXPIRESINSECONDS_DEFAULT);
// enablePageCache = ApplicationConfiguration.ReadSetting(settings, WEB_ENABLEPAGECACHE, WEB_ENABLEPAGECACHE_DEFAULT);
// enableSsl = ApplicationConfiguration.ReadSetting(settings, WEB_ENABLESSL, WEB_ENABLESSL_DEFAULT);
}

return settings;
}

public static String ConnectionString
{
get
{
return dbConnectionString;
}
}

// public static int test1
// {
// get
// {
// return test1p;
// }
// }

} //class JCartConfiguration
} //namespace JCart7.Common
APPLICATIONCONFIGURATION.CS

namespace JCart.SystemFramework
{
using System;
using System.Collections;
using System.Diagnostics;
using System.Configuration;
using System.Xml;
using System.Collections.Specialized;


/// <summary>
/// Standard configuration settings to enable tracing and logging
/// with the ApplicationLog class.
/// <remarks>
/// An application can use this class as a model for
/// adding additional settings to a Web.Config file.
/// Special Considerations:
/// The OnApplicationStart function in this class must be called
/// from the Application_OnStart event in Global.asax. This is
/// currently used to determine the path of the application,
/// the HttpContext object is passed it to enable the app
/// to read other settings in the future, and to minimize the code
/// in global.asax.
/// <example>
/// The global.asax file should be similar to the following code:
/// <code>
/// <%@ Import Namespace="Duwamish7.SystemFramework" %>
/// <script language="c#" runat="SERVER">
/// void Application_OnStart()
/// {
/// ApplicationConfiguration.OnApplicationStart(Context);
/// }
/// </script>
/// </code>
/// </example>
/// </remarks>
/// </summary>
public class ApplicationConfiguration : IConfigurationSectionHandler
{

//
// Constant values for all of the SystemFramework standard settings
//
private const String TRACING_ENABLED = "SystemFramework.Tracing.Enabled";
private const String TRACING_TRACEFILE = "SystemFramework.Tracing.TraceFile";
private const String TRACING_TRACELEVEL = "SystemFramework.Tracing.TraceLevel";
private const String TRACING_SWITCHNAME = "SystemFramework.Tracing.SwitchName";
private const String TRACING_SWITCHDESCRIPTION = "SystemFramework.Tracing.SwitchDescription";
private const String EVENTLOG_ENABLED = "SystemFramework.EventLog.Enabled";
private const String EVENTLOG_MACHINENAME = "SystemFramework.EventLog.Machine";
private const String EVENTLOG_SOURCENAME = "SystemFramework.EventLog.SourceName";
private const String EVENTLOG_TRACELEVEL = "SystemFramework.EventLog.LogLevel";

//
// Static member variables. These contain the application settings
// from Config.Web, or the default values.
//
private static bool tracingEnabled;
private static String tracingTraceFile;
private static TraceLevel tracingTraceLevel;
private static String tracingSwitchName;
private static String tracingSwitchDescription;
private static bool eventLogEnabled;
private static String eventLogMachineName;
private static String eventLogSourceName;
private static TraceLevel eventLogTraceLevel;

//
// The root directory of the application. Established in the
// OnApplicationStart callback form Global.asax.
//
private static String appRoot;

//
// Constant values for all of the default settings.
//
private const bool TRACING_ENABLED_DEFAULT = true;
private const String TRACING_TRACEFILE_DEFAULT = "ApplicationTrace.txt";
private const TraceLevel TRACING_TRACELEVEL_DEFAULT = TraceLevel.Verbose;
private const String TRACING_SWITCHNAME_DEFAULT = "ApplicationTraceSwitch";
private const String TRACING_SWITCHDESCRIPTION_DEFAULT = "Application error and tracing information";
private const bool EVENTLOG_ENABLED_DEFAULT = true;
private const String EVENTLOG_MACHINENAME_DEFAULT = ".";
private const String EVENTLOG_SOURCENAME_DEFAULT = "WebApplication";
private const TraceLevel EVENTLOG_TRACELEVEL_DEFAULT = TraceLevel.Error;

/// <summary>
/// Called from OnApplicationStart to initialize settings from
/// the Web.Config file(s).
/// <remarks>
/// The app domain will restart if settings change, so there is
/// no reason to read these values more than once. This funtion
/// uses the NameValueSectionHandler base class to generate a
/// hashtablefrom the XML, which is then used to store the current
/// settings. Because all settings are read here, we do not actually
/// store the generated hashtable object for later retrieval by
/// Context.GetConfig. The application should use the accessor
/// functions directly.
/// </remarks>
/// <param name="parent">An object created by processing a section
/// with this name in a Config.Web file in a parent directory.
/// </param>
/// <param name="configContext">The config's context.</param>
/// <param name="section">The section to be read.</param>
/// <retvalue>
/// <para>
/// A ConfigOutput object: which we leave empty because all settings
/// are stored at this point.
/// </para>
/// <para>
/// null: if there was an error.
/// </para>
/// </retvalue>
/// </summary>
public Object Create(Object parent, object configContext, XmlNode section)
{

NameValueCollection settings;

try
{
NameValueSectionHandler baseHandler = new NameValueSectionHandler();
settings = (NameValueCollection)baseHandler.Create(parent, configContext, section);
}
catch
{
settings = null;
}

if (settings == null)
{
tracingEnabled = TRACING_ENABLED_DEFAULT;
tracingTraceFile = TRACING_TRACEFILE_DEFAULT;
tracingTraceLevel = TRACING_TRACELEVEL_DEFAULT;
tracingSwitchName = TRACING_SWITCHNAME_DEFAULT;
tracingSwitchDescription = TRACING_SWITCHDESCRIPTION_DEFAULT;
eventLogEnabled = EVENTLOG_ENABLED_DEFAULT;
eventLogMachineName = EVENTLOG_MACHINENAME_DEFAULT;
eventLogSourceName = EVENTLOG_SOURCENAME_DEFAULT;
eventLogTraceLevel = EVENTLOG_TRACELEVEL_DEFAULT;
}
else
{
tracingEnabled = ReadSetting(settings, TRACING_ENABLED, TRACING_ENABLED_DEFAULT);
tracingTraceFile = ReadSetting(settings, TRACING_TRACEFILE, TRACING_TRACEFILE_DEFAULT);
tracingTraceLevel = ReadSetting(settings, TRACING_TRACELEVEL, TRACING_TRACELEVEL_DEFAULT);
tracingSwitchName = ReadSetting(settings, TRACING_SWITCHNAME, TRACING_SWITCHNAME_DEFAULT);
tracingSwitchDescription = ReadSetting(settings, TRACING_SWITCHDESCRIPTION, TRACING_SWITCHDESCRIPTION_DEFAULT);
eventLogEnabled = ReadSetting(settings, EVENTLOG_ENABLED, EVENTLOG_ENABLED_DEFAULT);
eventLogMachineName = ReadSetting(settings, EVENTLOG_MACHINENAME, EVENTLOG_MACHINENAME_DEFAULT);
eventLogSourceName = ReadSetting(settings, EVENTLOG_SOURCENAME, EVENTLOG_SOURCENAME_DEFAULT);
eventLogTraceLevel = ReadSetting(settings, EVENTLOG_TRACELEVEL, EVENTLOG_TRACELEVEL_DEFAULT);
}

return null;
}

/// <summary>
/// String version of ReadSetting.
/// <remarks>
/// Reads a setting from a hashtable and converts it to the correct
/// type. One of these functions is provided for each type
/// expected in the hash table. These are public so that other
/// classes don't have to duplicate them to read settings from
/// a hash table.
/// </remarks>
/// <param name="settings">The Hashtable to read from.</param>
/// <param name="key">A key for the value in the Hashtable.</param>
/// <param name="defaultValue">The default value if the item is not found.</param>
/// <retvalue>
/// <para>value: from the hash table</para>
/// <para>
/// default: if the item is not in the table or cannot be case to the expected type.
/// </para>
/// </retvalue>
/// </summary>
public static String ReadSetting(NameValueCollection settings, String key, String defaultValue)
{
try
{
Object setting = settings[key];

return (setting == null) ? defaultValue : (String)setting;
}
catch
{
return defaultValue;
}
}

/// <summary>
/// Boolean version of ReadSetting.
/// <remarks>
/// Reads a setting from a hashtable and converts it to the correct
/// type. One of these functions is provided for each type
/// expected in the hash table. These are public so that other
/// classes don't have to duplicate them to read settings from
/// a hash table.
/// </remarks>
/// <param name="settings">The Hashtable to read from.</param>
/// <param name="key">A key for the value in the Hashtable.</param>
/// <param name="defaultValue">The default value if the item is not found.</param>
/// <retvalue>
/// <para>value: from the hash table</para>
/// <para>
/// default: if the item is not in the table or cannot be case to the expected type.
/// </para>
/// </retvalue>
/// </summary>
public static bool ReadSetting(NameValueCollection settings, String key, bool defaultValue)
{
try
{
Object setting = settings[key];

return (setting == null) ? defaultValue : Convert.ToBoolean((String)setting);
}
catch
{
return defaultValue;
}
}

/// <summary>
/// int version of ReadSetting.
/// <remarks>
/// Reads a setting from a hashtable and converts it to the correct
/// type. One of these functions is provided for each type
/// expected in the hash table. These are public so that other
/// classes don't have to duplicate them to read settings from
/// a hash table.
/// </remarks>
/// <param name="settings">The Hashtable to read from.</param>
/// <param name="key">A key for the value in the Hashtable.</param>
/// <param name="defaultValue">The default value if the item is not found.</param>
/// <retvalue>
/// <para>value: from the hash table</para>
/// <para>
/// default: if the item is not in the table or cannot be case to the expected type.
/// </para>
/// </retvalue>
/// </summary>
public static int ReadSetting(NameValueCollection settings, String key, int defaultValue)
{
try
{
Object setting = settings[key];

return (setting == null) ? defaultValue : Convert.ToInt32((String)setting);
}
catch
{
return defaultValue;
}
}

/// <summary>
/// TraceLevel version of ReadSetting.
/// <remarks>
/// Reads a setting from a hashtable and converts it to the correct
/// type. One of these functions is provided for each type
/// expected in the hash table. These are public so that other
/// classes don't have to duplicate them to read settings from
/// a hash table.
/// </remarks>
/// <param name="settings">The Hashtable to read from.</param>
/// <param name="key">A key for the value in the Hashtable.</param>
/// <param name="defaultValue">The default value if the item is not found.</param>
/// <retvalue>
/// <para>value: from the hash table</para>
/// <para>
/// default: if the item is not in the table or cannot be case to the expected type.
/// </para>
/// </retvalue>
/// </summary>
public static TraceLevel ReadSetting(NameValueCollection settings, String key, TraceLevel defaultValue)
{
try
{
Object setting = settings[key];

return (setting == null) ? defaultValue : (TraceLevel)Convert.ToInt32((String)setting);
}
catch
{
return defaultValue;
}
}

/// <summary>
/// Function to be called by Application_OnStart as described in the
/// class description. Initializes the application root.
/// <param name="myAppPath">The path of the running application.</param>
/// </summary>
public static void OnApplicationStart(String myAppPath)
{
appRoot = myAppPath;

// System.Configuration.ConfigurationSettings.GetConfig("ApplicationConfiguration");

System.Configuration.ConfigurationSettings.GetConfig("JCartConfiguration");

// System.Configuration.ConfigurationSettings.GetConfig("SourceViewer");

}

/// <value>
/// Property AppRoot is used to get the root path of the application.
/// </value>
public static String AppRoot
{
get
{
return appRoot;
}
}

/// <value>
/// Property TracingEnabled is used to get the configuration setting, defaulting to False on error.
/// </value>
public static bool TracingEnabled
{
get
{
return tracingEnabled;
}
}

/// <value>
/// Property TracingTraceFile is used to get the full path name to the file that contains trace
/// settings, defaults to ApplicationTrace.txt.
/// </value>
public static String TracingTraceFile
{
get
{
return appRoot + "\\" + tracingTraceFile;
}
}

/// <value>
/// Property TracingTraceFile is used to get the highest logging level that should be written to
/// the tracing file, defaults to TraceLevel.Verbose (however, TracingEnabled defaults
/// to False, so you have to turn it on explicitly).
/// </value>
public static TraceLevel TracingTraceLevel
{
get
{
return tracingTraceLevel;
}
}

/// <value>
/// Property TracingSwitchName is used to get the trace switch name, defaults to ApplicationTraceSwitch.
/// </value>
public static String TracingSwitchName
{
get
{
return tracingSwitchName;
}
}

/// <value>
/// Property TracingSwitchDescription is used to get the trace settings file, defaults to
/// "Application error and tracing information".
/// </value>
public static String TracingSwitchDescription
{
get
{
return tracingSwitchDescription;
}
}

/// <value>
/// Property EventLogEnabled is used to get whether writing to the event log is support, defaults to True.
/// <remarks>Returns true if writing to the event log is enabled, false otherwise</remarks>
/// </value>
public static bool EventLogEnabled
{
get
{
return eventLogEnabled;
}
}
/// <value>
/// Property EventLogMachineName is used to get the machine name to log the event to, defaults to an
/// empty string, indicating the current machine. A machine name
/// (without \\), may be empty.
/// </value>
public static String EventLogMachineName
{
get
{
return eventLogMachineName;
}
}

/// <value>
/// Property EventLogMachineName is used to get the source of the error to be written to the event log,
/// defaults WebApplication.
/// </value>
public static String EventLogSourceName
{
get
{
return eventLogSourceName;
}
}

/// <value>
/// Property EventLogTraceLevel is used to get the highest logging level that should be written to the event log,
/// defaults to TraceLevel.Error.
/// </value>
public static TraceLevel EventLogTraceLevel
{
get
{
return eventLogTraceLevel;
}
}

} //class ApplicationConfiguration
} //namespace JCart.SystemFramework
WEB.CONFIG

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="ApplicationConfiguration" type="JCart.SystemFramework.ApplicationConfiguration, JCart.SystemFramework" />
<section name="JCartConfiguration" type="JCart.Common.JCartConfiguration, JCart.Common" />
</configSections>
<system.web>
<compilation defaultLanguage="c#" debug="true" />
<!-- xx The sessionState is currently set to inproc: the lines following [mode="inproc"] are not used but are present for ease of configuration -->
<sessionState cookieless="false" timeout="20" mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;user id=sa;password=" />
<globalization requestEncoding="utf-8" responseEncoding="utf-8" />
<!-- security -->

<authentication mode="Windows" />
<!--
<authentication mode="Forms">
<forms name=".ADUAUTH2" loginUrl="logon.aspx" protection="All" timeout="60" >
</forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
-->

<trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />
</system.web>
<ApplicationConfiguration>
<!-- Trace file settings -->
<add key="SystemFramework.Tracing.Enabled" value="False" />
<!-- Set this to the file with the trace settings. This file should be relative
to the root application directory. -->
<add key="SystemFramework.Tracing.TraceFile" value="DuwamishTrace.txt" />
<!-- The TraceLevel for this switch. -->
<add key="SystemFramework.Tracing.TraceLevel" value="4" />
<!-- This switch name. The trace level for this name can be set through
environment variables or the registry -->
<add key="SystemFramework.Tracing.SwitchName" value="DuwamishTraceSwitch" />
<!-- This description of the Tracing.SwitchName switch -->
<add key="SystemFramework.Tracing.SwitchDescription" value="Error and information tracing for Duwamish" />
<!-- Event log settings
Note: The default Duwamish7 event source name is created in the local machine during setup. If you wish to log events to a different event source
that event source must exist.
-->
<add key="SystemFramework.EventLog.Enabled" value="True" />
<add key="SystemFramework.EventLog.Machine" value="." />
<add key="SystemFramework.EventLog.SourceName" value="Duwamish7" />
<!-- Use the standard TraceLevel values:
0 = Off
1 = Error
2 = Warning
3 = Info
4 = Verbose -->
<add key="SystemFramework.EventLog.LogLevel" value="1" />
</ApplicationConfiguration>
<JCartConfiguration>
<!-- Settings specific to the Duwamish application -->
<add key="JCart.DataAccess.ConnectionString" value="server=EMPIRE2;User ID=sa;Password=;database=JCart;Connection Reset=FALSE" />
<add key="JCart.Web.EnablePageCache" value="True" />
<add key="JCart.Web.PageCacheExpiresInSeconds" value="3600" />
<add key="JCart.Web.EnableSsl" value="False" />
</JCartConfiguration>

<!-- String dsn = ConfigurationSettings.AppSettings["JCart"];
<appSettings>
<add key="JCart" value="server=EMPIRE2;User ID=sa;Password=;database=JCart;Connection Reset=FALSE" />
</appSettings>
-->
</configuration>
 
J

Jon Skeet

Not Available said:
The connection string is initialized from a web.config file.

I meant where is the connection string initialised, as in "in which
method". It looks like it's only initialised when the Create method is
called. Why not initialise it when the type is initialised instead?
 
N

Not Available

I meant where is the connection string initialised, as in "in which
method". It looks like it's only initialised when the Create method is

I see your point. I don't think it is initialized anywhere else. I'm just guessing but somehow JCartConfiguration.ConnectionString when used non-remotley must pick up some left over private variable/instance but that doesn't happen when the object trying to use JCartConfiguration.ConnectionString is remote. I'm not sure if this "NameValueCollection settings" object from the IConfigurationSectionHandler is instantiated anywhere and thought it was part of the whole configuration handler functionality. The whole concept of the Duwamish remote business_facade:CustomerSystem MarshelByRef is to totally encapsulate everything and to make it completly stateless. That's why I thought the whole IConfiguration base class would somehow let you use the configuration stuff it reads from web.config in all remote objects. It seems to work that way in the remote setup of the Duwamish sample. Since I basically cloned the code without the project template and couldn't get the <section name="ApplicationConfiguration" part to work I thought it had something to do with that.

I guess I should make some time to do a pared down example of this. Basically I think the 'know how' I'm looking for is how to make configuration settings available to a stateless remote completly encasulated class. It looked like IConfigurationSectionHandler woudl do that.
called. Why not initialise it when the type is initialised instead?

I might be misreading your question but I think the answer is because I want the remote class/dll/object to be totally encapsulated and stateless.

Here are some other thoughts:

I think there's something more going here because I cloned the Duwmaish system and didn't use a project template. For example I could not get this line to work:

System.Configuration.ConfigurationSettings.GetConfig("ApplicationConfiguration");

It kept saying it didn't like this web.config section:
<configSections>
<section name="ApplicationConfiguration" type="JCart.SystemFramework.ApplicationConfiguration, JCart.SystemFramework" />

I'm not sure if that's related. I don't think it likes the "ApplicationConfiguration" word and somehow treats it differently because of the template but that's just a guess.

To answer your question:

It hits this code only the first time it's run after restarting IIS:
global.asax:Application_Start
ApplicationConfiguration.OnApplicationStart(Context.Server.MapPath( Context.Request.ApplicationPath ));

then,
public class ApplicationConfiguration : IConfigurationSectionHandler
ApplicationConfiguration:JCart.SystemFramework::OnApplicationStart
System.Configuration.ConfigurationSettings.GetConfig("JCartConfiguration");

then it creates the NameValueCollection settings,
public class JCartConfiguration : IConfigurationSectionHandler
public Object Create(Object parent, object configContext, XmlNode section)
{
NameValueCollection settings;
try
{
NameValueSectionHandler baseHandler = new NameValueSectionHandler();
settings = (NameValueCollection)baseHandler.Create(parent, configContext, section);
}

dbConnectionString = ApplicationConfiguration.ReadSetting(settings, DATAACCESS_CONNECTIONSTRING,
DATAACCESS_CONNECTIONSTRING_DEFAULT);
}
return settings;
}

then, the ApplicationConfiguration.ReadSetting is this:
public static String ReadSetting(NameValueCollection settings, String key, String defaultValue)
{
Object setting = settings[key];
return (setting == null) ? defaultValue : (String)setting;
return defaultValue;
}

So finally JCartConfiguration returns setting to this Create method
public class ApplicationConfiguration : IConfigurationSectionHandler
public Object Create(Object parent, object configContext, XmlNode section)
{
NameValueCollection settings;
 
L

Louis

get a bigger scope

Not Available said:
I meant where is the connection string initialised, as in "in which
method". It looks like it's only initialised when the Create method is

I see your point. I don't think it is initialized anywhere else. I'm just
guessing but somehow JCartConfiguration.ConnectionString when used
non-remotley must pick up some left over private variable/instance but that
doesn't happen when the object trying to use
JCartConfiguration.ConnectionString is remote. I'm not sure if this
"NameValueCollection settings" object from the IConfigurationSectionHandler
is instantiated anywhere and thought it was part of the whole configuration
handler functionality. The whole concept of the Duwamish remote
business_facade:CustomerSystem MarshelByRef is to totally encapsulate
everything and to make it completly stateless. That's why I thought the
whole IConfiguration base class would somehow let you use the configuration
stuff it reads from web.config in all remote objects. It seems to work that
way in the remote setup of the Duwamish sample. Since I basically cloned the
code without the project template and couldn't get the <section
name="ApplicationConfiguration" part to work I thought it had something to
do with that.

I guess I should make some time to do a pared down example of this.
Basically I think the 'know how' I'm looking for is how to make
configuration settings available to a stateless remote completly encasulated
class. It looked like IConfigurationSectionHandler woudl do that.
called. Why not initialise it when the type is initialised instead?

I might be misreading your question but I think the answer is because I want
the remote class/dll/object to be totally encapsulated and stateless.

Here are some other thoughts:

I think there's something more going here because I cloned the Duwmaish
system and didn't use a project template. For example I could not get this
line to work:

System.Configuration.ConfigurationSettings.GetConfig("ApplicationConfigurati
on");

It kept saying it didn't like this web.config section:
<configSections>
<section name="ApplicationConfiguration"
type="JCart.SystemFramework.ApplicationConfiguration, JCart.SystemFramework"
/>

I'm not sure if that's related. I don't think it likes the
"ApplicationConfiguration" word and somehow treats it differently because of
the template but that's just a guess.

To answer your question:

It hits this code only the first time it's run after restarting IIS:
global.asax:Application_Start
ApplicationConfiguration.OnApplicationStart(Context.Server.MapPath(
Context.Request.ApplicationPath ));

then,
public class ApplicationConfiguration : IConfigurationSectionHandler
ApplicationConfiguration:JCart.SystemFramework::OnApplicationStart
System.Configuration.ConfigurationSettings.GetConfig("JCartConfiguration");

then it creates the NameValueCollection settings,
public class JCartConfiguration : IConfigurationSectionHandler
public Object Create(Object parent, object configContext, XmlNode section)
{
NameValueCollection settings;
try
{
NameValueSectionHandler baseHandler = new NameValueSectionHandler();
settings = (NameValueCollection)baseHandler.Create(parent,
configContext, section);
}

dbConnectionString = ApplicationConfiguration.ReadSetting(settings,
DATAACCESS_CONNECTIONSTRING,
DATAACCESS_CONNECTIONSTRING_DEFAULT);
}
return settings;
}

then, the ApplicationConfiguration.ReadSetting is this:
public static String ReadSetting(NameValueCollection settings, String key,
String defaultValue)
{
Object setting = settings[key];
return (setting == null) ? defaultValue : (String)setting;
return defaultValue;
}

So finally JCartConfiguration returns setting to this Create method
public class ApplicationConfiguration : IConfigurationSectionHandler
public Object Create(Object parent, object configContext, XmlNode section)
{
NameValueCollection settings;
 
J

Jon Skeet

[If you could get your newsreader to wrap at about 72 columns, it would
make your posts much easier to reply to.]

Not Available said:
I might be misreading your question but I think the answer is because
I want the remote class/dll/object to be totally encapsulated and
stateless.

Well it's not - it's clearly got state. If you wanted it to be
stateless, you'd need to declare it as a constant. The state in
question is "have I loaded in my configuration settings, and if so what
are they?". I don't see how you can have something loaded at runtime
but still stateless.

I'm not entirely sure how all of this works over remoting (I haven't
done much remoting at all) but I think you need to seriously think
about what you actually mean when you say you want the class to be
stateless.
 
N

Not Available

Yes, I guess I'm a bit off with the 'stateless' terminology. Stateless in
terms of the Duwamish example, means that no persistant database connection
is left open or required. The DataAccess layer object is also de-referenced
after it returns the information required. You are also correct that I'm
really not working with a specification, plan or design on what I want to
do. I picked apart the Duwamish sample as a tool to learn C# and an entry to
learning muiti-tier design. Reading the configuration file and having that
information available globally in static fields seems like the general
concept of what I'm trying to do.


Jon Skeet said:
[If you could get your newsreader to wrap at about 72 columns, it would
make your posts much easier to reply to.]

Not Available said:
I might be misreading your question but I think the answer is because
I want the remote class/dll/object to be totally encapsulated and
stateless.

Well it's not - it's clearly got state. If you wanted it to be
stateless, you'd need to declare it as a constant. The state in
question is "have I loaded in my configuration settings, and if so what
are they?". I don't see how you can have something loaded at runtime
but still stateless.

I'm not entirely sure how all of this works over remoting (I haven't
done much remoting at all) but I think you need to seriously think
about what you actually mean when you say you want the class to be
stateless.
 
J

Jon Skeet

Not Available said:
Yes, I guess I'm a bit off with the 'stateless' terminology. Stateless in
terms of the Duwamish example, means that no persistant database connection
is left open or required.

Right - that really *is* different from what I understand by the wor
d"stateless" :)
The DataAccess layer object is also de-referenced
after it returns the information required. You are also correct that I'm
really not working with a specification, plan or design on what I want to
do. I picked apart the Duwamish sample as a tool to learn C# and an entry to
learning muiti-tier design. Reading the configuration file and having that
information available globally in static fields seems like the general
concept of what I'm trying to do.

One thing you could do is change dbConnection to be a property, and
make the property check whether or not the configuration has been
loaded before it returns a value.

As an aside, if this is really the way you plan to *learn* C#, I'd
suggest a completely different approach - start with very simple
console apps, and work up. IMO, there's no point in looking at ASP.NET
and database access until you're happy with the fundamentals.
 
N

Not Available

One thing you could do is change dbConnection to be a property, and
make the property check whether or not the configuration has been
loaded before it returns a value.

dbConnection was the private variable to a public static ConnectionString
property.
As an aside, if this is really the way you plan to *learn* C#, I'd
suggest a completely different approach - start with very simple
console apps, and work up. IMO, there's no point in looking at ASP.NET
and database access until you're happy with the fundamentals.

Yes, that's how I started, but I'm a bit beyond that now. Using the Duwamish
as a learning tool I setup my own non-template solution, completely
eliminated the Shopping Cart portion using only the Account system and
renamed the namespaces. I started out with C# by learning winforms and
ADO.NET. Being an old Visual FoxPro/SQL, Cobol, Basic, Assembly, RSX11M
type, programmer those concepts weren't that hard for me, although there is
no substitution to actually sitting there for 8 hours a day doing it. I
actually see a lot of similarities in C# with FoxPro. The Duwamish re-code
helped me learn ASP, state maintenance, caching, multi-tier design,
serialialization, etc. It also helped with remoting, as I was able to get
the MarshalByRefObj class to work as a IIS remote dll. I was trying to keep
from re-reading the configuration each time it needed to be used and I think
the IConfiguration class can somehow be used for that. I'm also guessing
that somehow the ApplicationConfiguration code in Duwamish is used with
something going on with the templates or the Application namespace/whatever,
but I could be wrong. At any rate I'm moving on to delegates, events,
threading, ATL/COM in C++, etc. The Fitch sample seems to have a lot of good
non-web concepts to be learned. Hopefully one day I'll actually start a
paying job doing this. I do think that C# is going to be around for a long
time and there will be more and more work for C# programmers every day.
That's why I decided to invest my time in learning it well.

Thanks for your responses.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top