inject - InSessionScope Extension problems with AppFabric Cache - c#

Ninject doesn’t provide a InSessionScope Binding for Websites, so we have created our own extension:
public static IBindingNamedWithOrOnSyntax<T> InSessionScope<T>(this IBindingInSyntax<T> parent)
{
return parent.InScope(SessionScopeCallback);
}
private const string _sessionKey = "Ninject Session Scope Sync Root";
private static object SessionScopeCallback(IContext context)
{
if (HttpContext.Current.Session[_sessionKey] == null)
{
HttpContext.Current.Session[_sessionKey] = new object();
}
return HttpContext.Current.Session[_sessionKey];
}
This extension is working fine until we are using the standard local SessionStore.
But we changed the SessionStore and we now use the „AppFabricCacheSessionStoreProvider“ and this store is no longer on the local machine its on the server.
And the problem is that Ninject tries to resolve the reference of an object which was serialized and deserialized and comes from the server and not from the local memory and so ninject can’t find the reference. The result is, that ninjects allways creates a new Object and the SessionScope does not work any more.
Edit 1:
We are using this functionality
https://msdn.microsoft.com/en-us/library/hh361711%28v=azure.10%29.aspx
and here I can use the standard "HttpContext.Current.Session" Object and the list content is stored on the server and not on the local machine.

So architecturally you have a problem in that you need to store the settings for AppFabric somewhere, and this is an issue with your static method. But assume you create a public static class like so:
public static class AppCache
{
public static DataCache Cache { get; private set; }
static AppCache()
{
List<DataCacheServerEndpoint> servers = new List<DataCacheServerEndpoint>(1);
servers.Add(new DataCacheServerEndpoint("ServerName", 22233)); //22233 is the default port
DataCacheFactoryConfiguration configuration = new DataCacheFactoryConfiguration
{
Servers = servers,
LocalCacheProperties = new DataCacheLocalCacheProperties(),
SecurityProperties = new DataCacheSecurity(),
RequestTimeout = new TimeSpan(0, 0, 300),
MaxConnectionsToServer = 10,
ChannelOpenTimeout = new TimeSpan(0, 0, 300),
TransportProperties = new DataCacheTransportProperties() { MaxBufferSize = int.MaxValue, MaxBufferPoolSize = long.MaxValue }
};
DataCacheClientLogManager.ChangeLogLevel(System.Diagnostics.TraceLevel.Off);
var _factory = new DataCacheFactory(configuration);
Cache = _factory.GetCache("MyCache");
}
}
then you can change extension like so:
public static IBindingNamedWithOrOnSyntax<T> InSessionScope<T>(this IBindingInSyntax<T> parent)
{
return parent.InScope(SessionScopeCallback);
}
private const string _sessionKey = "Ninject Session Scope Sync Root";
private static object SessionScopeCallback(IContext context)
{
var cachedItem = AppCache.Cache.Get("MyItem"); // IMPORTANT: For concurrency reason, get the whole item down to method scope.
if (cachedItem == null)
{
cachedItem = new object();
AppCache.Cache.Put("MyItem", cachedItem);
}
return cachedItem;
}

I've found a "Solution" that works so far it's not perfect because I am avoiding the AppFabric Store with an Localstore for the Object Reference.
public static IBindingNamedWithOrOnSyntax<T> InSessionScope<T>(this IBindingInSyntax<T> parent)
{
return parent.InScope(SessionScopeCallback);
}
public static Dictionary<string, object> LocalSessionStore = new Dictionary<string, object>();
private const string _sessionKey = "Ninject Session Scope Sync Root";
private static object SessionScopeCallback(IContext context)
{
var obj = new object();
var key = (string)HttpContext.Current.Session[_sessionKey];
if (string.IsNullOrEmpty(key))
{
var guid = Guid.NewGuid().ToString();
HttpContext.Current.Session[_sessionKey] = guid;
LocalSessionStore.Add(guid, obj);
}
else if(!LocalSessionStore.ContainsKey(key))
{
LocalSessionStore.Add(key, obj);
return LocalSessionStore[key];
}
else if (LocalSessionStore.ContainsKey(key))
{
return LocalSessionStore[key];
}
return HttpContext.Current.Session[_sessionKey];
}
}

