http://blogs.remobjects.com/blogs/ck/2009/02/06/p251
Read the comments I posted to see why I like it!
http://blogs.remobjects.com/blogs/ck/2009/02/06/p251
Read the comments I posted to see why I like it!
My employer's support contract has finally come to an end which means I have to look for another job, haven't had to do that in a while!
Drop me an email if you have any positions vacant, in the meantime it's time to do a little "networking".
This is the funniest thing I have seen in a long time. It's a Nazi film that's been fraudulently subtitled to depict Hitler finding out that his name is on the leaked BNP membership list.
It seems they are unable to spell the word "money", because every time they send me their drivel of a newsletter they always want money. Usually it is for their "Van of truth" (which amuses me immensely) but this time it is to help them to become "the most technically advanced political party in the UK".
So, what are they going to do to earn this esteemed title?
Riiight.
If they think that is technologically advanced I had better not start my own political party, because my mobile phone is more technologically advanced than that, and it's broken!
I love the part where he says "This is a task of almost biblical proportions", brilliant! Nick Griffin has obviously not read The Bible! I can imagine Moses now. "Let my people go, or I will set up a small call centre with a telephone line, 8 computers with "Screens" and empty Bob's garage!"
As usual the entire thing is full of rubbish. Don't people realise that this party will never get into power, all they are doing is electing people into a system which will give them money for doing nothing at all?
Now what they should really do is to vote for this guy!
I don't mind people asking me questions, I enjoy helping people. What I don't like is when people ask me questions as a substitute for using their own brains. If the answer isn't obvious there is always Google!
That's why I love this website. When someone is asking me really basic questions that would easily be answered by Google I pop along to the site and enter the search phrase. I think it's a great way of getting a message across.
I'm trying to view this page in Firefox. When it loads the browser tells me I need Silverlight, so I download and install it and then restart my browser only to be told I need to install Silverlight.
That's not impressive at all!
My app has a wizard approach, the current control appears within a panel with Align set to fill the hosting panel. My first wizard step control merely had an image on it which resizes with its parent control. When I resize the form the host panel resizes, which resizes the wizard control, which resizes the image; and boy does it flicker!
I just had to spend some time upgrading my old Delphi DIB controls to D2009 just to get an image that doesn't flicker, crazy! By the way, I tried the same thing in VS2008 and there was no flicker at all, and I thought Delphi was supposed to be the tool that produced fast UI apps.
There was a potential deadlock in the last piece of code. When you obtain any kind of lock you will mostly use a try..finally block to ensure the lock is released when you have finished with it. The using() command expands to a try..finally block so the original code might look okay, however if you mentally expand the code you will see the problem.
using (FileLockingService.FileReadLock(product1.ID))
{
//Some code here
}
This becomes
var disposable = FileLockingService.FileReadLock(product1.ID);
try
{
//Some code here
}
finally
{
disposable.Dispose();
}
So why is this a problem? In a single threaded application it isn't, but this is a website so there are multiple threads running at the same time. Now take into account the fact that a web request has a timeout, what if the thread is aborted after the lock is obtained? Ordinarily this isn't a problem because the acquisition is followed immediately by a "try", but if we expand this code further it is evident that this isn't the case for the code I originally wrote. The code below is indented per method rather than the normal logical indendation
So here you see that rather than there being a TRY block immediately after the EnterWriteLock the code above would create a DisposableAction, check a parameter, assign two instance members, and then return a result. If anything went wrong at any of these points (OutOfMemoryException, ThreadAbortException, etc) then we'd end up with a lock that would not get removed. The code has been changed as follows.
public class FileLockingService : IFileLockingService
{
readonly object SyncRoot = new object();
readonly Dictionary<int, WeakReference> Locks = new Dictionary<int, WeakReference>();
public ReaderWriterLockSlim GetLockHandler(int productId)
{
WeakReference resultReference;
ReaderWriterLockSlim result;
lock (SyncRoot)
{
if (Locks.TryGetValue(productId, out resultReference))
{
result = (ReaderWriterLockSlim)resultReference.Target;
if (result != null)
return result;
}
result = new ReaderWriterLockSlim();
Locks[productId] = new WeakReference(result);
}
return result;
}
}
and when I use this service:
FileLockingService.GetLockHandler(product.ID).EnterReadLock();
//.NET wont allow any exceptions until flow passes into the try block
try
{
//This is the earliest point that an exception can occur after acquiring the lock
using (var sourceStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Response.ClearHeaders();
Response.AddHeader("Content-Type", "Application/Binary");
Response.AddHeader("Content-Disposition", "attachment; filename=" + product.ClientFileName);
using (var resultStream = DownloadService.Process(currentUser, new List<string>(), product.ClientFileName, sourceStream))
{
int bytesRead;
byte[] data = new byte[1024];
while ((bytesRead = resultStream.Read(data, 0, data.Length)) > 0)
Response.OutputStream.Write(data, 0, bytesRead);
Response.End();
}//using
}//filestream
}
finally
{
FileLockingService.GetLockHandler(product.ID).ExitReadLock();
}
Lesson learned: When it comes to thread synchronisation don't do anything fancy!
Apparently my boss used to be annoyed with something on his old website. When he wanted to upload an updated binary he often couldn't because his product was so popular that someone was always downloading it at the same time. He'd have to continuously hit Delete in his FTP client until eventually he'd slip in and manage to delete it before updating the new version.
This obviously isn't an ideal solution because:
For this website I have decided first of all to only update the files via a HTTP form post. So firstly any long running upload will not deny access to the currently available file, this eliminates problem 3. Additionally, using a form post means I can overwrite the existing file, so this eliminates problem 2.
The potential problems I have now though are:
My solution was to implement an IFileLockingService. Downloading a file should place a read lock, uploading the file should place a write lock. Multiple read locks may exist at once, but a write lock is exclusive. Any conflicts will result in the lock request waiting until it may proceed.
//Downloading
using (FileLockingService.FileReadLock(Product.Id))
{
//Write a binary response based on the file
}
//Uploading
using (FileLockingService.FileWriteLock(Product.Id))
{
//Write the posted file to disk
}
To implement the read/write lock I used a ReaderWriterLockSlim instance per Product.ID. To keep memory usage down I ensured that I used a WeakReference to hold the ReaderWriterLockSlim reference so that it may be collected once no longer referenced.
public class FileLockingService : IFileLockingService
{
readonly object SyncRoot = new object();
readonly Dictionary<int, WeakReference> Locks = new Dictionary<int, WeakReference>();
ReaderWriterLockSlim GetLockHandler(int id)
{
WeakReference resultReference;
ReaderWriterLockSlim result;
lock (SyncRoot)
{
if (Locks.TryGetValue(id, out resultReference))
{
result = (ReaderWriterLockSlim)resultReference.Target;
if (result != null)
return result;
}
result = new ReaderWriterLockSlim();
Locks[id] = new WeakReference(result);
}
return result;
}
public IDisposable FileReadLock(int productId)
{
var lockHandler = GetLockHandler(productId);
lockHandler.EnterReadLock();
return new DisposableAction(context => lockHandler.ExitReadLock(), null);
}
public IDisposable FileWriteLock(int productId)
{
var lockHandler = GetLockHandler(productId);
lockHandler.EnterWriteLock();
return new DisposableAction(context => lockHandler.ExitWriteLock(), null);
}
}
DisposableAction is a class I have mentioned here
If I had to write a large business app which accessed a DB, or a website, I would use .NET without hesitation. When it comes to small apps (less than 10MB) that will be downloaded by home users what should I use? I have such a project coming up soon, my boss has bought D2009 and wants me to use that because he is paranoid about people reverse engineering the binaries. I'm a little hesitant but I must admit that I think in this case Delphi 2009 probably is the best tool for the job, and I like to use the best tool for the job rather than the tool I like to use best for my job.
Hopefully things will go smoothly, it will be nice writing apps in two different languages.
An odd title for a coding blog I know, but I love martial arts too, especially competitive ones.
I'm just putting together a CD for my car. The tunes on the CD music really make my adrenaline pump, so I am putting together a compilation of tunes which make me want to win a fight...with style!