Thread Safety on my method - asp.net

Is this code considered thread safe even though multiple threads may be polling the directory for files on the webserver at once?
Thanks,
Mike
//Get a testimonial
virtualRoot = HostingEnvironment.ApplicationVirtualPath;
configuration = WebConfigurationManager.OpenWebConfiguration(virtualRoot);
pathToNewsDirectory = configuration.AppSettings.Settings["VanHinoWeb.news.dir"].Value;
fileListing = Directory.GetFiles(pathToNewsDirectory, "*xml");
int index = generator.Next(0, fileListing.Length);
//Put it into XML and get data into string array to return
testimonialReader = new XmlTextReader(fileListing[index]);
testimonialReader.ReadToFollowing("quote");
testimonialData[0] = testimonialReader.ReadString();
testimonialReader.ReadToFollowing("author");
testimonialData[1] = testimonialReader.ReadString();
testimonialReader.ReadToFollowing("authorTitle");
testimonialData[2] = testimonialReader.ReadString();
return testimonialData;
}

Most of the calls under the Get a testimonial comment should be thread safe. Accessing the hosting environment, app settings, and listing directory contents should be fine.
However, it's unclear where the generator object, testimonialReader, and testimonialData objects are created and whether they are shared across threads or not. If they are shared across threads, then the code is not thread safe.

As you are only reading files it looks that this is thread safe. Also you need to close the XmlTextReader (testimonialReader) after you are finished using it.

Related

Flex: recover from a corrupt local SharedObject

