Wednesday, October 26, 2011

Amazon S3 API


I had the simple task of writing the access to the “cloud storage”. It turns out that simple is not the correct description, plus the documentation is not the best there is.
The first task is easy – Create the bucket:
public bool AddBucket(string name)
{
try
{
Amazon.S3.Model.PutBucketRequest req = new Amazon.S3.Model.PutBucketRequest().WithBucketName(name);
client.PutBucket(req);
return true;
} catch {
return false;
}
}

Next task was the upload. At first I thought “why buzzer with the multi part upload, I need a max of 500MB”. After the first test, I had it. Multi part upload is safer for the large files (i.e. 10MB+) because it reduces the amounts of timeouts encountered.
The second issue, there’s no method to stream the bytes directly to the multi part upload.
Anyway I ended up with a send data function of this type:
public bool SendData(byte[] data, string key, string name)
{
string tmp_file = System.IO.Path.GetTempFileName();
bool res = false;
try
{
System.IO.File.WriteAllBytes(tmp_file, data);
if (data.Length < 5000000)
{
Amazon.S3.Model.PutObjectRequest req = new Amazon.S3.Model.PutObjectRequest().WithBucketName(name);
req.FilePath = tmp_file;
req.Key = key;
req.Timeout = int.MaxValue;
req.AddHeader("x-amz-acl", "public-read");
req.PutObjectProgressEvent += new EventHandler(req_PutObjectProgressEvent);
client.PutObject(req);
} else {
Amazon.S3.Transfer.TransferUtilityUploadRequest req = new Amazon.S3.Transfer.TransferUtilityUploadRequest().WithBucketName(name);
req.FilePath = tmp_file;
req.Key = key;
req.AddHeader("x-amz-acl", "public-read");
req.UploadProgressEvent += new EventHandler(req_UploadProgressEvent);
Amazon.S3.Transfer.TransferUtilityConfig config = new Amazon.S3.Transfer.TransferUtilityConfig();
config.MinSizeBeforePartUpload = 5000000;
config.DefaultTimeout = 1200000;
Amazon.S3.Transfer.TransferUtility utility = new Amazon.S3.Transfer.TransferUtility(client, config);
utility.Upload(req);
}
res = true;
}
catch (Amazon.S3.AmazonS3Exception amazonS3Exception)
{
if (amazonS3Exception.ErrorCode != null && amazonS3Exception.ErrorCode.Equals("NoSuchBucket"))
{
if (AddBucket(name))
{
res = SendData(data, key, name);
}
}
}
finally
{
System.IO.File.Delete(tmp_file);
}
return res;
}
Notes:
1.       I’m using 2 types of upload, each one raises a different event for progress (though they’ve got the same parameters inside).
2.       If the error is “bucket does not exist” a new one is created and the upload is re-initiated.
3.       The requests have a line “req.AddHeader("x-amz-acl", "public-read");”, this line sets the access to public. Without it you’ll receive a “403 – Forbidden” error message when accessing from the browser.
4.       I don’t set the ContentType property, if you want an automatic use of the file from the browser - set it.
5.       Incorrect “key” will result in an access denied error, the official document doesn’t say it, but there are limitations to the characters used (found it the hard way).
6.       Last, and probably the most important, in order to send the binary data I save it temporarily to a file.

2 more tasks remain – activating the web access, and doing the cleanup.
Activating the website:
public bool AddWebsiteConfig(string name)
{
try
{
Amazon.S3.Model.PutBucketWebsiteRequest putRequest = new Amazon.S3.Model.PutBucketWebsiteRequest().WithBucketName(name);
Amazon.S3.Model.WebsiteConfiguration config = new Amazon.S3.Model.WebsiteConfiguration();
config.IndexDocumentSuffix = "index.html";
putRequest.WithWebsiteConfiguration(config);
client.PutBucketWebsite(putRequest);
return true;
} catch {
return false;
}
}
The most straight forward method in this post. The only thing to pay attention to is the fact that “name” must be lower-case only, and the address is according to the region. Just as documented.