Related

C# file is null, crashes when making an instance.

This is my settings.cs class:
public class Settings
{
static FileIniDataParser _parser = new FileIniDataParser();
IniData _data = _parser.ReadFile("Config.ini");
public int GetInt(string section, string key)
{
string keyValue = _data[section][key];
int setting = int.Parse(keyValue);
return setting;
}
}
This will crash if Config.ini doesn't exist because it tries to read from a file that doesn't exist. But in order for me to make the file I first have to make an instance of the object. But when making the instance it crashes.
I can always do this to make it work, but if I do that I have to repeat my self when making GetBool
public int GetInt(string section, string key)
{
FileIniDataParser _parser = new FileIniDataParser();
IniData _data = _parser.ReadFile("Config.ini");
string keyValue = _data[section][key];
int setting = int.Parse(keyValue);
return setting;
}
And repeating your self is never good.
Just check if the file exists before reading it and put everything in the definition of the _data field in the default constructor of the Settings class:
public class Settings
{
static FileIniDataParser _parser = new FileIniDataParser();
IniData _data;
public Settings()
{
if (!File.Exists("Config.ini"))
{
// create the config file
}
_data = _parser.ReadFile("Config.ini");
}
public int GetInt(string section, string key)
{
string keyValue = _data[section][key];
int setting = int.Parse(keyValue);
return setting;
}
}
In addition to Steffens answer which provides the "how to solve" here is the "why to do so".
Generally you should never create instances that cannot be used. Creating an instance of Setting that excplicitely needs a file where the file does not exist should ALLWAYS throw an exeption. Using any methods on such an instances makes no sense at all as ALL of them will fail.
So check if the file exists (see Steffens answer on how to) within the ctor and if not throw an exception.
Use a FactoryMethod, initialising an object using IO in a (static) constructor is always a bad idea.
public class Settings
{
private readonly IniData _data;
private Settings(IniData data){
_data = data;
}
public static Settings InitFrom(string fname){
var _parser = new FileIniDataParser();
var data = _parser.ReadFile(fname);
return new Settings(data);
}
public int GetInt(string section, string key)
{
string keyValue = _data[section][key];
int setting = int.Parse(keyValue);
return setting;
}
}
Now you can create the Settings in a controlled way:
try{
var settings = Settings.InitFrom("Config.ini");
}
catch(IOException iox){
//something useful
}
var x = settings.GetInt("section","key");
And you make the clear that initialisation is more expensive then just a new {}

Need help to upgrade IronPython 2.0.2 to 2.7.5, called from C#