My Flex app uses local SharedObjects. There have been incidents of the Flash cookie getting corrupt, for example, due to a plugin crash. In this case SharedObjects.getLocal will throw an exception (#2006).
My client wants the app to recover gracefully: if the cookie is corrupt, I should replace it with an empty one.
The problem is, if SharedObject.getLocal doesn't return an instance of SharedObject, I've nothing to call clear() on.
How can I delete or replace such a cookie?
Many thanks!
EDIT:
There isn't much code to show - I access the local cookie, and I can easily catch the exception. But how can I create a fresh shared object at the same location once I caught the exception?
try {
localStorage = SharedObject.getLocal("heywoodsApp");
} catch (err:Error) {
// what do I do here?
}
The error is easily reproduced by damaging the binary content of a Flash cookie with an editor.
I'm not really sure why you'd be getting a range error - esp if you report that can find it. My only guess for something like this is there is a possibility of crossing boundries with respect to the cross-domain policy. Assuming IT has control over where the server is hosted, if the sub-domain ever changed or even access type (from standard to https) this can cause issues especially if the application is ongoing (having been through several releases). I would find it rather hard to believe that you are trying to retrieve a named SO that has already been named by another application - essentially a name collision. In this regard many of us still uses the reverse-dns style naming convention even on these things.
If you can catch the error it should be relatively trivial to recover from: - just declare the variable outside the scope of the try so it's accessible to catch as well. [edit]: Since it's a static method, you may need to create a postfix to essentially start over with a new identifier.
var mySO:SharedObject;
....
catch(e:Error)
{
mySO = SharedObject.getLocal('my.reversedns.so_name_temp_name');
//might want to dispatch an error event or rethrow a specific exception
//to alert the user their "preferences" were reset.
}
You need to be testing for the length of SharedObject and recreate if it's 0. Also, always use flush to write to the object. Here's a function we use to count the number of times our software is launched:
private function usageNumber():void {
usage = SharedObject.getLocal("usage");
if (usage.size > 0) {
var usageStr:String = usage.data.usage;
var usageNum:Number = parseInt(usageStr);
usageNum = usageNum + 1;
usageStr = usageNum.toString();
usage.data.usage = usageStr;
usage.flush();
countService.send();
} else {
usage.data.usage = "1";
usage.flush();
countService.send();
}
}
It's important to note that if the object isn't available it will automatically be recreated. That's the confusing part about SharedObjects.
All we're doing is declaring the variable globally:
public var usage:SharedObject;
And then calling it in the init() function:
usage = SharedObject.getLocal("usage");
If it's not present, then it gets created.

Safe cache-refresh pattern for ASP.net

I've got quite a lot of code on my site that looks like this;
Item item;
if(Cache["foo"] != null)
{
item = (Item)Cache["foo"];
}
else
{
item = database.getItemFromDatabase();
Cache.insert(item, "foo", null, DateTime.Now.AddDays(1), ...
}
One such instance of this has a rather expensive getItemFromDatabase method (which is the main reason it's cached). The problem I have is that with every release or restart of the application, the cache is cleared and then an army of users come online and hit the above code, which kills our database server.
What is the typical method of dealing with these sorts of scenarios?
You could hook into the Application OnStart event in the global.asax file and call a method to load the expensive database calls in a seperate thread when the application starts.
It may also be an idea to use a specialised class for accessing these properties using a locking pattern to avoid multiple database calls when the initial value is null.

ASP.NET cache Application Variable

I am wondering about potential issues with – alternatives to - caching using an application variable. To preface, I have a custom application object that stores all application data in ONE application variable – the object organizes data in an XML cloud and stores the cloud in one variable for performance.
I am aware of DataSet caching, but all of my DAL objects select (read only) into data readers for performance, so if the solution involves DataSets I have a ton of refactoring to do – not ideal. Record count is low to medium, involving website data and small to medium project management apps; we're not talking a half-million records.
Here is the structure of the function I intend to use in my DAL classes (Select All):
if (AppSetting.GetSetting(_CacheSettingName) == "")
{
SqlHelper objSqlHelper = new SqlHelper();
XmlReader objReader = objSqlHelper.GetXmlReaderByCmd("Select * From FAQ FOR XML PATH('item'), root('" + _CacheSettingName + "')");
//load Cache
StringBuilder _xml = new StringBuilder();
objReader.Read();
while (objReader.ReadState != ReadState.EndOfFile)
{
_xml.Append(objReader.ReadOuterXml());
}
objSqlHelper.Dispose();
AppSetting.SaveSetting(_CacheSettingName, _xml.ToString());
}
//we have cache loaded
// now load the object list from the XML cloud from the application cache
List<FAQBLL> objFAQList = new List<FAQBLL>();
FAQBLL objFAQ;
XmlDocument oXmlDocument = new XmlDocument();
oXmlDocument.LoadXml(AppSetting.GetSetting(_CacheSettingName));
foreach (XmlNode oNode in oXmlDocument.FirstChild.ChildNodes)
{
objFAQ = new FAQBLL();
objFAQ.ID = Convert.ToInt32(oNode.SelectSingleNode("ID").InnerXml);
objFAQ.Question = oNode.SelectSingleNode("Question").InnerXml;
objFAQ.Answer = oNode.SelectSingleNode("Answer").InnerXml;
objFAQList.Add(objFAQ);
objFAQ = null;
}
return objFAQList.Count > 0 ? objFAQList: null;
So my cache returns all to the calling proc, then I LINK to filter the object (by active, by location). On insert, update, and delete I have one line of code to clear the cache. Again, I have the advantage of using read only data readers for performance, and my application object organizes XML into one application variable. MY thinking was that this is low overhead, not having to discard data readers for data sets when I'm just reading data.
Thoughts? Opinions? Are you traumatized by this?
yes, it is a little traumatizing. The problem with using application variables as a cache is that you forfeit some of the best features of caches. For example, the asp.net cache provides some awesome cache invalidation features. This ensures that a) the cache does not increasingly take up more and more resources, and b) that the cache remains fresh (for example, if sourced from a database).
You should really think about using the right tool for the job

Httpruntime cache keys not unique?

Although i have specified a unique key, it seems the following code will return one value for 5 requests, then another for the next couple, then revert back to the value saved in the original request and just continue until there are 10's of different objects all stored under the same key.
It then seems almost random which of these values it will return from the cache.
string strDateTime = string.Empty;
string cachename = "datetimeexample";
object cachedobject = HttpRuntime.Cache.Get(cachename);
if (cachedobject != null)
strDateTime = (string)cachedobject;
else
{
strDateTime = DateTime.Now.ToString();
HttpRuntime.Cache.Insert(cachename, strDateTime, null, DateTime.MaxValue, TimeSpan.FromDays(10), CacheItemPriority.NotRemovable, null);
}
Response.Write(strDateTime +" keys:"+ HttpRuntime.Cache.Count);
Very confused, is this because of threading or something?
Ignoring the possibility of a server farm and load balancing, this behaviour can be caused by the application pool running as a web-garden. To quote the relevant section from MSDN:
Because Web gardens enable the use of
multiple processes, each process will
have its own copy of application
state, in-process session state,
caches, and static data. Web gardens
should not be used for all
applications, especially if they need
to maintain state. Be sure to
benchmark the performance of the
application before deciding whether
Web garden mode is appropriate.
This will cause it to appear as if caching is storing multiple values for the same key, effectively having duplicate entries in the cache.
To resolve this in IIS 7, open the application pool's Advanced Settings and set Maximum Worker Processes to 1. For IIS 6, see the MSDN article (With pretty screenshots).
Albeit 8 months late, I'm answering this question because I found it long before I found this decent article on web-garden gotchas. Hopefully this answer will save future searchers a chunk of time. :)
Your cachekey is always 'datetimeexample', therefore, you will always have one object in cache; and you will always receive that object back.
I am not quite sure what you are trying to accomplish here, as far as I'm concerned, this behaves exactly in the way it's supposed to do.

ASP.NET cache objects read-write

what happens if an user trying to read HttpContext.Current.Cache[key] while the other one trying to remove object HttpContext.Current.Cache.Remove(key) at the same time?
Just think about hundreds of users reading from cache and trying to clean some cache objects at the same time. What happens and is it thread safe?
Is it possible to create database aware business objects in cache?
The built-in ASP.Net Cache object (http://msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx) is thread-safe, so insert/remove actions in multi-threaded environments are inherently safe.
Your primary requirement for putting any object in cache is that is must be serializable. So yes, your db-aware business object can go in the cache.
If the code is unable to get the object, then nothing / null is returned.
Why would you bother to cache an object if you would have the chance of removing it so frequently? Its better to set an expiration time and reload the object if its no longer in the cache.
Can you explain "DB aware object"? Do you mean a sql cache dependency, or just an object that has information about a db connection?
EDIT:
Reponse to comment #3.
I think we are missing something here. Let me explain what I think you mean, and you can tell me if its right.
UserA checks for an object in cache
("resultA") and does not find it.
UserA runs a query. Results are
cached as "resultA" for 5 minutes.
UserB checks for an object in cache
("resultA") and does find it.
UserB uses the cached object "resultA"
If this is the case, then you dont need a Sql Cache dependency.
Well i have a code to populate cache:
string cacheKey = GetCacheKey(filter, sort);
if (HttpContext.Current.Cache[cacheKey] == null)
{
reader = base.ExecuteReader(SelectQuery);
HttpContext.Current.Cache[cacheKey] =
base.GetListByFilter(reader, filter, sort);
}
return HttpContext.Current.Cache[cacheKey] as List<CurrencyDepot>;
and when table updated cleanup code below executing:
private void CleanCache()
{
IDictionaryEnumerator enumerator =
HttpContext.Current.Cache.GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Key.ToString().Contains(_TableName))
{
try {
HttpContext.Current.Cache.Remove(enumerator.Key.ToString());
} catch (Exception) {}
}
}
}
Is this usage cause a trouble?

Resources