The last task is Delete. It should have been an easy one:
public bool DeleteBucket(string name)
{
try
{
Amazon.S3.Model.DeleteBucketRequest req = new Amazon.S3.Model.DeleteBucketRequest().WithBucketName(name);
client.DeleteBucket(req);
return true;
} catch {
return false;
}
}

As it turned out, the bucket must be cleared first. For the clearing a “Listing” procedure is needed.
The result is:
public bool DeleteBucket(string name)
{
try
{
Amazon.S3.Model.ListObjectsRequest list_req = new Amazon.S3.Model.ListObjectsRequest().WithBucketName(name);
do
{
using (Amazon.S3.Model.ListObjectsResponse response = client.ListObjects(list_req))
{
if (!response.IsTruncated)
{
list_req = null;
}
foreach (Amazon.S3.Model.S3Object entry in response.S3Objects)
{
Amazon.S3.Model.DeleteObjectRequest del_req = new Amazon.S3.Model.DeleteObjectRequest().WithBucketName(name);
del_req.Key = entry.Key;
client.DeleteObject(del_req);
}
}
} while (list_req != null);
Amazon.S3.Model.DeleteBucketRequest req = new Amazon.S3.Model.DeleteBucketRequest().WithBucketName(name);
client.DeleteBucket(req);
return true;
} catch {
return false;
}
Note: if you need a simple list put the following condition for fetching the next page:
if (response.IsTruncated)
{
list_req.Marker = response.NextMarker;
} else {
list_req = null;
}

I hope this post will solve some of the problems I had...

Sunday, May 29, 2011

VM - how to perform an auto deploy

While writing this blog I'm trying to configure a VM server.
The main idea is: revert to a well-known state and do the sanity-tests from it. So far for the idea, now for the reality. The first thing needed is the WM Server from VMWare. After installation I've still got troubles with the COM object it uses.

Working with the local workstation was by far easier, and the solution was tested on it.

Step 1: connect to the VM.
I've downloaded the VMWareTasks for the job, it's easy to use and removes the hassle of finding when/what went a miss with the VM.
The code for connecting to a VM is simple:
VMWareVirtualHost virtualHost = new VMWareVirtualHost();
virtualHost.ConnectToVMWareWorkstation();

VMWareVirtualMachine virtualMachine = virtualHost.Open(VMX_PATH);
virtualMachine.PowerOn();


Now we have a machine turned on and running.


Step 2: Revert to snapshot
VMWareSnapshot foundSnapshot = virtualMachine.Snapshots.GetNamedSnapshot(SNAPSHOT_NAME);
if (foundSnapshot == null)
return;
foundSnapshot.RevertToSnapshot(TIMEOUT);
virtualMachine.WaitForToolsInGuest();

The last line is a bit weird, but very important. The machine must be fully running in order to work. As we all know, M$ do a fake readiness state while loading necessary things in the back (and preventing work on the way).

Step 3: Login and run things
virtualMachine.LoginInGuest(VM_USERNAME, VM_PASSWORD, 8, TIMEOUT);

VIX_LOGIN_IN_GUEST_REQUIRE_INTERACTIVE_ENVIRONMENT = 8
Create needed folders
foreach (string dir in Dirs)
                {
                    if (!virtualMachine.DirectoryExistsInGuest(dir))
                    {
                        virtualMachine.CreateDirectoryInGuest(dir);
                        Console.WriteLine("Created " + dir);
                    }
                }

Copy files
foreach (KeyValuePair file in Files)
                {
                    CopyFileToMachine(file.Key, file.Value, virtualMachine);
                }

private static void CopyFileToMachine(string source, string target, VMWareVirtualMachine virtualMachine)
        {
            if (virtualMachine.FileExistsInGuest(target))
            {
                virtualMachine.DeleteFileFromGuest(target);
            }
            virtualMachine.CopyFileFromHostToGuest(source, target);
        }
 
Run programs
foreach (KeyValuePair prog in Progs)
                {
                    virtualMachine.RunProgramInGuest(prog.Key, prog.Value,
TIMEOUT);
                }


Step 4:  Get the output back & turn the machine off
foreach (string op_file in ReturnedFiles)
                {
                    CopyFileFromMachine(op_file, virtualMachine);
                }

private static void CopyFileFromMachine(string source, VMWareVirtualMachine virtualMachine)
        {
            if (virtualMachine.FileExistsInGuest(source))
            {
                virtualMachine.CopyFileFromGuestToHost(source, source.Substring(source.LastIndexOf('\\') + 1));
            }
        }

virtualMachine.PowerOff();

That's all, really.
It's worthy to mention there are 4 different types of VMs, but it's important only when initiating the connection, afterwards it's the same.

Happy VMing

Tuesday, May 17, 2011

iTextSharp - how to control the PDF

I'll put it simply like that:
I want a PDF where I control each and every object's location / size / other properties. Usually the objects are either texts or images. So I ended up with a small piece of code which does that, and returns byte array. The byte array is easier to transmit over the net.

Let's begin with the wrapping:
public byte[] GetPDF()
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
iTextSharp.text.Document doc = new iTextSharp.text.Document();
iTextSharp.text.pdf.PdfWriter writer = iTextSharp.text.pdf.PdfWriter.GetInstance(doc, ms);
doc.Open();
iTextSharp.text.Rectangle page = doc.PageSize;
iTextSharp.text.pdf.PdfContentByte cb = writer.DirectContent;
string fontsDirName = (string)Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders").GetValue("Fonts");
iTextSharp.text.FontFactory.RegisterDirectory(fontsDirName);
RenderPDFImages(doc);

RenderPDFTexts(cb, doc.PageSize.Height);
doc.Close();
ms.Flush();
return ms.ToArray();
}