I need to upgrade code calling IronPython from C# and would like to upgrade to IronPython 2.7.5. The problem is that one of the APIs has changed, and I am not familiar enough with the original code to fix it. I have written a console program that exhibits the problem
My Main:
class Program
{
static void Main()
{
var pythonTest = new PythonTest();
pythonTest.LoadScript();
Console.WriteLine("Area = {0}", pythonTest.Evaluate());
}
}
My test class:
public class PythonTest
{
private readonly ScriptEngine _engine;
private readonly ScriptScope _scope;
private ScriptSource _source;
private PythonFunction _currentFunction;
private readonly Dictionary<string, PythonFunction> _functions = new Dictionary<string, PythonFunction>();
private readonly double _scriptInput;
public PythonTest()
{
_scriptInput = 5;
_engine = Python.CreateEngine();
_scope = _engine.CreateScope();
}
public void LoadScript()
{
const string filename = #"../../Scripts/testscript.py";
_source = _engine.CreateScriptSourceFromFile(filename);
_source.Execute(_scope);
string firstFunction = "";
foreach (KeyValuePair<string, object> pair in _scope.GetItems())
{
var pairValue = pair.Value as PythonFunction;
if (pairValue != null)
{
_functions.Add(pair.Key, pairValue);
if (_functions.Count == 1)
{
firstFunction = _functions.Keys.First();
}
}
}
_currentFunction = _functions[firstFunction];
}
public string Evaluate()
{
if (_currentFunction == null)
return null;
var parameters = new ArrayList {_scriptInput};
LanguageContext cxt = Microsoft.Scripting.Hosting.Providers.HostingHelpers.GetLanguageContext(_engine);
var context = new CodeContext(new Scope(), cxt);
object result = _currentFunction.__call__(context, parameters.ToArray());
return result.ToString();
}
}
My test script:
from math import *
def AREA(h):
return (h * h)
This all works with the old Python DLLs. With the new DLLs the instantiation of the CodeContext (in the Evaluate method) is incorrect. The new API uses a PythonDictionary:
public CodeContext(PythonDictionary dict, ModuleContext moduleContext);
I don't know how to modify the code to fix this problem. Any help would be appreciated.
Your LanguageContext is a PythonContext so it can be cast. You can then use that along with a PythonDictionary to create a ModuleContext. Then you can use that along with a PythonDictionary to create your CodeContext:
PythonContext cxt = (PythonContext)Microsoft.Scripting.Hosting.Providers.HostingHelpers.GetLanguageContext(_engine);
PythonDictionary dict = new PythonDictionary();
ModuleContext modctx = new ModuleContext(dict, cxt);
var context = new CodeContext(dict, modctx);

Azure Redis Cache - pool of ConnectionMultiplexer objects

We are using C1 Azure Redis Cache in our application. Recently we are experiencing lots of time-outs on GET operations.
According to this article, one of possible solutions is to implement pool of ConnectionMultiplexer objects.
Another possible solution is to use a pool of ConnectionMultiplexer
objects in your client, and choose the “least loaded”
ConnectionMultiplexer when sending a new request. This should prevent
a single timeout from causing other requests to also timeout.
How would implementation of a pool of ConnectionMultiplexer objects using C# look like?
Edit:
Related question that I asked recently.
You can also accomplish this in a easier way by using StackExchange.Redis.Extensions
Sample code:
using StackExchange.Redis;
using StackExchange.Redis.Extensions.Core.Abstractions;
using StackExchange.Redis.Extensions.Core.Configuration;
using System;
using System.Collections.Concurrent;
using System.Linq;
namespace Pool.Redis
{
/// <summary>
/// Provides redis pool
/// </summary>
public class RedisConnectionPool : IRedisCacheConnectionPoolManager
{
private static ConcurrentBag<Lazy<ConnectionMultiplexer>> connections;
private readonly RedisConfiguration redisConfiguration;
public RedisConnectionPool(RedisConfiguration redisConfiguration)
{
this.redisConfiguration = redisConfiguration;
Initialize();
}
public IConnectionMultiplexer GetConnection()
{
Lazy<ConnectionMultiplexer> response;
var loadedLazys = connections.Where(lazy => lazy.IsValueCreated);
if (loadedLazys.Count() == connections.Count)
{
response = connections.OrderBy(x => x.Value.GetCounters().TotalOutstanding).First();
}
else
{
response = connections.First(lazy => !lazy.IsValueCreated);
}
return response.Value;
}
private void Initialize()
{
connections = new ConcurrentBag<Lazy<ConnectionMultiplexer>>();
for (int i = 0; i < redisConfiguration.PoolSize; i++)
{
connections.Add(new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(redisConfiguration.ConfigurationOptions)));
}
}
public void Dispose()
{
var activeConnections = connections.Where(lazy => lazy.IsValueCreated).ToList();
activeConnections.ForEach(connection => connection.Value.Dispose());
Initialize();
}
}
}
Where RedisConfiguration is something like this:
return new RedisConfiguration()
{
AbortOnConnectFail = true,
Hosts = new RedisHost[] {
new RedisHost()
{
Host = ConfigurationManager.AppSettings["RedisCacheAddress"].ToString(),
Port = 6380
},
},
ConnectTimeout = Convert.ToInt32(ConfigurationManager.AppSettings["RedisTimeout"].ToString()),
Database = 0,
Ssl = true,
Password = ConfigurationManager.AppSettings["RedisCachePassword"].ToString(),
ServerEnumerationStrategy = new ServerEnumerationStrategy()
{
Mode = ServerEnumerationStrategy.ModeOptions.All,
TargetRole = ServerEnumerationStrategy.TargetRoleOptions.Any,
UnreachableServerAction = ServerEnumerationStrategy.UnreachableServerActionOptions.Throw
},
PoolSize = 50
};
If you're using StackExchange.Redis, according to this github issue, you can use the TotalOutstanding property on the connection multiplexer object.
Here is a implementation I came up with, that is working correctly:
public static int POOL_SIZE = 100;
private static readonly Object lockPookRoundRobin = new Object();
private static Lazy<Context>[] lazyConnection = null;
//Static initializer to be executed once on the first call
private static void InitConnectionPool()
{
lock (lockPookRoundRobin)
{
if (lazyConnection == null) {
lazyConnection = new Lazy<Context>[POOL_SIZE];
}
for (int i = 0; i < POOL_SIZE; i++){
if (lazyConnection[i] == null)
lazyConnection[i] = new Lazy<Context>(() => new Context("YOUR_CONNECTION_STRING", new CachingFramework.Redis.Serializers.JsonSerializer()));
}
}
}
private static Context GetLeastLoadedConnection()
{
//choose the least loaded connection from the pool
/*
var minValue = lazyConnection.Min((lazyCtx) => lazyCtx.Value.GetConnectionMultiplexer().GetCounters().TotalOutstanding);
var lazyContext = lazyConnection.Where((lazyCtx) => lazyCtx.Value.GetConnectionMultiplexer().GetCounters().TotalOutstanding == minValue).First();
*/
// UPDATE following #Luke Foust comment below
Lazy<Connection> lazyContext;
var loadedLazys = lazyConnection.Where((lazy) => lazy.IsValueCreated);
if(loadedLazys.Count()==lazyConnection.Count()){
var minValue = loadedLazys.Min((lazy) => lazy.Value.TotalOutstanding);
lazyContext = loadedLazys.Where((lazy) => lazy.Value.TotalOutstanding == minValue).First();
}else{
lazyContext = lazyConnection[loadedLazys.Count()];
}
return lazyContext.Value;
}
private static Context Connection
{
get
{
lock (lockPookRoundRobin)
{
return GetLeastLoadedConnection();
}
}
}
public RedisCacheService()
{
InitConnectionPool();
}

