INTRODUCTION TO POSTSHARP - PART 2

by Viktor 14. October 2009 21:22

Time for part two of Introduction to PostSharp, part one can be found here Introduction to PostSharp - Part 1. In part two we will focus on PostSharp.Core. With PostSharp.Laos we get nice base classes that we just add our code to and PostSharp dose the rest for us, what I did not tell you in the first part is that PostSharp.Laos is a easy to use addin to PostSharp that is written with PostSharp.Core and as you my expect PostSharp.Core is not as easy to get a handle on.

The code for this example can be downloaded here, CacheExample.zip (303.53 kb), you need Visual Studio 2008 and PostSharp 1.5 RTM to compile and run the code.

In this part we will create a cache plugin for PostSharp using PostSharp.Core. What it will do is that at method entry generate a cache key based on the parameters, check if there is a values saved for this cache key and if there is return that value otherwise continue with the method. At the end of the method, at successfull exit, we will save the return value, using the cache key generated at method entry, in the cache for future use.

Lets start with the basic example program we have,

public class Program
{
        static void Main(string[] args)
        {
                string data;
                do
                {
                        Console.Write("Number: ");
                        data = Console.ReadLine();
                        Console.WriteLine("And the magic number is: {0}", DoBigCalculation(data));
                } while (data != "quit");

        }

        private static int DoBigCalculation(string data)
        {
                int number;
                if (int.TryParse(data, out number))
                {
                        //This is just to simulate a big calculation/data operation you may have in your application
                        //that can be much fast with cache
                        System.Threading.Thread.Sleep(2000);
                        return number * 2;
                }
                return 0;
        }
}      

The DoBigCalculation method is the slow method that we want to cache because it's just to slow in it's current form. The cache system we will use is very simple,

public static class Cache
{
        private static Dictionary _cache = new Dictionary();

        public static object Get(object key)
        {
                if (_cache.ContainsKey(key))
                {
                        return _cache[key];
                }
                return null;
        }

        public static object GenerateKey(params object[] paramlist)
        {
                string key = string.Empty;
                foreach (object obj in paramlist)
                {
                        key += obj.ToString();
                }
                return key;
        }

        public static void Set(object key, object value)
        {
                if (_cache.ContainsKey(key))
                {
                        _cache.Remove(key);
                }
                _cache.Add(key, value);
        }
}

Right now we have everything we need to cache the DoBigCalculation method and we could rewrite the method to look like this,

private static int DoBigCalculation(string data)
{
        object cacheValue = Caching.Cache.Get(Caching.Cache.GenerateKey(data));
        if (cacheValue != null)
        {
                return (int)cacheValue;
        }
        int number;
        if (int.TryParse(data, out number))
        {
                //This is just to simulate a big calculation/data operation you may have in your application
                //that can be much fast with cache
                System.Threading.Thread.Sleep(2000);
                number = number * 2;
        }
        else
        {
                number = 0;
        }
        Caching.Cache.Set(Caching.Cache.GenerateKey(data), number);
        return number;
}

and that works perfecly fin, but now we have added caching code to our calculation code and the calculation code is now responsible to have both working caching code and working calculation code. What we want to do insted is be able to write the caching code sepereate from the calculation code and then just be able to mark the method for caching and the caching code will be added to the method automaticly during compile time, to do this we write a caching aspect with PostSharp.Core and when we are finished the resulting code, after compile, will look very much like the example above but when we look at the code in our project it will still look like the code in the first example and only contain calculation code.

Lets begin by creating the caching attribute we want to use,

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
AllowMultiple = false, Inherited = false)]
[MulticastAttributeUsage(MulticastTargets.Method | MulticastTargets.Property, AllowMultiple = false)]
[RequirePostSharp("Aspects.Weaver", "Aspects.Weaver")]
public class CacheAttribute : MulticastAttribute
{
}