Quite self-explanatory, wrap the Render PDF methods with the creation of the document and the transform to byte array. Note that RenderPDFImages gets the document and RenderPDFTexts gets the content + page's height.
Both of the render methods loop over the objects and call the "Add" method. I'm supplying the "Add" methods, instead of the complete loop.
Important things to remember:
1. The Y coordinate is calculated from the bottom, not from the top. For this reason the code is full of Page Height - Y - Local Height.
2. Before starting to add texts call cb.BeginText(); and when you're done call cb.EndText();

First the AddImage:
private void AddImage(iTextSharp.text.Document doc, System.Drawing.Image img, float X, float Y)
{
iTextSharp.text.Image gif = iTextSharp.text.Image.GetInstance(imageToByteArray(img));
gif.Alignment = iTextSharp.text.Image.ALIGN_LEFT;
gif.SetAbsolutePosition(X, doc.PageSize.Height - Y - gif.PlainHeight);
doc.Add(gif);
}


Note: I convert the image to byte array, that way I can control the type of image inserted + it avoids a strange behavior I've encountered when trying to add it directly.

And the last method, AddText:
private void AddText(iTextSharp.text.pdf.PdfContentByte cb, float PageHeight, string txt, System.Drawing.Font fnt, System.Drawing.Color clr, float x, float y)
{
iTextSharp.text.pdf.BaseFont bf = iTextSharp.text.FontFactory.GetFont(fnt.Name).BaseFont;
cb.SetRGBColorFill(clr.R, clr.G, clr.B);
cb.SetFontAndSize(bf, fnt.Size);

cb.SetTextMatrix(x, PageHeight - y - fnt.Height);
cb.ShowText(txt);

}

There are many more things which can be done with those objects. I used the bare minimum to get the output in PDF format while making sure it looks almost like the original picture.

Thursday, April 28, 2011

Log request and response in IIS

