Programmatic Configuration

Topics: Developer Forum, Project Management Forum
Feb 2, 2009 at 2:52 PM
Edited Feb 2, 2009 at 2:58 PM
Hi,

We are evaluating SharedCache for inclusion in our application. One thing we would really like to do for our caching infrastructure is to centralize both cluster and client configuration.

The current thought is that we would store this configuration information inside our SQL server (Cluster). This would make physical access to each cache server unnecessary for configuration changes. Since our application is a installed at each client site (i.e. not centrally hosted at our location) having a central management capability in a single location is very important to us. Since the cache object is static, and the configuration is loaded via a provider, I was unable to see a clear entry point for programmatic configuration of the cluster/client.

Is there currently any way for us to use SharedCache in this manner?

Thanks.
Coordinator
Feb 2, 2009 at 6:20 PM
hi mike,

i have to dive into code to verify if i'm able to help you in a way.

i'm thinking about an overload of configuration for remote configuration which would handle also your case.

regards
Coordinator
Feb 9, 2009 at 9:51 PM
hi mike,
so far i don't see any good way how to manage the configuration automatically since i'm using .net default
configurations. i have to do some more researches about this issue but currently it will be hard to manage
this requirement. regards, roni
Feb 10, 2009 at 12:02 AM
Thanks. I figured as much. I think the main hurdle (as much as I like it) is that the main cache object is static. I ran into a similar issue with one of my projects and I had to resort to making the class instance based and using a static factory class to create the instance. The factory class Create() method has something like:

IComChannel ChannelFactory.Create()
IComChannel ChannelFactory.Create (ChannelConfg config)

In this way, I could use the XML configuration in the overload with no parameter and substitute the config passed in for the other.

--
"Maybe Jesus was right when he said that the meek shall inherit the earth—but they inherit very small plots, about six feet by three." --Robert A. Heinlein
Coordinator
Feb 10, 2009 at 5:24 AM
can you share this code with me, maybe i will be able easy to adapt it and use it for shared cache.
Feb 16, 2009 at 3:23 PM
Here is what I added to IndexusProviderSection.cs to enable programmatic configuration like this:

IndexusDistributionCache

.SetProvider(IndexusProviderSection.CreateForServerIPList(new [] { "127.0.0.1", "192.168.19.192" }));

 


This is not a general solution but one that works for what I am interested in, i.e. replicated scenario. But the basic solution is to fake out the .NET configuration with an XML string. I didn't see any way around that with the current design.I had to set all Required=true config elements to false and give them the default value you see in the sample config files. The nice thing about is this is I was able to get the config needed down to only this for testing:

<!--

bare minimum

 

<indexusNetSharedCache>

<servers>

<add ipaddress="127.0.0.1"/>

</servers>

</indexusNetSharedCache>

 

-->

 



 

private class CreateSectionFromString : IndexusProviderSection

 

{

 

public CreateSectionFromString(string s)

 

{

 

XmlReader reader = XmlReader.Create(new MemoryStream(ASCIIEncoding.UTF8.GetBytes(s)));

 

 

this.DeserializeSection(reader);

 

}

}

 

/// <summary>

 

 

/// Create a config section from a manual XML string to get around ^%&%$ .net config read only BS

 

 

/// </summary>

 

 

/// <param name="s"></param>

 

 

/// <returns></returns>

 

 

public static IndexusProviderSection CreateFromString(string s)

 

{

 

return new CreateSectionFromString(s);

 

}

 

/// <summary>

 

 

/// Create a config based solely on a list of IPs, using default options for everything else

 

 

/// </summary>

 

 

/// <returns></returns>

 

 

public static IndexusProviderSection CreateForServerIPList(IEnumerable<string> serverIPsEnum)

 