Now when we have a attribute its time to create the two classes that will form our aspect, the Task and Advice, as always for more information about exacly why and what check out PostSharp.org. Lets begin with the Task,

public class CacheTask : Task, IAdviceProvider
{
        protected override void Initialize()
        {
        }

        #region IAdviceProvider Members

        public void ProvideAdvices(PostSharp.CodeWeaver.Weaver codeWeaver)
        {
        }

        #endregion
}

and then continue with the advice,

public class CacheAdvice : IAdvice
{
        private readonly CacheTask _parent;
        private readonly CacheAttribute _attribute;
        private LocalVariableSymbol _cacheKeyVariable;


        public CacheAdvice(CacheTask parent, CacheAttribute attribute)
        {
                _parent = parent;
                _attribute = attribute;
        }

        #region IAdvice Members

        public int Priority
        {
                get { return 5; }
        }

        public bool RequiresWeave(WeavingContext context)
        {
                return true;
        }

        public void Weave(WeavingContext context, PostSharp.CodeModel.InstructionBlock block)
        {
        }

        private void WaveEntry(WeavingContext context, InstructionBlock block)
        {
        }

        private void WaveExit(WeavingContext context, InstructionBlock block)
        {
        }

        #endregion
}

One more thing needs to be added to the project, a file that binds the attribute and Task togerther, the Aspect.Weaver.psplugin file,



        
                
        

This plugin file has to be in the bin directory of the example program for it to work.

Lets start with the code for the task.

public void ProvideAdvices(PostSharp.CodeWeaver.Weaver codeWeaver)
{
        // Gets the dictionary of custom attributes.
        AnnotationRepositoryTask annotationRepository = AnnotationRepositoryTask.GetTask(this.Project);

        // Requests an enumerator of all instances of our CacheAttribute.
        IEnumerator customAttributeEnumerator = annotationRepository.GetAnnotationsOfType(typeof(CacheAttribute), false);
        // For each instance of our CacheAttribute.
        while (customAttributeEnumerator.MoveNext())
        {
                // Gets the method to which it applies.
                MethodDefDeclaration methodDef = customAttributeEnumerator.Current.TargetElement as MethodDefDeclaration;

                if (methodDef != null)
                {
                        // Build an advice based on this custom attribute.
                        CacheAdvice advice = new CacheAdvice(this, null);
                                                // Add join points at the start of the method and at the end of a successfull method
                        codeWeaver.AddMethodLevelAdvice(advice, new Singleton(methodDef), JoinPointKinds.BeforeMethodBody | JoinPointKinds.AfterMethodBodySuccess, null);
                }
        }
}

This code will call the advice for every instance of our cache attribute in the code and tell the advice that we want to add code to the method at the top of the method (BeforeMethodBody) to be able to check if the value requested can be found in our cache or not and then after a successfull running of the method to be able to add the return value to the cache and return the value. Now we need to add helper methods to the Task, this are instances of the cache methods that needs to be called in the advice,

internal IMethod CacheSetMethod;
internal IMethod CacheGetMethod;
internal IMethod CacheGenerateKeyMethod;

internal ITypeSignature ObjectType;
internal ITypeSignature ObjectArrayType;

This are variables that will containe methods and types that are needed by the advice. We override the initialize method to initialize the variables,

protected override void Initialize()
{
        ModuleDeclaration module = this.Project.Module;

        ObjectType = module.FindType(typeof(object), BindingOptions.Default);
        ObjectArrayType = module.FindType(typeof(object[]), BindingOptions.Default);
        this.CacheSetMethod = module.FindMethod(typeof(Caching.Cache).GetMethod("Set", new Type[]
        {
                typeof(object),
                typeof(object)
        }), BindingOptions.Default);

        this.CacheGetMethod = module.FindMethod(typeof(Caching.Cache).GetMethod("Get", new Type[]
        {
                typeof(object)
        }), BindingOptions.Default);
        this.CacheGenerateKeyMethod = module.FindMethod(typeof(Caching.Cache).GetMethod("GenerateKey", new Type[]
        {
                typeof(object[])
        }), BindingOptions.Default);
}