How to use a proxy with RedditSharp?

I'm using RedditSharp from https://github.com/SirCmpwn/RedditSharp in a script of mine, and I'm simply asking, when connecting using this how do I implement a proxy? and could I change the proxy midscript?
There no standalone way, you can't accomplish this without modifying this library source code.
So most painless-way:
Overload constructor of RedditSharp - add new argument with IWebAgent as type. So it will look like this:
public Reddit() : this(new WebAgent())
{
}
public Reddit(IWebAgent agent)
{
JsonSerializerSettings = new JsonSerializerSettings();
JsonSerializerSettings.CheckAdditionalContent = false;
JsonSerializerSettings.DefaultValueHandling = DefaultValueHandling.Ignore;
_webAgent = agent;
CaptchaSolver = new ConsoleCaptchaSolver();
}
Remove "sealed" keyword from RedditSharp.WebAgent class declaration.
Make RedditSharp.WebAgent.CreateRequest method virtual, so it will look like this:
public virtual HttpWebRequest CreateRequest(string url, string method, bool prependDomain = true)
{
...
}
Create your own WebAgent based on old-one:
public class MyAgent: WebAgent
{
public IWebProxy Proxy { get; set; }
public override HttpWebRequest CreateRequest(string url, string method, bool prependDomain = true)
{
var base_request = base.CreateRequest(url, method, prependDomain);
if (Proxy != null)
{
base_request.Proxy=Proxy;
}
return base_request;
}
}
Use it in your code:
var agent = new MyAgent();
var reddit = new Reddit(agent);
...
agent.Proxy = new WebProxy("someproxy.net", 8080);
So now you can set proxy anytime, from anywhere. Not tested really, but it must work.