I needed a basic logging feature in order to debug IIS on our client's machine.
This is probably the most forward way to log the request and the matching response. It can be done using the IIS logging features, but it requires touching places we don't want to disturb.
So how does it work?
First build a HTTPModule:
public class LogHTTP : System.Web.IHttpModule

IHttpModule requires 2 methods:
Dispose() - The clean up method, needed only when the GC can't do the cleaning.
Init(System.Web.HttpApplication context) - called upon initialization phase. The common use for it is the hooking of event handlers and setting global variables. Its code is as follows:
public void Init(System.Web.HttpApplication context)
        {
            context.BeginRequest += new EventHandler(context_BeginRequest);
        }


An event handler for each incoming request.
Note: I didn't use PreRequestHandlerExecute because of AJAX. When an AJAX request enters it doesn't reach this phase.
The event handler method code is:
private void context_BeginRequest(object sender, EventArgs e)
        {
            if (sender is System.Web.HttpApplication)
            {
                string l_ID = Guid.NewGuid().ToString();
                System.Web.HttpApplication app = (System.Web.HttpApplication)sender;
                System.Web.HttpRequest request = app.Context.Request;
                request.SaveAs(Base_Dir + l_ID + ".req", true);
                System.Web.HttpResponse response = app.Context.Response;
                response.Filter = new CaptureResponse(response.Filter, Base_Dir + l_ID + ".res");
            }
        }


Pretty straight forward, except for the response.Filter. What is it?
In order to save the response, I had to use the filter stream. CaptureResponse is a class which creates a copy of the written data to a local file.
internal class CaptureResponse : System.IO.MemoryStream
    {
        private readonly string l_filename;
        private readonly System.IO.Stream _stream;

        public CaptureResponse(System.IO.Stream stream, string filename)
        {
            l_filename = filename;
            _stream = stream;
        }
        public override void Write(byte[] buffer, int offset, int count)
        {
            System.IO.StreamWriter sw = new System.IO.StreamWriter(l_filename, true);
            sw.BaseStream.Write(buffer, offset, count);
            sw.Flush();
            sw.Close();
            _stream.Write(buffer, offset, count);
        }
    }

Note: In order to use the same Write method I used the BaseStream rather than the normal call to Write.

The resulting module can easily be added to any site by putting the DLL in the path (or /bin) and adding the following line to web.config, under configuration/system.web/httpModules:
      <add name="DLL-NAME" type="NAMESPACE.LogHTTP"/>

Sunday, February 20, 2011

Serializing Font


As usual I bumped into the strange phenom of font serialization by a mistake. The class I was working on needed the System.Drawing.Font for styling and when trying to serialize the property directly I got the infamous line: “System.Drawing.Font cannot be serialized because it does not have a parameterless constructor.”

A simple test yielded, it’s true. There’s no System.Drawing.Font().

The class was already working, changing the interface of a working class is a very bad idea. Yet in order to serialize it I had to. So I did the minimum required, add properties. Unlike deleting, this approach allows (most of) the code to work after recompiling, or in the case of reflection without a change (see note later on).

How to Serialize the Font
1.       Change it to a read-only property. Easy, remove the “set” part.
note: if you really need to leave it just put [System.Xml.Serialization.XmlIgnore] on the property, thus the serializer won't parse it.
2.       Split it into a few properties:

private System.Drawing.Font l_Font = new System.Drawing.Font("Times New Roman", 24);