We use the FindType and FindMethod methods to find the types and methods we need to work with later. Now when the Task class is ready its time to move on to the advice. First we add code to our Weave method,

switch (context.JoinPoint.JoinPointKind)
{
        case JoinPointKinds.BeforeMethodBody:
                this.WaveEntry(context, block);
                break;
        case JoinPointKinds.AfterMethodBodySuccess:
                this.WaveExit(context, block);
                break;
        default:
                throw new ArgumentException(string.Format("Unexpected join point kind: {0}", context.JoinPoint.JoinPointKind));
}

This is the method that will be called from our Task whenever a attribute is found and when its time to add code to one of our defined Joinpoints. Now we get into the hard part, the code generation, lets start with WaveEntry, here we want to generate a cache key, check if the cache contains a object and return that object or if it's null continue with the method. I have added alot of code comments here so read them to get a unerstanding of what happens here,

private void WaveEntry(WeavingContext context, InstructionBlock block)
{
        // Create a new instruction sequence and add it to the block
        // dedicated to our advice. Attach the InstructionWriter.
        InstructionSequence entrySequence = context.Method.MethodBody.CreateInstructionSequence();
        // Create another instruction sequence that we will jump to if nothing was found in the cache
        InstructionSequence endSequence = context.Method.MethodBody.CreateInstructionSequence();

        // Add the instruction sequence at the top of the method
        block.AddInstructionSequence(entrySequence, NodePosition.Before, null);
        // Add the instruction sequence after the previus instruction sequence
        block.AddInstructionSequence(endSequence, NodePosition.After, entrySequence);
        // Attach the instruction sequence to the writer so that we can being writing code
        context.InstructionWriter.AttachInstructionSequence(entrySequence);
        // Hide the sequence from debuggers.
        context.InstructionWriter.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden);

        // Create a local variable of type object, this will hold the cache key we create for this method call and
        // will be used both there in Entry and in the Exit method
        _cacheKeyVariable = block.DefineLocalVariable(_parent.ObjectType, "~cache~key~{0}");
        // Create a local variable that will be used as the argument to the generate cache key method
        LocalVariableSymbol tmpCacheKey = block.DefineLocalVariable(_parent.ObjectArrayType, "~tmp~cache~key~{0}");
        // Create a local variable that will hold the object that is returned from the caches Get method
        LocalVariableSymbol objectFromCache = block.DefineLocalVariable(_parent.ObjectType, "~object~from~cache~{0}");
        // Get the number of parameters sent to this method
        int parameters = context.Method.Parameters.Count;
        // Push the size of the array to the stack
        context.InstructionWriter.EmitInstructionInt32(OpCodeNumber.Ldc_I4, parameters);
        // Create a new array object
        context.InstructionWriter.EmitInstructionType(OpCodeNumber.Newarr, _parent.ObjectType);
        // Save the new array to the variable
        context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Stloc, tmpCacheKey);

        //Loop all of the paramters for this method
        for (int i = 0; i < context.Method.Parameters.Count; i++)
        {
                // Push the array onto the stack
                context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, tmpCacheKey);
                // Push the position index where you want to save the object in the array onto the stack
                context.InstructionWriter.EmitInstructionInt32(OpCodeNumber.Ldc_I4, i);
                // Push the value you want to save onto the stack
                context.InstructionWriter.EmitInstructionInt32(OpCodeNumber.Ldarg_S, i);
                // Copy everyting into the array
                context.InstructionWriter.EmitInstruction(OpCodeNumber.Stelem_Ref);
        }
        // Push the array onto the stack as a parameter for the next method call
        context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, tmpCacheKey);
        // Call the GenerateKey method with the array as a parameter
        context.InstructionWriter.EmitInstructionMethod(OpCodeNumber.Call, _parent.CacheGenerateKeyMethod);
        // Copy the return value from GenerateKey to the variable
        context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Stloc, _cacheKeyVariable);

        // Push the cache key onto the stack
        context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, _cacheKeyVariable);
        // Call the cache Get method with the cacke key as a parameter
        context.InstructionWriter.EmitInstructionMethod(OpCodeNumber.Call, _parent.CacheGetMethod);
        // Get the return value from the cache Get method
        context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Stloc, objectFromCache);

        // Push the object we got from the cache method onto the stack
        context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, objectFromCache);
        // Push null to to stack
        context.InstructionWriter.EmitInstruction(OpCodeNumber.Ldnull);
        // Check if the value we got from the stack and null are equal
        context.InstructionWriter.EmitInstruction(OpCodeNumber.Ceq);

        // If they are equel we want to continue with the method as it's written
        context.InstructionWriter.EmitBranchingInstruction(OpCodeNumber.Brtrue_S, endSequence);
        // If they are not equal we want to return the value we got from the cache Get method back from the calling method
        context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc_S, objectFromCache);
        context.InstructionWriter.EmitInstruction(OpCodeNumber.Ret);
        context.InstructionWriter.DetachInstructionSequence();

        // If we did not get anything back from the cahce do nothing and return to the method and continue executing
        context.InstructionWriter.AttachInstructionSequence(endSequence);
        context.InstructionWriter.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden);
        context.InstructionWriter.EmitInstruction(OpCodeNumber.Nop);
        context.InstructionWriter.DetachInstructionSequence();
}