Caching fails after FileDependency file changes

I am using the Microsoft EnterPrise Library Caching library (Version 5) with a FileDependency.
On the class that I want cached, I have a static property that will either return the item from the cache, or else create a new class and add it to the cache.
This initially works well and the class is created once, and from then on, the cached copy is returned. However once the dependency file changes the cached item is never returned.
I have put together a sample program below to illustrate the issue.
The output from this is
999 cached , 1 uncached
999 cached , 1001 uncached
I would expect the results to be
999 cached , 1 uncached
1998 cached , 2 uncached
It would look like the object is added back to the cache, but is then immediately deleted as expired.
Any ideas why?
using System;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;
namespace TestCache
{
static class Program
{
[STAThread]
static void Main()
{
Cache.Create();
for (int i = 0; i < 1000; i++)
TestClass.Current.DummyMethod();
Console.WriteLine(String.Format("{0} cached , {1} uncached", TestClass.CachedItems, TestClass.UncachedItems));
System.IO.File.AppendAllText(Cache.dependencyFileName, "Test");
for (int i = 0; i < 1000; i++)
TestClass.Current.DummyMethod();
Console.WriteLine(String.Format("{0} cached , {1} uncached", TestClass.CachedItems, TestClass.UncachedItems));
Console.ReadLine();
}
}
public class Cache
{
public static CacheManager cacheManager = null;
public static string dependencyFileName;
public static FileDependency objFileDependency;
public static void Create()
{
var builder = new ConfigurationSourceBuilder();
builder.ConfigureCaching()
.ForCacheManagerNamed("TestCache")
.UseAsDefaultCache()
.StoreInMemory();
var configSource = new DictionaryConfigurationSource();
builder.UpdateConfigurationWithReplace(configSource);
EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);
cacheManager = (CacheManager)EnterpriseLibraryContainer.Current.GetInstance<ICacheManager>("TestCache");
dependencyFileName = "testCache.xml";
if (!System.IO.File.Exists(dependencyFileName))
using (System.IO.File.Create(dependencyFileName)) { }
objFileDependency = new FileDependency(dependencyFileName);
}
}
public class TestClass
{
public static int CachedItems =0;
public static int UncachedItems = 0;
public void DummyMethod()
{
}
public static TestClass Current
{
get
{
TestClass current = (Cache.cacheManager.GetData("Test") as TestClass);
if (current != null)
CachedItems++;
else
{
UncachedItems++;
current = new TestClass();
Cache.cacheManager.Add("Test", current, CacheItemPriority.Normal, null, new ICacheItemExpiration[] { Cache.objFileDependency });
}
return current;
}
}
}
}
Your issue is that you are using a static FileDependency. This is causing the LastUpdateTime of the FileDependency to never be updated which in turn causes all items added to the cache to show as being expired (HasExpired() == true). Even though you are adding items to the cache since they are expired you can never retrieve them.
The solution is to use a new FileDependency object for all additions to the cache. The easiest change would be to replace the objFileDependency field with a property. Using your existing names and approach, the code would look like:
public class Cache
{
public static CacheManager cacheManager = null;
public static readonly string dependencyFileName = "testCache.xml";
public static FileDependency objFileDependency
{
get
{
return new FileDependency(dependencyFileName);
}
}
public static void Create()
{
var builder = new ConfigurationSourceBuilder();
builder.ConfigureCaching()
.ForCacheManagerNamed("TestCache")
.UseAsDefaultCache()
.StoreInMemory();
var configSource = new DictionaryConfigurationSource();
builder.UpdateConfigurationWithReplace(configSource);
EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);
cacheManager = (CacheManager)EnterpriseLibraryContainer.Current.GetInstance<ICacheManager>("TestCache");
if (!System.IO.File.Exists(dependencyFileName))
using (System.IO.File.Create(dependencyFileName)) { }
}
}

Categories