{

 

if (serverIPsEnum == null) throw new ArgumentNullException("serverIPsEnum");

 

 

List<string> serverIPs = new List<string>(serverIPsEnum);

 

 

if (serverIPs.Count == 0) throw new ArgumentOutOfRangeException("Must have at least one cache server");

 

 

//first is main cache server

 

 

string MainCacheServer = "<add key=\"MainCacheServer\" ipaddress=\"" + serverIPs[0] + "\"/>";

 

 

//rest are replication servers

 

 

List<string> replicatedServerAddStrings = new List<string>();

 

 

for (int i = 1; i < serverIPs.Count; i++)

 

{

 

string serverIP = serverIPs[i];

 

replicatedServerAddStrings.Add(

"<add key=\"ReplicationServer" + i + "\" ipaddress=\"" + serverIP + "\"/>");

 

}

 

return CreateFromString(

 

 

"<indexusNetSharedCache><servers>" + MainCacheServer +

 

 

"</servers><replicatedServers>" +

 

 

String.Join("", replicatedServerAddStrings.ToArray()) +

 

 

"</replicatedServers></indexusNetSharedCache>"

 

);

}

 

/// <summary>

 

 

/// Create a config based solely on a single IP, using default options for everything else

 

 

/// </summary>

 

 

/// <returns></returns>

 

 

public static IndexusProviderSection CreateForSingleServerIP(string serverIP)

 

{

 

return CreateForServerIPList(new List<string> { serverIP });

 

}




In IndexusDistributionCache:

 

 

private static void LoadProvider()

 

{

 

 

 

#region

Access Log

 

 

 

 

#if

TRACE

 

 

 

 

 

{

Handler.LogHandler.Tracking("Access Method: " + typeof(IndexusDistributionCache).FullName + "->" + ((object)MethodBase.GetCurrentMethod()).ToString() + " ;");

}

 

 

 

#endif

#endregion

Access Log

 

 

if (providerBase == null)

 

{

 

lock (bulkObject)

 

{

 

if (providerBase == null)

 

{

 

// get a reference to the <cacheProvider> section

 

 

 

 

SetProvider((

IndexusProviderSection)WebConfigurationManager.GetSection("indexusNetSharedCache"));

 

}

}

}

}

 

/// <summary>

 

 

 

 

 

/// Set the provider manually rather than through the config

 

 

 

 

 

/// </summary>

 

 

 

 

 

/// <param name="externalSection"></param>

 

 

 

 

 

public static void SetProvider(IndexusProviderSection externalSection)

 

{

 

//don't do anything if not set at all, wait for something externally to set it

 

 

 

 

 

if (externalSection == null) return;

 

providerSection = externalSection;

 

// load registered provider and point provider base to the default provider

 

 

 

 

providerCollection =

new IndexusProviderCollection();

 

 

ProvidersHelper.InstantiateProviders(

 

providerSection.Providers,

providerCollection,

 

typeof(IndexusProviderBase)

 

);

providerBase = providerCollection[providerSection.DefaultProvider];

 

if (providerBase == null)

 

{

 

throw new ProviderException(@"Unable to load default Shared Cache Provider!");

 

}

}

Coordinator
Feb 16, 2009 at 3:53 PM
do you have this code within a sample project you're able to share with us?

regards,
roni
Feb 17, 2009 at 12:19 AM
I uploaded my version of WinServiceCommon in the patches area since I can't just attach it to a message. It is compiled as .NET 2.0 and all the Linq references removed because we have a few projects not yet 3.5 which was the main reason I picked this over Velocity CTP2 since it depends on WCF/3.5
Feb 17, 2009 at 12:45 AM
Sorry, I haven't been able to get you the example, as I have to pull it out of our codebase. I have been putting in lots of hours at work to get a project out on time. I will see if I can get something this week.
Feb 17, 2009 at 1:56 PM
I have a sample project that illustrates what I am talking about. Is there some where I can upload, or can I send to you?
Coordinator
Feb 17, 2009 at 2:23 PM
will send you a private message with my details.

regards,
roni