And then the WaveExit method, here we want to take the value that's returned form the method and put it into our cache using our generated cache key as the key,

private void WaveExit(WeavingContext context, InstructionBlock block)
{
        //Create a instruction sequence
        InstructionSequence entrySequence = context.Method.MethodBody.CreateInstructionSequence();
        // Add the new instruction sequence at the end of the method body (but before the last return)
        block.AddInstructionSequence(entrySequence, NodePosition.After, null);
        // Attache the new instruction sequence to the current context
        context.InstructionWriter.AttachInstructionSequence(entrySequence);
        // Hide the code from debuggers
        context.InstructionWriter.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden);

        // Push the cachekey we created in the WaveEntry method onto the stack
        context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc_S, _cacheKeyVariable);
        // Push the return value onto the stack
        context.InstructionWriter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc_S, context.ReturnValueVariable);
        // Call the cache Set method with the two parameters we have pushed onto the stack
        context.InstructionWriter.EmitInstructionMethod(OpCodeNumber.Call, _parent.CacheSetMethod);

        context.InstructionWriter.DetachInstructionSequence();
}

And to put it all to good use lets update our example program to look like this,

[Aspect.Cache]
private static int DoBigCalculation(string data)
{
        int number;
        if (int.TryParse(data, out number))
        {
                //This is just to simulate a big calculation/data operation you may have in your application
                //that can be much fast with cache
                System.Threading.Thread.Sleep(2000);
                return number * 2;
        }
        return 0;
}

Now we have added a cache to the big calculation method and when you call it with the same argument again you should get the respnse much faster as its taken from the cache and not calculated again.

A couple of notes about the example program that I have included here, you have to copy the dll from the Weaver project to your bin directory and also the *.psplugin file, as there are not references to this project the files are not copied when you compile the application.

Example program for Part 2: CacheExample.zip (303.53 kb)

Tags: , , , ,

Development

Comments

10/26/2009 7:22:22 PM #

msn adresleri

i cant do itFrown

msn adresleri Sweden

10/27/2009 5:26:42 AM #

Tiffany Bracelets

yes  I  am  

Tiffany Bracelets People's Republic of China

10/31/2009 6:58:46 AM #

dofollow blog commenting service

Introducing such a topic you'd like to congratulate you've let us know. Have good work--