public System.Drawing.Font Font
{
get
{
return l_Font;
}
}
public string FontName
{
get
{
return l_Font.Name;
}
set
{
l_Font = new System.Drawing.Font(value, l_Font.Size, l_Font.Style, l_Font.Unit, l_Font.GdiCharSet, l_Font.GdiVerticalFont);
}
}
public float FontSize
{
get
{
return l_Font.Size;
}
set
{
l_Font = new System.Drawing.Font(l_Font.Name, value, l_Font.Style, l_Font.Unit, l_Font.GdiCharSet, l_Font.GdiVerticalFont);
}
}
public System.Drawing.FontStyle FontStyle
{
get
{
return Font.Style;
}
set
{
l_Font = new System.Drawing.Font(l_Font.Name, l_Font.Size, value, l_Font.Unit, l_Font.GdiCharSet, l_Font.GdiVerticalFont);
}
}
public System.Drawing.GraphicsUnit Unit
{
get
{
return l_Font.Unit;
}
set
{
l_Font = new System.Drawing.Font(l_Font.Name, l_Font.Size, l_Font.Style, value, l_Font.GdiCharSet, l_Font.GdiVerticalFont);
}
}
public byte CharSet
{
get
{
return l_Font.GdiCharSet;
}
set
{
l_Font = new System.Drawing.Font(l_Font.Name, l_Font.Size, l_Font.Style, l_Font.Unit, value, l_Font.GdiVerticalFont);
}
}
public bool Vertical
{
get
{
return l_Font.GdiVerticalFont;
}
set
{
l_Font = new System.Drawing.Font(l_Font.Name, l_Font.Size, l_Font.Style, l_Font.Unit, l_Font.GdiCharSet, value);
}
}

Nice hack, but works well.

P.S. Just before submitting I remembered to add this 2 nice (actually supreme useful) methods to the class:
public static void Serialize(string Filename, SerializableFont obj)
{
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(SerializableFont));
System.IO.StreamWriter sw = new System.IO.StreamWriter(Filename);
x.Serialize(sw, obj);
sw.Close();
}
public static SerializableFont DeSerialize(string Filename)
{
SerializableFont res;
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(SerializableFont));
System.IO.StreamReader sr = new System.IO.StreamReader(Filename);
res = (SerializableFont)x.Deserialize(sr);
sr.Close();
return res;
}

The serialization methods that saves the rewriting of serialize... in every location needed in the code.

Tuesday, January 4, 2011

Multi threading and Locks

Recently we had a problem with a multi-threaded app. The symptoms were database locks.
In order to solve it a co-worker (who was not at his best, to say the least) did something like this:

lock(this)
{
//Some actions
}

looks normal? Well, not if the class was instantiated on the thread. In those cases this lock is utterly useless. Here's a simple code to demonstrate the issue.

using System;
namespace lock_test
{
    internal class MyClass
    {
        private string ID;
        public MyClass(string inID)
        {
            ID = inID;
        }
        public void DoRun()
        {
            lock (this)
            {
                Console.WriteLine("Start " + ID);
                System.Threading.Thread.Sleep(10000);
                Console.WriteLine("Stop " + ID);
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 5; i++)
            {
                MyClass x = new MyClass(i.ToString());
                System.Threading.Thread th = new System.Threading.Thread(x.DoRun);
                th.Start();
                System.Threading.Thread.Sleep(100);
            }
            System.Console.ReadKey();
        }
    }
}


This code produces the result
Start 0
Start 1
Start 2
Start 3
Start 4
And a few seconds afterwards adds
Stop 0
Stop 1
Stop 2
Stop 3
Stop 4

The "lock(this)" statement was completely ignored, for practical purposes, putting a timer on it might show the compiler didn't remove it.
So how should it be done?

1. Add to the internal class a new static variable 
private static object lock_obj = new object();

2. Change the "lock(this)" to "lock(lock_obj)".

That's all, suddenly the app works as expected, the output (in my last run) was:
Start 0
Stop 0
Start 3
Stop 3
Start 2
Stop 2
Start 1
Stop 1
Start 4
Stop 4


Note the order, it's due to the lock. The 1st thread (ID 0) locked it, but afterwards it's up to the mutex handling mechanism to decide who does the new lock. The only thing guaranteed is you'll see the "Start" and the "Stop" of the same ID, unlike the output of the first run.