dofollow blog commenting service Thailand

12/11/2009 11:55:40 AM #

Sex harassment lawyers CA

Thank you for another great article. Where else could anyone get that kind of information in such a perfect way of presentation.


Regards
Trujillo



Sex harassment lawyers CA United States

1/10/2010 12:56:26 PM #

منتدى

Nice!

Thank you

http://www.2fnn.com

منتدى Saudi Arabia

1/27/2010 5:19:10 AM #

دردشة

fghghfgh

دردشة Austria

1/30/2010 8:30:14 PM #

منتديات

thanks,

is this OK For ) DB (
i thinks Some Problem from this  , ,  ,

thanks, Alot

منتديات Germany

2/17/2010 6:46:17 AM #

frwc's royal trader

Commercial companies often trade fairly small amounts compared to those of banks or speculators and their trades often have little short term impact on market rates.

frwc's royal trader United States

2/27/2010 7:45:37 AM #

dentists

Completed article.Thanks to shear.

dentists bd

2/27/2010 8:34:10 AM #

Fatcow Review

Should I get a Virtual Private Server? Right now I am using shared hosting but they keep disabling my account because of high server load. Im getting about 2,000 UV a day. What hosting should I get?

Fatcow Review United States

3/2/2010 3:21:39 PM #

how to treat genital warts

And that is because it is highly contagious and transmitted skin to skin during sexual activity.

how to treat genital warts Kuwait

3/6/2010 1:57:54 PM #

games funny

Hello blogger, thanks for sharing this post! I found it great. Take care, Erica..

games funny Turkey

3/6/2010 7:27:04 PM #

Watch Series

Using an Internet Service Provider, something which is common in many homes in the developed world,the user simply enters their chosen website address.
  

Watch Series United Kingdom

3/11/2010 6:47:14 AM #

Adult Blu-ray

nice to be here....i really enjoyed the reading the blog..

Adult Blu-ray United States

3/11/2010 10:48:48 AM #

meilleures probabilités au poker

I was in the opposite position as I have BinDiff but I didn't have the file in question (go.exe). I mailed muzzy and he hooked me up with the file.The first column shows the hex address where the table can be found in the go.exe file, the second column shows the name of the table as it appears in the LAME source code and the third column shows the LAME source file where the table can be found.

meilleures probabilités au poker India

3/11/2010 6:26:03 PM #

dentists

So beautiful article. I visit this site. It gives me lots of pleasure and interest. It’s a most important post. Please every one visit this site quickly. Thanks.

dentists bd

3/16/2010 11:12:32 PM #

Mobile Crane Hire

Hi vey nice interesting blog im from  i found this on msn i found this blog very interesting good luck with it i will return to this blog soon

Mobile Crane Hire United Kingdom

3/25/2010 12:01:07 AM #

tiffany jewlery sale

keep at it man, your almost there , thanks for the read!

tiffany jewlery sale United States

3/26/2010 1:04:29 AM #

jordan fusion

keep at it man, your almost there , thanks for the read!

jordan fusion United States

3/28/2010 2:34:20 PM #

بنات قطر

thank u my daer

بنات قطر Qatar

4/2/2010 10:12:59 PM #

jump manual review

This site is more appropriate to publish some of the article.I hear this news INTRODUCTION TO POSTSHARP - PART 2 in my life first time. I discus this topic with some of my friends.We think this article is one of the best and great in this site.

jump manual review bd

4/8/2010 1:35:37 PM #

bağkur sorgulama

Thanks a lot for enjoying this beauty article with me. I am apreciating it very much! Looking forward to another great article. Good luck to the author! all the best!

bağkur sorgulama Spain

4/9/2010 8:44:09 PM #

Certified Loose Diamonds

Have a nice and most popular post. I visit this site and find lot of valuable things from this post. I sharing this post with some of my friends and they are very interest to visit this site. Thanks

Certified Loose Diamonds bd

4/9/2010 9:17:24 PM #

sports betting champ review

This post INTRODUCTION TO POSTSHARP is one of the best in all.I belief in this site. All the user in this site was posting their notice about the post so great.So i posted this comment to discus their post.

sports betting champ review bd

4/12/2010 10:29:07 AM #

games

Шановні колеги! Перевірте і напишіть, будь ласка, чи вже можливий цей доступ. Буду щиро вдячний...

games Egypt

4/16/2010 7:23:06 PM #

wedding services scotland

Excellent article.Its really a good article. It gives me lots of pleasure and interest. It’s a most important post. So i want to know some other details about this article. Thanks

wedding services scotland bd

4/18/2010 7:08:02 AM #

Goodie Bag

Thank you very much for sharing this information. I like this side. Its really a great article. So please give me some important information about this side.

Goodie Bag United States

4/19/2010 10:04:00 AM #

Tiffany Necklaces

I visit this site. It gives me lots of pleasure and interest. It’s a most important post. Please every one visit this site quickly. Thanks.

Tiffany Necklaces United States

4/20/2010 3:39:56 PM #

Clasificados Gratis

Clasificados Online. Anuncios Clasificados Gratis en España.

Clasificados Gratis United States

4/21/2010 4:34:06 PM #

Bani pe internet

afaceri online - your online bussiness

Bani pe internet United States

5/2/2010 2:10:24 PM #

cool tattoo designs

Im impressed, I must say.  Very rarely do I come across a blog thats both informative and entertaining, and let me tell you, youve hit the nail on the head.  Your blog is important; the issue is something that not enough people are talking intelligently about.  Im really happy that I stumbled across this in my search for something relating to this issue.

cool tattoo designs United States

5/3/2010 11:43:00 AM #

Free Call To India

This is a very good article, im thankful I stubled onto this. Ill be back later on to check out other posts that you have on your blog.

Free Call To India United Kingdom

5/25/2010 2:33:20 AM #

Sammie Suder

Hello, here is my wecsite.

Sammie Suder United States

5/27/2010 9:13:03 AM #

alternative treatments for depression

Dude, please tell me that youre going to write more.  I notice you havent written another blog for a while (Im just catching up myself).  Your blog is just too important to be missed.  Youve got so much to say, such knowledge about this subject it would be a shame to see this blog disappear.  The internet needs you, man!

alternative treatments for depression United States

5/28/2010 6:07:26 PM #

Panic and Anxiety Attacks

This is a smart blog.  I mean it.  You have so much knowledge about this issue, and so much passion.  You also know how to make people rally behind it, obviously from the responses.  Youve got a design here thats not too flashy, but makes a statement as big as what youre saying.  Great job, indeed.

Panic and Anxiety Attacks United States

6/4/2010 11:57:52 AM #

lipo 6

I want to in place of charming  made the effort  in the direction of announce this.

lipo 6 United States

6/6/2010 10:19:29 AM #

Ana Brennan

Make sure you in fact moderate the comments here

Ana Brennan United States

6/6/2010 6:47:04 PM #

Rocco Zelinski

Experts say you should pick up fairly the look and usability of your blog.

Rocco Zelinski United States

6/6/2010 11:08:22 PM #

Robena Bernardoni

I don't agree with all on that post, but you do make some very good things. I'm very excited about this subject and I myself do alot of study as well. Either way it was a well thoughtout & fine read so I figured I would leave u a remark. Feel free to take a look at my web page sometime and let me know what u feel.

Robena Bernardoni United States

6/7/2010 6:45:02 PM #

Tana Kalert

One has to suppose via it before coming to a conclusion on about it,lovely site I just like the header.

Tana Kalert United States

6/8/2010 9:08:07 PM #

Mose Ormand

Dude.. I am not a great deal into reading, but somehow I got to read several articles on your weblog. Its amazing how interesting it is for me to visit you very often.

Mose Ormand United States

6/9/2010 3:15:27 PM #

buy cheap viagra online without prescription

Greetings everyone, This website is high-quality and so is the manner in which the issue was expanded. I like some of the comments as well although I would prefer we don't err from the main point so that to add value to the subject. It will be also encouraging to the author if we all could pass it around (for many of us who use social media such as a digg, twitter,..). Again, Thanks..

buy cheap viagra online without prescription United States

6/9/2010 11:02:02 PM #

Matt Tso

If he does, neither of you personal this place, it would be like me shifting into a brand new condominium with a good friend and saying that I get to plan everything. If the furnishings there is already yours and whatnot, I see a number of the factors, but if he's paying rent, yea, he should get a say.

Matt Tso United States

6/13/2010 7:01:29 AM #

Sammy Hoste

You should in fact moderate the comments here

Sammy Hoste United States

6/14/2010 9:53:32 AM #

Eleni Hydrick

pls extra photoes

Eleni Hydrick United States

6/15/2010 11:40:33 PM #

D&amp;G Jeans

This is so cool that you are writing this. Because I’m fairly new to blogging in fact only 7 months. I’m having so much fun with it. Now, I can’t wait till the time comes when I’m traveling the world at speaking engagements.

D&amp;G Jeans United States

6/20/2010 1:08:44 AM #

Ernest Corriveau

I came across this topic on another site and didn't really understand it, but your article makes it clearer to me now. Thanks!

Ernest Corriveau United States

6/21/2010 9:58:16 PM #

Justin Lucky

Just in case you didn't know... your web site looks really bizarre in Mozilla on a Mac

Justin Lucky United States

6/23/2010 10:07:34 AM #

Lane Oconnor

I truly like the fresh perpective you do on the concern. Truly was not expecting that when I began off studying. Your concepts had been easy to understand that I wondered why I in no way looked at it prior to. Glad to know that there's a writer out there that definitely understands what he's discussing. Excellent.

Lane Oconnor United States

6/24/2010 4:28:25 PM #

Caprice Kebede

I saw a program concerning that on TV yesterday. Thanks for the more in-depth explanation

Caprice Kebede United States

6/25/2010 9:22:40 AM #

Abdul Emerson

I don't really know as well much about this, i actually just desired to obtain some ideas from your website, but your post caught my attention.Although this is not one of my favorite topics i had been nevertheless very entertained through the way you presented it. you've a really high quality blog.I hope that i can mimic your achievement, cheers.

Abdul Emerson United States

6/28/2010 2:42:05 PM #

دروس فوتوشوب


This article is very helpful in teaching kids some healthy manners and self discipline. Thank you so much for sharing such a vital information.

دروس فوتوشوب Albania

6/30/2010 10:54:50 AM #

fleas on humans

You lost me, friend. I mean, I suppose I get what youre declaring. I recognize what you are saying, but you just appear to have forgotten that you'll find some other individuals within the world who view this issue for what it genuinely is and may possibly not agree with you. You may perhaps be turning away alot of persons who may have been lovers of your blog site.

fleas on humans United States

6/30/2010 11:41:54 AM #

Alfred Bush

You raise many questions in my mind; you wrote an superb article, but this post can also be thought provoking, and I am going to have to ponder it somewhat more; I will be back when I'm free.

Alfred Bush United States

6/30/2010 5:08:53 PM #

car brake parts

When will you provide an update?  I would like to stay informed.  Thanks.

car brake parts United States

7/4/2010 3:11:25 PM #

Kelley Greem

Can I quote you in my report for school?

Kelley Greem United States

7/5/2010 9:41:02 AM #

Vernia Washum

I enjoy your site

Vernia Washum Norway

7/5/2010 10:22:06 AM #

Rae Reisz

Rae Reisz Romania

7/5/2010 3:20:57 PM #

Amos Gucman

Just in case you didn't know... your website looks extremely bizarre in Chameleon on a mac

Amos Gucman United States

7/5/2010 9:28:37 PM #

Lamar Pouge

Just curious if youre implementing the new jigga-star plugin for BE or at any time you made this theme on your own?

Lamar Pouge Republic of the Philippines

7/7/2010 2:37:43 AM #

Juliana Kebede

I stumbled on a link to your website on a Forex site, and I must say... Your website is much better. You explain it more clearly, thanks

Juliana Kebede United States

7/8/2010 3:58:24 AM #

Eddy Baccouche

Hey - nice web site, simply looking around some blogs, appears a very nice platform you're using. I am presently utilizing Wordpress for a number of of my websites however trying to change one in all them over to a platform similar to yours as a trial run. Anything in particular you'd suggest about it?

Eddy Baccouche Georgia

7/8/2010 4:05:36 AM #

Ema Glisson

I should in fact be working

Ema Glisson Serbia

7/9/2010 12:14:20 AM #

vampire

Trubloods.com is genuinely the site specializing in bringing you all the goodness and also night in the hit show True Blood. True Blood is actually called given that the artificial bloodstream that the western have got created and now vampires regarding the actual underworld come out in the darkness to be able to try and coexist with humans. An individual follow Sookie Stackhouse since the actual lady bargains with the actual disarray which will be out there on the world. There is romance, comedy, action, and also several much additional when you watch vampires, humans and also supernaturals clash in the town regarding Bon Temperatures, Louisiana. View free of charge of cost channels with trubloods.com!

vampire Hong Kong S.A.R.

7/9/2010 8:50:52 AM #

Tommy Kim

Well, this is my first visit to your blog! We're a group of volunteers and beginning a brand new initiative in a community within the exact same specialized niche. Your weblog supplied us valuable information to operate on. You've done a marvellous work!

Tommy Kim United States

7/9/2010 5:38:33 PM #

Deb Callarman

Deb Callarman Kazakhstan

7/11/2010 2:25:07 PM #

setting up salon

I had a site like this once, but it attracted so many spam comments I had to shut it. You appear to have a better spam filter! Kudos!

setting up salon United States

7/12/2010 11:34:50 PM #

Freeman Hepp

Awesome! Not clear for me, how frequently you�d updating your site?

Freeman Hepp Faroe Islands

7/13/2010 7:47:27 AM #

Audrie Mckin

Just wanted to grant you a shout from the valley of the sun, great information. Much appreciated.

Audrie Mckin Croatia

7/13/2010 11:29:57 AM #

chanel



top notch seller, great buying experience, beautiful item, quick shipping|dexterlab1

very nice product and fast shipping too!|jokershill

Excellent seller as usual. Thank you ver

chanel Maldives

7/16/2010 4:47:06 PM #

Eye Makeup Remover

My partner and i treasured this kind of submit so much We have added in the item to help my own book marks and subsribed on your Rss, fantastic job!

Eye Makeup Remover United States

7/16/2010 7:40:04 PM #

3d computer

Preserve 'em heading... every person carry out this kind of an admirable job with like Thoughts... cannot let you know simply how much When i, first value most of you need to do!

3d computer United States

7/28/2010 10:25:20 AM #

Michael Stanton

Certainly agree with what you explained. Your explanation was certainly the easiest to understand. I tell you, I usually get irked when folks focus on issues that they plainly do not know about. You managed to hit the nail right on the head and explained out everything without having complication. Perhaps, people can consider a signal. Will most likely be back to get more. Many thanks

Michael Stanton United States

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading



Creative Commons License
This work is licensed under a Creative Commons Attribution-Share Alike 2.5 Sweden License.


Welcome to the Dropit blog!

Here we, the people that work at Dropit, will write about stuff that interests us. For example web development, especially with .NET and EPiServer - but we'll also talk about other techniques that interest us, marketing on the web, social phenomenons, pop culture, games and software development in general.