<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6935909766549467205</id><updated>2024-09-19T14:58:21.327+01:00</updated><category term="Development"/><category term=".Net"/><category term="Blog / General / Personal"/><category term="Visual Studio"/><category term="T-SQL"/><category term="Code generation"/><category term="Contracting"/><category term="MVC"/><category term="SQL Server"/><category term="TDD"/><category term="Unit Testing"/><category term="360"/><category term="AutoMapper"/><category term="JQuery"/><category term="Mocking"/><category term="Moq"/><category term="SSIS"/><category term="Unity3D"/><category term="gaming"/><category term="nTier"/><category term="Cryptography"/><category term="Encryption"/><category term="Entity Framework"/><category term="GAC"/><category term="GDPR"/><category term="Hashing"/><category term="NAS"/><category term="PBKDF2"/><category term="SHA"/><category term="SSDT"/><category term="SSL"/><category term="Security"/><category term="SourceControl"/><category term="WebMatrix"/><category term="Windows"/><category term="async"/><category term="fitness"/><category term="git"/><category term="health"/><category term="nutrition"/><category term="weight loss"/><title type='text'>Spikeh&#39;d</title><subtitle type='html'>Mercenary programmer</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.shadowmoses.co.uk/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>39</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-2741382107484589749</id><published>2018-03-19T17:39:00.004+00:00</published><updated>2018-03-21T09:57:33.100+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="Cryptography"/><category scheme="http://www.blogger.com/atom/ns#" term="Encryption"/><category scheme="http://www.blogger.com/atom/ns#" term="GDPR"/><category scheme="http://www.blogger.com/atom/ns#" term="Hashing"/><category scheme="http://www.blogger.com/atom/ns#" term="PBKDF2"/><category scheme="http://www.blogger.com/atom/ns#" term="Security"/><category scheme="http://www.blogger.com/atom/ns#" term="SHA"/><title type='text'>GDPR: Application Password Security in 2018</title><content type='html'>&lt;b&gt;Security Primer&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
As we hurtle towards GDPR, more and more of my clients are becoming concerned with data security. This is great news - I&#39;ve always recommended best practices but come up against resistance occasionally due to the extra amount of time some implementations take - after all, time is money, and to some clients money is more important than security. Thankfully we&#39;re all now being forced to consider it more seriously.&lt;br /&gt;
&lt;br /&gt;
I&#39;m no security or cryptographic expert but as part of my job I have to provide secure authentication and storage systems to protect my client&#39;s data. As I&#39;m a Microsoft stack guy this is often dealt with by an Active Directory or Federated Identity Server - but on occasion I need to &quot;roll my own&quot; authentication system or heavily modify an existing one.&lt;br /&gt;
&lt;br /&gt;
One client recently asked me about the password hashing I&#39;d put in place for them - I&#39;d implemented SHA-256 with salting, using the same piece of code for about a decade. Its fast, relatively light weight and portable - but unbeknownst to me (until now), is no longer recommended or appropriate for hashing passwords. The client wanted me to implement PBKDF2 as they&#39;d heard it was more secure.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Hashing vs Encryption&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Security novices often confuse hashing and encryption. They are both cryptographic concepts but that&#39;s where the similarities end; in simple terms, hashing is a one-way operation that takes some data, makes a right old mess of it (&quot;a hash&quot;), and stores it somewhere for future reference. The aim of &quot;hashing&quot; is to make that data unreadable by humans and computers even when they know how it was originally created. The output hash aims to be impossible to reverse engineer, but computationally exact given the same input.&lt;br /&gt;
&lt;br /&gt;
Encryption on the other hand, is a two-way operation. Data can be encrypted, then decrypted back to its original format at a later date using a global key - anyone who knows what encryption algorithm was used and has access to the key can read the data. It&#39;s usually very fast and can be used for securing large amounts of data (such as data on your hard disk). Its also useful for sending sensitive data across boundaries - for example, sending a the contents of a web page to a client web browser via TLS/SSL, or sending a secure email message.&lt;br /&gt;
&lt;br /&gt;
There are multiple types of hashing and encryption algorithms - you&#39;ve probably heard of MD5 and SHA - two of the most widely used. AES and PGP are popular encryption algorithms, but there are dozens that have been developed by different bodies and individuals over the years. Its worth noting that the vast majority of these algorithms are RFCs or open-source, so anyone with a bit of maths knowledge could theoretically figure out how they work and use them in their software. Most languages and frameworks have their own implementations that are well tested - therefore &lt;i&gt;rolling your own algorithm implementation is not advised&lt;/i&gt;; someone more experienced has already done that work for you, so you should use their libraries and focus on your business logic.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Security Never Changes&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
There are people out there that want your data for one reason or another. No, you&#39;re not special or unique - you&#39;re just part of a numbers game. Malicious users might gain access to a database where your password is stored in plain text, then use that same password to &lt;i&gt;legitimately&lt;/i&gt; log on to your bank account - if you used the same password of course. They might simply be after a list of email addresses that they can sell to spammers - either way, that line of data in a database is worth something to someone, somewhere.&lt;br /&gt;
&lt;br /&gt;
Computers are getting faster and attackers are always finding new ways to break cryptographic algorithms. MD5 used to be considered the most secure hashing function, but it was severely compromised in 2013, and it now takes less than one second to crack a MD5 hash on a standard home computer. The same is true for SHA-0 and SHA-1 - both compromised. Even SHA-2 (which comprises of SHA-256 and SHA-512) is considered to have some weaknesses. Tools are getting easier to use - even amateurs are able to get access to cryptographic toolkits that do all the complex maths for them.&lt;br /&gt;
&lt;br /&gt;
Security experts and developers are therefore constantly trying to stay ahead of threats. Let&#39;s look at a few security breach scenarios and discuss which method is best to secure the data.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Scenario: Brute force attack against your api / application / login form&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
An attacker has set up an automated script or botnet that generates passwords and tries to log in to your online system. Depending on how the attack script is throttled, it may appear to to be a DDoS attack.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Mitigation&lt;/b&gt;: No amount of encryption or hashing will help here. You should implement hardware traffic management / monitoring and some kind of application level account lockout procedure - i.e. 3 incorrect passwords and the user can no longer log in.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Scenario: Attacker gains raw access to your database&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
An attacker has breached your server / network and has taken a copy of the database files stored there. This usually indicates that there are other major security flaws in your system that should be sorted out as soon as possible. However, it&#39;s happened - so how can you make sure that the hacker can&#39;t read the database?&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Mitigation&lt;/b&gt;: Most modern databases can be encrypted using an integrated feature / tool; it&#39;s usually a relatively simple task, and should be a priority. It requires a little bit of overhead and a little bit more development work, but it&#39;s always worth it.&lt;br /&gt;
&lt;br /&gt;
If the database isn&#39;t encrypted, or the attacker also has access to the encryption key, then they can read all plain text data in the database. This is where password hashing comes in - although the attacker now has access to all of the data in your database, you can still make it difficult for them to figure out what each user&#39;s password is by using a hashing algorithm such as MD5, SHA, bcrypt, scrypt or PBKDF2.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Sub-Scenario: The Dictionary / Rainbow Table Attack&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
So, you&#39;ve hashed the heck out of your user&#39;s passwords - now what? Well, there&#39;s still a vulnerability you may not be aware of; attackers who gain raw access to your database can use a &lt;i&gt;dictionary attack&lt;/i&gt; or &lt;i&gt;rainbow table attack&lt;/i&gt;&amp;nbsp;in order to crack a password or ascertain your global hash key or passphrase.&lt;br /&gt;
&lt;br /&gt;
In simple terms, this works by using a pre-compiled list of words / phrases (&lt;i&gt;a dictionary&lt;/i&gt;) or hashes (in a &lt;i&gt;rainbow table&lt;/i&gt;) to search for common passwords in your database. The larger your database, the greater the likelihood of more than one user using the same password. If two users use the password &quot;password&quot;, it will be hashed into exactly the same string - and attackers know how to reverse engineer these patterns into passwords or hashes.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Mitigation:&lt;/b&gt; You can control the passwords your users use to some extent using application level rules, though less security conscious people will try to use the simplest password possible, or simply increment a number at the end of their existing password when the system asks them for a new one. Whilst you can protect against people using &quot;12345&quot; and &quot;password&quot; with pattern matching, you still can&#39;t protect against people using &quot;P@ssword1&quot; (which would satisfy even the most annoying of password rules).&lt;br /&gt;
&lt;br /&gt;
So what do we do? We &lt;i&gt;salt&lt;/i&gt; the hash. A salt is a cryptographically safe string of a certain length, unique to each user. This string is concatenated with the plain text password before hashing takes place - its randomly generated, then stored alongside the hashed password. Its visible to anyone with access to the raw data - even attackers that manage to get their hands on your database.&lt;br /&gt;
&lt;br /&gt;
It sounds mad - why does a salt help if the attacker can see it? Well, because the added salt generates a unique hash for each user&#39;s password - even when two users use the exact same password. Every password essentially now has its own key, making the pre-compiled dictionary or rainbow table attack infeasible as a new table will need to be generated for every user. Consider the following pseudocode:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;var user1Password = &quot;password&quot;;&lt;br /&gt;
var user2Password = &quot;password&quot;;&lt;br /&gt;
var user1Hash = Hash(user1Password);&lt;br /&gt;
var user2Hash = Hash(user2Password);&lt;br /&gt;
&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;
user1Hash and user2Hash will output exactly the same value - which creates a predictable pattern that can be exploited.&lt;br /&gt;
&lt;br /&gt;
Now consider this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;
var user1Password = &quot;password&quot;;&lt;br /&gt;
var user2Password = &quot;password&quot;;&lt;br /&gt;
var user1Hash = Hash(user1Password + GenerateSalt());&lt;br /&gt;
var user2Hash = Hash(user2Password&amp;nbsp;+ GenerateSalt());&lt;br /&gt;
&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;
GenerateSalt() returns a random string. user1Hash and user2Hash are unique, even though the passwords are the same, reducing the overall risk. As long as the output of GenerateSalt() is stored alongside the hash, you can validate that any future input matches the original hash value.&lt;br /&gt;
&lt;br /&gt;
There are some recommendations that a salt should be globally unique, but I don&#39;t subscribe to this thinking. Yes, a user might use the same password on your website as another website, but the likelihood that you&#39;re going to generate exactly the same salt as the other application is extremely thin. I believe this advice exists to discourage developers from using predictable data such as username, email addresses or other unique identifiers that the user has control over. My advice is to make sure that you use any framework provided salt generation methods, and ensure you use the recommended minimum salt length.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Sub-Scenario: Using PBKDF2 instead of SHA for password hashing&lt;/b&gt;&lt;/div&gt;
&lt;br /&gt;
Why did my client ask me to strip out SHA-256 and replace it with PBKDF2? SHA-256 is secure enough, right? Well, yes - generally SHA-2 is still considered secure, and the salting I put in place makes it even more so. However, attackers are now using the extreme processing power of GPUs (graphics cards with thousands of cores, processing hundreds of millions - possibly billions - of operations per second) rather than CPUs (standard computer processors with dozens of cores, processing millions of operations per second), which makes password cracking a much quicker affair.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://security.stackexchange.com/questions/32816/why-are-gpus-so-good-at-cracking-passwords&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;This post&lt;/a&gt; on StackOverflow gives some 2009 figures for older CPUs / GPUs - 48 million vs 160 million ops per second respectively, so - applying Moore&#39;s Law - you&amp;nbsp;can imagine how much more powerful GPUs are in 2018.&lt;br /&gt;
&lt;br /&gt;
The basic decision points come down to this:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;SHA is designed to be as fast as possible, and will only get faster as processors increase in speed.&lt;/li&gt;
&lt;li&gt;PBKDF2 stands for&amp;nbsp;&lt;i&gt;Password-Based Key Derivation Function 2&lt;/i&gt;, and as the name suggests, it was specifically designed for password hashing. It is &lt;i&gt;slow by design&lt;/i&gt; and&amp;nbsp;iterates X times over a pseudo-random function such as SHA-1 or HMAC to create a derived key.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
The one drawback to using PBKDF2 is that you have to review the number of iterations used to generate passwords often. As hardware improves you&#39;ll have to increase these iterations to continue to keep up with the attackers - I expect that high-end password cracking rigs exist with similar specs to the popular high-end bitcoin mining rigs, as they perform very similar functions. The more GPU power available, the quicker an attacker can succeed in performing a brute force attack.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
It seems that brute force is still the preferred vector for password cracking - attackers are leveraging better hardware to perform more operations per second, decreasing the time it takes for a password to be cracked.&lt;br /&gt;
&lt;br /&gt;
There are now more suitable password algorithms available - Argon2 deserves a special mention, though it&#39;s still relatively new (2015) and not quite as trusted as PBKDF2.&lt;br /&gt;
&lt;br /&gt;
Of course this blog post is not exhaustive. There are many more steps you can take towards application and network security. Drop me a line if you require any advice on securing your applications or network.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Disclaimer&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
This blog post aims to provide advice only - I am not a security expert, though I have much more experience in application and network security than I do with implementing and understanding the minutiae surrounding cryptographic functions. Please let me know if you notice any mistakes and I&#39;ll update this post ASAP.&lt;br /&gt;
&lt;br /&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/2741382107484589749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/2741382107484589749'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2018/03/gdpr-application-password-security-in.html' title='GDPR: Application Password Security in 2018'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-8517495428979106409</id><published>2017-08-16T16:12:00.004+01:00</published><updated>2017-08-18T09:34:30.921+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fitness"/><category scheme="http://www.blogger.com/atom/ns#" term="health"/><category scheme="http://www.blogger.com/atom/ns#" term="nutrition"/><category scheme="http://www.blogger.com/atom/ns#" term="weight loss"/><title type='text'>How I Learned to Lose Weight and Love Exercise (again)</title><content type='html'>Back in my youth I was an avid gym-goer, badminton and basketball player, utility cyclist and swimmer. I did all this because I enjoyed it / life necessitated it, and I never once thought about my weight or fitness levels - though I did care about how I &lt;i&gt;looked&lt;/i&gt;. Everything stopped when I moved to a new town and made new friends; I took up music as a hobby and sport fell by the wayside. Lugging 250lb of bass gear up and down 3 flights of stairs every week felt like enough to me - alas, the lack of exercise over a period of about 10 years (combined with my love of all forms of food and drink) resulted in me gaining a considerable amount of weight without me really noticing it.&lt;br /&gt;
&lt;br /&gt;
About a year and a half ago, I &lt;i&gt;did&lt;/i&gt;&amp;nbsp;notice it. I started hating pictures of myself, I was struggling to live everyday life without sweating constantly and getting out of breath doing menial tasks. Walking 2 miles into town was a huge amount of effort, and even sleeping was difficult (for both myself and my wife) due to my snoring. I decided to do something about it - inspired by a few friends who recently lost a ton of weight, and my wife who was already on her own weight loss journey, I set my mind on shedding the pounds and getting fit again.&lt;br /&gt;
&lt;br /&gt;
I jumped on the scales for the first time in years... 298lb! That&#39;s just over 21 stone, to my UK brethren. I didn&#39;t think much of it at first as I&#39;ve always been a &quot;big lad&quot;; in my twenties I was 16 stone with around 10% body fat - but I was at the gym 4 hours a night and took part in many different sporting activities. Looking back, I was very, very fit, without really knowing it.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDELuse86bUY-ZJ_JSzpVY8pqQNUlDZfHuBQtK7LJA-Na2VuVRyAhf9-_32_2kDiEz8MYrnHaQEoKSkVKKU50qBp77MDk9IyB-ULp89eUnSfZ4MDWZgPz-WnphyOTKXNR-7MHr_PVWO8c/s1600/I_need_your_clothes%252C_your_boots%252C_and_your_motorcycle.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;356&quot; data-original-width=&quot;277&quot; height=&quot;200&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDELuse86bUY-ZJ_JSzpVY8pqQNUlDZfHuBQtK7LJA-Na2VuVRyAhf9-_32_2kDiEz8MYrnHaQEoKSkVKKU50qBp77MDk9IyB-ULp89eUnSfZ4MDWZgPz-WnphyOTKXNR-7MHr_PVWO8c/s200/I_need_your_clothes%252C_your_boots%252C_and_your_motorcycle.jpg&quot; width=&quot;155&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Not pictured; modesty&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
That day I had a bacon butty for breakfast, followed by a mid-morning can of coke and a Mars bar. For lunch, I would have had a massive butty from a shop in whatever city I was working in at the time, a bag of crisps, a cake, another can of coke, followed by a massive afternoon tea of frozen beige food (regularly I&#39;d have a chicken kiev, chicken nuggets, breaded fish AND oven chips in one meal), or even a takeaway. I&#39;d have takeaways at least 2 times a week.&lt;br /&gt;
&lt;br /&gt;
I was bought up on a truly awful diet (even worse than the above), and knew literally nothing about nutrition. Looking back, I&#39;m not in the slightest surprised about my weight gain - but it just goes to show that it really can creep up on you if you don&#39;t treat your health and fitness as a priority.&lt;br /&gt;
&lt;br /&gt;
This was back in March 2016. It took me a few weeks to really start taking my weight loss seriously - on 7th April I got on my old mountain bike and did a 2 mile loop of my local park with an average speed of 10.9mph.&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe allowtransparency=&quot;true&quot; frameborder=&quot;0&quot; height=&quot;405&quot; scrolling=&quot;no&quot; src=&quot;https://www.strava.com/activities/538066265/embed/5aa351f35c6a35b572cae49062a4e2b3e1a0260b&quot; width=&quot;590&quot;&gt;&lt;/iframe&gt;

&lt;/div&gt;
&lt;br /&gt;
I was absolutely exhausted, but I knew I needed to do exercise as part of my new regime. That&#39;s all I knew, though - my diet remained the same (i.e. I ate anything I wanted)... if anything, it got worse because I thought I needed more food to compensate for the pitiful amount of exercise I was doing.&lt;br /&gt;
&lt;br /&gt;
A few weeks later I&#39;d improved marginally, but was doing the same route every morning. I started varying things up, adding a mile here and there. I distinctly remember going from my 2 - 4 mile morning ride to attempting a 10 mile ride. Off I went, breaking a number of &quot;personal bests&quot; in the process. Halfway up a &quot;hill&quot; I just couldn&#39;t go any further, so I turned back and only managed 8.9 miles.&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe allowtransparency=&quot;true&quot; frameborder=&quot;0&quot; height=&quot;405&quot; scrolling=&quot;no&quot; src=&quot;https://www.strava.com/activities/573743664/embed/081db95a717b2e7477815cda45c44fb311cf96e8&quot; width=&quot;590&quot;&gt;&lt;/iframe&gt;

&lt;/div&gt;
&lt;br /&gt;
I bought a new bike in early June 2016 - a BMC hybrid, which I loved to bits. It was light(er), and was much nicer to ride than my old two-ton MTB.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnxbmLFH8OfFdluGeIojGbThhpSdMrHbIT4PdCJcVs00f90sb5PNle-hNmFPKoM4dp9_-4-KpJ569zlrr8KyZQZX_N4EdPFb-w-EjRyUZgCL8W_rdjWReNe5GLfw-0GPOFaRisNCFWBL4/s1600/BMC.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;900&quot; data-original-width=&quot;1600&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnxbmLFH8OfFdluGeIojGbThhpSdMrHbIT4PdCJcVs00f90sb5PNle-hNmFPKoM4dp9_-4-KpJ569zlrr8KyZQZX_N4EdPFb-w-EjRyUZgCL8W_rdjWReNe5GLfw-0GPOFaRisNCFWBL4/s320/BMC.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
N+1&lt;/div&gt;
I used this to do my first &quot;big&quot; ride on 16th June, about 20 miles around the local lanes.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe allowtransparency=&quot;true&quot; frameborder=&quot;0&quot; height=&quot;405&quot; scrolling=&quot;no&quot; src=&quot;https://www.strava.com/activities/611208612/embed/1f99e70d6d54f8a9b9825befe6c39b0fb3361674&quot; width=&quot;590&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;br /&gt;
Then Pokemon Go came out. My rides suddenly became less about speed, distance and effort, and more about Catching &#39;em All. Thankfully that didn&#39;t last too long, and shortly after I decided to try riding my bike in a group - I tagged along with &lt;a href=&quot;http://www.blackpoolclarion.webs.com/&quot; target=&quot;_blank&quot;&gt;Blackpool Clarion Cycling Club&lt;/a&gt; (BCCC) for a few rides before joining the club properly a few weeks later.&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe allowtransparency=&quot;true&quot; frameborder=&quot;0&quot; height=&quot;405&quot; scrolling=&quot;no&quot; src=&quot;https://www.strava.com/activities/713579435/embed/5c264d4cc8e9ff181b4891c1737826d19955ade8&quot; width=&quot;590&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
My ability improved and I eventually splashed out on a mid-range (though still rather expensive) Giant Defy Advanced Pro.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH8DMSRctHTw_Zmc205-5UOPpn54rTDyUbcXTQ7HSdEO5z7E8lyj2ftDKSN2JnMx8XXw1fl5YVpu4RVfAKpaCPHAzeT6zD9agXZyIzMB6JUiXpplwyskJExd95fUq-ASZXMSS3S7iXZUE/s1600/15171105_10154809762430353_3794843279667785953_n.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;540&quot; data-original-width=&quot;960&quot; height=&quot;225&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH8DMSRctHTw_Zmc205-5UOPpn54rTDyUbcXTQ7HSdEO5z7E8lyj2ftDKSN2JnMx8XXw1fl5YVpu4RVfAKpaCPHAzeT6zD9agXZyIzMB6JUiXpplwyskJExd95fUq-ASZXMSS3S7iXZUE/s400/15171105_10154809762430353_3794843279667785953_n.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;I love two things in this picture&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
However, the weekend I ordered it I managed to come off my BMC hybrid during a club ride and break my right elbow!&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe allowtransparency=&quot;true&quot; frameborder=&quot;0&quot; height=&quot;405&quot; scrolling=&quot;no&quot; src=&quot;https://www.strava.com/activities/739548728/embed/361997b4b72d8c4e82e38ccc98fa1b8b47853de7&quot; width=&quot;590&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
This set my weight loss and exercise regime back a little bit, but luckily it didn&#39;t destroy my motivation. In fact, I was so into biking at this point that I just couldn&#39;t wait to get back on the bike, and bought a second hand turbo trainer to try and keep my fitness up. Turns out turbos aren&#39;t for me, but at least it kept me going for a few weeks. I recovered pretty well, though I still have issues with it today.&lt;br /&gt;
&lt;br /&gt;
Suffice to say, I am now regularly doing 40 - 100 mile bike rides on my own, with BCCC and various other cycling groups and friends I&#39;ve made along the way. The &quot;hills&quot; that I was initially struggling on don&#39;t even register on my radar any longer, though there are of course still some very difficult undulations out there. I now seek out steep hills, as most cyclists of-a-certain-level-of-fitness do.&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe allowtransparency=&quot;true&quot; frameborder=&quot;0&quot; height=&quot;405&quot; scrolling=&quot;no&quot; src=&quot;https://www.strava.com/activities/975556760/embed/9f6d099a6bd37a4e9eaf6a5335891dfaba4e3c37&quot; width=&quot;590&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
This posts isn&#39;t meant to be about cycling, it&#39;s just become a real passion of mine over the last year. Exercise is important for your cardiovascular system and as part of a weight loss routine, but you &lt;i&gt;can&lt;/i&gt; lose a significant amount of weight without it. I&#39;ve come to really enjoy exercise again - I now try to do something every day, whether it&#39;s 30 minutes of interval training in the pool, a high speed / intensity Time Trial, or a 5 hour leisurely bike ride.&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;br /&gt;
In June 2016 I started writing my weight down in a notebook. Weigh-ins were sporadic and&lt;br /&gt;
infrequent, and I wasn&#39;t really making that much progress (especially considering what I know now).&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Wed, 1 Jun 2016 - 290.1 Pounds&lt;br /&gt;
Sun, 12 Jun 2016 - 287.0 Pounds&lt;br /&gt;
Sat, 9 Jul 2016 - 282.8 Pounds&lt;br /&gt;
Sat, 30 Jul 2016 - 283.2 Pounds&lt;/blockquote&gt;
My notebook entries continued until 2nd Jan 2017, when I started to use an app called &quot;My Fitness Pal&quot; (MFP) to log my weight instead. The choice of app was largely due to its integration with my new Garmin 820 bike computer, but logging weight was still a manual process. At the same time I also started logging my food and drink intake via MFP... and I logged &lt;i&gt;everything;&lt;/i&gt;&amp;nbsp;from a single gram of added salt, to the nuts and seeds I sprinkled on my breakfast on a morning. This lead me to buy some new kitchen scales accurate to 0.1 of a gram, and on March 8th I bought some Garmin scales which (after writing some rather dissatisfied emails to both Garmin and UnderArmor (the company behind MFP)) automatically synchronised my weight and other biometric data (bone mass, body water, body fat, BMI etc) to my Garmin Connect account, and subsequently MFP. This made the laborious task of logging my progress in all my apps a thing of the past.&lt;br /&gt;
&lt;br /&gt;
I was already recording my exercise activity and seeing some mild gains, but this is when my weight loss journey got serious. The beauty of these kind of apps is that they have a huge database of user-managed consumables listing calories and micro-nutrients; you can use your smart phone to scan product barcodes to make logging food easier. It&#39;s not 100% accurate - and at first I entered everything manually as I didn&#39;t trust the database - but as I learned more about the foods I was eating, the less important it was to log my exact calorie intake; I used it as more of a general guide to make sure that I wasn&#39;t over-eating for my lifestyle. I work at home and am quite sedentary most of the day, so my calorie intake should be less than that of a plumber or roofer who&#39;s active all day - and it&#39;s worth noting that your calorie intake needs to be regularly reviewed based on your current weight, lifestyle and exercise regime in order to keep losing weight whilst remaining healthy. I started on 1,800 calories a day, but reduced it to 1,500 once I hit a plateau and stopped losing weight. MFP helps with this, but you can override all settings with custom values if you so wish.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl_ZXwBQ8hXYoVgbhuH52TVgnaawv5tf75thVTEL05FiV9cUcJmeltwZvUoN3T41cfKXxoxd3-tzwJWVFIExIcMIOtPl59De_xqmxGMpPD1vGxaVwQr6SNRPy0XNCMdgRROphlDpGUFF8/s1600/MFP.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1067&quot; data-original-width=&quot;741&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl_ZXwBQ8hXYoVgbhuH52TVgnaawv5tf75thVTEL05FiV9cUcJmeltwZvUoN3T41cfKXxoxd3-tzwJWVFIExIcMIOtPl59De_xqmxGMpPD1vGxaVwQr6SNRPy0XNCMdgRROphlDpGUFF8/s320/MFP.png&quot; width=&quot;222&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;I&#39;m more familiar with this screen than I am with CSS3&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
This might all seem a bit too much for some of you. I am a detail oriented person - if I do something, I do it fully and completely to the very best of my abilities - a principal I apply to both my personal and professional lives. You might not need to log as much detail as I have, but it helped me greatly and my weight loss improved massively once I started doing it. I&#39;ve been using MFP now constantly for 212 days straight... I&#39;m not sure how to stop at this point!&lt;br /&gt;
&lt;br /&gt;
Once I figured out that diet is much, much more important than exercise when it comes to weight loss (and maintaining weight), I started making some significant progress - I cut out refined carbs such as white rice, white bread and white pasta (replacing with brown equivalents), almost entirely excluded carbonated drinks and fruit juices, cut down on added sugar and salt significantly, and stopped snacking (I still occasionally have a cheeky chocolate bar, though). Some people need to make sure they don&#39;t have any temptations in the house; we still have a sweetie cupboard, but we also have the willpower to only treat ourselves when we deserve it (after a week of decent weight loss, on a birthday or other special occasion, or on cheat day). Learning about nutrition and how food is processed by my body is the number one offence &lt;i&gt;and &lt;/i&gt;defense I have against obesity - and I really can&#39;t see me back-sliding now.&lt;br /&gt;
&lt;br /&gt;
At some point I set an initial weight goal of 200lb - that would take me down to around 14 stone, which is right at the top end of the &quot;healthy&quot; part of my BMI scale. You shouldn&#39;t fuss too much about BMI though, as it doesn&#39;t take into consideration people who are muscular, have particularly dense bones, or have extremely low body fat such as elite athletes. It&#39;s still a good guide, and unfortunately the NHS and health insurance companies rely on this metric quite heavily for determining your health status.&lt;br /&gt;
&lt;br /&gt;
So this brings us to the present day. The reason for this blog post is that as of 15th August 2017 I finally hit my goal! I woke up to my fancy Garmin scales showing this:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5m-izVN_YvZoAjbrLEOpoMEhEVVzWxRgCuZs7GfRXayZtVkXq3zywmhGr6CwEIf9bljvneTlhOF-tkO_4TAwjooBL9WatXcJNjZr5m6diYJgg_EUNFACqv9hJPRcLYS6Ju-Fj1w65m3Y/s1600/scales.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;900&quot; data-original-width=&quot;1600&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5m-izVN_YvZoAjbrLEOpoMEhEVVzWxRgCuZs7GfRXayZtVkXq3zywmhGr6CwEIf9bljvneTlhOF-tkO_4TAwjooBL9WatXcJNjZr5m6diYJgg_EUNFACqv9hJPRcLYS6Ju-Fj1w65m3Y/s320/scales.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
And whilst that&#39;s still a rather large number, be aware that I&#39;m 6&#39; 3&quot; and I have particularly long limbs, big hands and feet, and of course a weighty ego to match. The last 2 months have been the most difficult - I was 210lb on Jun 22nd 2017 and have been struggling to lose that last 10lb since then. Here&#39;s my weight loss graph from Garmin Connect:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFuUE8Heii5h2JYkhSCvTsDpKU5GT3ENmbyyLkz-Sgv1N_j5u7yCwy-10xChv7S4GfBDF9thy6rHXKUki7WauUoxKz3KdmOXmreCuzD8HYNosiuf7CrGsCdYi6cAOO6gPsq15ov4GzZmA/s1600/11_garmin_weight_12mnths.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1066&quot; data-original-width=&quot;1227&quot; height=&quot;278&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFuUE8Heii5h2JYkhSCvTsDpKU5GT3ENmbyyLkz-Sgv1N_j5u7yCwy-10xChv7S4GfBDF9thy6rHXKUki7WauUoxKz3KdmOXmreCuzD8HYNosiuf7CrGsCdYi6cAOO6gPsq15ov4GzZmA/s320/11_garmin_weight_12mnths.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I&#39;ve now upped my calorie intake to 1,900 calories a day so I can continue to lose weight, but at a slower rate - I&#39;m aiming for 1 lb per week, but it already looks like I&#39;m exceeding that.&lt;br /&gt;
&lt;br /&gt;
Here are my weight loss stats. They&#39;re not 100% accurate as I didn&#39;t really log anything at the start, but they give you a good idea:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Weight started at 298lb between April - June 2016. I&#39;m now 198lb (21.3 -&amp;gt; 14.3 stone). Total loss is 100lb or 7 stone in ~471 days.&lt;/li&gt;
&lt;li&gt;Body fat is down to 19.9%. First recording was 31.6% when I was 252lb on March 8th 2017, the day I got my Garmin scales. I would imagine that I was closer to 40% when I started. That&#39;s about 20% body fat lost.&lt;/li&gt;
&lt;li&gt;BMI started at 37.3 (critically obese), now 25 (healthy weight)&lt;/li&gt;
&lt;li&gt;Waist started at 48&quot;, now 37&quot; (11&quot; loss)&lt;/li&gt;
&lt;li&gt;Chest started at 55&quot;, now 42&quot; (14&quot; loss)&lt;/li&gt;
&lt;li&gt;Bicep started at 16&quot;, now 13&quot; (3&quot; loss)&lt;/li&gt;
&lt;/ul&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0a6UVsU6DdVjPl1ZbUNmOVtXKDhCrV21Cz7tv0mQXCsVzZrQBJVFZpx7WqI4DNZpAD_-njt4pMHl4XxG0ZqdeyvF7iZbDe7NTQzE5gfYRkin65UW8zQ2nLlw7pmgNukQMo_ddsox5Zv0/s1600/7_nhs_BMI_1_before.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;294&quot; data-original-width=&quot;579&quot; height=&quot;162&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0a6UVsU6DdVjPl1ZbUNmOVtXKDhCrV21Cz7tv0mQXCsVzZrQBJVFZpx7WqI4DNZpAD_-njt4pMHl4XxG0ZqdeyvF7iZbDe7NTQzE5gfYRkin65UW8zQ2nLlw7pmgNukQMo_ddsox5Zv0/s320/7_nhs_BMI_1_before.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;BMI Before&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQqVMxgkzSeAzC_AYos2uROx2LGtT_PzZEsmTJ6zEieRjlTereSJCt0jaY9zO3tOaCyTCKdkJ0mPQMvHPS8GJBUhNS2J9DmzgO-2xjRfVW7KE-y16Pzy0azmUJPg9EIb7ME-wSoqOgdII/s1600/8_nhs_BMI_2_after.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;283&quot; data-original-width=&quot;577&quot; height=&quot;156&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQqVMxgkzSeAzC_AYos2uROx2LGtT_PzZEsmTJ6zEieRjlTereSJCt0jaY9zO3tOaCyTCKdkJ0mPQMvHPS8GJBUhNS2J9DmzgO-2xjRfVW7KE-y16Pzy0azmUJPg9EIb7ME-wSoqOgdII/s320/8_nhs_BMI_2_after.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;BMI After&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
Some of this loss will be muscle - I&#39;ve not really done much exercise other than cycling, so my legs are like tree-trunks but my torso is pretty weak in comparison to what it used to be back in my weight training days. I&#39;m trying to mitigate that at the moment by eating lots of protein, doing more intense swimming, and I&#39;m planning to do some light weight / resistance training - though I will never become a gym bunny again - those days are well behind me.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here are some before and after pics (apologies if this puts you off your food ;)):&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPEM8yWVMKXjGhPGUTps3m3aBl_eTLfNplZU60B2FwHXnFN7eWbk20jIuB1cbFToVKVSPJWmbjEa9ks_fGO7zRKd4UrteUFAN5Rs3hv9LePmIyzXOMvAqidtJe0ETkWAz-4ozlDea9Gvg/s1600/3_before_after.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1099&quot; data-original-width=&quot;1008&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPEM8yWVMKXjGhPGUTps3m3aBl_eTLfNplZU60B2FwHXnFN7eWbk20jIuB1cbFToVKVSPJWmbjEa9ks_fGO7zRKd4UrteUFAN5Rs3hv9LePmIyzXOMvAqidtJe0ETkWAz-4ozlDea9Gvg/s320/3_before_after.jpg&quot; width=&quot;293&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil9s_15AZ2WTnCmYH1LU9t_9gLhulYN2BpGeUG61w_s7ZD6AeGWMM5LtofxTJTMBoT7Qlp9mY-wF-Dv4pkptF3K-DdqhYO-i0M7R9t6yKHvYyRqoJMwpviJcyYTgi9bvyeMhPq9wKPJu0/s1600/1_before_after.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1099&quot; data-original-width=&quot;1008&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil9s_15AZ2WTnCmYH1LU9t_9gLhulYN2BpGeUG61w_s7ZD6AeGWMM5LtofxTJTMBoT7Qlp9mY-wF-Dv4pkptF3K-DdqhYO-i0M7R9t6yKHvYyRqoJMwpviJcyYTgi9bvyeMhPq9wKPJu0/s320/1_before_after.jpg&quot; width=&quot;293&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-pEgMsUQzN7GXIMqSRZlZPLT_0HXnzXUBff7Qg7D9YaiJZlbLjGyrA_K9MR9P3aqd50uh83iModoA1nnwWC3SbSe6PDpL7V8ephiYOatbvMWkb3V_RYELQJKsoVy7gsZyhuQdEWcJcdA/s1600/2_before_after.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1099&quot; data-original-width=&quot;1008&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-pEgMsUQzN7GXIMqSRZlZPLT_0HXnzXUBff7Qg7D9YaiJZlbLjGyrA_K9MR9P3aqd50uh83iModoA1nnwWC3SbSe6PDpL7V8ephiYOatbvMWkb3V_RYELQJKsoVy7gsZyhuQdEWcJcdA/s320/2_before_after.jpg&quot; width=&quot;293&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Yeah, I&#39;m not perfect, but I&#39;m certainly a lot happier than I was. I also learned a hell of a lot about food, nutrition and the human body in the process. I&#39;m no nutritionist or personal trainer but here&#39;s some of the important points that will stay with me for the rest of my life:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Losing weight is easy; battling with your cravings and &quot;hunger&quot; is not&lt;/i&gt;&lt;/b&gt;. If you have low willpower then join a weight loss group or find some family members or friends that want to do it with you. Support is very important - I am a very strong willed person, but my wife losing weight at the same time as me made things so much easier.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;I am never hungry&lt;/i&gt;&lt;/b&gt;. Westerners generally don&#39;t know hunger, especially those that can afford to buy food. Those pangs you get are just cravings - ignore them or fail.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;A lot of patience is required&lt;/i&gt;&lt;/b&gt;. Unless you&#39;re 600lb your weight loss is going to be a gradual, drawn out process. It&#39;s a permanent lifestyle change that you must embrace rather than a quick fix / fad diet - which do absolutely nothing except line the pockets of the people that come up with them. There is no pill, no magic wand or words you can utter to make the process quicker. Don&#39;t be tempted to starve yourself, skip meals or do excessive amounts of exercise to lose weight faster. 2lb a week is enough, though if you do things right from the start you will lose much more than that initially. &lt;i&gt;Always&lt;/i&gt; keep in mind that you are aiming to lose 2lb a week - any more is a bonus but it is &lt;i&gt;not &lt;/i&gt;sustainable, and you&#39;re only going to be disappointed when you get to a point where you can no longer drop 8lb a week without much effort. Once you get your head around this lifestyle change, you&#39;ll never go back - there are many more benefits to weight loss than just looking better.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Learning about what you&#39;re eating is the single most important piece of advice I can give you&lt;/i&gt;&lt;/b&gt;. There are many things I learned during the process; a glass of orange juice contains just as much sugar as a can of coke, and consuming the same amount of sugar that&#39;s in a pint of orange juice in whole oranges would be extremely difficult, though it would still be better for you as the fibre in the whole orange helps with the digestion and absorption of the fruit&#39;s sugars. Knowing some general facts helps your food decision making process massively. Learn as much as you can about the foods you eat, and work to guidelines you set yourself.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Logging your calorie intake is frustrating, but invaluable&lt;/i&gt;&lt;/b&gt;. Once I figured out that diet was more important than exercise I logged every single thing that passed my lips using MFP - even water (though water serves a different purpose and is calorie free). A cup of tea with milk and two sugars comes in at around 70 calories. Without sugar it&#39;s about 55 calories (I weaned myself off sugar in my tea gradually and now I don&#39;t miss it). If you have 8 cups a day (like I used to) that&#39;s&amp;nbsp;560 calories - which is more than a third of your entire daily calorie limit.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Snacking is evil, especially unconscious snacking&lt;/i&gt;&lt;/b&gt;. I no longer snack during the day and limit my intake in the evening to one or two snacks at the most, &lt;i&gt;after &lt;/i&gt;my evening meal.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;It&#39;s OK to occasionally go over your calorie limit&lt;/i&gt;&lt;/b&gt;. However, doing it too much will undo all your hard work. Remember that your calorie intake during weight loss will depend directly on your sex, body type, job activity levels and the amount of exercise you do.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Sugar and refined carbs are the enemy, not fat&lt;/i&gt;&lt;/b&gt;. Regardless of what food manufacturers try to tell us. In fact some fats are good for you - but added sugar is very dangerous - it&#39;s just a shame it tastes awesome. Sugar comes in two main forms - fructose and glucose. Fructose is the stuff that tastes sweet and is unfortunately all but useless to our body. Glucose apparently has no taste and is our body&#39;s preferred energy source. Because of this, they are both processed differently by our bodies - if you don&#39;t need the sugar you&#39;re eating&amp;nbsp;(or carbs, for that matter, as they are converted into sugar by your body) it&#39;ll be converted straight to fat. Manufacturers add sugars to things like ready meals and pasta sauces in order to make them &quot;taste better&quot; and appeal to us more - avoid these like the plague. When you want to make a pasta dish and you use an off-the-shelf sauce, it contains much more sugar (and salt) than you need. Do you and your family a favour - get some tinned or fresh tomatoes, some fresh herbs and garlic and make your own sauce. It takes no time and in my opinion tastes better anyway. Read more about sugar&amp;nbsp;&lt;a href=&quot;http://healthyeating.sfgate.com/difference-between-sucrose-glucose-fructose-8704.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Hydration, hydration, hydration.&lt;/i&gt;&lt;/b&gt;&amp;nbsp;Try and drink 2.5 litres of water a day as standard. This not only keeps you hydrated, but helps to fill you up and reduce your cravings. When you&#39;re doing exercise drink a lot more water to replace what you lose through sweating - I don&#39;t measure my water intake any more, but I drink a lot more than I used to. Generally, if I&#39;m thirsty, I&#39;ll get a pint of filtered water. Funnily enough the more water your drink (within limits - drinking too much water can be dangerous) the less water your body retains. Not 100% on how this works, but it&#39;s good to know.&lt;/li&gt;
&lt;li&gt;&lt;b style=&quot;font-style: italic;&quot;&gt;Monitoring micro-nutrients can be helpful.&lt;/b&gt; If&amp;nbsp;you have bowel issues (my IBS has all but disappeared now), or want to lower or increase your intake of a certain nutrient. Apps like MFP will help you do that - so long as you do your research and don&#39;t just rely on what other users have entered into the database. I&#39;ve only really used this to reduce my salt and sugar intake (to reduce my risk of cardiovascular issues), but it&#39;s also good to know which foods are low or high in particular nutrients. I&#39;ve been inadvertently exceeding my recommended salt intake for years just because I didn&#39;t realise that the processed meats I was adding to my salads are extremely high in it.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Meal quality is critical&lt;/i&gt;&lt;/b&gt;. A full English breakfast is usually around 1,000 calories, but eating one means you can&#39;t eat much else for the rest of the day in order to continue to lose weight. Processed meats are also full of saturated fats and salt - too much of which are &lt;i&gt;really&lt;/i&gt; bad for your cardiovascular system. A big bowl rammed full of fresh fruit, Greek yogurt, seeds and nuts usually comes in at around 400 calories, but fills you up just as much and is infinitely better for you. If you don&#39;t like fruits and vegetables then you need to STFU and deal with it ;) I also learned that apps like MFP don&#39;t distinguish between fruit sugar and added sugar - meaning these days MFP often warns me that I&#39;ve exceed my sugar intake for the day just for breakfast. I generally ignore this because I know those sugars are being processed adequately by my body. I do still have a cooked breakfast once or twice a week, but tend to go for the smaller option at cafes, rather than the &quot;landscaper&#39;s Breakfast&quot; with 8 sausages and 46 black puddings.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Cheat&lt;/i&gt;&lt;/b&gt;. When you&#39;re on a 1,500 calorie diet for nearly a year and a half, you need a day off at least once a week. I generally also eat one or two &quot;naughty snacks&quot; a day but I&#39;ve still cut down on bad foods considerably.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Exercise is not absolutely necessary to lose weight, 95% of the effort is your diet&lt;/i&gt;&lt;/b&gt;. Saying that, doing exercise is obviously good for you and increases the amount you can eat that day whilst still losing weight. Just be careful to not overeat on exercise days - I&#39;ve been known to indulge a little more after an 80 mile bike ride that burned ~5,000 calories, only to have put weight on the day after.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Start to think of food as &quot;fuel&quot; for your body&lt;/i&gt;&lt;/b&gt;. Don&#39;t think that your body can deal with a 6 mile swim on just a Mars bar. No matter how much brand advertising and slogans make you think a product is good for you or full of good stuff, &lt;i&gt;do your research&lt;/i&gt; before relying on a particular product regularly.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Healthy muscle retains a more water than body fat.&lt;/i&gt;&lt;/b&gt;&amp;nbsp;I went from 50% body water when I was 250lb to 58% now.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Loose skin is weird&lt;/i&gt;&lt;/b&gt;. If you&#39;re going to be losing lots of weight be prepared to have some sag afterwards, especially if you&#39;ve been fat for a long time and / or you&#39;re excessively overweight. If you&#39;re only losing a stone or two you&#39;ll be fine, or if you&#39;re young and your skin is still elastic. Unfortunately I missed the boat there, but here&#39;s to hoping my skin is just being a bit lazy and I can tone up a little bit in the next year or two. I&#39;m still a lot happier than I was when I was fat and my lose skin is hardly noticeable at the moment.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Being skinny is unfathomably more comfortable than being fat&lt;/i&gt;&lt;/b&gt;. Life in general is easier, happier and less sweaty.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Gadgets are cool, but not necessary&lt;/i&gt;&lt;/b&gt;. The metrics you get from them can be a double-edged sword, but as long as you don&#39;t obsess over them too much they can be a great way to monitor your progress. I don&#39;t currently have a 24 hour activity tracker, but I&#39;m planning on getting one to monitor my fitness improvement going forward.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;BMI should only be used as a general guide.&lt;/i&gt;&lt;/b&gt;&amp;nbsp;Definitely don&#39;t stress about it too much. Use a mirror and common sense instead.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Putting weight on during weight loss is not the end of the world.&lt;/i&gt;&lt;/b&gt;&amp;nbsp;As long as its not a trend. If you plateau or start to put weight on and you&#39;re being 100% honest with yourself about what you&#39;re eating, then you need to do something about it. Also, unless you&#39;re doing some intense weight training don&#39;t fool yourself into the old &quot;muscle weighs more than fat&quot; bull - your aim is to lose weight, and light to moderate weight / resistance training is apparently one of the best ways to burn fat.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Weigh yourself consistently&lt;/i&gt;&lt;/b&gt;. Since I got my fancy Garmin scales I weigh myself every day. I do this first thing on a morning before any water / food, and after a poo. The scales automatically upload and sync with all my apps, which makes monitoring your process a lot less laborious. A lot of people prefer to weigh themselves weekly to see larger chunks come off at once, but I like to know that on a daily basis I&#39;ve been doing things right the day before. This has allowed me to monitor trends in my consumption and make minor changes in my diet to lose weight quicker. I can pretty much predict how much I&#39;ll put on or lose each day now.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;Weight loss will start quick, but slow down&lt;/i&gt;&lt;/b&gt;. Initially I was losing up to 8lb per week - that slowed down over time (doing the same stuff) until I plateaued.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;You WILL plateau at some point&lt;/i&gt;&lt;/b&gt;. I thought I was safe from this - I lost well over 80lb before it happened to me. When it happens lower your calorie intake, do more regular / intense exercise, or take stock on the amount or type of foods that you&#39;re eating. I started doing interval training at the pool (as well as doing around 420 miles on the bike per month), and lowered my &quot;sedentary&quot; calorie intake from 1,800 to 1,500 calories - I started to lose 2lb+ per week again after I did that.&lt;/li&gt;
&lt;/ul&gt;
This is probably one of the biggest personal achievements of my life so far, and has been all-consuming for the best part of 2 years. The upshot is that I am now health-aware and have a much more active, healthy and happy lifestyle. Yes, eating all the food you want is awesome, but being fat is most definitely NOT awesome - and you can&#39;t have it both ways. I&#39;ve considerably lowered my risk of cardiovascular disease, diabetes and numerous other potential issues, but the most noticeable thing has been that I no longer have constant aches and pains in my knees and other parts of my body. I sleep better, feel better and am generally more positive about life.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;
So, how did I celebrate this momentous occasion? I had the day off work, went out for a nice meal in the countryside with my wife, then chilled out all evening. Not particularly exciting to most, but it was ideal for me!&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/8517495428979106409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/8517495428979106409'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2017/08/how-i-learned-to-lose-weight-and-love.html' title='How I Learned to Lose Weight and Love Exercise (again)'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDELuse86bUY-ZJ_JSzpVY8pqQNUlDZfHuBQtK7LJA-Na2VuVRyAhf9-_32_2kDiEz8MYrnHaQEoKSkVKKU50qBp77MDk9IyB-ULp89eUnSfZ4MDWZgPz-WnphyOTKXNR-7MHr_PVWO8c/s72-c/I_need_your_clothes%252C_your_boots%252C_and_your_motorcycle.jpg" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-2679584246217348375</id><published>2015-01-09T16:28:00.001+00:00</published><updated>2015-01-09T16:28:30.407+00:00</updated><title type='text'>Deleting All PlayerPrefs for your Unity3D Project on Windows</title><content type='html'>As a Unity3D developer you&#39;ll eventually find yourself wanting to delete the &lt;a href=&quot;http://docs.unity3d.com/ScriptReference/PlayerPrefs.html&quot; target=&quot;_blank&quot;&gt;PlayerPrefs &lt;/a&gt;for a particular project on a regular basis. I&#39;ve been recently using PlayerPrefs to store player settings like FOV, mouse sensitivity and acceleration, and I wanted to make sure that my code will run on a freshly installed machine as well as my development box.&lt;br /&gt;
&lt;br /&gt;
If you click the&amp;nbsp;&lt;a href=&quot;http://docs.unity3d.com/ScriptReference/PlayerPrefs.html&quot; target=&quot;_blank&quot;&gt;link above&lt;/a&gt;, you&#39;ll see that all PlayerPrefs are stored in the registry - for a Windows machine at least. So, instead of writing some delete-later code to run PlayerPrefs.DeleteAll(), you can just create a simple registry file that you can click on whenever you want to clean up your machine. All you need to do is prefix the registry key of your project with a dash (-), and run the file.&lt;br /&gt;
&lt;br /&gt;
Below is a sample file for Windows 8.1 - you&#39;ll need to alter the Registry Editor version at the top of the file if you&#39;re using any other version of Windows, but it should still work:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background-color: white; color: black; padding: 10px;&quot;&gt;Windows Registry Editor Version 5.00

[-HKEY_CURRENT_USER\Software\Shadow Moses Developments Ltd\Subnet-POC]
&lt;/pre&gt;
&lt;br /&gt;
Simple, yet effective. Happy coding!</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/2679584246217348375'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/2679584246217348375'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2015/01/deleting-all-playerprefs-for-your.html' title='Deleting All PlayerPrefs for your Unity3D Project on Windows'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-4968885290193324303</id><published>2014-02-11T11:56:00.000+00:00</published><updated>2014-02-11T19:18:42.323+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type='text'>Why GUIDs Are a Bad Choice for SQL Server Key and Identity Columns</title><content type='html'>I&#39;ve spent many years debating with my fellow developers across all manor of subjects (I do love to talk), but one subject that comes up time and time again is the usage of the UNIQUEIDENTIFIER data type in SQL Server; especially when they&#39;re used as identity and key columns. In fact, I see this more often than you would expect, and misconfigured UNIQUEIDENTIFIER columns can create &quot;hidden&quot; problems that can be difficult to discover and / or rectify, depending on the SQL experience throughout your team.
&lt;br /&gt;
If you care to ask around your colleagues, it&#39;s almost guaranteed that you&#39;ll get multiple conflicting opinions on why you should or should not use GUIDs in SQL Server, but few developers actually realise the impact of such a design choice. In the interests of science, I&#39;ll try and keep this as factual as possible, and I&#39;ll focus on the topic at hand, rather than GUIDs / UUIDs in general.&lt;br /&gt;
&lt;br /&gt;
Here&#39;s a list of common reasons for using a GUID in your database design:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;You require an unpredictable seed for your records as it is exposed directly via some kind of public interface&lt;/li&gt;
&lt;li&gt;You need a globally unique identifier for the record.&lt;/li&gt;
&lt;li&gt;You have more than 2^31 (2,147,483,647) records in your table&lt;/li&gt;
&lt;li&gt;You have more than 2^63 (9,223,372,036,854,775,807) records in your table&lt;/li&gt;
&lt;li&gt;You use GUIDs all the time / you prefer GUIDs as they&#39;re a more secure solution&lt;/li&gt;
&lt;/ol&gt;
From the above, the only really acceptable scenario is no. 4. There aren&#39;t many tables in the world that hold 9.2 quintillion records, but if you happen to have one I can guarantee that choosing a data type for its primary key is the least of your problems (and you probably won&#39;t be reading this anyway)!&lt;br /&gt;
&lt;br /&gt;
So here&#39;s a list of reasons - with code examples and supporting facts - as to why GUIDs are a bad design choice when it comes to SQL Server identity and key columns. I&#39;m using primitive benchmarking techniques, but it still should give you a good idea of what you&#39;re up against - I will be inserting 1 million records into each table I test, and each table will have a single column with the data type and / or indices that are being tested.&lt;br /&gt;
&lt;br /&gt;
First off, create a database - I&#39;ve called mine &quot;test&quot;, cos that&#39;s how I roll.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;DATABASE&lt;/span&gt; test;&lt;/pre&gt;
&lt;br /&gt;
And before I begin my assault, let&#39;s write a bit of SQL to compare the three data types:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;USE&lt;/span&gt; test;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; NOCOUNT &lt;span class=&quot;kwrd&quot;&gt;ON&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyInt&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyInt
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyBigInt&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyBigInt
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyGuid&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuid
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyGuidSeq&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuidSeq
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyInt (
    ID &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyBigInt (
    ID BIGINT &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuid (
    ID UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; NEWID()
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuidSeq (
    ID UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; NEWSEQUENTIALID()
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @StartTime DATETIME2, @Endtime DATETIME2, @i &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @noRecords &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @noRecords = 1000000
&lt;span class=&quot;rem&quot;&gt;-- MyInt&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @StartTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyInt &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @EndTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;MyInt Time Taken: &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEDIFF(ms, @StartTime, @EndTime)) + &lt;span class=&quot;str&quot;&gt;&#39;ms&#39;&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyBigInt&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @StartTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyBigInt &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @EndTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;MyBigInt Time Taken: &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEDIFF(ms, @StartTime, @EndTime)) + &lt;span class=&quot;str&quot;&gt;&#39;ms&#39;&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyGuid&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @StartTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyGuid &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @EndTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;MyGuid Time Taken: &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEDIFF(ms, @StartTime, @EndTime)) + &lt;span class=&quot;str&quot;&gt;&#39;ms&#39;&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyGuidSeq&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @StartTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyGuidSeq &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @EndTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;MyGuidSeq Time Taken: &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEDIFF(ms, @StartTime, @EndTime)) + &lt;span class=&quot;str&quot;&gt;&#39;ms&#39;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;exec&lt;/span&gt; sp_spaceused &lt;span class=&quot;str&quot;&gt;&#39;MyInt&#39;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;exec&lt;/span&gt; sp_spaceused &lt;span class=&quot;str&quot;&gt;&#39;MyBigInt&#39;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;exec&lt;/span&gt; sp_spaceused &lt;span class=&quot;str&quot;&gt;&#39;MyGuid&#39;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;exec&lt;/span&gt; sp_spaceused &lt;span class=&quot;str&quot;&gt;&#39;MyGuidSeq&#39;&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
So, here we&#39;re inserting 1 million records with their default values into 4 separate tables. I&#39;ve written two tests for the UNIQUEIDENTIFIER data type - one to test Identity creation using NEWID() and NEWSEQUENTIALID() respectively. The results are predictable, but interesting. I&#39;ve added a little bit extra formatting for clarity:&lt;br /&gt;
&lt;pre&gt;MyInt Time Taken: 105,080ms
MyBigInt Time Taken: 104,380ms
MyGuid Time Taken: 159,670ms
MyGuidSeq Time Taken: 102,950ms&lt;/pre&gt;
&lt;pre&gt;&lt;strong&gt;Table name  No. Rows   Reserved Space  Actual space  Index Size  Unused Space&lt;/strong&gt;
MyInt       1,000,000  12,936 KB       12,864 KB     56 KB       16 KB
MyBigInt    1,000,000  16,904 KB       16,808 KB     88 KB       8 KB
MyGuid      1,000,000  34,760 KB       34,552 KB     160 KB      48 KB
MyGuidSeq   1,000,000  24,968 KB       24,768 KB     176 KB      24 KB&lt;/pre&gt;
And now the critique...&lt;br /&gt;
&lt;h3&gt;
  1. Table Storage Size
 &lt;/h3&gt;
&quot;Disk Space is Cheap!&quot; I hear you cry. Indeed it is, but why use more than you have to? This is probably the most contentious (but probably least important) issue surrounding the use of GUIDs in SQL Server, mainly because it&#39;s easy to have an opinion on it. I think it&#39;s safe to say that most developers understand how basic disk allocation works - but often enterprise storage systems are a lot more complex than your developer box.&lt;br /&gt;
&lt;br /&gt;
So, on to the facts. INT columns have a numerical range of -2^31 to 2^31, and store only 4 bytes. BIGINT columns have a numerical range of -2^63 to 2^63, taking up 8 bytes. UNIQUEIDENTIFIER columns can have 2^122 possible combinations, but store a whopping 16 bytes; this results in noticeably larger table sizes when using a UNIQUEIDENTIFIER over the recommended key data types.&lt;br /&gt;
&lt;br /&gt;
You&#39;ll have probably noticed that MyGuid is larger than MyGuidSeq; this is because SQL Server tables &lt;i&gt;with a clustered index&lt;/i&gt; are stored in the indices physical order, something which I was unaware of until I posted &lt;a href=&quot;http://stackoverflow.com/questions/20974062/why-does-using-newid-use-more-space-than-newsequentialid&quot; target=&quot;_blank&quot;&gt;this stack overflow question&lt;/a&gt;! I actually thought that clustered indices were a separate entity, stored along side the table.&lt;br /&gt;
&lt;br /&gt;
So then, to make it űberfair, let&#39;s take the MyGuidSeq table and work out how much more storage is uses than the MyBigInt table: 24,986 - 16,904 = 8,064Kb extra storage per 1 million rows at its best, 21,824Kb at it&#39;s worst. Not much on its own, but consider that a table is likely to be much larger than that, and using the column as a foreign key in other tables means your storage requirements will rapidly expand.&lt;br /&gt;
&lt;h3&gt;
  2. Index Size
 &lt;/h3&gt;
The above table also helps when comparing the size of UNIQUEIDENTIFIER, INT and BIGINT based &lt;i&gt;indices&lt;/i&gt;. It&#39;s obvious for reasons already mentioned that a UNIQUEIDENTIFIER will use more space than an INT or BIGINT, and whilst the numbers in the Index Size column above are tiny for now, their sizes will increase considerably when more columns are included or referenced in the index. You can also see that both UNIQUEIDENTIFIER columns use roughly double or more space than even a BIGINT; the size of an index has repercussions, which I will address later in this article.&lt;br /&gt;
&lt;h3&gt;
  3. Index Fragmentation
 &lt;/h3&gt;
The fragmentation of an SQL Server index often goes unchecked - in fact, most developers that work with databases don&#39;t even know that indices can get fragmented, yet it can often be the first place to look when you run into sudden performance issues in your software.&lt;br /&gt;
&lt;br /&gt;
Index fragmentation occurs when a new page is inserted into an existing index, and the index does not have space for the page. Pages can be inserted or moved around for lots of different reasons, but the most common are inserting new records, and updating indexed columns in existing records.&lt;br /&gt;
&lt;br /&gt;
The following SQL will give us stats on all four tables:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
    I.name,
    ROUND(S.avg_fragmentation_in_percent, 2) &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; FragmentationPercent,
    i.fill_factor,
    s.page_count
&lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; sys.dm_db_index_physical_stats (DB_ID(&lt;span class=&quot;str&quot;&gt;&#39;test&#39;&lt;/span&gt;), OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyInt&#39;&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;) S
&lt;span class=&quot;kwrd&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;JOIN&lt;/span&gt; sys.indices I (nolock) &lt;span class=&quot;kwrd&quot;&gt;ON&lt;/span&gt; (
    S.object_id = I.object_id
 &lt;span class=&quot;kwrd&quot;&gt;AND&lt;/span&gt; S.index_id = I.index_id
)
&lt;span class=&quot;kwrd&quot;&gt;UNION&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
    I.name,
    ROUND(S.avg_fragmentation_in_percent, 2) &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; FragmentationPercent,
    i.fill_factor,
    s.page_count
&lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; sys.dm_db_index_physical_stats (DB_ID(&lt;span class=&quot;str&quot;&gt;&#39;test&#39;&lt;/span&gt;), OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyBigInt&#39;&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;) S
&lt;span class=&quot;kwrd&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;JOIN&lt;/span&gt; sys.indices I (nolock) &lt;span class=&quot;kwrd&quot;&gt;ON&lt;/span&gt; (
    S.object_id = I.object_id
 &lt;span class=&quot;kwrd&quot;&gt;AND&lt;/span&gt; S.index_id = I.index_id
)
&lt;span class=&quot;kwrd&quot;&gt;UNION&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
    I.name,
    ROUND(S.avg_fragmentation_in_percent, 2) &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; FragmentationPercent,
    i.fill_factor,
    s.page_count
&lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; sys.dm_db_index_physical_stats (DB_ID(&lt;span class=&quot;str&quot;&gt;&#39;test&#39;&lt;/span&gt;), OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyGuid&#39;&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;) S
&lt;span class=&quot;kwrd&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;JOIN&lt;/span&gt; sys.indices I (nolock) &lt;span class=&quot;kwrd&quot;&gt;ON&lt;/span&gt; (
    S.object_id = I.object_id
 &lt;span class=&quot;kwrd&quot;&gt;AND&lt;/span&gt; S.index_id = I.index_id
)
&lt;span class=&quot;kwrd&quot;&gt;UNION&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
    I.name,
    ROUND(S.avg_fragmentation_in_percent, 2) &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; FragmentationPercent,
    i.fill_factor,
    s.page_count
&lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; sys.dm_db_index_physical_stats (DB_ID(&lt;span class=&quot;str&quot;&gt;&#39;test&#39;&lt;/span&gt;), OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyGuidSeq&#39;&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;) S
&lt;span class=&quot;kwrd&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;JOIN&lt;/span&gt; sys.indices I (nolock) &lt;span class=&quot;kwrd&quot;&gt;ON&lt;/span&gt; (
    S.object_id = I.object_id
 &lt;span class=&quot;kwrd&quot;&gt;AND&lt;/span&gt; S.index_id = I.index_id
)&lt;/pre&gt;
&lt;br /&gt;
And here are the results:&lt;br /&gt;
&lt;pre&gt;name                            FragmentationPercent  fill_factor   page_count
PK__MyGuidSe__3214EC276477ECF3  0.71                  0             3096
PK__MyGuid__3214EC275FB337D6    99.08                 0             4343
PK__MyInt__3214EC275812160E     0.44                  0             1608
PK__MyBigInt__3214EC275BE2A6F2  0.48                  0             2101
&lt;/pre&gt;
There&#39;s a tiny amount of fragmentation on the INT and BIGINT tables, and a little bit more for UNIQUEIDENTIFIER when NEWSEQUENTIALID() is used, but as you can see, the MyGuid table (which uses NEWID() as the column default value) is almost 100% fragmented. This is bad, in case you haven&#39;t been following. Fragmentation slows down the retrieval of data from the table, meaning the SQL query engine has more work to do when it needs to scan the index.&lt;br /&gt;
&lt;br /&gt;
So why does NEWID() fragment the index so much? Well, NEWID() produces a pseudo-random GUID which is pretty much unpredictable, and 100% non-sequential. By their very nature, non-sequential rows are inserted into the middle of an index, whereas sequential rows are generally appended to the end of an index. When an insertion takes place, SQL Server will move pages around so that the new rows will fit in the space allocated to that particular page. If there&#39;s no space available in the page - or a new page won&#39;t fit in the space available - SQL Server will create the page at the end of the index. This causes index fragmentation.&lt;br /&gt;
&lt;br /&gt;
Let&#39;s just take a very quick look at how quickly the MyGuid table gets to 99% fragmentation:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;USE&lt;/span&gt; test;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; NOCOUNT &lt;span class=&quot;kwrd&quot;&gt;ON&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyGuid&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuid
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuid (
    ID UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; NEWID()
)
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @StartTime DATETIME2, @Endtime DATETIME2, @i &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @noRecords &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @Fragmentation &lt;span class=&quot;kwrd&quot;&gt;DECIMAL&lt;/span&gt;(4,2)
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @noRecords = 1000000
&lt;span class=&quot;rem&quot;&gt;-- MyGuid&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @StartTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyGuid &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
        
 &lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
            @Fragmentation = ROUND(S.avg_fragmentation_in_percent, 2)
 &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; sys.dm_db_index_physical_stats (DB_ID(&lt;span class=&quot;str&quot;&gt;&#39;test&#39;&lt;/span&gt;), OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyGuid&#39;&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;) S
        
 &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt;(@Fragmentation &amp;gt; 99)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;99% fragmentation after &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, @i) + &lt;span class=&quot;str&quot;&gt;&#39; records&#39;&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;BREAK&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @EndTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;MyGuid Time Taken: &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEDIFF(ms, @StartTime, @EndTime)) + &lt;span class=&quot;str&quot;&gt;&#39;ms&#39;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;exec&lt;/span&gt; sp_spaceused &lt;span class=&quot;str&quot;&gt;&#39;MyGuid&#39;&lt;/span&gt;, true&lt;/pre&gt;
&lt;br /&gt;
Output:&lt;br /&gt;
&lt;br /&gt;
99% fragmentation after 23495 records&lt;br /&gt;
&lt;br /&gt;
So, without anything else going on with the table, we can insert 23,495 records before the table is fully fragmented. As it stands, this doesn&#39;t mean too much - as you&#39;d want to avoid getting to 99% fragmentation anyway (by managing any indices that become more than 5% fragmented - but that&#39;s a &lt;a href=&quot;http://blog.shadowmoses.co.uk/2013/06/intelligent-sql-server-reorganize-and.html&quot; target=&quot;_blank&quot;&gt;whole other article&lt;/a&gt;). So, I also ran the above test with 5% and 30% fragmentation values, and &lt;i&gt;both &lt;/i&gt;got to 324 records before becoming fragmented. Regardless of the reasons for this, I think you&#39;ll agree that having to perform index maintenance after 324 new records is pretty unreasonable.&lt;br /&gt;
&lt;br /&gt;
We haven&#39;t even touched upon the differences between Internal and External fragmentation, CLUSTERED and NON CLUSTERED indices, and how to set up index specific properties such as fill factors. There is a lot more to database design than initially presents itself; I remember learning all about normal form at college, which - whilst important - doesn&#39;t prepare you for all the funky under-the-hood mechanics that goes on in the real world.&lt;br /&gt;
&lt;br /&gt;
I won&#39;t go into any more detail here, as there are hundreds of articles out there explaining fragmentation and at what point you should reorganize or rebuild an index. A while back I also wrote&amp;nbsp;&lt;a href=&quot;http://blog.shadowmoses.co.uk/2013/06/intelligent-sql-server-reorganize-and.html&quot;&gt;a script&lt;/a&gt;&amp;nbsp;to assist with automated index management which I still find quite handy, though it should be noted that the more complex your database, the more specific you should be about individual indices.&lt;br /&gt;
&lt;br /&gt;
The only thing that&#39;s left for me to say on index fragmentation is this: if you absolutely must use a UNIQUEIDENTIFIER as your primary key (you &lt;i&gt;don&#39;t&lt;/i&gt;, btw), then ALWAYS use NEWSEQUENTIALID() over NEWID(). However, if your reason for using a GUID is that you want a unique identifier that&#39;s difficult to guess, then you&#39;re shit out of luck. Unfortunately NEWSEQUENTIALID() generated identifiers are predictable.&lt;br /&gt;
&lt;br /&gt;
NEWSEQUENTIALID() also inherently helps to keep indices contiguous - filling data and index pages fully before creating a new page. However, it stands to reason that - due to the fact &lt;a href=&quot;http://technet.microsoft.com/en-us/library/ms189786.aspx&quot;&gt;NEWSEQUENTIALID() is reset when Windows is restarted&lt;/a&gt;&amp;nbsp;(and can subsequently start at a lower GUID seed value than the last seed) - that the use of NEWSEQUENTIALID() can still insert pages into the middle of an index, fragmenting the index quicker than you otherwise would with an INT or BIGINT.&lt;br /&gt;
&lt;br /&gt;
Also worth mentioning - if you ever update a UNIQUEIDENTIFIER column that is indexed, even if you use NEWSEQUENTIALID(), it will increase fragmentation quicker over time. Saying that, the same would apply to an INT or BIGINT column, as the new value is likely to create a new page in the index.&lt;br /&gt;
&lt;h3&gt;
  4. Join and Index Lookup Speed
 &lt;/h3&gt;
Ignoring the NEWID() tables I created earlier (I think it&#39;s safe to say that I have already provided enough evidence that NEWID() is not suitable for use in a default constraint on a key column), we can now take a look at how quickly joins and lookups perform across the data types. If you&#39;re coding along with me, the below SQL will take a while (we&#39;re generating and inserting 6 million rows, and doing 3 million individual lookups - I would NOT recommend doing anything even remotely like this on a production server). Set it running and go and make a brew, hug your wife, feed your cat, or snuggle your guinea pigs (you have guinea pigs, right?). This takes around 11 minutes to run on my development PC:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;USE &lt;/span&gt;test;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; NOCOUNT &lt;span class=&quot;kwrd&quot;&gt;ON&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyInt&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyInt
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyIntJoin&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyIntJoin
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyBigInt&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyBigInt
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyBigIntJoin&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyBigIntJoin
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyGuidSeq&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuidSeq
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyGuidSeqJoin&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuidSeqJoin
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyIntJoin (
    ID &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyBigIntJoin (
    ID BIGINT &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuidSeqJoin (
    ID UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; NEWSEQUENTIALID()
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyInt (
    ID &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;,
    fk &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;FOREIGN&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;REFERENCES&lt;/span&gt; MyIntJoin(ID)
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyBigInt (
    ID BIGINT &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;,
    fk BIGINT &lt;span class=&quot;kwrd&quot;&gt;FOREIGN&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;REFERENCES&lt;/span&gt; MyBigIntJoin(ID)
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuidSeq (
    ID UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; NEWSEQUENTIALID(),
    fk UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;FOREIGN&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;REFERENCES&lt;/span&gt; MyGuidSeqJoin(ID)
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @StartTime DATETIME2, @Endtime DATETIME2, @i &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @noRecords &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @fkInt &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @fkBigInt BIGINT, @fkGuid UNIQUEIDENTIFIER
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @noRecords = 1000000
&lt;span class=&quot;rem&quot;&gt;-- Join tables&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyInt&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyIntJoin &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyBigInt&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyBigIntJoin &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyGuidSeq&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyGuidSeqJoin &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- Source Tables&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyInt&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;rem&quot;&gt;-- Just get a random ID between 1 and @noRecords&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
            @fkInt = ABS(&lt;span class=&quot;kwrd&quot;&gt;CAST&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;CAST&lt;/span&gt;(NEWID() &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; VARBINARY) &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)) % @noRecords
        
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyInt(fk)
 &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;(@fkInt)
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyBigInt&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;rem&quot;&gt;-- Just get a random ID between 1 and @noRecords&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
            @fkBigInt = ABS(&lt;span class=&quot;kwrd&quot;&gt;CAST&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;CAST&lt;/span&gt;(NEWID() &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; VARBINARY) &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)) % @noRecords
        
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyBigInt(fk)
 &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;(@fkBigInt)
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyGuidSeq&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;rem&quot;&gt;-- Getting a random row efficiently is a bit more complex&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TOP&lt;/span&gt; 1
            @fkGuid = ID
 &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; MyGuidSeqJoin
 &lt;span class=&quot;kwrd&quot;&gt;WHERE&lt;/span&gt; (ABS(&lt;span class=&quot;kwrd&quot;&gt;CAST&lt;/span&gt;((BINARY_CHECKSUM(id, NEWID())) &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)) % 100) &amp;lt; 1 &lt;span class=&quot;rem&quot;&gt;-- Only process 1%&lt;/span&gt;
        
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyGuidSeq(fk)
 &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;(@fkGuid)
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
    END&lt;/pre&gt;
&lt;br /&gt;
Back with me? Good... so, what we&#39;re doing here is generating some primary key values in three tables (the ones suffixed with Join) as we did before. After that, we&#39;re randomly inserting some of those foreign key values into each source table, so we can perform lookups and joins against them. The inefficient bit is getting the random foreign key value from the Join tables - so for the int and bigint tables, I&#39;ve just generated a random value between 1 and 1,000,000 (as we can guess the PKs for those tables). However, because I&#39;m unable to re-generate the GUID values out of thin air (like I did with the int and bigint keys), I have to retrieve a random row from the MySeqGuidJoin table directly. I&#39;ve used the most efficient method I could muster (generating a checksum for each row and only processing the top 1% of records), which is nearly as efficient as the random number generation, but a lot more cumbersome. I initially used the ORDER BY NEWID() method to get random values, but this is way too slow and inefficient.&lt;br /&gt;
&lt;br /&gt;
Ok, so let&#39;s just check the fragmentation on the newly created tables as before to make sure we&#39;re getting similar results. I won&#39;t paste the SQL again (you can re-use the sys.dm_db_index_physical_stats statements above and apply the new table names):&lt;br /&gt;
&lt;pre&gt;name                            FragmentationPercent  fill_factor  page_count
PK__MyInt__3214EC272F9A1060     0.38                  0            2101
PK__MyIntJoi__3214EC272334397B  0.37                  0            1608
PK__MyGuidSe__3214EC2739237A9A  0.67                  0            5077
PK__MyBigInt__3214EC272704CA5F  0.57                  0            2101
PK__MyGuidSe__3214EC272AD55B43  0.71                  0            3096
PK__MyBigInt__3214EC27345EC57D  0.45                  0            3096
&lt;/pre&gt;
&lt;br /&gt;
So, things are looking good to start with. Low fragmentation on all the indices, and we have 1 million records in each of the 6 tables for us to test with.&lt;br /&gt;
&lt;br /&gt;
First the join speed tests. We&#39;re going to return all 1,000,000 records in each source table (MyInt, MyBigInt and MyGuidSeq) and time the results.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;USE&lt;/span&gt; test;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; NOCOUNT &lt;span class=&quot;kwrd&quot;&gt;ON&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyInt&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyInt
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyIntJoin&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyIntJoin
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyBigInt&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyBigInt
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyBigIntJoin&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyBigIntJoin
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyGuidSeq&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuidSeq
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;MyGuidSeqJoin&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuidSeqJoin
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyIntJoin (
    ID &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyBigIntJoin (
    ID BIGINT &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuidSeqJoin (
    ID UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; NEWSEQUENTIALID()
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyInt (
    ID &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;,
    fk &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;FOREIGN&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;REFERENCES&lt;/span&gt; MyIntJoin(ID)
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyBigInt (
    ID BIGINT &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;,
    fk BIGINT &lt;span class=&quot;kwrd&quot;&gt;FOREIGN&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;REFERENCES&lt;/span&gt; MyBigIntJoin(ID)
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyGuidSeq (
    ID UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; NEWSEQUENTIALID(),
    fk UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;FOREIGN&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;REFERENCES&lt;/span&gt; MyGuidSeqJoin(ID)
)
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @i &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @noRecords &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @fkInt &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @fkBigInt BIGINT, @fkGuid UNIQUEIDENTIFIER
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @noRecords = 10000000
&lt;span class=&quot;rem&quot;&gt;-- Join tables&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyInt&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyIntJoin &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyBigInt&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyBigIntJoin &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyGuidSeq&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyGuidSeqJoin &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- Source Tables&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyInt&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;rem&quot;&gt;-- Just get a random ID between 1 and @noRecords&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
            @fkInt = (ABS(&lt;span class=&quot;kwrd&quot;&gt;CAST&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;CAST&lt;/span&gt;(NEWID() &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; VARBINARY) &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)) % @noRecords) + 1
        
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyInt(fk)
 &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;(@fkInt)
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyBigInt&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;rem&quot;&gt;-- Just get a random ID between 1 and @noRecords&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
            @fkBigInt = (ABS(&lt;span class=&quot;kwrd&quot;&gt;CAST&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;CAST&lt;/span&gt;(NEWID() &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; VARBINARY) &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)) % @noRecords) + 1
        
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyBigInt(fk)
 &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;(@fkBigInt)
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- MyGuidSeq&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noRecords)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;rem&quot;&gt;-- Getting a random row efficiently is a bit more complex&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TOP&lt;/span&gt; 1
            @fkGuid = ID
 &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; MyGuidSeqJoin
 &lt;span class=&quot;kwrd&quot;&gt;WHERE&lt;/span&gt; (ABS(&lt;span class=&quot;kwrd&quot;&gt;CAST&lt;/span&gt;((BINARY_CHECKSUM(id, NEWID())) &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)) % 100) &amp;lt; 1 &lt;span class=&quot;rem&quot;&gt;-- Only process 1%&lt;/span&gt;
        
 &lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyGuidSeq(fk)
 &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;(@fkGuid)
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
    END&lt;/pre&gt;
&lt;br /&gt;
And the results:&lt;br /&gt;
&lt;pre&gt;MyInt Time Taken: 4,727ms
MyBigInt Time Taken: 4,812ms
MyGuidSeq Time Taken: 5,687ms
&lt;/pre&gt;
&lt;br /&gt;
So, for a table that contains 1 million records, int and bigint perform similarly. UNIQUEIDENTIFIER increases the lookup by around 0.8 seconds (I ran this a few times and the results were consistent). This isn&#39;t the end of the world, but this still shows that GUID lookups are slower than both INT and BIGINT; and remember, these tables have no other columns, constraints, indices or keys - just a single primary key (and its clustered index), and a foreign key constraint.&lt;br /&gt;
&lt;br /&gt;
I ran the same tests above with 10,000,000 rows to see what impact it would have on larger data sets. Here are the results - suffice to say that my dev PC was out of order for the afternoon whilst it generated over 1.5GB of data:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;MyInt Time Taken: 47,357ms
MyBigInt Time Taken: 48,970ms
MyGuidSeq Time Taken: 58,940ms
&lt;/pre&gt;
&lt;br /&gt;
So, about 11 seconds difference - which makes it a bit more obvious that GUID keys are slower than bigint, and int. These numbers include the time it takes to retrieve the data from the server - which probably makes this specific test a bit unfair.&lt;br /&gt;
&lt;br /&gt;
These times may not seem like much, but yet again, it will be further affected by larger table sizes, larger indices, more complex queries.&lt;br /&gt;
&lt;h3&gt;
  4. Uniqueness
 &lt;/h3&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;b&gt;7895D7B4-6402-4552-A7CE-D3B48C5256CC&lt;/b&gt;
 &lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
Apparrently, no one has ever seen the above string before now...
 &lt;/div&gt;
&lt;br /&gt;
OK. This is a bit of a daft point to make, but it&#39;s still valid in my sick little mind. Let&#39;s start with the facts: there can be 2^122 GUID possibilities (that&#39;s 5,316,911,983,139,663,491,615,228,241,121,400,000 - a number I would struggle to say out loud, let alone ever expect to reach in terms of the number of rows in a table). This makes it extremely unlikely you&#39;ll ever collide with another GUID, but &lt;i&gt;it is still possible&lt;/i&gt;, and&amp;nbsp;as a defensive programmer, I try my best to cater for any and all possibilities. The more GUIDs you generate, the more likely it is you&#39;ll collide with an already generated GUID.&lt;br /&gt;
&lt;br /&gt;
Using NEWSEQUENTIALID() gets around the uniqueness issue, although theoretically, it could make things even worse. The more often you restart the SQL box, the more likely it is that you&#39;ll get a conflict - and if you do, it won&#39;t be possible to insert another record until you restart the server. If you get a conflict in this situation, it&#39;s because the conflicted GUID, plus the range of sequential GUIDs generated after the conflicted GUID, have already been generated.&lt;br /&gt;
&lt;br /&gt;
The possibility of a GUID conflict is insignificant. For this reason, most developers and database designers will largely ignore uniqueness as a concern when considering GUIDs as primary keys. It&#39;s a fair point, and not one I argue against very often - but I can tell you that I&#39;m weirdly looking forward to the day I see a GUID conflict, so I can make notes, screenshot it and use it as physical proof that I was right all along! :P&lt;br /&gt;
&lt;h3&gt;
  6. Type Comparison
 &lt;/h3&gt;
I decided to perform a little test on how SQL deals with comparisons between data types. I wanted to compare two INT variables, an INT and a VARCHAR, two UNIQUEIDENTIFIERs, then a UNIQUEIDENTIFIER and a VARCHAR. The only way I could think to reasonably test this was the following:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;USE&lt;/span&gt; test;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @noTests &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @i &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @StartTime DATETIME2, @EndTime DATETIME2
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @int1 &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @int2 &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @int3 &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(10)
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @guid1 UNIQUEIDENTIFIER, @guid2 UNIQUEIDENTIFIER, @guid3 &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(36)
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @noTests = 100000000
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @int1 = 76253421
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @int2 = 93948585
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @int3 = &lt;span class=&quot;str&quot;&gt;&#39;348975764&#39;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @guid1 = NEWID()
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @guid2 = NEWID()
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @guid3 = NEWID()
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @StartTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noTests)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt;(@int1 = @int2)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;&#39;&lt;/span&gt; &lt;span class=&quot;rem&quot;&gt;-- Will never get called&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @EndTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;Int1 = Int2 Time Taken: &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEDIFF(ms, @StartTime, @EndTime)) + &lt;span class=&quot;str&quot;&gt;&#39;ms&#39;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @StartTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noTests)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt;(@int1 = @int3)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;&#39;&lt;/span&gt; &lt;span class=&quot;rem&quot;&gt;-- Will never get called&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @EndTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;Int1 = Int3 Time Taken: &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEDIFF(ms, @StartTime, @EndTime)) + &lt;span class=&quot;str&quot;&gt;&#39;ms&#39;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @StartTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noTests)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt;(@guid1 = @guid2)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;&#39;&lt;/span&gt; &lt;span class=&quot;rem&quot;&gt;-- Will never get called&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @EndTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;Guid1 = Guid2 Time Taken: &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEDIFF(ms, @StartTime, @EndTime)) + &lt;span class=&quot;str&quot;&gt;&#39;ms&#39;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = 1
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @StartTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; (@i &amp;lt;= @noTests)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt;(@guid1 = @guid3)
 &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;&#39;&lt;/span&gt; &lt;span class=&quot;rem&quot;&gt;-- Will never get called&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @i = @i + 1
 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @EndTime = GETDATE()
&lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;Guid1 = Guid3 Time Taken: &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEDIFF(ms, @StartTime, @EndTime)) + &lt;span class=&quot;str&quot;&gt;&#39;ms&#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
So, I&#39;m looping 100,000,000 times for each test and timing the results:&lt;br /&gt;
&lt;pre&gt;Int1 = Int2 Time Taken: 50,043ms
Int1 = Int3 Time Taken: 62,137ms
Guid1 = Guid2 Time Taken: 52,333ms
Guid1 = Guid3 Time Taken: 72,560ms
&lt;/pre&gt;
The results clearly show that SQL server deals with strongly typed comparisons similarly - UNIQUEIDENTIFIER to UNIQUEIDENTIFIER comparisons are marginally slower than INT to INT (by 2 seconds), INT to VARCHAR takes considerably longer (12 seconds), and UNIQUEIDENTIFIER to VARCHAR is even slower (22 seconds).&lt;br /&gt;
&lt;br /&gt;
100,000,000 records is a fair amount to test with, but it still shows that UNIQUEIDENTIFIER comparisons are slower than INT.&lt;br /&gt;
&lt;h3&gt;
  7. Retrieving recently inserted identity values
 &lt;/h3&gt;
So, you&#39;ve just inserted a record into a table, and you want to get the last generated IDENTITY value for use in your application. If you have any experience with T-SQL, I would imagine you&#39;re thinking about @@IDENTIFIER or SCOPE_IDENTITY() right now:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; MyInt(fk)
&lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;(2)
&lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;preproc&quot;&gt;@@IDENTITY&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt; SCOPE_IDENTITY()&lt;/pre&gt;
&lt;br /&gt;
Both SELECT statements above return the same results in this instance, but they wouldn&#39;t 100% of the time. It is extremely handy having both @@IDENTITY and SCOPE_IDENTITY() immediately available for INT and BIGINT columns, even if you don&#39;t use them both that often (you should use SCOPE_IDENTITY() most of the time).&lt;br /&gt;
&lt;br /&gt;
We already know that a UNIQUEIDENTIFIER column cannot have an IDENTITY specification, and that @@IDENTITY and SCOPE_IDENTITY() both return INT or BIGINT, but what happens when you want the most recently inserted DEFAULT value, such as the NEWSEQUENTIALID() default defined below?&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; IdentityTest (
    Id UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; NEWSEQUENTIALID()
)
 &lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt; Id &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; IdentityTest
&lt;/pre&gt;
&lt;br /&gt;
In the above instance, a simple SELECT will do the trick, but when you have multiple rows and multiple columns, it becomes impossible. When using NEWSEQUENTIALGUID() you can&#39;t rely on an ORDER BY Id DESC clause to get you the latest value, because if the server restarts, it&#39;s entirely possible for the new DEFAULT seed value to start below the last seed value.&lt;br /&gt;
&lt;br /&gt;
There is a solution, but it is (in my opinion) cumbersome, more intensive (if only marginally), and only caters for the current scope:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; IdentityTest (
    Id UNIQUEIDENTIFIER &lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; NEWSEQUENTIALID()
)
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @IdentityTest &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; (
    Id UNIQUEIDENTIFIER
)
&lt;span class=&quot;kwrd&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; IdentityTest
 &lt;span class=&quot;kwrd&quot;&gt;OUTPUT&lt;/span&gt; INSERTED.Id &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; @IdentityTest(ID)
&lt;span class=&quot;kwrd&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VALUES&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt; Id
 &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; @IdentityTest&lt;/pre&gt;
&lt;br /&gt;
So, we CAN get the newly inserted GUID value, but it&#39;s not pretty.&lt;br /&gt;
&lt;h3&gt;
  8. SSIS / BIDS / SSDT Handling
 &lt;/h3&gt;
If you&#39;re writing an enterprise level database in SQL Server, it&#39;s very likely that at some point, you - or someone else - will run an SSIS package against it. If your primary keys are GUIDs, this creates more work for any BI tasks, as SSIS (both BIDS and SSDT) doesn&#39;t deal with GUID data very well.&lt;br /&gt;
&lt;br /&gt;
Say, for example, you store a GUID as an SSIS package variable - first of all, you have to store it as a string. While this is all well and good, it&#39;s when you come to compare the variable in an SSIS expression (such as inside an Execute SQL Task or OLE DB Source) that it starts to become difficult. Take the following expression:&lt;br /&gt;
&lt;br /&gt;
[CustomerId] == @[User::CustomerIdVariable]&lt;br /&gt;
&lt;br /&gt;
CustomerId is a UNIQUEIDENTIFIER column (DT_GUID in SSIS), and CustomerIdVariable is (surprise, surprise) a string variable storing a GUID. One would expect an implicit cast to take place, but noooooo... instead, we get error after error until we stumble upon the correct cast, conversion and comparison. So, let&#39;s try casting CustomerIdVariable to a DT_GUID:&lt;br /&gt;
&lt;br /&gt;
[CustomerId] == (DT_GUID)@[User::CustomerIdVariable]&lt;br /&gt;
&lt;br /&gt;
Nope, doesn&#39;t like that... after a bit of Googling, you&#39;ll eventually discover that you should wrap any GUID data in curly brackets in order to work with it:&lt;br /&gt;
&lt;br /&gt;
[CustomerId] == (DT_GUID)(&quot;{&quot; + @[User::CustomerIdVariable] + &quot;}&quot;)&lt;br /&gt;
&lt;br /&gt;
But that doesn&#39;t work either:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Error at Process results into database [Create additional columns [158]]: The data type &quot;DT_GUID&quot; cannot be used with binary operator &quot;==&quot;. The type of one or both of the operands is not supported for the operation. To perform this operation, one or both operands need to be explicitly cast with a cast operator.
 &lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Error at Process results into database [Create additional columns [158]]: Attempt to set the result type of binary operation &quot;CustomerId == (DT_GUID)(&quot;{&quot; + @[User::CustomerIdVariable] + &quot;}&quot;)&quot; failed with error code 0xC0047081.&amp;nbsp;
 &lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Error at Process results into database [Create additional columns [158]]: Computing the expression &quot;[CustomerId] == (DT_GUID)(&quot;{&quot; + @[User::CustomerIdVariable] &amp;nbsp;+ &quot;}&quot;)&quot; failed with error code 0xC0047084. The expression may have errors, such as divide by zero, that cannot be detected at parse time, or there may be an out-of-memory error.&amp;nbsp;
 &lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Error at Process results into database [Create additional columns [158]]: The expression &quot;[CustomerId] == (DT_GUID)(&quot;{&quot; + @[User::CustomerIdVariable] &amp;nbsp;+ &quot;}&quot;)&quot; on &quot;output column &quot;MyColumn&quot; (222)&quot; is not valid.&amp;nbsp;
 &lt;/blockquote&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Error at Process results into database [Create additional columns [158]]: Failed to set property &quot;Expression&quot; on &quot;output column &quot;Mycolumn&quot; (222)&quot;.
 &lt;/blockquote&gt;
Which broadly translates as &quot;Sorry, me no understand what GUID is - do not use a UNIQUEIDENTIFIER column in an expression, ever&quot;, without any good explaination as to why, which is nice. Naturally, the next step would be to try and convert the UNIQUEIDENTIFIER column to a string:&lt;br /&gt;
&lt;br /&gt;
(DT_WSTR,36)[CustomerId] &amp;nbsp;== @[User::CustomerIdVariable]&lt;br /&gt;
&lt;br /&gt;
But guess what? This STILL doesn&#39;t work... the actual solution is to to convert the UNIQUEIDENTIFIER column to a string, and wrap the variable in curly brackets, as such:&lt;br /&gt;
&lt;br /&gt;
(DT_WSTR,36)[CustomerId] &amp;nbsp;== (&quot;{&quot; + @[User::CustomerIdVariable] &amp;nbsp;+ &quot;}&quot;)&lt;br /&gt;
&lt;br /&gt;
And I&#39;m not going to even get into non-unicode conversions.&lt;br /&gt;
&lt;br /&gt;
This is an issue with SSIS rather than the use of a UNIQUEIDENTIFIER in your table, but it&#39;s still worth bearing in mind when designing your DB. If all of your primary and foreign keys are GUIDs, your BI guys aren&#39;t gonna thank you for it.&lt;br /&gt;
&lt;h3&gt;
  Summary
 &lt;/h3&gt;
I&#39;m not saying GUIDs are useless, or should be totally avoided - I&#39;m just yet to come across a situation where using a GUID as a key column is a better option than an INT or a BIGINT.&lt;br /&gt;
&lt;br /&gt;
If you genuinely need a unique and unpredictable GUID for any reason, then simply create a separate UNIQUEIDENTIFIER column in your table, but don&#39;t index it or use it as a foreign key:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;TABLE&lt;/span&gt; MyTest (
    Id           &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;              &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;IDENTITY&lt;/span&gt;,
    UniqueKey    UNIQUEIDENTIFIER D&lt;span class=&quot;kwrd&quot;&gt;EFAULT&lt;/span&gt; NEWID()
)&lt;/pre&gt;
&lt;br /&gt;
If you want to assure that UniqueKey is actually Unique, then add a Unique constraint to the column. However, be aware that by creating a UNIQUE constraint, you are also creating an index - which will need to be set up and maintained appropriately. The main thing we&#39;re trying to avoid here is having a fragmented clustered index.&lt;br /&gt;
&lt;br /&gt;
INT and BIGINT outperform UNIQUEIDENTIFIER in every test I&#39;ve performed here (and I challenge you to come up with a test where they don&#39;t) - some results are marginal, others are more obvious, but this speaks volumes. Your column keys should always be as small and efficient as possible, therefore using a 16 byte UNIQUEIDENTIFIER is counter-productive when a perfectly good 4 byte INT is sat there waiting for you.&lt;br /&gt;
&lt;br /&gt;
Remember that the performance tests I&#39;ve written here are only rough. Ideally each of these tests should be executed on a server a number of times and the results aggregated, as it&#39;s very likely that other applications on my dev machine are affecting SQL Server&#39;s I/O, CPU and memory usage. However, I think they serve to demonstrate my concerns well.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Finally, if you&#39;re considering using a GUID as a table key, ask yourself the following questions:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Do you really need a &lt;i&gt;globally &lt;/i&gt;unique identifier?&lt;/li&gt;
&lt;li&gt;Could the table end up holding millions of rows?&lt;/li&gt;
&lt;li&gt;Could any of the table&#39;s foreign references hold millions of rows?&lt;/li&gt;
&lt;li&gt;Would it be better to store UNIQUEIDENTIFIER data in another column, or even another table?&lt;/li&gt;
&lt;li&gt;Does every row need a GUID, or can you generate a GUID ad-hoc?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  Further reading
 &lt;/h3&gt;
I used some of these links as a reference, but I&#39;m also providing some that offer the &quot;other&quot; side of the argument. One or two are also written by people a lot more knowledgeable than I am when it comes to SQL Server:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.sqlskills.com/blogs/kimberly/disk-space-is-cheap/&quot;&gt;http://www.sqlskills.com/blogs/kimberly/disk-space-is-cheap/&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.sqlskills.com/blogs/kimberly/guids-as-primary-keys-andor-the-clustering-key/&quot;&gt;http://www.sqlskills.com/blogs/kimberly/guids-as-primary-keys-andor-the-clustering-key/&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.codinghorror.com/blog/2007/03/primary-keys-ids-versus-guids.html&quot;&gt;http://www.codinghorror.com/blog/2007/03/primary-keys-ids-versus-guids.html&lt;/a&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/4968885290193324303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/4968885290193324303'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2014/02/why-guids-are-bad-choice-for-sql-server.html' title='Why GUIDs Are a Bad Choice for SQL Server Key and Identity Columns'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-8209131298139534071</id><published>2014-01-15T12:26:00.001+00:00</published><updated>2014-01-16T07:49:13.451+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="Mocking"/><category scheme="http://www.blogger.com/atom/ns#" term="Moq"/><category scheme="http://www.blogger.com/atom/ns#" term="TDD"/><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing"/><title type='text'>Moq&#39;ing Successive Calls to a Method - void method exception handling</title><content type='html'>My &lt;a href=&quot;http://blog.shadowmoses.co.uk/2014/01/moqing-successive-calls-to-method-void.html&quot; target=&quot;_blank&quot;&gt;last post&lt;/a&gt; expanded on a piece of code I found on Phil Haack&#39;s blog that extends Moq to allow you to return different values on each successive call to a method - I also improved it to allow you mock up any of the iterations to throw an exception in place of the return value.&lt;br /&gt;
&lt;br /&gt;
This is great for methods that actually return values, but what happens when you want to throw optional exceptions when you invoke void methods in Moq? Well, void methods on Moq mocks return ISetup&amp;lt;TMock&amp;gt; instead of ISetup&amp;lt;TMock, TResult&amp;gt;, which means that you can&#39;t use the ReturnsInOrder method to handle exceptions. Normally, you would just append a .Throws() to the respective Setup method, but Throws() has no params[] parameter, and no Action based override (as Returns() does), so the only way to apply this kind of rule is with recursive callbacks, which are both cumbersome and hard to read. This is demonstrated below; I&#39;m mocking up a call to an FTP class. The first and third calls to this method will return void (success), the second call will throw an exception:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;mockFTP
    .Setup(x =&amp;gt; x.Put(It.IsAny&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;(), It.IsAny&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;()))
    .Callback(() =&amp;gt;
        mockFTP
            .Setup(x1 =&amp;gt; x1.Put(It.IsAny&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;(), It.IsAny&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;()))
            .Callback(() =&amp;gt;
                mockFTP
                    .Setup(x2 =&amp;gt; x2.Put(It.IsAny&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;(), It.IsAny&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;())))
            .Throws(expectedException));&lt;/pre&gt;
&lt;br /&gt;
Wouldn&#39;t it be much nicer if you could do something like this?&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;mockFTP
    .Setup(x =&amp;gt; x.Put(It.IsAny&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;(), It.IsAny&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;()))
    .ThrowsInOrder(&lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;, expectedException, &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;);&lt;/pre&gt;
&lt;br /&gt;
The answer is &quot;Yes&quot;, in case you&#39;ve forgotten what you&#39;re agreeing to. Well... now you can! The answer is to create another extension method specifically for ISetup&amp;lt;TMock&amp;gt; that uses the same kind of queuing mechanism in Phil&#39;s original post, but wraps a load of recursive callbacks:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; IThrowsResult ThrowsInOrder&amp;lt;TMock&amp;gt;(&lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; ISetup&amp;lt;TMock&amp;gt; setup,
            &lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt; Exception[] exceptions) where TMock: &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; queue = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Queue(exceptions);

            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; setup.Callback(() =&amp;gt; {
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; result = queue.Dequeue() &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; Exception;

                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (result == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) {
                    setup.Throws(&lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;);
                    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;
                }

                setup.Throws(result);
            });
        }&lt;/pre&gt;
&lt;br /&gt;
Enjoy!</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/8209131298139534071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/8209131298139534071'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2014/01/moqing-successive-calls-to-method-void.html' title='Moq&#39;ing Successive Calls to a Method - void method exception handling'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-3249002685379562594</id><published>2013-12-24T15:31:00.000+00:00</published><updated>2013-12-28T15:50:38.950+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="Mocking"/><category scheme="http://www.blogger.com/atom/ns#" term="Moq"/><category scheme="http://www.blogger.com/atom/ns#" term="TDD"/><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing"/><title type='text'>Moq&#39;ing Successive Calls to a Method</title><content type='html'>I just ran into a little problem when using Moq - I wanted to be able to mock up the result of a method call, but return a different result each time the mocked method was called (I&#39;m pulling messages out of an MSMQ within a loop). Anyone who&#39;s used Moq will know that you usually mock results with the Setup() method - however, Moq has no built in way of achieving this (that I&#39;m aware of).&lt;br /&gt;
&lt;br /&gt;
To cut a long explanation short, I found a series of articles on &lt;a href=&quot;http://haacked.com/archive/2009/09/29/moq-sequences.aspx/&quot; target=&quot;_blank&quot;&gt;Phil Haack&#39;s blog&lt;/a&gt; addressing (almost) the same issue. &lt;a href=&quot;http://haacked.com/archive/2010/11/24/moq-sequences-revisited.aspx/&quot; target=&quot;_blank&quot;&gt;Phil&#39;s second post&lt;/a&gt; adds exception handling to his original example, but I wanted to return a &quot;null&quot;, rather than throw an exception. Here&#39;s the code from Phil&#39;s blog, slightly rehashed to deal with nulls:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MoqExtensions {
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; IReturnsResult&amp;lt;T&amp;gt; ReturnsInOrder&amp;lt;T, TResult&amp;gt;(&lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; ISetup&amp;lt;T, TResult&amp;gt; setup,
            &lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;[] results) where T: &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; queue = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Queue(results);

            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; setup.Returns(() =&amp;gt; {
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; result = queue.Dequeue();
                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (result &lt;span class=&quot;kwrd&quot;&gt;is&lt;/span&gt; Exception) {
                    &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; result &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; Exception;
                }
                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (result == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) {
                    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;(TResult);
                }
                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; (TResult)result;
            });
        }
    }&lt;/pre&gt;
&lt;br /&gt;
And here it is in use:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;mockQueue
    .Setup(x =&amp;gt; x.GetNextMessage())
    .ReturnsInOrder(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; InputMessage(), &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; InputMessage(), &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; InputMessage(), &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;);
&lt;/pre&gt;
&lt;br /&gt;
Thanks Phil.&lt;br /&gt;
&lt;br /&gt;
Thil&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
&lt;b&gt;UPDATE 28th Dec 2013&lt;/b&gt;&lt;/h4&gt;
&lt;br /&gt;
I&#39;ve just been trying to append a callback to the above method using Moq&#39;s fluent notation - but I couldn&#39;t, as it returned void. I&#39;ve modified the example above to return setup.Returns, allowing you to then chain notation as you would normally with Moq.</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/3249002685379562594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/3249002685379562594'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2013/12/moqing-successive-calls-to-method.html' title='Moq&#39;ing Successive Calls to a Method'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-7299111437878426775</id><published>2013-12-17T13:22:00.001+00:00</published><updated>2013-12-17T13:22:09.727+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="SourceControl"/><category scheme="http://www.blogger.com/atom/ns#" term="Unity3D"/><title type='text'>Getting Unity 3D working with Git on Windows</title><content type='html'>Git is a brilliant, yet peculiar beast. It has the most flexibility of any of the VCS&#39;s I&#39;ve used, and it&#39;s extremely powerful and quick once you get used to how it works. Suffice to say that I&#39;ve fallen in love with it over the past year, for both personal and commercial projects, and online services like github and bitbucket just enhance the overall appeal of it. I therefore want to use it as my VCS of choice when developing games... but those who have tried to get Unity and git working together will probably either be dead by their own hand, or crouched in a corner, rocking back and forth in the foetal position.&lt;br /&gt;
&lt;br /&gt;
Unity3D is an entirely different, and possibly more peculiar&amp;nbsp;beast. It&#39;s a great tool, and the editor is feature rich, but it&#39;s source control compatibility is weak to say the least. I don&#39;t know if this is through necessity, or the marketing people at Unity have pressed the developers to make it as complicated as possible in order to sell their Asset Server control system. The complexity is mostly due to the fact that the Unity editor serializes most assets into binary by default, and git - by it&#39;s very nature - is built to compare textual files. In addition, Unity3D creates a shed load of files that should &lt;i&gt;not &lt;/i&gt;be version controlled (such as its asset cache), and the Visual Studio / MonoDevelop solution and project files change constantly.&lt;br /&gt;
&lt;br /&gt;
I spent the good part of a couple of weeks getting Git and Unity3D&amp;nbsp;playing nice together, but, because I&#39;m not currently collaborating with other developers I&#39;m still not 100% convinced that Unity3D and git are suited to each other yet. Regardless, it&#39;s very handy for me at the moment, so here&#39;s how I&#39;ve implemented my git repo for &lt;a href=&quot;http://www.nineteenstoneninjas.com/&quot; target=&quot;_blank&quot;&gt;Subnet&lt;/a&gt;, my upcoming First Person stealth and parkour game.&lt;br /&gt;
&lt;br /&gt;
This tutorial is for Unity Pro 4.1.5f, which - at the time of writing - is a little bit out of date, but I believe Unity have recently made a number of pro only features available in the indie version as well (such as asset serialization), so you should be able to follow this for any of the later versions. &lt;a href=&quot;http://docs.unity3d.com/Documentation/Manual/ExternalVersionControlSystemSupport.html&quot; target=&quot;_blank&quot;&gt;Unity have provided a tutorial&lt;/a&gt; on how to integrate with VCS&#39;s, but (as with pretty much all of the Unity documentation) it&#39;s not great.&lt;br /&gt;
&lt;h3&gt;
Setting Up Unity&lt;/h3&gt;
Open up your Unity project and go to Edit -&amp;gt; Project Settings -&amp;gt; Editor:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf-xMj_XdOlaoyqjyUkkui0lJjZHWHD3hOeCH_PzOi1tTdmn3miPZbYYj1oTf_6NUtIr9dk9N9f4BZgApqifhaDGdJGDgqw0D9uu7UeOlCbt1dKtg0rHBTDQQftNdLHZy92iwj80Ck0W8/s1600/001+2013-12-17+11.37.34.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf-xMj_XdOlaoyqjyUkkui0lJjZHWHD3hOeCH_PzOi1tTdmn3miPZbYYj1oTf_6NUtIr9dk9N9f4BZgApqifhaDGdJGDgqw0D9uu7UeOlCbt1dKtg0rHBTDQQftNdLHZy92iwj80Ck0W8/s200/001+2013-12-17+11.37.34.jpg&quot; width=&quot;150&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
This will open the Editor Settings in the Inspector. Here you should set &quot;Version Control -&amp;gt; Mode&quot; to &quot;Meta Files&quot; and &quot;Asset Serialization -&amp;gt; Mode&quot; to &quot;Force Text&quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfIYHYmPvcwTS2z0Wu-CQ4wYxAaBZrVsVWNOZigKRo2AOaRY21MgqRJW12VAKj6zVtwkWRG1IH1mAJw7NkzfgOhvlBzXxqv4LHP-rx6He6v39K2PhAHsBDdiM8ExnCrdqUIN54u7eR9-U/s1600/002+2013-12-17+11.47.25.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;177&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfIYHYmPvcwTS2z0Wu-CQ4wYxAaBZrVsVWNOZigKRo2AOaRY21MgqRJW12VAKj6zVtwkWRG1IH1mAJw7NkzfgOhvlBzXxqv4LHP-rx6He6v39K2PhAHsBDdiM8ExnCrdqUIN54u7eR9-U/s320/002+2013-12-17+11.47.25.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The &quot;Meta Files&quot; option will run through your entire Assets folder and generate a text based .meta file for each file and folder contained within. This file holds some internal Unity data, such as identifiers, version numbers and import settings. You will not need to manually interact with these files, unless you start moving assets around outside of the Unity Editor.&lt;br /&gt;
&lt;br /&gt;
The &quot;Force Text&quot; setting will force relevant assets to serialize as YAML. This allows git to compare changes to editor settings, such as the assets location and scale. It&#39;s not brilliant (sometimes even changing a single setting in a prefab might regenerate the entire file), but it&#39;s about as good as you&#39;re going to get.&lt;br /&gt;
&lt;br /&gt;
That&#39;s it for Unity Editor settings. The only other thing to mention is that you should always move files around within Unity Editor, rather than on your file system, unless you know exactly what you&#39;re doing, otherwise you might break physical references to your assets that can be difficult to resolve, especially if you have a lot of references set up to the moved asset within Unity.&lt;br /&gt;
&lt;h3&gt;
Setting Up Git&lt;/h3&gt;
My git repository has my Unity project inside it, as well as a number of standard Visual Studio solutions and projects that I use for creating some shared and unit tested code. I tend to set up the following directory structure:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;/build/&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;For unity builds. This directory contains a .gitignore file with a single line in it - &quot;!.gitignore&quot;, as I do not wish to push any of my unity builds to git.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;/source/&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;For all source code. I create sub-directories inside this folder for each individual solution - so, one for my Unity project, and another directory for my separate VS solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;br /&gt;
I also set up a .gitignore file in the root of my repository containing the following patterns:&lt;br /&gt;
&lt;br /&gt;
*.suo&lt;br /&gt;
*.sqlsuo&lt;br /&gt;
*.user&lt;br /&gt;
*_ReSharper.*&lt;br /&gt;
*.suo&lt;br /&gt;
*.log&lt;br /&gt;
obj/&lt;br /&gt;
bin/&lt;br /&gt;
Library/&lt;br /&gt;
Temp/&lt;br /&gt;
*.pidb&lt;br /&gt;
*.userprefs&lt;br /&gt;
*.orig&lt;br /&gt;
Assembly-CSharp*.csproj&lt;br /&gt;
Assembly-UnityScript*.unityproj&lt;br /&gt;
.DS_Store&lt;br /&gt;
&lt;br /&gt;
*.subnet&lt;br /&gt;
source/POC/SubnetPOC/SubnetPOC-csharp.sln&lt;br /&gt;
source/POC/SubnetPOC/SubnetPOC.sln&lt;br /&gt;
&lt;br /&gt;
The last three entries are project specific; &quot;*.subnet&quot; is the extension I have applied to my serialized Save Game files, and the other two lines are direct links to the generated Unity solution files. You don&#39;t &lt;i&gt;have &lt;/i&gt;to be explicit here; if you don&#39;t have any .sln files in your repo that are external to the Unity directory (which I do), then you should just add &quot;*.sln&quot; to the list at the top.&lt;br /&gt;
&lt;br /&gt;
A lot of the ignore patterns are pretty standard when using git with .Net repositories, but .Net developers paying attention might wonder why I&#39;m also excluding .sln, .csproj and .unityproj files from the repo. This is because they are recreated every single time you modify the Project structure within the Unity Editor. Different versions of Unity also create slightly different versions of these files, meaning that if you&#39;re collaborating with someone who has a different version of Unity than you, these files will be constantly updated as you both commit to the repo, even if you don&#39;t change anything in the project structure. Because Unity Editor manages the creation of these files, you don&#39;t need to worry about them - anyone cloning the repo will generate their own version of the project and solution files as soon as they open up Unity.&lt;br /&gt;
&lt;br /&gt;
This raises another &quot;gotcha&quot;. You cannot add projects to the Unity Visual Studio / MonoDevelop solution, as they will be automatically removed next time you change a file inside Unity. This is why I have a separate solution containing any shared code - so Unity doesn&#39;t screw up my references and project links constantly!&lt;br /&gt;
&lt;br /&gt;
Also notice that the Library, obj and Temp directories are excluded from the repo. Again, Unity generates these directories whenever you open the editor or build the solution - they are local cache directories that each collaborator will have a local copy of. They&#39;re full of binary files, and can get absolutely HUGE. The more assets you have, the larger these directories will become.&lt;br /&gt;
&lt;br /&gt;
Lastly, but possibly most importantly, is the .gitattributes file. This controls the line endings that git applies to each file type when you check files in and out. If I remember correctly, Unity applies LF line endings to most files by default, which can confuse things (and present you with a lot of laborious popups in the various editors you might use) on a Windows machine. I found a template somewhere online (which I can&#39;t find again - please let me know if this if your file so I can credit you), but it still took me a while to get everything working to an acceptable level. I&#39;m still not 100% convinced that this list is comprehensive, but it&#39;s a damn good start:&lt;br /&gt;
&lt;br /&gt;
# Apply native OS line-endings on checkout of these files...&lt;br /&gt;
*.boo &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.c &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.cginc &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.config &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
*.contentproj &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.cpp &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.dae &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.DAE &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.dtd &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.fx &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
*.glsl &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
*.h &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.inc &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.ini &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.js &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
*.JSFL &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
*.jsfl &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
*.json &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
*.log &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.md &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
*.mel &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.php &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.shader &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
*.txt &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.TXT &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.xaml &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
*.xml &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
*.xsd &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
.gitattributes &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
.gitignore &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
COPYING &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
INSTALL* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
KEYS* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
LICENSE* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text&lt;br /&gt;
NEWS* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
NOTICE* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
README* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
TODO* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
WHATSNEW* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text&lt;br /&gt;
&lt;br /&gt;
# Apply Unix-style LF line-endings on checkout of these files...&lt;br /&gt;
*.meta &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text eol=lf&lt;br /&gt;
*.sh &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text eol=lf&lt;br /&gt;
*.vspscc &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text eol=lf&lt;br /&gt;
.htaccess &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text eol=lf&lt;br /&gt;
&lt;br /&gt;
# Previous &quot;binary&quot;&lt;br /&gt;
*.unity &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text eol=lf&lt;br /&gt;
*.asset &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text eol=lf&lt;br /&gt;
*.prefab &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text eol=lf&lt;br /&gt;
&lt;br /&gt;
# Apply Windows/DOS-style CR-LF line-endings on checkout of these files...&lt;br /&gt;
*.bat &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text eol=crlf&lt;br /&gt;
*.cmd &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text eol=crlf&lt;br /&gt;
*.csproj &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text eol=crlf&lt;br /&gt;
*.sln &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text eol=crlf&lt;br /&gt;
*.user &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text eol=crlf&lt;br /&gt;
*.vcproj &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text eol=crlf&lt;br /&gt;
*.cs &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text eol=crlf&lt;br /&gt;
*.css &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text eol=crlf&lt;br /&gt;
*.htm &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;text eol=crlf&lt;br /&gt;
*.html &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; text eol=crlf&lt;br /&gt;
&lt;br /&gt;
# No end-of-line conversions are applied (i.e., &quot;-text -diff&quot;) to these files...&lt;br /&gt;
*.7z &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.ai &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.anim &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.apk &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.bin &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.bmp &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.BMP &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.com &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.COM &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.controller &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.cubemap &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.dex &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.dll &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.DLL &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.dylib &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.eps &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.exe &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.EXE &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.exr &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.fbx &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.FBX &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.fla &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.flare &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.flv &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.gif &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.guiskin &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.gz &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.ht &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.ico &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.jpeg &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.jpg &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.keystore &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.mask &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.mat &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.mb &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.mp3 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.mp4 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.mpg &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.ogg &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.PCX &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.pcx &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.pdb &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.pdf &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.physicMaterial &amp;nbsp; binary&lt;br /&gt;
*.physicmaterial &amp;nbsp; binary&lt;br /&gt;
*.png &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.ps &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.psd &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.qt &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.so &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.swf &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.tga &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.tif &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.tiff &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.ttf &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.TTF &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.unitypackage &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.unityPackage &amp;nbsp; &amp;nbsp; binary&lt;br /&gt;
*.wav &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.wmv &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.zip &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
*.ZIP &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;binary&lt;br /&gt;
&lt;br /&gt;
You can read more about .gitattributes &lt;a href=&quot;https://help.github.com/articles/dealing-with-line-endings&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;h3&gt;
Unity Script Default Line Endings&lt;/h3&gt;
As I alluded to a bit earlier, Unity uses LF line endings by default. This is particularly annoying on Windows, especially considering that every time you create a script, you have to modify the line endings manually. Luckily, Unity uses text based template files to create the default scripts, and you can modify the line endings in a program like &lt;a href=&quot;http://notepad-plus-plus.org/&quot; target=&quot;_blank&quot;&gt;Notepad++&lt;/a&gt;&amp;nbsp;yourself. The templates are located in the following folder by default:&lt;br /&gt;
&lt;br /&gt;
C:\Program Files (x86)\Unity\Editor\Data\Resources\ScriptTemplates\&lt;br /&gt;
&lt;br /&gt;
In Notepad++ it&#39;s as simple as opening all the files at once, and replacing &quot;\n&quot; with &quot;\r\n&quot; In All Open Documents.&lt;br /&gt;
&lt;br /&gt;
There&#39;s not much point of me providing these files for you, as it&#39;s possible they could be different in each version of Unity, and you might have already modified them yourself.&lt;br /&gt;
&lt;h3&gt;
That&#39;s It&lt;/h3&gt;
&lt;div&gt;
As I said, I&#39;m not 100% convinced this approach will work for everyone, and I&#39;m still very nervous about two people modifying a single Unity scene or prefab file at the same time (I had numerous issues last time I collaborated), but it&#39;s about as close as anyone&#39;s going to get, I think.&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/7299111437878426775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/7299111437878426775'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2013/12/getting-unity-3d-working-with-git-on.html' title='Getting Unity 3D working with Git on Windows'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf-xMj_XdOlaoyqjyUkkui0lJjZHWHD3hOeCH_PzOi1tTdmn3miPZbYYj1oTf_6NUtIr9dk9N9f4BZgApqifhaDGdJGDgqw0D9uu7UeOlCbt1dKtg0rHBTDQQftNdLHZy92iwj80Ck0W8/s72-c/001+2013-12-17+11.37.34.jpg" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-2940939596736919103</id><published>2013-07-27T23:25:00.001+01:00</published><updated>2013-07-27T23:25:42.928+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="Unity3D"/><title type='text'>A Brave New World</title><content type='html'>Anyone who reads my blog regularly will know that when it comes to development, I generally stick to Microsoft or web-based technology, and rarely step outside that comfortable little bubble. I made a promise to myself back in&amp;nbsp;&lt;a href=&quot;http://spikehd.blogspot.co.uk/2013/01/2012-year-world-would-end.html&quot; target=&quot;_blank&quot;&gt;January&lt;/a&gt;&amp;nbsp;that I&#39;d get into mobile or games development this year, and finally I&#39;ve found the time to start looking at one of them.&lt;br /&gt;
&lt;br /&gt;
I&#39;m no ideas man, but occasionally a spark ignites and the juices start flowing. Armed with an idea that&#39;s been rattling around in my head for a few years, I spoke to a friend who&#39;s been focusing on indie games development, and he&amp;nbsp;suggested using Unity3D, a fully featured game engine that supports C# and JavaScript out of the box (making my learning curve a little bit easier). I told him my idea, and - as geeks do - we spent the next few hours hashing out concepts, and by the end of the night, we were fully bought into the idea. The next step was seeing how Unity would fit in.&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
So, for the past few months, my good friend &lt;a href=&quot;http://www.rotates.org/&quot; target=&quot;_blank&quot;&gt;Lew&lt;/a&gt;&amp;nbsp;and I have been prototyping various aspects of our game, and playing around with source control and collaboration tools for Unity3D. There&#39;s a stark difference between developing client / server applications in .Net and developing for 3D games, but Unity&#39;s use of &lt;a href=&quot;http://www.mono-project.com/Main_Page&quot; target=&quot;_blank&quot;&gt;Mono&lt;/a&gt;&amp;nbsp;for scripting (with built in support for C#, Boo and a weird derivative of JavaScript) has made the transition a lot easier than it would have been if I was to learn C++.&lt;br /&gt;
&lt;br /&gt;
Of course, 3D game design is - and always will be - a completely different animal to enterprise application development; even if you consider that you&#39;ll need to learn at least the basics of 3D vector maths (which I totally &lt;i&gt;suck &lt;/i&gt;at), you still have to factor in that game development - by its very nature - relies on multiple pieces of code executing asynchronously, which is completely the opposite of how most .Net developers go about their day-to-day jobs. Most of us have touched on asynchronous operations using .Net&#39;s built in libraries, but it really doesn&#39;t help when programming in Unity.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Developers Unite&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Unity is a pretty advanced (yet generic) 3D games engine that comes with a plethora of &lt;a href=&quot;http://unity3d.com/unity/quality/&quot; target=&quot;_blank&quot;&gt;built in functionality&lt;/a&gt; including (but not limited to) skeletal rig animation, a nifty physics engine and dynamic lighting. A lot of this you can get for &lt;a href=&quot;http://unity3d.com/unity/download/&quot; target=&quot;_blank&quot;&gt;free&lt;/a&gt;, though you really need the Pro version if you&#39;re going to do anything serious.&lt;br /&gt;
&lt;br /&gt;
By far the most appealing aspect of using Unity is the thriving open source community that&#39;s built up around it. Whilst their &lt;a href=&quot;http://answers.unity3d.com/&quot; target=&quot;_blank&quot;&gt;Answers&lt;/a&gt; pages don&#39;t quite match the awesome prowess that is Stack Overflow, and their &lt;a href=&quot;http://unity3d.com/learn/documentation&quot; target=&quot;_blank&quot;&gt;documentation&lt;/a&gt;&amp;nbsp;is a little out of date and lacking in some areas, the community is alive and their &lt;a href=&quot;http://unity3d.com/asset-store/&quot; target=&quot;_blank&quot;&gt;Asset Store&lt;/a&gt; provides many free scripts, textures, models and systems to help you develop your game. I&#39;ve generally found myself discarding or re-writing the scripts I&#39;ve downloaded as I&#39;ve started to understand things more, but they definitely help to point you in the right direction, and some are pretty awesome.&lt;br /&gt;
&lt;br /&gt;
Obviously I&#39;m no game dev pro, but I think it&#39;s safe to say that Unity helps you make a simple game, quickly. However, as with all games, anything more advanced will require a &lt;i&gt;lot&lt;/i&gt; of your time. It&#39;s not long before you realize the potential - and limitations - of the engine, and of course figure out exactly how much work you&#39;ve let yourself in for - in our case, it&#39;s a &lt;i&gt;fuckton.&lt;/i&gt; Without revealing too much at this point, we&#39;re putting together a 3D FPS game with a heavy focus on stealth,&amp;nbsp;parkour and hacking. The best way to describe it is Deus Ex meets Mirror&#39;s Edge. The ideas we&#39;ve had are probably a bit ambitious, but I suppose it&#39;s better to aim too high than too low!&lt;br /&gt;
&lt;br /&gt;
Unity&#39;s IDE is a bit buggy, but is also very extensible (in fairness the bugs I&#39;ve experienced seem to be related to 3rd party scripts and plugins rather than Unity itself, though there are still definitely problems with it). It&#39;s not quite Winforms programming, and the Unity crew have written the Editor scripting objects in a very weird way, but you can achieve almost anything you want within the IDE; drag and drop systems, simple property enhancements, graphs, flow diagrams etc. This neat little addition increases your productivity when working with game objects that share custom scripts - which is basically how you write games in Unity.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Scripted Away&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Unity&#39;s modular approach to object scripting is both refreshingly easy, and infinitely frustrating. It&#39;s a very different way to work than I&#39;m used to, and certainly feels more like scripting / hacking than proper development. Saying all that, it&#39;s perfectly acceptable to abstract code out of the C# scripts within Unity and put them into your own project and develop them separately (maybe with TDD etc), but for the simple reason that Unity is a bit fiddly anyway, I can&#39;t see it being an easy task to accomplish.&lt;br /&gt;
&lt;br /&gt;
As it stands, I&#39;ve written quite a lot of C# scripts in Unity that deal with everything from player movement to object interaction and message relaying, but it doesn&#39;t feel quite right. It very much feels like I&#39;m back to basics with C#; I know the syntax, and a number of patterns, but Unity&#39;s way of working feels loose and fumbly. I never feel like I&#39;m doing things the right way, and my code is definitely starting to look a little bit like spaghetti code, and is at risk of bug creep. This has a lot to do with the code being &quot;Proof of Concept&quot;, and me being unfamiliar with all this new stuff to play with, but I do feel that some things could have been organised just a little bit nicer when they were designing the engine.&lt;br /&gt;
&lt;br /&gt;
Each &quot;script&quot; is basically a C# class that inherits from the Unity base class, MonoBehaviour. Within this class, there&#39;s a well documented event pipeline that helps you get off the ground quickly, and is fairly intuitive - for example, you override Start() to execute code when the script starts, and Update() when you want to control things on a per-frame basis. MonoBehaviour also provides a number of protected / public properties that can be used to access common components directly - although Unity suggests using the built in GetComponent() method to get them instead. I do like the way it works, but I&#39;d like to add further redundancy by putting my code into a separate assembly, and writing unit tests for it.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Not So Safe Source&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
If you&#39;re doing any kind of collaboration with Unity, you&#39;ll soon discover that its source control support is not very good. Mainly, complaints have arisen to do with the free version previously not supporting text serialization of assets (which Unity have rectified recently in version&amp;nbsp;&lt;a href=&quot;http://blogs.unity3d.com/2013/07/22/unity-4-2-has-arrived/&quot; target=&quot;_blank&quot;&gt;4.2&lt;/a&gt;), but I can confirm that it doesn&#39;t make that much difference, especially when it comes to large or complex assets like scenes. We&#39;re using git for our project, and I spent a considerable amount of time setting it up to work as well as it does at the moment. I&#39;ll write a blog post about it at a later date.&lt;br /&gt;
&lt;br /&gt;
Through many months of trial and error, it seems that two people can&#39;t work on a single scene at once - and if you do, you basically have to ignore any merge that takes place and manually apply the changes. Obviously this can get very complex and time consuming, but it&#39;s the only way to do it. Instead, Lew and I have been working on separate scenes or projects; I really can&#39;t imagine what it&#39;s going to be like when we end up putting some proper levels together.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Model and the World Models with You&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I&#39;ve worked directly with some very good designers over the years, and I&#39;ve been very appreciative of the experiences. My creativity comes in the form of architecture of systems and structuring code... most things graphical are quite literally mind-bending to me. I&#39;ve used Photoshop and Illustrator for years, and I know them quite well, but only to manipulate images that already exist; I&#39;ve never been able to create anything from scratch, but I&#39;ve gawped at plenty of designers as they&#39;ve magically created something awesome from literally nothing. Obviously there&#39;s going to be a certain amount of graphical work involved in game development, though I&#39;m not sure how I&#39;m gonna get through it!&lt;br /&gt;
&lt;br /&gt;
Modelling, on the other hand, is something I quite enjoy. I&#39;ve created a few designs over the years for custom built stuff around the house; my console collection cabinet, the BBQ in the back yard, and sound diffusers for my studio, and enjoyed making all of them. The thing is, I&#39;ve only really modelled complex cubes... when it comes to doing anything more sophisticated, I&#39;m pretty much starting from scratch. It&#39;s been challenging, especially having to learn new tools like &lt;a href=&quot;http://www.sketchup.com/&quot; target=&quot;_blank&quot;&gt;SketchUp&lt;/a&gt;, &lt;a href=&quot;http://www.autodesk.co.uk/products/autodesk-3ds-max/overview&quot; target=&quot;_blank&quot;&gt;3DS Max&lt;/a&gt;, and&amp;nbsp;&lt;a href=&quot;http://www.blender.org/&quot; target=&quot;_blank&quot;&gt;Blender&lt;/a&gt;, and all the new terminology and 3D modelling techniques like hierarchies and UV maps. It&#39;s a crazy, new experience, and there&#39;s a hell of a lot to learn.&lt;br /&gt;
&lt;br /&gt;
Then there&#39;s how to actually design models and levels for our game. So far, it&#39;s a lot of trial and error - different export settings, playing with hierarchies and origins, figuring out what we need to model individually and what we can combine inside other models, and how to arrange our meshes. Unity allows you to import entire 3D models into your project, automatically generating things like colliders, and UV lightmaps, seriously reducing the amount of time it takes to get things up and running. The hard part is exporting the model from whatever 3D package you have in a way that makes sense in Unity.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The Sound of Silence&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
These days, good sound design can make or break a game. Even &lt;a href=&quot;http://www.ponggame.org/&quot; target=&quot;_blank&quot;&gt;Pong&lt;/a&gt; had sound effects, but anyone who&#39;s played any modern triple A title will know we&#39;ve come a hell of a long way since then. Unity features a very easy to use audio system that lets you play various formats of audio file directly from disk, and adjust properties like pitch, volume, and distance rolloff. Luckily, my past experience in the recording studio pays off here, as I&#39;ve got an array of tools available to me for both recording and editing. At the moment I&#39;m just finding royalty free samples online, though I&#39;m having to do some minor editing to most of them so they fit in with our game.&lt;br /&gt;
&lt;br /&gt;
A game is a pretty boring place if the items your character is interacting with don&#39;t make a sound. One thing I didn&#39;t think about much before taking this on was that I&#39;d have to think about how every single object will make a number of different noises depending on what you&#39;re doing with it. A gun, for example, requires numerous bullet firing sounds, a reload clip, a dry fire noise, noises for shells hitting the ground and bouncing, then there are bullet impact sounds for different materials, glass shattering, crates breaking, and ricochet noises. It all depends on the level of realism you want to achieve, or the type of game you&#39;re making, but each new sound you add and calibrate properly really makes a difference when you&#39;re play testing.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Hello World&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
If the coming months are anything like the last few, I&#39;ll be spending most of my nights following beginners tutorials on youtube and writing hello world scripts for every new thing I need to accomplish. It makes a refreshing change from writing software for insurance and travel companies, and challenges me on every level. I&#39;m not sure if I&#39;d have managed to get into it if I wasn&#39;t for Unity&#39;s C# support; I think the challenge of learning something like C++, plus all the extras I&#39;ve mentioned above would have been overwhelming. It&#39;s a good move from the guys at Unity.&lt;br /&gt;
&lt;br /&gt;
So, expect my normal blog posts to be interjected with the occasional Unity 3D related ramble... I imagine I&#39;ll be developing this game for a while!&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/2940939596736919103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/2940939596736919103'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2013/07/a-brave-new-world.html' title='A Brave New World'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-293433242585768572</id><published>2013-06-05T11:30:00.000+01:00</published><updated>2013-12-24T16:19:42.191+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type='text'>Intelligent SQL Server REORGANIZE and REBUILD Script</title><content type='html'>I&#39;ve been doing a lot of database analysis recently, and fortunately I&#39;m one of those people that enjoys it. I&#39;m primarily a .Net developer, but I&#39;ve spent many years looking after SQL Server databases, helping out (and even educating) DBAs, writing ETL packages and designing both large and complex databases.&lt;br /&gt;
&lt;br /&gt;
The database in question was in pretty bad shape; missing, unnecessary, and extremely fragmented indexes, missing primary and foreign keys, bad normalisation, and (the main reason I decided to look into it) undesired table locks during ETL operations. It&#39;s a 24/7 system, and live lookups are performed around the clock - data is imported early in the morning (when usage is at a minimum), which is when most of errors occur.&lt;br /&gt;
&lt;br /&gt;
Amongst many other pre-emptive actions I&#39;ve recently performed on the database, I decided to set up regular table index maintenance job to keep queries as quick as possible. Unfortunately the database is SQL Server Standard edition, and with it being a 24/7 system, we had to schedule some downtime to do a REBUILD of the indexes (the vast majority of the indexes on the primary application tables are at 90% or greater fragmentation), but I wanted to try to eliminate, or at least reduce any future downtime.&lt;br /&gt;
&lt;br /&gt;
Some of you will know that an index can be rebuilt (on-line or offline, depending on the version of SQL Server you have installed) or reorganized (which can only be performed on-line). You might also know that you shouldn&#39;t just run these commands willy-nilly, and shouldn&#39;t rebuild or reorganize &lt;b&gt;at all&lt;/b&gt; under certain conditions. &lt;a href=&quot;http://technet.microsoft.com/en-us/library/ms189858.aspx&quot; target=&quot;_blank&quot;&gt;This article&lt;/a&gt; on MSDN provides a decent overview of when you should perform a rebuild or reorganize operation, but I also found quite a bit of evidence out there that says performing a REBUILD or REORGANIZE against small indexes yields no noticeable performance improvement.&lt;br /&gt;
&lt;br /&gt;
Armed with this information, I set out to find an already written table maintenance script, but failed to find anything that was robust enough for my needs. I wanted to be able to specify a number of parameters that determine which indexes are rebuilt, determine if an index can be rebuilt online or not, and perform optional logging.&lt;br /&gt;
&lt;br /&gt;
The script below has been tested on SQL Server 2008 R2 and SQL Server 2012, and although I&#39;m sure it&#39;ll work on previous versions of SQL Server, I would do some testing before running it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;
&lt;span class=&quot;rem&quot;&gt;----------------------------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- Developer:   Chris Sebok&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- Date:        10th May 2013&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;-- Description: A stored procedure that rebuilds or reorganizes indexes intelligently depending on&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;--              the SQL Server version.&lt;/span&gt;
&lt;span class=&quot;rem&quot;&gt;----------------------------------------------------------------------------------------------------&lt;/span&gt;
/*
&lt;span class=&quot;rem&quot;&gt;-- Pre-run server configuration&lt;/span&gt;

&lt;span class=&quot;kwrd&quot;&gt;EXEC&lt;/span&gt; sp_configure &lt;span class=&quot;str&quot;&gt;&#39;show advanced options&#39;&lt;/span&gt;, 1
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;RECONFIGURE&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;EXEC&lt;/span&gt; sp_configure &lt;span class=&quot;str&quot;&gt;&#39;xp_cmdshell&#39;&lt;/span&gt;, 1
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;RECONFIGURE&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;
*/

/*
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @&lt;span class=&quot;kwrd&quot;&gt;Database&lt;/span&gt;                &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(100)  &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @&lt;span class=&quot;kwrd&quot;&gt;Database&lt;/span&gt;                = &lt;span class=&quot;str&quot;&gt;&#39;MyDatabase&#39;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @PageCountThreshold      &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;           &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @PageCountThreshold      = 1000
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @ReorganiseThreshold     &lt;span class=&quot;kwrd&quot;&gt;DECIMAL&lt;/span&gt;(5,2)  &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @ReorganiseThreshold     = 5.00
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @RebuildThreshold        &lt;span class=&quot;kwrd&quot;&gt;DECIMAL&lt;/span&gt;(5,2)  &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @RebuildThreshold        = 30.00
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @Debug                   &lt;span class=&quot;kwrd&quot;&gt;BIT&lt;/span&gt;           &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @Debug                   = 1
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @SafeMode                &lt;span class=&quot;kwrd&quot;&gt;BIT&lt;/span&gt;           &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @SafeMode                = 1
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @DefaultFillFactorIfZero &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;           &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @DefaultFillFactorIfZero = 90
&lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @LogPath                 &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(1000) &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @LogPath                 = &lt;span class=&quot;str&quot;&gt;&#39;D:\logs\mydatabase\&#39;&lt;/span&gt;

&lt;span class=&quot;kwrd&quot;&gt;EXEC&lt;/span&gt; spReindex @&lt;span class=&quot;kwrd&quot;&gt;Database&lt;/span&gt;, @LogPath, @Debug, @SafeMode, @PageCountThreshold, @ReorganiseThreshold, @RebuildThreshold, @DefaultFillFactorIfZero

*/
&lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; OBJECT_ID(&lt;span class=&quot;str&quot;&gt;&#39;spReindex&#39;&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;PROC&lt;/span&gt; spReindex
&lt;span class=&quot;kwrd&quot;&gt;GO&lt;/span&gt;

&lt;span class=&quot;kwrd&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;PROC&lt;/span&gt; spReindex (
    @&lt;span class=&quot;kwrd&quot;&gt;Database&lt;/span&gt;                &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(100),           &lt;span class=&quot;rem&quot;&gt;-- Database to reindex&lt;/span&gt;
    @LogPath                 &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(1000),          &lt;span class=&quot;rem&quot;&gt;-- The path to store log files in. Must be prefixed with a back slash.&lt;/span&gt;
    @Debug                   &lt;span class=&quot;kwrd&quot;&gt;BIT&lt;/span&gt;            = 1,     &lt;span class=&quot;rem&quot;&gt;-- 0 = Index work is carried out. 1 = Index statements are not executed, but everything is logged as normal (for analysis)&lt;/span&gt;
    @SafeMode                &lt;span class=&quot;kwrd&quot;&gt;BIT&lt;/span&gt;            = 1,     &lt;span class=&quot;rem&quot;&gt;-- 0 = Rebuilds indexes regardless of SQL Server version. 1 = Only rebuilds indexes if they can be rebuilt online.&lt;/span&gt;
    @PageCountThreshold      &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;            = 1000,  &lt;span class=&quot;rem&quot;&gt;-- Number of paged in the index before a rebuild / reorganize occurs&lt;/span&gt;
    @ReorganiseThreshold     &lt;span class=&quot;kwrd&quot;&gt;DECIMAL&lt;/span&gt;(5,2)   = 5.00,  &lt;span class=&quot;rem&quot;&gt;-- The lower percentage threshold for a REORGANIZE&lt;/span&gt;
    @RebuildThreshold        &lt;span class=&quot;kwrd&quot;&gt;DECIMAL&lt;/span&gt;(5,2)   = 30.00, &lt;span class=&quot;rem&quot;&gt;-- The lower percentage threshold for a REBUILD&lt;/span&gt;
    @DefaultFillFactorIfZero &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;            = 90     &lt;span class=&quot;rem&quot;&gt;-- The default fillfactor percentage for an index if it&#39;s currently set to 0 (100%)&lt;/span&gt;
)
&lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt;

    &lt;span class=&quot;rem&quot;&gt;-- Validation&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; RTRIM(LTRIM(ISNULL(@&lt;span class=&quot;kwrd&quot;&gt;Database&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&#39;&#39;&lt;/span&gt;))) = &lt;span class=&quot;str&quot;&gt;&#39;&#39;&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, GETDATE(), 113) + &lt;span class=&quot;str&quot;&gt;&#39;: &#39;&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;@Database can not be null or empty.&#39;&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;RETURN&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;

    &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; ISNULL(@ReorganiseThreshold, 0) &amp;gt;= ISNULL(@RebuildThreshold, 0) &lt;span class=&quot;kwrd&quot;&gt;OR&lt;/span&gt; ISNULL(@ReorganiseThreshold, 0) = 0 &lt;span class=&quot;kwrd&quot;&gt;OR&lt;/span&gt; ISNULL(@RebuildThreshold, 0) = 0
        &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, GETDATE(), 113) + &lt;span class=&quot;str&quot;&gt;&#39;: &#39;&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;@ReorganiseThreshold must be less than @RebuildThreshold, and neither can be null or zero.&#39;&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;RETURN&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;

    &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;RIGHT&lt;/span&gt;(@LogPath, 1) != &lt;span class=&quot;str&quot;&gt;&#39;\&#39;&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, GETDATE(), 113) + &lt;span class=&quot;str&quot;&gt;&#39;: &#39;&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;@LogPath must end with a backslash (\), and be a valid path.&#39;&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;RETURN&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;

    &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; DB_ID(@&lt;span class=&quot;kwrd&quot;&gt;Database&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;PRINT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, GETDATE(), 113) + &lt;span class=&quot;str&quot;&gt;&#39;: &#39;&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;@Database (&#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Database&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;) does not exist.&#39;&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;RETURN&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;


    &lt;span class=&quot;rem&quot;&gt;-- Sproc variables&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @OnlineRebuildEnabled &lt;span class=&quot;kwrd&quot;&gt;BIT&lt;/span&gt;             &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @OnlineRebuildEnabled = &lt;span class=&quot;kwrd&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, SERVERPROPERTY(&lt;span class=&quot;str&quot;&gt;&#39;Edition&#39;&lt;/span&gt;)) &lt;span class=&quot;kwrd&quot;&gt;LIKE&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;%Enterprise%&#39;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;THEN&lt;/span&gt; 1 &lt;span class=&quot;kwrd&quot;&gt;ELSE&lt;/span&gt; 0 &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @LogFile              &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(2000)   &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @LogFile              = @LogPath + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEPART(yyyy, GETDATE())) + &lt;span class=&quot;str&quot;&gt;&#39;_&#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;RIGHT&lt;/span&gt;(&lt;span class=&quot;str&quot;&gt;&#39;00&#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, DATEPART(MM, GETDATE())), 2) + &lt;span class=&quot;str&quot;&gt;&#39;_spReindex.log&#39;&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @StartTime            DATETIME
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @EndTime              DATETIME
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @Difference           &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @&lt;span class=&quot;kwrd&quot;&gt;Prefix&lt;/span&gt;               &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(500)
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @Instruction          &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(8000)
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @IndexStatement       NVARCHAR(4000)

    &lt;span class=&quot;rem&quot;&gt;-- Cursor variables&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @&lt;span class=&quot;kwrd&quot;&gt;Table&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(200), @&lt;span class=&quot;kwrd&quot;&gt;Schema&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(200)
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; @IndexName &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(500), @Fragmentation &lt;span class=&quot;kwrd&quot;&gt;DECIMAL&lt;/span&gt;(5, 2), @&lt;span class=&quot;kwrd&quot;&gt;Fillfactor&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @Pages &lt;span class=&quot;kwrd&quot;&gt;INT&lt;/span&gt;, @Type &lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;(30)


    &lt;span class=&quot;rem&quot;&gt;-- Manage log directory&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @Instruction = &lt;span class=&quot;str&quot;&gt;&#39;md &#39;&lt;/span&gt; + @LogPath
    &lt;span class=&quot;kwrd&quot;&gt;EXEC&lt;/span&gt; master..xp_cmdshell @Instruction, &lt;span class=&quot;str&quot;&gt;&#39;NO_OUTPUT&#39;&lt;/span&gt;;


    &lt;span class=&quot;rem&quot;&gt;-- Start cursor operations&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; cTables &lt;span class=&quot;kwrd&quot;&gt;CURSOR&lt;/span&gt; READ_ONLY FAST_FORWARD &lt;span class=&quot;kwrd&quot;&gt;FOR&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
            s.name &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; SchemaName,
            t.name &lt;span class=&quot;kwrd&quot;&gt;AS&lt;/span&gt; TableName
        &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; sys.tables            (nolock) t
        &lt;span class=&quot;kwrd&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;JOIN&lt;/span&gt; sys.schemas    (nolock) s &lt;span class=&quot;kwrd&quot;&gt;ON&lt;/span&gt; t.schema_id = s.schema_id
        &lt;span class=&quot;kwrd&quot;&gt;WHERE&lt;/span&gt; t.[type] = &lt;span class=&quot;str&quot;&gt;&#39;u&#39;&lt;/span&gt;

    &lt;span class=&quot;kwrd&quot;&gt;OPEN&lt;/span&gt; cTables

    &lt;span class=&quot;kwrd&quot;&gt;FETCH&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NEXT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; cTables &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; @&lt;span class=&quot;kwrd&quot;&gt;Schema&lt;/span&gt;, @&lt;span class=&quot;kwrd&quot;&gt;Table&lt;/span&gt;

    &lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; &lt;span class=&quot;preproc&quot;&gt;@@FETCH_STATUS&lt;/span&gt; = 0
        &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
            
            &lt;span class=&quot;kwrd&quot;&gt;DECLARE&lt;/span&gt; cIndexes &lt;span class=&quot;kwrd&quot;&gt;CURSOR&lt;/span&gt; READ_ONLY FAST_FORWARD &lt;span class=&quot;kwrd&quot;&gt;FOR&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;SELECT&lt;/span&gt;
                    I.name,
                    ROUND(S.avg_fragmentation_in_percent, 2),
                    i.fill_factor,
                    s.page_count,
                    i.type_desc
                &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; sys.dm_db_index_physical_stats (DB_ID(@&lt;span class=&quot;kwrd&quot;&gt;Database&lt;/span&gt;), OBJECT_ID(@&lt;span class=&quot;kwrd&quot;&gt;Table&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt;) S
                &lt;span class=&quot;kwrd&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;JOIN&lt;/span&gt; sys.indexes I (nolock) &lt;span class=&quot;kwrd&quot;&gt;ON&lt;/span&gt; (
                    S.object_id        = I.object_id
                    &lt;span class=&quot;kwrd&quot;&gt;AND&lt;/span&gt; S.index_id    = I.index_id
                )
                &lt;span class=&quot;kwrd&quot;&gt;WHERE&lt;/span&gt; name &lt;span class=&quot;kwrd&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;rem&quot;&gt;-- Ignore heap indexes&lt;/span&gt;

            &lt;span class=&quot;kwrd&quot;&gt;OPEN&lt;/span&gt; cIndexes

            &lt;span class=&quot;kwrd&quot;&gt;FETCH&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NEXT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; cIndexes &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; @IndexName, @Fragmentation, @&lt;span class=&quot;kwrd&quot;&gt;Fillfactor&lt;/span&gt;, @Pages, @Type

            &lt;span class=&quot;kwrd&quot;&gt;WHILE&lt;/span&gt; &lt;span class=&quot;preproc&quot;&gt;@@FETCH_STATUS&lt;/span&gt; = 0
                &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
                    &lt;span class=&quot;rem&quot;&gt;-- Reset index statement&lt;/span&gt;
                    &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @IndexStatement = &lt;span class=&quot;str&quot;&gt;&#39;&#39;&lt;/span&gt;
                    
                    &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @&lt;span class=&quot;kwrd&quot;&gt;Prefix&lt;/span&gt; = @&lt;span class=&quot;kwrd&quot;&gt;Database&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;.&#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Schema&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;.&#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Table&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;.&#39;&lt;/span&gt; + @IndexName

                    &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @Instruction = &lt;span class=&quot;str&quot;&gt;&#39;echo &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, GETDATE(), 113) + &lt;span class=&quot;str&quot;&gt;&#39;: &#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Prefix&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;:: Index info: Type = &#39;&lt;/span&gt; + @Type + &lt;span class=&quot;str&quot;&gt;&#39;, No. of Pages = &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, @Pages) + &lt;span class=&quot;str&quot;&gt;&#39;, Fragmentation = &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, @Fragmentation) + &lt;span class=&quot;str&quot;&gt;&#39;%, Fill Factor = &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, @&lt;span class=&quot;kwrd&quot;&gt;Fillfactor&lt;/span&gt;) + &lt;span class=&quot;str&quot;&gt;&#39;%) &amp;gt;&amp;gt; &#39;&lt;/span&gt; + @LogFile
                    &lt;span class=&quot;kwrd&quot;&gt;EXEC&lt;/span&gt; master..xp_cmdshell @Instruction, &lt;span class=&quot;str&quot;&gt;&#39;NO_OUTPUT&#39;&lt;/span&gt;;

                    &lt;span class=&quot;rem&quot;&gt;-- Make sure the index should be rebuilt or reorganized&lt;/span&gt;
                    &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; @Pages &amp;gt;= @PageCountThreshold &lt;span class=&quot;kwrd&quot;&gt;AND&lt;/span&gt; @Fragmentation &amp;gt;= @ReorganiseThreshold
                        &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
                            &lt;span class=&quot;rem&quot;&gt;-- Rebuild or reorganize?&lt;/span&gt;
                            &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; @Fragmentation &amp;gt;= @RebuildThreshold
                                &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
                                    &lt;span class=&quot;rem&quot;&gt;-- REBUILD&lt;/span&gt;
                                    &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; @OnlineRebuildEnabled = 1 &lt;span class=&quot;kwrd&quot;&gt;OR&lt;/span&gt; @SafeMode = 0 &lt;span class=&quot;kwrd&quot;&gt;OR&lt;/span&gt; (@SafeMode = 1 &lt;span class=&quot;kwrd&quot;&gt;AND&lt;/span&gt; @OnlineRebuildEnabled = 1)
                                        &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
                                            &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @IndexStatement = &lt;span class=&quot;str&quot;&gt;&#39;ALTER INDEX &#39;&lt;/span&gt; + @IndexName + &lt;span class=&quot;str&quot;&gt;&#39; ON &#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Schema&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;.&#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Table&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39; REBUILD WITH (&#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;WHEN&lt;/span&gt; @OnlineRebuildEnabled = 1 &lt;span class=&quot;kwrd&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;ONLINE = ON, &#39;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;ELSE&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&#39;&#39;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;FILLFACTOR = &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;CASE&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;WHEN&lt;/span&gt; @&lt;span class=&quot;kwrd&quot;&gt;Fillfactor&lt;/span&gt; = 0 &lt;span class=&quot;kwrd&quot;&gt;THEN&lt;/span&gt; @DefaultFillFactorIfZero &lt;span class=&quot;kwrd&quot;&gt;ELSE&lt;/span&gt; @&lt;span class=&quot;kwrd&quot;&gt;Fillfactor&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;) +&lt;span class=&quot;str&quot;&gt;&#39;);&#39;&lt;/span&gt;
                                        &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
                                    &lt;span class=&quot;kwrd&quot;&gt;ELSE&lt;/span&gt;
                                        &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
                                            &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @Instruction = &lt;span class=&quot;str&quot;&gt;&#39;echo &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, GETDATE(), 113) + &lt;span class=&quot;str&quot;&gt;&#39;: &#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Prefix&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;; unable to rebuild index ONLINE, SQL Enterprise required, or server must be taken offline. &amp;gt;&amp;gt; &#39;&lt;/span&gt; + @LogFile
                                            &lt;span class=&quot;kwrd&quot;&gt;EXEC&lt;/span&gt; master..xp_cmdshell @Instruction, &lt;span class=&quot;str&quot;&gt;&#39;NO_OUTPUT&#39;&lt;/span&gt;;
                                            &lt;span class=&quot;kwrd&quot;&gt;GOTO&lt;/span&gt; FetchNext &lt;span class=&quot;rem&quot;&gt;-- Move to next index&lt;/span&gt;
                                        &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
                                &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
                            &lt;span class=&quot;kwrd&quot;&gt;ELSE&lt;/span&gt;
                                &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
                                    &lt;span class=&quot;rem&quot;&gt;-- REORGANIZE&lt;/span&gt;
                                    &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @IndexStatement = &lt;span class=&quot;str&quot;&gt;&#39;ALTER INDEX &#39;&lt;/span&gt; + @IndexName + &lt;span class=&quot;str&quot;&gt;&#39; ON &#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Schema&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;.&#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Table&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39; REORGANIZE;&#39;&lt;/span&gt;
                                &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;

                            &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @Instruction = &lt;span class=&quot;str&quot;&gt;&#39;echo &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, GETDATE(), 113) + &lt;span class=&quot;str&quot;&gt;&#39;: &#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Prefix&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;; Running: &#39;&lt;/span&gt; + @IndexStatement + &lt;span class=&quot;str&quot;&gt;&#39; &amp;gt;&amp;gt; &#39;&lt;/span&gt; + @LogFile
                            &lt;span class=&quot;kwrd&quot;&gt;EXEC&lt;/span&gt; master..xp_cmdshell @Instruction, &lt;span class=&quot;str&quot;&gt;&#39;NO_OUTPUT&#39;&lt;/span&gt;;

                            &lt;span class=&quot;rem&quot;&gt;-- Perform reindex and time it&lt;/span&gt;
                            &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @StartTime = GETDATE()

                            &lt;span class=&quot;kwrd&quot;&gt;IF&lt;/span&gt; @Debug = 0
                                &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
                                    &lt;span class=&quot;kwrd&quot;&gt;EXEC&lt;/span&gt; sp_executesql @IndexStatement
                                &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;

                            &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @EndTime = GETDATE()

                            &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @Difference = DATEDIFF(ss, @StartTime, @EndTime)

                            &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @Instruction = &lt;span class=&quot;str&quot;&gt;&#39;echo &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, GETDATE(), 113) + &lt;span class=&quot;str&quot;&gt;&#39;: &#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Prefix&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;; Finished. Time elapsed &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, @Difference) + &lt;span class=&quot;str&quot;&gt;&#39; seconds (&#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, @Difference / 60) + &lt;span class=&quot;str&quot;&gt;&#39; minutes) &amp;gt;&amp;gt; &#39;&lt;/span&gt; + @LogFile
                            &lt;span class=&quot;kwrd&quot;&gt;EXEC&lt;/span&gt; master..xp_cmdshell @Instruction, &lt;span class=&quot;str&quot;&gt;&#39;NO_OUTPUT&#39;&lt;/span&gt;;
                        &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
                    &lt;span class=&quot;kwrd&quot;&gt;ELSE&lt;/span&gt;
                        &lt;span class=&quot;kwrd&quot;&gt;BEGIN&lt;/span&gt;
                            &lt;span class=&quot;rem&quot;&gt;-- No need to index&lt;/span&gt;
                            &lt;span class=&quot;kwrd&quot;&gt;SET&lt;/span&gt; @Instruction = &lt;span class=&quot;str&quot;&gt;&#39;echo &#39;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;CONVERT&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;VARCHAR&lt;/span&gt;, GETDATE(), 113) + &lt;span class=&quot;str&quot;&gt;&#39;: &#39;&lt;/span&gt; + @&lt;span class=&quot;kwrd&quot;&gt;Prefix&lt;/span&gt; + &lt;span class=&quot;str&quot;&gt;&#39;; Index does not require reorganizing or rebuilding. &amp;gt;&amp;gt; &#39;&lt;/span&gt; + @LogFile
                            &lt;span class=&quot;kwrd&quot;&gt;EXEC&lt;/span&gt; master..xp_cmdshell @Instruction, &lt;span class=&quot;str&quot;&gt;&#39;NO_OUTPUT&#39;&lt;/span&gt;;
                        &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;
FetchNext:
                    &lt;span class=&quot;kwrd&quot;&gt;FETCH&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NEXT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; cIndexes &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; @IndexName, @Fragmentation, @&lt;span class=&quot;kwrd&quot;&gt;Fillfactor&lt;/span&gt;, @Pages, @Type
                &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;

            &lt;span class=&quot;kwrd&quot;&gt;CLOSE&lt;/span&gt; cIndexes
            &lt;span class=&quot;kwrd&quot;&gt;DEALLOCATE&lt;/span&gt; cIndexes

            &lt;span class=&quot;kwrd&quot;&gt;FETCH&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;NEXT&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;FROM&lt;/span&gt; cTables &lt;span class=&quot;kwrd&quot;&gt;INTO&lt;/span&gt; @&lt;span class=&quot;kwrd&quot;&gt;Schema&lt;/span&gt;, @&lt;span class=&quot;kwrd&quot;&gt;Table&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;END&lt;/span&gt;

    &lt;span class=&quot;kwrd&quot;&gt;CLOSE&lt;/span&gt; cTables
    &lt;span class=&quot;kwrd&quot;&gt;DEALLOCATE&lt;/span&gt; cTables
GO&lt;/pre&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/293433242585768572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/293433242585768572'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2013/06/intelligent-sql-server-reorganize-and.html' title='Intelligent SQL Server REORGANIZE and REBUILD Script'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-893667916480637229</id><published>2013-06-05T10:25:00.001+01:00</published><updated>2013-06-05T10:41:43.558+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="JQuery"/><category scheme="http://www.blogger.com/atom/ns#" term="MVC"/><title type='text'>Handling uploads with MVC4, JQuery, Plupload and CKEditor</title><content type='html'>I spent a considerable amount of time trying to get MVC to work nicely with various file uploaders while I was writing&amp;nbsp;&lt;a href=&quot;http://www.rustyshark.com/&quot; target=&quot;_blank&quot;&gt;RustyShark&lt;/a&gt;, and I have to admit it&#39;s been pretty frustrating at times. On the plus side, it&#39;s taught me a lot about how Microsoft MVC works behind the scenes, and allowed me to play with quite a few different uploading tools that&#39;re out there.&lt;br /&gt;
&lt;br /&gt;
My upload page on RustyShark has quite a complex model - each review is related to multiple Formats (PS3, 360, DVD, Blu Ray etc), each review / format combination can have multiple images associated with it, and each image has additional meta data attached, such as a caption and an upload date. The upload form is created using a combination of Editor Templates, JQuery and AJAX. I will be stripping down any examples to their bare bones to make things a little clearer.&lt;br /&gt;
&lt;br /&gt;
This article assumes you are familiar with MVC fundamentals such as creating controllers, views and models within Visual Studio 2010 or later, you understand the Razor view engine syntax, you know how to use MVC Editor Templates, and you are fluent with the .Net Framework v4.0 or later. All code is provided as an example only, and is untested.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Input type=&quot;file&quot;&lt;/h3&gt;
&lt;br /&gt;
To start, let&#39;s look at a standard &amp;lt;input type=&quot;file&quot; /&amp;gt; upload. First, set up a controller:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MyController : Controller {
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ActionResult UploadImage() {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; View();
    }
}&lt;/pre&gt;
&lt;br /&gt;
Then create a view for the controller called &quot;UploadImage.cshtml&quot; that will contain the form mark-up.&lt;br /&gt;
&lt;br /&gt;
When it comes to building your form, first and foremost (and something quite a few people forget) is the encoding type of the form submitting the file data:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;@&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt;(Html.BeginForm(&lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;, FormMethod.Post, &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; { enctype = &lt;span class=&quot;str&quot;&gt;&quot;multipart/form-data&quot;&lt;/span&gt; })) {
    &amp;lt;input type=&lt;span class=&quot;str&quot;&gt;&quot;file&quot;&lt;/span&gt; id=&lt;span class=&quot;str&quot;&gt;&quot;testingupload&quot;&lt;/span&gt; name=&lt;span class=&quot;str&quot;&gt;&quot;testingupload&quot;&lt;/span&gt;/&amp;gt;
    &amp;lt;input type=&lt;span class=&quot;str&quot;&gt;&quot;submit&quot;&lt;/span&gt; value=&lt;span class=&quot;str&quot;&gt;&quot;Upload image&quot;&lt;/span&gt;/&amp;gt;
}&lt;/pre&gt;
&lt;br /&gt;
The vast majority of the time in MVC you&#39;ll be using Html.BeginForm() without any parameters - remember, all a HTML helper does is output HTML, and most helpers have the &quot;htmlAttributes&quot; parameter to catch any attributes that aren&#39;t catered for by defined arguments. Here, we&#39;ve added the &quot;enctype&quot; &amp;lt;form&amp;gt; attribute and set it so we can upload binary data when the form is submitted.&lt;br /&gt;
&lt;br /&gt;
By default, when a form action isn&#39;t set, HTML forms POST to the current page. You don&#39;t need to set the &quot;action&quot; or &quot;controller&quot; parameters unless you&#39;re posting to a different location (which I only really use in shared partials or special AJAX forms anyway), hence why the first two parameters in my example are &quot;null&quot;.&lt;br /&gt;
&lt;br /&gt;
Note that the &quot;id&quot; attribute of the file input is not required for this example. However, it is recommended that you give all form elements an ID, to identify them as a &lt;b&gt;unique&lt;/b&gt; element in the HTML DOM. The &quot;name&quot; attribute is the important thing here, though this does &lt;b&gt;not&lt;/b&gt; need to be unique. You can give multiple form elements the same name so they&#39;re posted to the server as a collection, but you already knew that, right? :) More on that later.&lt;br /&gt;
&lt;br /&gt;
You now have a page that should compile, but you&#39;ll get an error when you click the submit button as there&#39;s no code to handle the postback. Add the following to your controller:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;[HttpPost]
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ActionResult UploadImage(HttpPostedFileBase testingupload) {
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; View();
}&lt;/pre&gt;
&lt;br /&gt;
As with all form posting in MVC, the HttpPost action filter restricts the action so that it only accepts the POST verb from your browser. The only other notable thing here is the single parameter - HttpPostedFileBase, and its name, &quot;testingupload&quot;, which should always match the file input&#39;s &quot;name&quot; attribute. This (along with the parameter&#39;s type) allows MVC to automagically map form values to method parameters. Neat!&lt;br /&gt;
&lt;br /&gt;
Now, when you select an image to upload, and click the submit button, the &quot;testingupload&quot; parameter should be populated with all the details you need for the file you&#39;ve selected. From there you can do what you want - there&#39;s a &quot;SaveAs&quot; method on the HttpPostedFileBase object that allows you to easily save the file to disk, though you&#39;ll usually want to do a little bit more than just that, like resize an image or notify someone the upload has completed.&lt;br /&gt;
&lt;br /&gt;
That&#39;s a simple file upload example, and as you can see there&#39;s nothing to it; but only really much use if you plan to upload a single file.&lt;br /&gt;
&lt;br /&gt;
There&#39;s one last thing I need to mention before I move on - you can (and should, in this developer&#39;s opinion) implement your file input in a view model as you would any other form property, which makes the whole process a lot cleaner and more robust. Below is a sample model:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MyModel {
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; EntityID { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;    [Display(Name = &lt;span class=&quot;str&quot;&gt;&quot;Select the image you would like to upload.&quot;&lt;/span&gt;)]
    [Required(AllowEmptyStrings = &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;, ErrorMessage = &lt;span class=&quot;str&quot;&gt;&quot;Please select the image to upload.&quot;&lt;/span&gt;)]
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; HttpPostedFileBase ImageToUpload { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
}&lt;/pre&gt;
&lt;br /&gt;
And the corresponding view:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;@model MyModel
@&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt;(Html.BeginForm(&lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;, FormMethod.Post, &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; { enctype = &lt;span class=&quot;str&quot;&gt;&quot;multipart/form-data&quot;&lt;/span&gt; })) {
    @Html.HiddenFor(m =&amp;gt; m.EntityID)
    &amp;lt;div&amp;gt;
        &amp;lt;fieldset&amp;gt;
            &amp;lt;legend&amp;gt;Upload my image&amp;lt;/legend&amp;gt;
            &amp;lt;div &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot;&gt;&quot;formField&quot;&lt;/span&gt;&amp;gt;
                &amp;lt;div &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot;&gt;&quot;label&quot;&lt;/span&gt;&amp;gt;
                    @Html.LabelFor(m =&amp;gt; m.ImageToUpload)
                &amp;lt;/div&amp;gt;
                &amp;lt;div &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;str&quot;&gt;&quot;input&quot;&lt;/span&gt;&amp;gt;
                    @Html.FileUploadFor(m =&amp;gt; m.ImageToUpload)
                &amp;lt;/div&amp;gt;
                @Html.ValidationMessageFor(m =&amp;gt; m.ImageToUpload)
            &amp;lt;/div&amp;gt;
            &amp;lt;input type=&lt;span class=&quot;str&quot;&gt;&quot;submit&quot;&lt;/span&gt; value=&lt;span class=&quot;str&quot;&gt;&quot;Upload!&quot;&lt;/span&gt;/&amp;gt;
        &amp;lt;/fieldset&amp;gt;
    &amp;lt;/div&amp;gt;
}&lt;/pre&gt;
&lt;br /&gt;
MVC does not provide a helper for file upload inputs. The @Html.FileUploadFor() is a custom helper I&#39;ve written that allows you to bind to your model, and it looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; MvcHtmlString FileUploadFor&amp;lt;TModel, TValue&amp;gt;(&lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; HtmlHelper&amp;lt;TModel&amp;gt; helper, Expression&amp;lt;Func&amp;lt;TModel, TValue&amp;gt;&amp;gt; expression, &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; multiple = &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;) {
    &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; props;
    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(multiple) {
        props = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; {
            type = &lt;span class=&quot;str&quot;&gt;&quot;file&quot;&lt;/span&gt;,
            multiple = &lt;span class=&quot;str&quot;&gt;&quot;multiple&quot;&lt;/span&gt;,
            @&lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; = &lt;span class=&quot;str&quot;&gt;&quot;file&quot;&lt;/span&gt;
        };
    } &lt;span class=&quot;kwrd&quot;&gt;else&lt;/span&gt; {
        props = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; {
            type = &lt;span class=&quot;str&quot;&gt;&quot;file&quot;&lt;/span&gt;,
            @&lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; = &lt;span class=&quot;str&quot;&gt;&quot;file&quot;&lt;/span&gt;
        };
    }
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; helper.TextBoxFor(expression, props);
}&lt;/pre&gt;
&lt;br /&gt;
Discerning readers will have noticed that I&#39;ve implemented the &quot;multiple&quot; attribute too... more on that later.&lt;br /&gt;
&lt;br /&gt;
Unfortunately, without using some crazy reflection code, I don&#39;t think I can avoid using the if-else statement (please, please, &lt;i&gt;please&lt;/i&gt; tell me if I&#39;m wrong!). I usually prefer ternary operators for this kind of thing, but it&#39;s not possible with anonymous objects.&lt;br /&gt;
&lt;br /&gt;
So, after you start using a strongly-typed view model, your POST controller method would look like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;[HttpPost]
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ActionResult UploadImage(MyModel model) {
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; image = model.ImageToUpload;
    &lt;span class=&quot;rem&quot;&gt;// TODO: Do something with image&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; RedirectToAction(&lt;span class=&quot;str&quot;&gt;&quot;UploadImage&quot;&lt;/span&gt;);
}&lt;/pre&gt;
&lt;br /&gt;
The above described method forms a solid basis for understanding how any of the other file upload tools work, so commit it to memory and get ready to do some serious configuration...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;JQuery Uploadify&lt;/h3&gt;
&lt;br /&gt;
I used JQuery &lt;a href=&quot;http://www.uploadify.com/&quot; target=&quot;_blank&quot;&gt;uploadify&lt;/a&gt; for the first release of RustyShark, but very quickly realised it couldn&#39;t do everything I wanted, and sometimes just stoped dead when uploading a lot of files or using multiple uploaders on one page. I also had a trouble manipulating the generated HTML elements and attaching to various events. During my development phase, a new version was released which - whilst much better - completely broke everything I&#39;d already done; for that reason, I&#39;m going to outline a number of gotchas, but not actually post any plugin code (I have since stripped it out, and I don&#39;t have the energy to rewrite it here).&lt;br /&gt;
&lt;br /&gt;
My Uploadify implementation was sat in a control panel, behind .Net Forms Authentication. This created a security issue, which took me a good while to pin down; I was receiving a 403 when posting the image to the controller, which made little sense as I was logged in and all other form posts were working fine. It turned out that it was the flash object that Uploadify implements that didn&#39;t have the access, because the ASPNET Session cookie wasn&#39;t passed through on the form post. To rectify it, I needed to include the ASPNET session / cookie information in the form post manually, and write some code to create the ASPNET session cookies at the Application_BeginRequest() stage. In short, it was a right ball-ache.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;PLUpload&lt;/h3&gt;
&lt;br /&gt;
After my catastrophe with Uploadify, I tried out a few more JQuery uploaders (and even experimented&amp;nbsp;with writing my own), finally settling on&amp;nbsp;&lt;a href=&quot;http://www.plupload.com/&quot; target=&quot;_blank&quot;&gt;PLUpload&lt;/a&gt;. Whilst it has it&#39;s own little issues, I actually found it to be a lot more robust and reliable than any of the other plugins I tried. Again, I spent minimal time on customising the look and feel, but I&#39;m confident I could integrate it in to my site completely with a few hours of styling.&lt;br /&gt;
&lt;br /&gt;
PLUpload was particularly appealing because it renders different implementations of itself based upon the user&#39;s browser capabilities, and supports multi-file uploads out of the box. Although I haven&#39;t tested it in a great amount of detail, you can implement browserplus, google gears, html5 or js - which means it&#39;s compatible with a wide range of browsers. It also offers an easy way to delete any accidentally uploaded items on the same screen, and lets you use AJAX to perform all operations.&lt;br /&gt;
&lt;br /&gt;
The implementation I went with is way to complex to copy + paste here, so yet again I will break it down to the fundamentals to make it&#39;s use a bit clearer. My actual implementation uses both the input type=&quot;file&quot; example above, plus it iterates though a custom object (IEnumerable&amp;lt;ImageModel&amp;gt;), rendering the PLUpload control for each item. Below, I&#39;ll just show you a single PLUpload control, which is all handled with AJAX calls to one of my MVC controllers.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Model&lt;/b&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;namespace&lt;/span&gt; Upload {
 &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ImageModel {
  &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; UniqueId { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }

  [Display(Name = &lt;span class=&quot;str&quot;&gt;&quot;Select any images related to this format.&quot;&lt;/span&gt;)]
  &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; PLUploadPlaceholder { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
 }
}&lt;/pre&gt;
&lt;br /&gt;
The &quot;PLUploadPlaceholder&quot; property above exists only to allow us to use MVC helpers to render the HTML, and use the DataAnnotation attributes to provide metadata to the view. My model is considerably more complex than this, so it made total sense to put this little bit of extra effort in, though you could easily get away with omitting the model entirely and rendering the PLUpload HTML manually. The UniqueId property is used to distinguish between each PLUpload control. Mine comes from a database.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt; &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; UploadingImageModel {
  &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; UniqueId { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
  &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; HttpPostedFileBase file { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
  &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; name { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
 }&lt;/pre&gt;
&lt;br /&gt;
The above class is used for the upload request. &quot;file&quot; and &quot;name&quot; are posted automatically from PLUpload, whereas &quot;UniqueID&quot; is set in the JavaScript during each upload.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;View&lt;/b&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;@model ImageModel
&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;plUploadContainer&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
 @Html.Hidden(&quot;AUTHID&quot;, Request.Cookies[FormsAuthentication.FormsCookieName] != null ? Request.Cookies[FormsAuthentication.FormsCookieName].Value : string.Empty)
 @Html.Hidden(&quot;ASPSESSID&quot;, Session.SessionID)
 @Html.HiddenFor(m =&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt; m.UniqueId)
 &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;fieldset&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;legend&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Upload Your Files&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;legend&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt; 
  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;formField&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    @Html.LabelFor(m =&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt; m.PLUploadPlaceholder)
   &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;input&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;file&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
     &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;id&lt;/span&gt;=&quot;@&lt;span class=&quot;attr&quot;&gt;Html&lt;/span&gt;.&lt;span class=&quot;attr&quot;&gt;ClientIDFor&lt;/span&gt;(&lt;span class=&quot;attr&quot;&gt;m&lt;/span&gt; =&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt; m.PLUploadPlaceholder)&quot; title=&quot;@Html.ClientNameFor(m =&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt; m.PLUploadPlaceholder)&quot;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;fieldset&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
The above View is actually a modified version of the Editor Template I use within my view model structure (I use @Html.EditorFor() to render each item of the IEnumerable&amp;lt;ImageModel&amp;gt; in my parent view model), but it serves perfectly well as the view if you only want one PLUpload control.&lt;br /&gt;
&lt;br /&gt;
Secondly, notice that the UniqueId property is being written out to a hidden form control. We will use JQuery traversal to retrieve that Id, and send it as a POST parameter to the server.&lt;br /&gt;
&lt;br /&gt;
Thirdly, the other two hidden fields AUTHID and ASPSESSID are used to get around a flash authentication issue I was running into. In hindsight, I really should have created some HTML helpers for these fields, as they expose too much logic to the view. Flash based uploaders do not forward ASP.Net session information to the URLs they send their requests to (the requests are anonymous and probably create a new session), so when you&#39;re doing this behind Forms Authentication, you have to mimic this behaviour yourself. To get this working, you will also need to put the following code into your Global.asax file:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Application_BeginRequest(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; sender, EventArgs e) {
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; ctx = HttpContext.Current;

    &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt; {
        &lt;span class=&quot;kwrd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; sessionParamName = &lt;span class=&quot;str&quot;&gt;&quot;ASPSESSID&quot;&lt;/span&gt;;
        &lt;span class=&quot;kwrd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; sessionCookieName = &lt;span class=&quot;str&quot;&gt;&quot;ASP.NET_SessionId&quot;&lt;/span&gt;;

        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(ctx.Request.Form[sessionParamName] != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) {
            UpdateCookie(sessionCookieName, ctx.Request.Form[sessionParamName]);
        } &lt;span class=&quot;kwrd&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(ctx.Request.QueryString[sessionParamName] != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) {
            UpdateCookie(sessionCookieName, ctx.Request.QueryString[sessionParamName]);
        }
    } &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt;(Exception ex) {
        // Do something with the exception
    }

    &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt; {
        &lt;span class=&quot;kwrd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; authParamName = &lt;span class=&quot;str&quot;&gt;&quot;AUTHID&quot;&lt;/span&gt;;
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; authCookieName = FormsAuthentication.FormsCookieName;

        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(ctx.Request.Form[authParamName] != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) {
            UpdateCookie(authCookieName, ctx.Request.Form[authParamName]);
        } &lt;span class=&quot;kwrd&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(ctx.Request.QueryString[authParamName] != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) {
            UpdateCookie(authCookieName, ctx.Request.QueryString[authParamName]);
        }
    } &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt;(Exception ex) {
        // Do something with the excetion
    }
}

&lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; UpdateCookie(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; name, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; value) {
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; cookie = HttpContext.Current.Request.Cookies.Get(name) ?? &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; HttpCookie(name);
    cookie.Value = value;
    HttpContext.Current.Request.Cookies.Set(cookie);
}&lt;/pre&gt;
&lt;br /&gt;
The last thing to mention in the view is the two helper methods, @Html.ClientIDFor() and @Html.ClientNameFor(). The code for these is below, and basically allow me to use property meta data for rendering custom controls, debugging or simply displaying the data to the user. Here, I&#39;m using it to render a &amp;lt;div&amp;gt; with a unique id that we can replace with a PLUpload plugin.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;  &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; MvcHtmlString ClientIDFor&amp;lt;TModel, TProperty&amp;gt;(&lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; HtmlHelper&amp;lt;TModel&amp;gt; htmlHelper, Expression&amp;lt;Func&amp;lt;TModel, TProperty&amp;gt;&amp;gt; expression) {
   &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; MvcHtmlString.Create(
    htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(
     ExpressionHelper.GetExpressionText(expression)));
  }

  &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; MvcHtmlString ClientNameFor&amp;lt;TModel, TProperty&amp;gt;(&lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; HtmlHelper&amp;lt;TModel&amp;gt; htmlHelper,Expression&amp;lt;Func&amp;lt;TModel, TProperty&amp;gt;&amp;gt; expression) {
   &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; MvcHtmlString.Create(
    htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(
     ExpressionHelper.GetExpressionText(expression)));
  }&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Controller&lt;/b&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; UploadController: Controller {
  [HttpPost]
  &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; JsonResult UploadImage(UploadingImageModel model) {
   &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (model.file != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) {
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; uploadedImageResult = MyService.UploadMyImage(model);
    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!relatedImageResult.Success) {
     &lt;span class=&quot;rem&quot;&gt;// Throw exception so javascript can handle it&lt;/span&gt;
     &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Exception(relatedImageResult.ErrorMessage);
    }
    &lt;span class=&quot;rem&quot;&gt;// Return object as Json string&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; Json(uploadedImageResult);
   }
   &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ArgumentException(&lt;span class=&quot;str&quot;&gt;&quot;&#39;file&#39; is null&quot;&lt;/span&gt;);
  }

  [HttpPost]
  &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; JsonResult DeleteImage(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; imageId) {
   &lt;span class=&quot;rem&quot;&gt;// Try to delete the image&lt;/span&gt;
   &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; deletedImageResult = MyService.DeleteMyImage(imageId);
   &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!deletedImageResult.Success) {
    &lt;span class=&quot;rem&quot;&gt;// Throw exception so javascript can handle it&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Exception(deletedImageResult.ErrorMessage);
   }
   &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; Json(deletedImageResult);
  }
}&lt;/pre&gt;
&lt;br /&gt;
These two action methods are called via AJAX to perform an individual upload and delete of each image. MyService is a business component that deals with the complex logic for each method. However, the details of this are out of scope in this post.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;JQuery&lt;/b&gt;
&lt;br /&gt;
&lt;br /&gt;
The JQuery required to get PLUpload working isn&#39;t very complicated (assuming you&#39;ve installed it correctly and referenced the correct files), so I&#39;ll just annotate the code itself below:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;$(document).ready(function () {
    &lt;span class=&quot;rem&quot;&gt;// Used to retrieve the correct uploader for the current ajax request.&lt;/span&gt;
    function getUploader(file) {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; $(&lt;span class=&quot;str&quot;&gt;&quot;#&quot;&lt;/span&gt; + file.id).parents(&lt;span class=&quot;str&quot;&gt;&#39;div[id$=&quot;PLUploadPlaceholder&quot;]&#39;&lt;/span&gt;);
    }

    &lt;span class=&quot;rem&quot;&gt;// Get all uploaders on the page&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; uploaders = $(&lt;span class=&quot;str&quot;&gt;&#39;div[id$=&quot;PLUploadPlaceholder&quot;]&#39;&lt;/span&gt;);

    &lt;span class=&quot;rem&quot;&gt;// Apply PLUpload to each of the above DIVs&lt;/span&gt;
    uploaders.plupload({
        &lt;span class=&quot;rem&quot;&gt;// Setting details available here: http://www.plupload.com/documentation.php&lt;/span&gt;
        runtimes: &lt;span class=&quot;str&quot;&gt;&#39;html5,flash,browserplus&#39;&lt;/span&gt;,
        flash_swf_url: &lt;span class=&quot;str&quot;&gt;&#39;/res/img/l/u/plupload.flash.swf&#39;&lt;/span&gt;,
        url: &lt;span class=&quot;str&quot;&gt;&#39;/Upload/UploadImage/&#39;&lt;/span&gt;, &lt;span class=&quot;rem&quot;&gt;// Determines the URL to POST each upload to.&lt;/span&gt;
        max_file_size: &lt;span class=&quot;str&quot;&gt;&#39;10mb&#39;&lt;/span&gt;,
        unique_names: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;rem&quot;&gt;// Generates client side unique names before the files are uploaded to the server&lt;/span&gt;
        multipart: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;,
        &lt;span class=&quot;rem&quot;&gt;// Specify what files to browse for in the client side browse dialogue&lt;/span&gt;
        filters: [{
            title: &lt;span class=&quot;str&quot;&gt;&quot;Image files&quot;&lt;/span&gt;,
            extensions: &lt;span class=&quot;str&quot;&gt;&quot;jpg,jpeg,gif,png&quot;&lt;/span&gt;
        }],
        preinit: {
            &lt;span class=&quot;rem&quot;&gt;// The preinit.UploadFile event is called just before a file is uploaded&lt;/span&gt;
            UploadFile: function (up, file) {
                &lt;span class=&quot;rem&quot;&gt;// Use JQuery traversal to retrieve the unique ID (and any other information you might need)&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; uniqueId = getUploader(file)
                 .closest(&lt;span class=&quot;str&quot;&gt;&#39;.plUploadContainer&#39;&lt;/span&gt;)
                 .children(&lt;span class=&quot;str&quot;&gt;&#39;input[type=&quot;hidden&quot;][name$=&quot;UniqueId&quot;]&#39;&lt;/span&gt;)
                 .first()
                 .val();

                &lt;span class=&quot;rem&quot;&gt;// Set up the additional parameters to be sent with the upload request.&lt;/span&gt;
                up.settings.multipart_params = {
                    ASPSESSID: $(&lt;span class=&quot;str&quot;&gt;&quot;#ASPSESSID&quot;&lt;/span&gt;).val(),    &lt;span class=&quot;rem&quot;&gt;// Ignored by the action method, used internally by ASP.Net&lt;/span&gt;
                    AUTHID: $(&lt;span class=&quot;str&quot;&gt;&quot;#AUTHID&quot;&lt;/span&gt;).val(),            &lt;span class=&quot;rem&quot;&gt;// Ignored by the action method, used internally by ASP.Net&lt;/span&gt;
                    UniqueId: uniqueId                    &lt;span class=&quot;rem&quot;&gt;// Used by the action method, shown on the UploadingImageModel above.&lt;/span&gt;
                };
            }
        },
        init: {
            &lt;span class=&quot;rem&quot;&gt;// The init.FilesRemoved event is called when the user requests the deletion of a file from the PLUpload UI.&lt;/span&gt;
            FilesRemoved: function (up, files) {
                &lt;span class=&quot;rem&quot;&gt;// Loop through each file selected for removal and make an ajax call to the server&lt;/span&gt;
                $.each(files, function (i, file) {
                    $.ajax({
                        url: &lt;span class=&quot;str&quot;&gt;&#39;/Upload/DeleteImage&#39;&lt;/span&gt;,
                        async: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;,
                        type: &lt;span class=&quot;str&quot;&gt;&quot;POST&quot;&lt;/span&gt;,
                        data: {
                            imageId: file.ImageId
                        }
                    });
                });
            },
            &lt;span class=&quot;rem&quot;&gt;// The init.FileUploaded event is called after a file has been uploaded to the server.&lt;/span&gt;
            FileUploaded: function (up, file, info) {
                &lt;span class=&quot;rem&quot;&gt;// Upload Success. Get the response as json&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; json = $.parseJSON(info.response);
                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (json) {
                    &lt;span class=&quot;rem&quot;&gt;// Add the newly generated ImageId to the PLUpload file (so we can use it for deleting images)&lt;/span&gt;
                    $.extend(file, { ImageId: json.ImageId });
                    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;
                }

            }
        }
    });
});&lt;/pre&gt;
&lt;br /&gt;
And that&#39;s it. Obviously I haven&#39;t provided a 100% complete solution here, but you get the general idea of how it works. I&#39;m sure there are things you can do to clean things up a little bit, but hopefully this will give you a good head start!&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;CKEditor Custom Uploader&lt;/h3&gt;
&lt;br /&gt;
&lt;a href=&quot;http://ckeditor.com/&quot; target=&quot;_blank&quot;&gt;CKEditor &lt;/a&gt;is a fairly bulky, but highly configurable and feature rich JavaScript based HTML editor. As is the case with an uncanny number of JS plugins out there, the documentation is not particularly intuitive, though there is a lot of it. Luckily, to simplify(!) matters, a JQuery plugin is available.&lt;br /&gt;
&lt;br /&gt;
By default it uses an integrated single-image upload form, which can be customised if you wish. My requirements are simple and I don&#39;t care much for layout / looks at the moment, as long as it works; I wanted to upload an image, resize it and place it inside my review / news articles. Suffice to say, I had to bust out &lt;a href=&quot;http://fiddler2.com/fiddler2/&quot; target=&quot;_blank&quot;&gt;Fiddler&lt;/a&gt;&amp;nbsp;to figure out what was actually going on in the background in order to get it working with MVC.&lt;br /&gt;
&lt;br /&gt;
As with the input type=&quot;file&quot; example above, CKEditor posts form values directly to the server, along with a few other details that may or may not be useful to you. You can safely use the following MVC action to pick up the CKEditor upload post:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ActionResult UploadImage(HttpPostedFileBase upload, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; CKEditorFuncNum, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; CKEditor, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; langCode) {
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; output = &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Concat(&lt;span class=&quot;str&quot;&gt;&quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;script&amp;gt;window.parent.CKEDITOR.tools.callFunction(&quot;&lt;/span&gt;,
        CKEditorFuncNum, &lt;span class=&quot;str&quot;&gt;&quot;, \&quot;{0}\&quot;, \&quot;{1}\&quot;);&amp;lt;/script&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot;&lt;/span&gt;);
    &lt;span class=&quot;rem&quot;&gt;// Do something with the image&lt;/span&gt;

    &lt;span class=&quot;rem&quot;&gt;// Return the content expected by CKEditor&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; webPath = &lt;span class=&quot;str&quot;&gt;&quot;/images/path-to-my-new-image.jpg&quot;&lt;/span&gt;;
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; error = &lt;span class=&quot;str&quot;&gt;&quot;Any custom errors associated with uploading&quot;&lt;/span&gt;;
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; Content(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Format(output, webPath, error));
}&lt;/pre&gt;
&lt;br /&gt;
You could, in theory turn the action parameters into its own model, but I didn&#39;t bother myself - mainly due to the fact that no other form values are sent to the server, they&#39;re case sensitive, and I&#39;m a stickler for consistency. If I implemented it, the model would look like this (note the varying case of members):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; CKUploadModel {
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; HttpPostedFileBase upload { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; CKEditorFuncNum { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; CKEditor { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; langCode { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
}&lt;/pre&gt;

&lt;br /&gt;
Once installed, you can implement the upload features of CKEditor via JQuery with as little code as this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;
$(&lt;span class=&quot;str&quot;&gt;&quot;#MyEditor&quot;&lt;/span&gt;).ckeditor({
    filebrowserUploadUrl: &lt;span class=&quot;str&quot;&gt;&#39;/MyController/UploadImage/&#39;&lt;/span&gt;
});&lt;/pre&gt;
&lt;br /&gt;
Which is nice and neat. Installation isn&#39;t all that hard - as usual, it means copying some files to your web site and including them on the page. Read more about it &lt;a href=&quot;http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Installation&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;
The above example isn&#39;t without its issues. One interesting thing to note is that I had a few problems when I wanted to send additional parameters with the upload POST. CKEditor doesn&#39;t have anything built in to it extend the POST parameters, but you &lt;i&gt;can&lt;/i&gt; - with a &lt;i&gt;lot&lt;/i&gt; of faffing - append a querystring to the filebrowserUploadUrl, and send additional information through to the action method. This, however, requires you to destroy and reload the editor each time you want to amend the querystring, which in my case, meant writing a few functions that I called whenever the relevant control on the parent form changed:&lt;br /&gt;
&lt;br /&gt;

&lt;pre class=&quot;csharpcode&quot;&gt;
$(&lt;span class=&quot;str&quot;&gt;&quot;#SomeFormControl&quot;&lt;/span&gt;).change(function () {
    setFileBrowserUrl();
});
function setFileBrowserUrl() {
    &lt;span class=&quot;rem&quot;&gt;// Remove editor instance&lt;/span&gt;
    $(&lt;span class=&quot;str&quot;&gt;&quot;#Content&quot;&lt;/span&gt;).ckeditorGet().destroy();
    &lt;span class=&quot;rem&quot;&gt;// Recreate editor instance (needed to reset the file browser url)&lt;/span&gt;
    createEditor();
}
function createEditor() {
    $(&lt;span class=&quot;str&quot;&gt;&#39;#Content&#39;&lt;/span&gt;).ckeditor({
        filebrowserUploadUrl: &lt;span class=&quot;str&quot;&gt;&#39;/MyController/UploadImage/?MyCustomID=&#39;&lt;/span&gt; + $(&lt;span class=&quot;str&quot;&gt;&quot;#SomeFormControl&quot;&lt;/span&gt;).val()
    });
}&lt;/pre&gt;

&lt;br /&gt;
This then allows me to modify my &lt;i&gt;UploadImage&lt;/i&gt; action method as such:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ActionResult UploadImage(HttpPostedFileBase upload, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; CKEditorFuncNum, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; CKEditor, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; langCode, int MyCustomID) {
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; output = &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Concat(&lt;span class=&quot;str&quot;&gt;&quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;script&amp;gt;window.parent.CKEDITOR.tools.callFunction(&quot;&lt;/span&gt;,
        CKEditorFuncNum, &lt;span class=&quot;str&quot;&gt;&quot;, \&quot;{0}\&quot;, \&quot;{1}\&quot;);&amp;lt;/script&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot;&lt;/span&gt;);
    &lt;span class=&quot;rem&quot;&gt;// Do something with the image and MyCustomID&lt;/span&gt;

    &lt;span class=&quot;rem&quot;&gt;// Return the content expected by CKEditor&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; webPath = &lt;span class=&quot;str&quot;&gt;&quot;/images/path-to-my-new-image.jpg&quot;&lt;/span&gt;;
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; error = &lt;span class=&quot;str&quot;&gt;&quot;Any custom errors associated with uploading&quot;&lt;/span&gt;;
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; Content(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Format(output, webPath, error));
}&lt;/pre&gt;
&lt;br /&gt;
It&#39;s not pretty, and it&#39;s not the most efficient piece of code I&#39;ve ever written, but as far as I can tell, it&#39;s the only way to change settings within CKEditor on the fly. When looking through the CKEditor code, I noticed that the properties seem to be &lt;a href=&quot;http://en.wikipedia.org/wiki/Lazy_initialization&quot; target=&quot;_blank&quot;&gt;initialized lazily&lt;/a&gt;, meaning that they&#39;re cached for the duration of the object&#39;s lifetime, and any values that are set against the properties are ignored unless it&#39;s reloaded.&lt;br /&gt;
&lt;br /&gt;
At the moment, CKEditor is my rich text editor of choice. I&#39;m yet to find another (free) editor that has all the features I want.</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/893667916480637229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/893667916480637229'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2013/06/handling-uploads-with-mvc4-jquery.html' title='Handling uploads with MVC4, JQuery, Plupload and CKEditor'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-3946073715166814434</id><published>2013-05-30T12:23:00.000+01:00</published><updated>2014-02-04T09:13:35.976+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="GAC"/><category scheme="http://www.blogger.com/atom/ns#" term="SSDT"/><category scheme="http://www.blogger.com/atom/ns#" term="SSIS"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio"/><title type='text'>SSDT With Visual Studio 2012 and Using Custom Assemblies</title><content type='html'>&lt;h3&gt;
 SQL Server Data Tools
&lt;/h3&gt;
&lt;br /&gt;
SSIS 2012 / SQL Server Data Tools (SSDT) offers considerable benefits over SSIS 2008 / Business Intelligence Development Studio (BIDS). The UX is much quicker, smoother, feature rich (undo and redo, woohoo!), and one of the best new features is that we can finally attach the debugger to script components - &lt;a href=&quot;http://spikehd.blogspot.co.uk/2011/11/debugging-ssis-script-component.html&quot; target=&quot;_blank&quot;&gt;which has been a bit of an issue in the past&lt;/a&gt;. It&#39;s not exactly perfect (opening the VSTA environment seems to take a lot longer than it used to, breakpoints are unpredictable, and there are a few little issues surrounding package encryption that I keep running in to), but the improvements are more than welcome, and certainly enhance development.&lt;br /&gt;
&lt;br /&gt;
If you&#39;re familiar with SSIS, but you&#39;ve avoided script tasks / components before, I have to say you&#39;re missing out; they&#39;re very powerful tools in the right hands, and basically allow you to do anything you can do in a .Net app within the context of a control flow or data flow in a package. Do remember though, that most of the time SSIS already offers a component that already does what you&#39;re looking for. It&#39;s very easy to go crazy with SSIS scripting, so pick and chose your components well.&lt;br /&gt;
&lt;br /&gt;
Often you&#39;ll find the built in components lacking in some way, and you&#39;ll either have to implement your own component, buy one in, or write your own script task to do it. I usually prefer the script task method, mainly due to the fact it gives me more control over what I&#39;m trying to do. Just to point out a few examples, SFTP isn&#39;t supported by the FTP component, and if you want to connect to a web service using anything more advanced than anonymous HTTP/S, then you&#39;ll have to go custom. I&#39;ve ran in to both of these problems in the last few years, and solved them using both script tasks and script components.&lt;br /&gt;
&lt;br /&gt;
SQL Server 2012 comes bundled with SSDT (using the VS2010 shell), but there are also options to install SSDT in both VS2010 and VS2012 separately.&amp;nbsp;&lt;a href=&quot;http://msdn.microsoft.com/en-gb/data/hh297027&quot; target=&quot;_blank&quot;&gt;This page&lt;/a&gt;&amp;nbsp;kept popping up when I was searching for the right installer, but none of the links actually installed anything into VS2012, even though they claimed to do so. It&amp;nbsp;&lt;i&gt;was&lt;/i&gt;&amp;nbsp;last year, and there have been a few updates to the pages since, so I&#39;m hoping the packages are now valid. In response to criticism received, Microsoft have since released a separate&amp;nbsp;&lt;a href=&quot;http://www.microsoft.com/en-gb/download/details.aspx?id=36843&quot; target=&quot;_blank&quot;&gt;Visual Studio 2012 SSDT installer&lt;/a&gt;, though there are still some gotchas when running it.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
If you already have an instance of SQL Server 2012 (I use SQL Server 2012 Business Intelligence on my development machines), the installer in the above link gives you the option to upgrade or install a new instance of SQL Server. Obviously I didn&#39;t want to install another SQL Server instance, so I tried to upgrade. Once I&#39;d confirmed the components, I was told that my CPU Architecture was different in my current installation, so I resigned to the &quot;New Instance&quot; option and everything installed properly.
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvIzZkETBRhadAkJ8nHwQ9WFuW88XvSlXe7_BkhruZWlnyA9oez9owNwTzSqk9tx1wcBfXudNFcMZuZm2Za0AmYuspq57l2G43fxbauI8h8dXG1pgfT6OmlJypNHXDdHu5TXw_rtZZjjM/s1600/SSDTInstall.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvIzZkETBRhadAkJ8nHwQ9WFuW88XvSlXe7_BkhruZWlnyA9oez9owNwTzSqk9tx1wcBfXudNFcMZuZm2Za0AmYuspq57l2G43fxbauI8h8dXG1pgfT6OmlJypNHXDdHu5TXw_rtZZjjM/s400/SSDTInstall.png&quot; height=&quot;300&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
This installs a new Start Menu short cut inside your SQL Server 2012 folder:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiynMiRCdpKcMN-88wHuykjv2KQhhbgG9t6d594a4IkKU-Vq-uj-TJPN2XjxqJaq9RaOLte_5CxFqPL-n6M5MgTFx6qadYNavNCyHh5hfneWOJzCxErciubONoizFSLRtMD5iKG_GMpNc/s1600/StartMenu.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiynMiRCdpKcMN-88wHuykjv2KQhhbgG9t6d594a4IkKU-Vq-uj-TJPN2XjxqJaq9RaOLte_5CxFqPL-n6M5MgTFx6qadYNavNCyHh5hfneWOJzCxErciubONoizFSLRtMD5iKG_GMpNc/s1600/StartMenu.png&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Which opens either a VS2012 Shell (as per BIDS 2008 and the SSDT VS2010 shell), or (thankfully) your already installed version of VS2012, giving you new project templates to play with:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxNz79MNefyU_iApd0dsoCN9402oIzMRQq90SSGGJOZt4EeaYWEZXedxKY__3MaOiya710Cg0jRpgJFaR57EPvptc0an3WV4htArUlkLdd0FSW0uNVfG3e5mmQ1sT1hilG8feNVj-XMl0/s1600/VS2012.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxNz79MNefyU_iApd0dsoCN9402oIzMRQq90SSGGJOZt4EeaYWEZXedxKY__3MaOiya710Cg0jRpgJFaR57EPvptc0an3WV4htArUlkLdd0FSW0uNVfG3e5mmQ1sT1hilG8feNVj-XMl0/s400/VS2012.png&quot; height=&quot;276&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
 Custom .Net Assemblies
&lt;/h3&gt;
&lt;br /&gt;
There are already a number of blog posts out there explaining how to get started with SSDT, so instead I thought I&#39;d post a little on getting custom .Net assemblies&amp;nbsp;working with SSDT 2012. The concept is similar to the BIDS 2008 method, but there a few specifics that might catch you out. Unfortunately there&#39;s still no assembly installer / package manager, so all assemblies that you want to reference in your script tasks and components still have to be installed in to the GAC.&lt;br /&gt;
&lt;br /&gt;
On the plus side, you can now use .Net 4.0 (VS2010 shell) and .Net 4.5 (VS2012) assemblies, which is great news to those who want to use any of the latest .Net features. My examples are all going to use VS2012 and .Net 4.5, and I&#39;ll be connecting to a local copy of the Microsoft provided AdventureWorks SQL Server 2008 R2 sample database (all SQL Server versions can be downloaded from &lt;a href=&quot;http://msftdbprodsamples.codeplex.com/releases/view/93587&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;). You can use any compatible version of SQL Server to do this, the data source is not important for the purposes of the demo.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
 Brief
&lt;/h4&gt;
&lt;br /&gt;
Let&#39;s take a list of all Products in the database, and do something arbitrary with the data (for the purposes of the example, I&#39;ll be simply sending the SSDT data to a .Net assembly doing a very simple calculation, and returning it to the script component. Usually the assembly would do something more complicated with the row data, like send it to an MSMQ, a WCF service, validate it, or clean it up). We&#39;ll create a very simple SSDT package to do this.&lt;br /&gt;
&lt;br /&gt;
The below example assumes you are familiar with SQL Server, Visual Studio, basic windows batch files / commands, and how to use basic SSDT components.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
 Project Setup
&lt;/h4&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
1. Start Visual Studio 2012 and create a new Integration Services Project (with a new solution).&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1ES2mb5oe80vQM1Q73tU7tK6CqBK2yLmxlAg-ChtDB4yr21AZnaTVZU4qeQCJSlTwXoYGMxyaUsBM2IsecO4hwqCJ_jrpc0hM-5VUGVxrGYvrUwG99NBmkVTkUvUKA-PTI2ozYe-2A0s/s1600/new-integration-project.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1ES2mb5oe80vQM1Q73tU7tK6CqBK2yLmxlAg-ChtDB4yr21AZnaTVZU4qeQCJSlTwXoYGMxyaUsBM2IsecO4hwqCJ_jrpc0hM-5VUGVxrGYvrUwG99NBmkVTkUvUKA-PTI2ozYe-2A0s/s400/new-integration-project.jpg&quot; height=&quot;226&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
2. Add a new &quot;Class Library&quot; project to the solution.
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnU672kuCC5-dULUK6a8zTE2ZAZ7xtmII8iCtal5_hMbAdwzkrkg7ecaY_pGs3-fH61ugzXyCE1gz_JSsLiuYwZ7QUV4UNX_1g62gD5ZCzocY5ntVbyzlFWofuEhNyUNqN1HxEsUF93eA/s1600/add-class-library.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnU672kuCC5-dULUK6a8zTE2ZAZ7xtmII8iCtal5_hMbAdwzkrkg7ecaY_pGs3-fH61ugzXyCE1gz_JSsLiuYwZ7QUV4UNX_1g62gD5ZCzocY5ntVbyzlFWofuEhNyUNqN1HxEsUF93eA/s400/add-class-library.jpg&quot; height=&quot;228&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
3. Check if the Class Library is set to target .Net 4.5 (Right Click Project in Solution Explorer -&amp;gt; Properties -&amp;gt; Application Tab -&amp;gt; Target Framework drop down).
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYtXCLq58ntxlJJHdCrMr8g7yi7Y8GpADl1pTSoqO1MxyVHooBSyl6RJls-cg3jrgBc3zcbDUcVKDUB37ZVYAsJQtUfbXCTO4PkEbgMGtsOfT52TKPHJk2AEpdrBP63aMXRWT77XCx518/s1600/target-framework.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYtXCLq58ntxlJJHdCrMr8g7yi7Y8GpADl1pTSoqO1MxyVHooBSyl6RJls-cg3jrgBc3zcbDUcVKDUB37ZVYAsJQtUfbXCTO4PkEbgMGtsOfT52TKPHJk2AEpdrBP63aMXRWT77XCx518/s1600/target-framework.png&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
4. Create a new Class with the following code and compile the ClassLibrary1 project:
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;namespace&lt;/span&gt; ClassLibrary1 {
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ProductHelper {
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; GetStockCount(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; id) {
&lt;span class=&quot;rem&quot;&gt;// TODO: Perform inventory stock count via 3rd party service&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; 4321;
        }
    }
}&lt;/pre&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
5. Open Package.dtsx and create a Data Flow Task:
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3Wk3JqMj7x0AUBdHhNP6S1PWjxw9PQeGiyQNv4IShp2HDtI23HkUuLXjKGODCYBh-nyhzpRzb7idaxt7kiaOaePH99GgZid40Ctv_986AEv3oVeaXRDrDOpC-64_E5dcBL5BVoOaqJtU/s1600/data-flow-task.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3Wk3JqMj7x0AUBdHhNP6S1PWjxw9PQeGiyQNv4IShp2HDtI23HkUuLXjKGODCYBh-nyhzpRzb7idaxt7kiaOaePH99GgZid40Ctv_986AEv3oVeaXRDrDOpC-64_E5dcBL5BVoOaqJtU/s1600/data-flow-task.jpg&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
6. Double Click the Data Flow Task and create an &quot;ADO NET Source&quot;, a &quot;Script Component&quot; (select &quot;Transformation&quot;), and an &quot;ADO NET Destination&quot;, linking them together as follows:
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEkpzURHSa2hqTicyTkTfpheETp13Yn5xuDLNpeDvXD5uU5FVczrbfAQewF2qjfFCWyXrt4aKoXuH3ZpyWhoq5bkCQVBOX6bBIlcuIETCXuWtfhdY0oxGOuJLPblnw3EzEb44en8U5jKE/s1600/data-flow-detail.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEkpzURHSa2hqTicyTkTfpheETp13Yn5xuDLNpeDvXD5uU5FVczrbfAQewF2qjfFCWyXrt4aKoXuH3ZpyWhoq5bkCQVBOX6bBIlcuIETCXuWtfhdY0oxGOuJLPblnw3EzEb44en8U5jKE/s1600/data-flow-detail.jpg&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
7. Configure the ADO NET Source to pull all products out of the database:
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiudmCnz63ryVOfMfAzGYnjX1fDU6DKku7xzScc99yuWGQUTzg65pkueKEiJ-lcYASwb0vN6DxefZCz-iZdLefJTK194CGMewoZ_MacyPviw0vyvXe8qhmS8zy_Jo_uxzRyKAS_jkldMdY/s1600/ado-net-source-setup.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiudmCnz63ryVOfMfAzGYnjX1fDU6DKku7xzScc99yuWGQUTzg65pkueKEiJ-lcYASwb0vN6DxefZCz-iZdLefJTK194CGMewoZ_MacyPviw0vyvXe8qhmS8zy_Jo_uxzRyKAS_jkldMdY/s400/ado-net-source-setup.png&quot; height=&quot;346&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
8. Double click the Script Component and perform the following steps:
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Select &quot;ProductID&quot;, &quot;Name&quot; and &quot;ProductNumber&quot; as the input columns.&lt;/li&gt;
&lt;li&gt;Click &quot;Edit Script&quot; on the &quot;Script&quot; tab to open up the VS2012 VSTA Editor&lt;/li&gt;
&lt;li&gt;Right Click the VSTA project, and change the &quot;Target Framework&quot; to &quot;.Net Framework 4.5&quot;&lt;/li&gt;
&lt;li&gt;Add a project reference to &quot;ClassLibrary1&quot; by browsing to the &quot;bin\Debug\&quot; directory of the solution.&lt;/li&gt;
&lt;li&gt;Go to the Code Editor and find &quot;public override void Input0_ProcessInputRow(Input0Buffer Row)&quot;&lt;/li&gt;
&lt;li&gt;
  Add the following code into the method:

&lt;pre class=&quot;csharpcode&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; x = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ClassLibrary1.ProductHelper();
  &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; count = x.GetStockCount(Row.ProductID);&lt;/pre&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Close the VSTA Editor and click &quot;OK&quot; on the Script Transform Editor dialogue.&lt;/li&gt;
&lt;/ol&gt;
Keen observers will notice that I haven&#39;t actually done anything with the &quot;count&quot; reference. This tutorial is to demonstrate that you can get Script Components and Script Tasks to work with your own custom assembly, not to demonstrate what to do with the results. Normally, you would update a column or append this value to a row or variable, but for now I just want to show you that it&#39;ll compile.&lt;br /&gt;
&lt;br /&gt;
9. Double click the &quot;ADO NET Destination&quot; component, create a new table in the AdventureWorks database, then click &quot;OK&quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAc3g0oagapKGl7GZfLegcx30NdlRf-Qn7Bk3vTV7eE-kf0Kbts1t9hpvg7LR8bvI0V9bXmyCJPR8yLUvSzNRqUv2irLu_dc_apRJd0y4QNjgZXQ9JHUmY3ymbxxXPRQZMInu2a-RtlqQ/s1600/ado-net-dest-setup.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAc3g0oagapKGl7GZfLegcx30NdlRf-Qn7Bk3vTV7eE-kf0Kbts1t9hpvg7LR8bvI0V9bXmyCJPR8yLUvSzNRqUv2irLu_dc_apRJd0y4QNjgZXQ9JHUmY3ymbxxXPRQZMInu2a-RtlqQ/s400/ado-net-dest-setup.png&quot; height=&quot;370&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
10. If we weren&#39;t trying to get an external assembly working with the Script Component, the SSIS package would now normally be in a compilable state. However, if you debug it (F5), you will receive the following error:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4xDFEGfnyslQkOpXEcOjPPvtuzkxxLPb4I7Gr31GqTcms63AWifD8CStBihF3bVsD94kFoQCDCem-azsREK4ep9Yii1aWCBHwtbTUsRwc_-M03-RR3rMXBYWuc61IDoQGi6x4xR33i10/s1600/GAC-error.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4xDFEGfnyslQkOpXEcOjPPvtuzkxxLPb4I7Gr31GqTcms63AWifD8CStBihF3bVsD94kFoQCDCem-azsREK4ep9Yii1aWCBHwtbTUsRwc_-M03-RR3rMXBYWuc61IDoQGi6x4xR33i10/s400/GAC-error.png&quot; height=&quot;269&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
This is due to the fact that the assembly is not available to the DTSDebugHost.exe process. Dependent assemblies are not copied or loaded as they would be with a normal .Net project, so you need to tell the project to use a strongly signed GAC assembly instead.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
 Global Assembly Cache
&lt;/h4&gt;
&lt;br /&gt;
1. The first thing we need to do is sign the dependent assemblies. You can do this by right clicking your Class Library project -&amp;gt; Properties -&amp;gt; Signing Tab -&amp;gt; Check &quot;Sign the assembly&quot;. You can then create a new strong key file:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi64rFUd_cRGcdDxKkruSOH9HZQPdc0OiMeybeW3IRmVWr1SKf8LEuy4YWGkTVxkL3hGq6tWXbesCROIu-jSCG-M1MY5HS1CHpgMvkVs-uuu_oITIu3G5paOzgtNw_3rSANh3hBIOP6MuU/s1600/sign-assembly.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi64rFUd_cRGcdDxKkruSOH9HZQPdc0OiMeybeW3IRmVWr1SKf8LEuy4YWGkTVxkL3hGq6tWXbesCROIu-jSCG-M1MY5HS1CHpgMvkVs-uuu_oITIu3G5paOzgtNw_3rSANh3hBIOP6MuU/s400/sign-assembly.png&quot; height=&quot;295&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
In the &quot;Create Strong Name Key&quot; dialogue, I usually name the key file the same as the libraries root namespace (in this instance, &quot;ClassLibrary1&quot;), then uncheck the &quot;Protect my key file with a password&quot; box, and leave the Signature Algorithm as the default. Of course, you can still protect the file with a password if you want, but you will need to adjust a number of the below steps.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhnrUDE8Oi_zWYG4Pipqq-0zxrL9eFTyBQSn_iKr6sE70psn8eVAxLcGzFsUm5ISjK7142hQHnygQDuLyN9EDG4_FhdqXs65jXy0gw8C74C_tb9i4hsEV6VoXs8wcKYnh0SpLSIhGJSC8/s1600/create-strong-name-key.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhnrUDE8Oi_zWYG4Pipqq-0zxrL9eFTyBQSn_iKr6sE70psn8eVAxLcGzFsUm5ISjK7142hQHnygQDuLyN9EDG4_FhdqXs65jXy0gw8C74C_tb9i4hsEV6VoXs8wcKYnh0SpLSIhGJSC8/s1600/create-strong-name-key.png&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
Once created, a filed called &quot;ClassLibrary1.snk&quot; will show in the root of your ClassLibrary1 project.
&lt;/div&gt;
&lt;br /&gt;
2. Now we need to create a directory that the dependent assemblies can live in once they&#39;re installed to the GAC. I usually use a project or deployment path, but for the purposes of this demo, I&#39;ll use C:\MyAssemblies\.&lt;br /&gt;
&lt;br /&gt;
3. The next step is to keep your local GAC up to date with the latest assemblies, and inform Visual Studio 2012 where these dependent assemblies are so they can be displayed in the &quot;Add References&quot; dialogue. The following commands expect you to be logged in as an administrator, and should be copied into the ClassLibrary1 project&#39;s Post-Build commands:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;reg add HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\MyAssemblies\ /f /t REG_SZ /d C:\MyAssemblies\&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;xcopy &quot;$(TargetPath)&quot; /Y/R/F &quot;C:\MyAssemblies\&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\gacutil.exe&quot; /uf &quot;$(TargetName)&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\gacutil.exe&quot; /i &quot;C:\MyAssemblies\$(TargetFileName)&quot; /f&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLmDf7sxaqHM1ODiMimKFBsl3Te9FanGDtvCM1UjEOW23F05Gd3RVY83sC4ewxuBnbBWPtXste6_RPYLjuupDJ7M7-CBXglVpG6NT2TeWi6dTOHy_vyd6EdfOKJQEfVUrJxzXQqJfcGHI/s1600/post-build.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLmDf7sxaqHM1ODiMimKFBsl3Te9FanGDtvCM1UjEOW23F05Gd3RVY83sC4ewxuBnbBWPtXste6_RPYLjuupDJ7M7-CBXglVpG6NT2TeWi6dTOHy_vyd6EdfOKJQEfVUrJxzXQqJfcGHI/s400/post-build.png&quot; height=&quot;115&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
Here&#39;s a summary of each line:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;reg add HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\MyAssemblies\ /f /t REG_SZ /d C:\MyAssemblies\&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This creates / overwrites a registry key that tells Visual Studio where to find your custom GAC assemblies. It&#39;s not strictly necessary in a post-build command (you only need to run it once), but it does no harm, and allows other developers who might start working on the package to get up and running straight away. You can read more about it &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/wkze6zky(v=vs.100).aspx&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;xcopy &quot;$(TargetPath)&quot; /Y/R/F &quot;C:\MyAssemblies\&quot;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This command copies and overwrites any files in C:\MyAssemblies\ with the deployed project files.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\gacutil.exe&quot; /uf &quot;$(TargetName)&quot;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This command uses the latest version of gacutil to UNINSTALL the target assembly from the GAC. You&#39;ll see a warning in the output window the first time it executes on your machine, but it&#39;s needed to reinstall the assembly every time you compile your code.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\gacutil.exe&quot; /i &quot;C:\MyAssemblies\$(TargetFileName)&quot; /f&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;/div&gt;
This command uses gacutil to install the assembly into the GAC.&lt;br /&gt;
&lt;br /&gt;
4. You can now build your ClassLibrary1 project again. If it succeeds, you will see something similar to this in the Output window:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt;------ Build started: Project: ClassLibrary1, Configuration: Debug Any CPU ------&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;ClassLibrary1 -&amp;gt; D:\code_temp\Integration Services Project1\ClassLibrary1\bin\Debug\ClassLibrary1.dll&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;The operation completed successfully.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;D:\code_temp\Integration Services Project1\ClassLibrary1\bin\Debug\ClassLibrary1.dll -&amp;gt; C:\MyAssemblies\ClassLibrary1.dll&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;1 File(s) copied&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;Microsoft (R) .NET Global Assembly Cache Utility. &amp;nbsp;Version 4.0.30319.17929&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;Copyright (c) Microsoft Corporation. &amp;nbsp;All rights reserved.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;No assemblies found matching: ClassLibrary1&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;Number of assemblies uninstalled = 0&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;Number of failures = 0&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;Microsoft (R) .NET Global Assembly Cache Utility. &amp;nbsp;Version 4.0.30319.17929&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;Copyright (c) Microsoft Corporation. &amp;nbsp;All rights reserved.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;1&amp;gt; &amp;nbsp;Assembly successfully added to the cache&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The assembly is now installed, and your project is set up to keep the GAC reference up to date as you develop it.&lt;br /&gt;
&lt;br /&gt;
5. The next step is to update the reference in the Script Component in&amp;nbsp;&lt;i&gt;Package.dtsx&lt;/i&gt; to look to the new GAC assembly. In the Data Flow Task, double click the Script Component and click &quot;Edit Script&quot;. In the VSTA editor, remove the ClassLibrary1 reference from the project, and add a new assembly reference.&lt;br /&gt;
&lt;br /&gt;
In the Reference Manager dialogue, click &quot;Assemblies&quot; -&amp;gt; &quot;Extensions&quot;. You should see two entries for ClassLibrary1. My screenshot only shows one, because I&#39;ve restarted VS2012 since removing the original reference. Just hover over each of them and add the one that says &quot;C:\MyAssemblies\ClassLlibrary1.dll&quot; in the tooltip.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMOrfr-L098K-xZSySLiWGRYGIgb7CTrLCgT22lDTxwC2Qq5c-e9E8ppA67lQgqD7v592cfh7enTSFaOmkZaBmxNniX-eBp5SuV9q_YVUH7NNfWwiId0FuaoP8bgTm6-TOAF7OcNCaWZo/s1600/add-reference.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMOrfr-L098K-xZSySLiWGRYGIgb7CTrLCgT22lDTxwC2Qq5c-e9E8ppA67lQgqD7v592cfh7enTSFaOmkZaBmxNniX-eBp5SuV9q_YVUH7NNfWwiId0FuaoP8bgTm6-TOAF7OcNCaWZo/s400/add-reference.png&quot; height=&quot;211&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
6. In the VSTE editor, stick a breakpoint on the following line, then save and exit the editor:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP0KUUL5cddPoaPXb9GN7RxRgnavL2bT6cFQu3pWZOYGQg6rZt6JWB2pp2QuCyEZhQjDk6fmwSTpYBSpZbL8E6honCbwogMGiICFY-SZ0bM1-gml1Li4Y8-adKIC-94Yhyphenhypheni5qapglPvII/s1600/breakpoint.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP0KUUL5cddPoaPXb9GN7RxRgnavL2bT6cFQu3pWZOYGQg6rZt6JWB2pp2QuCyEZhQjDk6fmwSTpYBSpZbL8E6honCbwogMGiICFY-SZ0bM1-gml1Li4Y8-adKIC-94Yhyphenhypheni5qapglPvII/s1600/breakpoint.png&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
7. You can now debug (F5) the project, and after a little while, the breakpoint will be hit (give it time, it takes at least 15 seconds to open on my development machine). If you step through the code, you can see that the assembly is now being hit, and the values from the assembly are being returned:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJrf7YFHRg1oxP1tw-TnVu_DW4avCu0ruC6ADfqwpUJEgMyOYAzLzWMFj3dI2HlDTt-XaUtZVUX-4lEcN3OMbcUXdG_xdE0hc2xdF8F4b8ioVHk54OdmKfaG6DNkpXFK6PXP2wDQda82w/s1600/debug.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJrf7YFHRg1oxP1tw-TnVu_DW4avCu0ruC6ADfqwpUJEgMyOYAzLzWMFj3dI2HlDTt-XaUtZVUX-4lEcN3OMbcUXdG_xdE0hc2xdF8F4b8ioVHk54OdmKfaG6DNkpXFK6PXP2wDQda82w/s1600/debug.png&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
Each row (all 504 of them) will hit the breakpoint, so delete it and press F5 to close the VSTE editor and finish the package:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh41U1j3m5UmUm5MFYQiXANMOMoyRtQJ-vqBywOPHgxPrZhJ5-Y4yDferktRrDvT0omKItXPqhdD1hnihpa7L9N4oBHwxnaWPwsuu9mcA1CrCnHmrR1ax-2LglkqIuKJ0gEL_CCGRCXrWw/s1600/data-flow.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh41U1j3m5UmUm5MFYQiXANMOMoyRtQJ-vqBywOPHgxPrZhJ5-Y4yDferktRrDvT0omKItXPqhdD1hnihpa7L9N4oBHwxnaWPwsuu9mcA1CrCnHmrR1ax-2LglkqIuKJ0gEL_CCGRCXrWw/s1600/data-flow.png&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
 Installing on a Server
&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Although I&#39;m sure you have your own methods when deploying an SSIS package, figuring out how to install a GAC assembly isn&#39;t the easiest of tasks, and it&#39;s not usually something your casual DBA or even Database Developer would be familiar with. However, knowing how to install to the GAC on your development machine gives you an advantage, and the good news is that you don&#39;t need to install an SDK to get it working.
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
My install package is a simple zip file, which contains the following items:
&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;The assemblies you want to install into the GAC.&lt;/li&gt;
&lt;li&gt;The SSIS packages to deploy.&lt;/li&gt;
&lt;li&gt;An installation batch file.&lt;/li&gt;
&lt;li&gt;gacutil.exe and its dependencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
gacutil.exe, like many other Visual Studio tools, changes with each version of .Net. To install a .Net 4.5 assembly, copy the following files into your install package folder&amp;nbsp;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\1033\gacutlrc.dll&lt;br /&gt;
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\gacutil.exe&lt;br /&gt;
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\gacutil.exe.config&lt;br /&gt;
&lt;br /&gt;
The installation batch file needs to contain a number of commands, similar to the post build command we set earlier, only using the server&#39;s physical path instead of your local development path. The first line should be changed to the directory you extract the zip file to:&lt;br /&gt;
&lt;br /&gt;
set installPath=C:\MyProject&lt;br /&gt;
set assemblyName=ClassLibrary1&lt;br /&gt;
&quot;%installPath%\gacutil.exe&quot; /uf &quot;%assemblyName%&quot;&lt;br /&gt;
&quot;%installPath%\gacutil.exe&quot; /i &quot;%installPath%\%assemblyName%.dll&quot; /f&lt;br /&gt;
&lt;br /&gt;
After you&#39;ve successfully installed the assembly to the GAC, all you need to do is deploy your SSIS package and schedule it to run - if everything is set up correctly, your GAC enabled SSIS package is ready to go!&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Benefits&lt;/h4&gt;
I&#39;m not a fan of using the GAC, if I&#39;m entirely honest, but with any kind of complex SSIS package that requires you to write or reuse .Net code, it&#39;s a necessary evil. The main benefits of importing a custom assembly into a script task / component is separation of concerns - you can unit test, build and manage the assembly separately from SSDT, and of course, keep any complex logic out of the fiddly script tasks and script components.&lt;br /&gt;
I&#39;ve used this method to carry out many different tasks, including complex validation, advanced web service integration, custom logging, complex transformations, and data retrieval and generation. It&#39;s easy to see how powerful SSIS can be, especially when using the GAC opens up your entire code base for reuse within an ETL process. The opportunities are endless.</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/3946073715166814434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/3946073715166814434'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2013/05/ssdt-with-visual-studio-2012-and-using.html' title='SSDT With Visual Studio 2012 and Using Custom Assemblies'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvIzZkETBRhadAkJ8nHwQ9WFuW88XvSlXe7_BkhruZWlnyA9oez9owNwTzSqk9tx1wcBfXudNFcMZuZm2Za0AmYuspq57l2G43fxbauI8h8dXG1pgfT6OmlJypNHXDdHu5TXw_rtZZjjM/s72-c/SSDTInstall.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-815188674209658690</id><published>2013-01-07T19:16:00.003+00:00</published><updated>2013-01-07T19:16:37.102+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="TDD"/><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing"/><title type='text'>TDD and Unit Testing with Moq</title><content type='html'>In my last post, I mentioned that I&#39;ve been using TDD and mocking quite a bit this year, and I&#39;ve fallen in love. It&#39;s something I&#39;m very keen on continuing with, as I&#39;ve now seen that the benefits outweigh the extra time needed to develop your tests.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve written my fair share of stand alone unit and integration tests throughout the years, but until recently I&#39;ve not used object mocking or stubbing. I&#39;ve never really appreciated what tests are, and what benefits they give me as a developer, other than they let me write a quick bit of throw-away code that enables me to test the functionality of a class or a method. Only now - &lt;em&gt;16 years in to my career&lt;/em&gt; - do I realise how critical unit tests are to an application, especially in enterprise level systems that have a lot of code reuse and crossover. Not only do well written tests test the functionality of your code base, they also allow you to modify anything with complete confidence that your changes aren&#39;t going to affect anything else in the software.&lt;br /&gt;
&lt;br /&gt;
So, on to the wonderful world Test Driven Development (TDD). Shunned by many because of the extra time needed to implement it properly, and ultimately due to the perception that TDD is &quot;doing development backwards&quot;. The fact of the matter is, the process of writing a test and making sure it fails before you even write a line of implementation code, proves that you haven&#39;t written the test incorrectly in the first place, or written a test that&#39;ll pass regardless of your implementation. It&#39;s also self documenting, and forces modular, well-written, and concise code - as long as you follow the TDD guidelines and principals. Probably most importantly, it forces developers to think about what they&#39;re writing; there&#39;s little point in writing a test that confirms that &lt;i&gt;a + b = c&lt;/i&gt; if you haven&#39;t figured out what &lt;i&gt;c&lt;/i&gt; is going to be used for.&lt;br /&gt;
&lt;br /&gt;
Skipping merrily down the street hand in hand with TDD is mocking. I&#39;ve tried to get my head around it in the past, but - as with TDD - I&#39;ve never really understood its use, so I&#39;ve never made time to learn it. Why would I want to mock an object up in my tests when I need to test real code? Why would I write a test against a mocked object? Both silly questions in hindsight, and both easily answerable if you consider that you don&#39;t actually test mocked objects - they merely give you the ability to ignore any logic contained in your external dependencies, letting you concentrate on one particular function block, or &quot;unit&quot; of code.&lt;br /&gt;
&lt;br /&gt;
I&#39;m gonna delve in to this a little deeper, in the vain hope that I can get a few people on board with TDD. Consider this simplified real world scenario; say you want to test if pressing the power button on your TV remote control will issue your TV with a &quot;turn on&quot; signal, and power it on. Now, consider that in order for this test to work, the TV must be plugged in and supplied with electricity, be in &quot;stand by&quot; mode, and the remote must have sufficiently powered batteries installed. All these variables make the original requirement hard to reliably test - how I can accurately and consistently test if the remote sends the &quot;turn on&quot; signal if the batteries might be dead, or if the TV will receive the signal when someone has turned the TV off at the wall, or a fuse has blown? My test will fail if one or more of the dependencies don&#39;t function as I expect them to, meaning I could spend a while trying to fix something that isn&#39;t even broken in the first place.&lt;br /&gt;
&lt;br /&gt;
Suddenly you&#39;re presented with a plethora of things that can go wrong; if we were to run this test without mocking up the dependencies, we would be performing an integration test rather than a unit test. Integration tests are still important, but tests at the unit level are extremely useful to us. They confirm that - even after modification - one particular part of the software still functions as it was originally intended to, and our modifications haven&#39;t changed that. Further to this, mocking allows us to replace the batteries, electricity, and stand-by mode dependencies with rock-solid, predictable implementations that will always function in the same way.&lt;br /&gt;
&lt;br /&gt;
Let&#39;s put this remote / TV scenario in to a code implementation. I&#39;ve simplified things for clarity - I wouldn&#39;t normally pass around &quot;magic strings&quot;, and I probably wouldn&#39;t design it this way if it was going in to production, but I think it makes things a bit clearer for the purposes of an example. I&#39;m using MSTest and Moq in my examples, but the same can be achieved with any testing / mocking frameworks.&lt;br /&gt;
&lt;br /&gt;
In TDD we write tests before code, so let&#39;s write one that checks to see if the TV is receiving signals from the remote (we&#39;re using text to represent the remote codes that a TV might receive):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;        [TestMethod]
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DoesTVReceiveSignalFromRemote() {
            &lt;span class=&quot;rem&quot;&gt;// Arrange&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// Create a mock TV - we don&#39;t really care what the TV does,&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// we just need to know that the remote successfully sends a signal&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tv = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Mock&amp;lt;ITelevision&amp;gt;();

            &lt;span class=&quot;rem&quot;&gt;// Create a concrete RemoteControl instance to test, passing in the &lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// TV via constructor injection.&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; remote = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; RemoteControl(tv.Object);

            &lt;span class=&quot;rem&quot;&gt;// Act&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// Have the remote send a signal&lt;/span&gt;
            remote.Send(&lt;span class=&quot;str&quot;&gt;&quot;foobar&quot;&lt;/span&gt;);

            &lt;span class=&quot;rem&quot;&gt;// Assert&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// Assert that the TV received a signal with the text sent with the Send() method&lt;/span&gt;
            tv.Verify(x =&amp;gt; x.ReceiveSignal(It.Is&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;(s =&amp;gt; s == &lt;span class=&quot;str&quot;&gt;&quot;foobar&quot;&lt;/span&gt;)), Times.Once());
        }&lt;/pre&gt;
&lt;br /&gt;
Obviously, because the ITelevision interface and the RemoteControl class don&#39;t exist, you won&#39;t even be able to compile the code, but this gives you a starting point. If I&#39;m honest, I usually implement the very basics of my classes and interfaces before I write any tests (throwing a NotImplementedExceptions in any method implementations), but only because I find trying to build a test that&#39;s broken at compile-time a little bit pointless. The point of writing tests first is so you can confirm that your test is well written and concise. It also makes sure that your test is correct - if your test passes straight away, you&#39;ve either already implemented the code you&#39;re testing (which means you&#39;ve got a duplicate test somewhere), or your test has been written badly.&lt;br /&gt;
&lt;br /&gt;
So, in the above test I&#39;m passing a mocked TV object in to the RemoteControl as a dependency (which does nothing at all - it&#39;s just satisfying the constructor requirement for an instantiated class), invoking the RemoteControl&#39;s Send() method (passing the string &quot;foobar&quot;), then checking if the TV&#39;s ReceiveSignal() method is invoked with the same string. This test tells us that the RemoteControl&#39;s Send() method &lt;em&gt;requires&lt;/em&gt; the invocation of the TV&#39;s ReceiveSignal() method as part of its functionality, and that the signal that&#39;s received must be the same as the one that&#39;s sent by the remote. The signal &quot;foobar&quot; is arbitrary - we&#39;re not testing the validity of the signal, we&#39;re just testing that a signal can be received by the TV.&lt;br /&gt;
&lt;br /&gt;
One of the main principals of TDD is to write as little code as possible in order to make your test pass. This ensures you have clear, maintainable code, and have tests for as much functionality as possible. Here&#39;s the minimal implementation for the above test:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; ITelevision {    
        &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ReceiveSignal(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; signal);
    }

    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; RemoteControl {
        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; ITelevision pairedTV;

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; RemoteControl(ITelevision tv) {
            pairedTV = tv;
        }
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Send(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; signal) {
            pairedTV.ReceiveSignal(signal);
        }
    }&lt;/pre&gt;
&lt;br /&gt;
The test now passes. Notice that there&#39;s no implementation of ITelevision; as I mentioned earlier, I don&#39;t care what the television does at this stage, because I&#39;m just testing that the RemoteControl.Send() method physically sends a message to the TV it&#39;s been paired with. Let&#39;s go a little deeper.&lt;br /&gt;
&lt;br /&gt;
Imagine that I wanted to save the remote&#39;s battery consumption by detecting if the TV has electricity flowing to it before sending an &quot;on&quot; request. Ignoring the fact that the technicalities are extremely questionable, I could check this bit of logic by creating a new test:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;        [TestMethod]
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; RemoteDoesNotSendSignalIfTVIsTurnedOff() {
            &lt;span class=&quot;rem&quot;&gt;// Arrange&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tv = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Mock&amp;lt;ITelevision&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;            &lt;span class=&quot;rem&quot;&gt;// Setup the TV mock so it is turned off&lt;/span&gt;
            tv.Setup(x =&amp;gt; x.HasElectricalPower)
              .Returns(&lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;);

            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; remote = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; RemoteControl(tv.Object);

            &lt;span class=&quot;rem&quot;&gt;// Act&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// Have the remote invoke the Send() method - the data sent&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// does not matter (we are not testing the data)&lt;/span&gt;
            remote.Send(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Empty);

            &lt;span class=&quot;rem&quot;&gt;// Assert&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// Assert that the TV implementation does not invoke ReceiveSignal() at all.&lt;/span&gt;
            tv.Verify(x =&amp;gt; x.ReceiveSignal(It.IsAny&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;()), Times.Never());
        }&lt;/pre&gt;
&lt;br /&gt;
I&#39;ve now introduced the &quot;HasElectricalPower&quot; property to the ITelevision interface, and hard-wired the mock to return &quot;false&quot; in every circumstance. I&#39;m then sending an empty string to the RemoteControl.Send() method, as the data I&#39;m sending is even less important than in our first test; we&#39;re not testing the signal&#39;s value at all here, so we don&#39;t need to populate it; you could just as easily leave it as &quot;foobar&quot;, or any other random string. Last but not least, I&#39;ve changed the assertion to make sure that the ITelevision.ReceiveSignal() method is &lt;em&gt;never&lt;/em&gt; invoked. Notice that I&#39;ve also changed the matching condition (It.IsAny&amp;lt;T&amp;gt;()) so it will accept any string whatsoever.&lt;br /&gt;
&lt;br /&gt;
This test tells us that the ITelevision.HasElectricalPower property must be &quot;true&quot; before a signal can be sent. To make this test pass with the minimal amount of code, add the following highlighted code to your implementation:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; ITelevision {    
        &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ReceiveSignal(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; signal);
        &lt;span style=&quot;color: red; font-weight: bold;&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; HasElectricalPower { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; }&lt;/span&gt;
    }

    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; RemoteControl {
        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; ITelevision pairedTV;

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; RemoteControl(ITelevision tv) {
            pairedTV = tv;
        }
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Send(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; signal) {
            &lt;span style=&quot;color: red; font-weight: bold;&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (pairedTV.HasElectricalPower) {&lt;/span&gt;
                pairedTV.ReceiveSignal(signal);
            &lt;span style=&quot;color: red; font-weight: bold;&quot;&gt;}&lt;/span&gt;
        }
    }&lt;/pre&gt;
&lt;br /&gt;
The test now passes, but those who&#39;ve been following along will notice that the first test we wrote now fails. This is because you&#39;ve introduced an additional dependency that needs to be mocked; the ITelevision.HasElectricalPower() property. This now needs to return &quot;true&quot;, because otherwise the first test we wrote will never pass. While we&#39;re at it, let&#39;s rename the test to reflect the changes we&#39;re making, and parameterise the signal text that we&#39;re sending (which is what I would do in my own tests to make them easier to maintain):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;        [TestMethod]
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DoesTVReceiveSignalFromRemoteIfTurnedOn() {
            &lt;span class=&quot;rem&quot;&gt;// Arrange&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// Create the signal text that we&#39;re going to send. We can use this variable &lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// to check the received text too.&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; expectedSignal = &lt;span class=&quot;str&quot;&gt;&quot;foobar&quot;&lt;/span&gt;;

            &lt;span class=&quot;rem&quot;&gt;// Create a mock TV - we don&#39;t really care what the TV does,&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// we just need to know that the remote successfully sends a signal&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tv = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Mock&amp;lt;ITelevision&amp;gt;();

            &lt;span class=&quot;rem&quot;&gt;// Setup the TV mock to it&#39;s always turned on&lt;/span&gt;
            tv.Setup(x =&amp;gt; x.HasElectricalPower)
              .Returns(&lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;);

            &lt;span class=&quot;rem&quot;&gt;// Create a concrete RemoteControl instance to test, passing in the &lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// TV via constructor injection.&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; remote = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; RemoteControl(tv.Object);

            &lt;span class=&quot;rem&quot;&gt;// Act&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// Have the remote send the signal&lt;/span&gt;
            remote.Send(expectedSignal);

            &lt;span class=&quot;rem&quot;&gt;// Assert&lt;/span&gt;
            &lt;span class=&quot;rem&quot;&gt;// Assert that the TV received the signal&lt;/span&gt;
            tv.Verify(x =&amp;gt; x.ReceiveSignal(It.Is&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;(s =&amp;gt; s == expectedSignal)), Times.Once());
        }&lt;/pre&gt;
&lt;br /&gt;
And there we have it - two working tests, and a better understanding of our code and why we should test it. Refactoring is part of the TDD design principals, and you can do it in confidence that you have tests that&#39;ll catch any slip ups you might make. I&#39;m going to cover one more scenario before I finish.&lt;br /&gt;
&lt;br /&gt;
Moving away from mocks; say we want to check that the TV actually turns on when we send the signal &quot;on&quot; to it. This time, I&#39;m going to write three tests before I write the implementation:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;        [TestMethod]
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; TVIsOffByDefault() {
            &lt;span class=&quot;rem&quot;&gt;// Arrange&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tv = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Television();

            &lt;span class=&quot;rem&quot;&gt;// Assert&lt;/span&gt;
            Assert.IsFalse(tv.IsOn);
        }

        [TestMethod]
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; TVTurnsOnWhenTurnOnSignalIsReceived() {
            &lt;span class=&quot;rem&quot;&gt;// Arrange&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tv = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Television();

            &lt;span class=&quot;rem&quot;&gt;// Act&lt;/span&gt;
            tv.ReceiveSignal(&lt;span class=&quot;str&quot;&gt;&quot;on&quot;&lt;/span&gt;);

            &lt;span class=&quot;rem&quot;&gt;// Assert&lt;/span&gt;
            Assert.IsTrue(tv.IsOn);
        }

        [TestMethod]
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; TVDoesNotTurnOnWhenOtherSignalIsReceived() {
            &lt;span class=&quot;rem&quot;&gt;// Arrange&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tv = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Television();

            &lt;span class=&quot;rem&quot;&gt;// Act&lt;/span&gt;
            tv.ReceiveSignal(&lt;span class=&quot;str&quot;&gt;&quot;foobar&quot;&lt;/span&gt;);

            &lt;span class=&quot;rem&quot;&gt;// Assert&lt;/span&gt;
            Assert.IsFalse(tv.IsOn);
        }&lt;/pre&gt;
&lt;br /&gt;
These tests now require me to implement a Television class. Notice that we&#39;re not using the RemoteControl class or mocking here - for the purposes of this example, the Television class doesn&#39;t have any external dependencies, so we&#39;re just checking that when it&#39;s first instantiated it&#39;s turned off. Also worth noting is that the Television implementation won&#39;t affect any of the previous tests, because they&#39;re testing with a mock implementation of the ITelevision interface, rather than the real implementation. In our production code, we would inject the Television class in to the RemoteControl implementation, similar to the way we injected the mock in our tests.&lt;br /&gt;
&lt;br /&gt;
Once the Television class is created, the &lt;i&gt;TVIsOffByDefault &lt;/i&gt;and &lt;i&gt;TVDoesNotTurnOnWhenOtherSignalIsReceived &lt;/i&gt;tests will pass straight away (which is contrary to everything I&#39;ve been saying about TDD), but what they do allow us to do is define that &lt;i&gt;IsOn&lt;/i&gt; is always handled correctly when we finally get the &lt;i&gt;TVTurnsOnWhenTurnOnSignalIsReceived &lt;/i&gt;implementation working. They allow us to check that you or any other developers don&#39;t do anything undesired, like implement a constructor that sets &lt;i&gt;IsOn = true&lt;/i&gt;, or allow any signal at all to turn the TV on.&lt;br /&gt;
&lt;br /&gt;
The &lt;i&gt;TVTurnsOnWhenTurnOnSignalIsReceived &lt;/i&gt;checks that the receipt of the &quot;on&quot; signal turns the TV on, and the &lt;i&gt;TVDoesNotTurnOnWhenOtherSignalIsReceived &lt;/i&gt;test makes sure that sending anything but &quot;on&quot; will not turn the TV on (well, not exactly, but it&#39;s as close as we&#39;re gonna get). The implementation for the Television class is below:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Television : ITelevision {
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; HasElectricalPower { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; IsOn { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ReceiveSignal(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; signal) {
            IsOn = signal.Equals(&lt;span class=&quot;str&quot;&gt;&quot;on&quot;&lt;/span&gt;);
        }
    }&lt;/pre&gt;
&lt;br /&gt;
So, there we have it - a beginners insight in to the world of TDD. As with anything to do with development, you can go absolutely crazy with mocking and testing, but I find it depends on the project. Unit tests should be simple and to the point, and a mocked object should only really ever implement the properties and methods that are required for the test you&#39;re writing to pass.</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/815188674209658690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/815188674209658690'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2013/01/tdd-and-unit-testing-with-moq.html' title='TDD and Unit Testing with Moq'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-3719870311069434410</id><published>2013-01-04T19:55:00.001+00:00</published><updated>2013-01-05T15:58:18.753+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Blog / General / Personal"/><category scheme="http://www.blogger.com/atom/ns#" term="Contracting"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><title type='text'>2012: The Year The World Would End</title><content type='html'>Despite my growing cynicism towards anything even remotely joyous and celebratory, 2012 has been the best year of my life so far. I married my wonderful wife; celebrated 30 years on the Earth; visited a number of historic landmarks and cities in the UK; spent August travelling through nine American states, sampling a vast array of cuisine and witnessing some amazing sights; and dug my teeth in to a lot of patterns and technology that&#39;s really interested me. I&#39;ve also started on the path to clearing out all of the junk I&#39;ve accumulated over the past 15 years, which has turned out to be an extremely liberating experience, even if it means I had to bite the bullet and chuck out a vast number of things that &quot;I might use before I die&quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
    &lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu4f7phowtNHFUWdHLWFfYDT9y8-ckh9h-rRScdlBo0iuYMeLhCHioe5IgTpKNoRHPelJYKQUVtRHNurABbPRX11hKy7T7zmbYY4InbgS_FGAF8mrPDoft0s7n7ujtrecQvsq_mmuipkA/s1600/computer-junk-2.jpeg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;
      &lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu4f7phowtNHFUWdHLWFfYDT9y8-ckh9h-rRScdlBo0iuYMeLhCHioe5IgTpKNoRHPelJYKQUVtRHNurABbPRX11hKy7T7zmbYY4InbgS_FGAF8mrPDoft0s7n7ujtrecQvsq_mmuipkA/s320/computer-junk-2.jpeg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;
    &lt;/td&gt;
   &lt;/tr&gt;
&lt;tr&gt;
    &lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Fig 1. A shit tip&lt;/span&gt;&lt;/td&gt;
   &lt;/tr&gt;
&lt;/tbody&gt;
 &lt;/table&gt;
&lt;br /&gt;
I could prattle on about how awesome married life is, or regale you with my adventures across land and sea, but this isn&#39;t one of those god-awful social networking sites where all but the most discerning have an ultrasound as their profile picture, and I&#39;m pretty sure that the few subscribers I do have are more interested in development tech than how many inches my beard grew this year, or how I just spilled avocado soup on my crotch. So instead I&#39;m choosing to highlight some of the interesting projects I&#39;ve worked on, the tech I&#39;ve managed to pick up, and some lessons I&#39;ve learned.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Intermediary Code&lt;/h3&gt;
&lt;br /&gt;
2012 was a very productive year for me. I started out finishing up a contract with Paymentshield Ltd, an insurance broker that were undergoing a complete overhaul of their internal and external systems. I ended up doing quite a lot of different things while I was there, but my main task was designing and implementing a completely bespoke, role-based security system that could be used in other developers&#39; systems, and by 3rd parties such as clients, brokers and insurance companies. It also needed to integrate in to their existing legacy core system seamlessly, which is where the main challenge presented itself. The experience fully exposed me to the wonderful world of WCF and SOA, and I really got my hands dirty with SSIS, writing some pretty complex packages that transfer heaps of data between their systems in a matter of minutes. I also put together a custom CMS for their new &lt;a href=&quot;https://www.paymentshield-advisers.co.uk/&quot; target=&quot;_blank&quot;&gt;intermediary website&lt;/a&gt; in ASP.Net Web Forms, including the functional public facing pages, the CMS administration panel, and the vast majority of the control panel for their intermediaries.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
    &lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8h64NGq29XDwUP1pab58OT6hfTCFZ3_7iXi3ce5WiHjpBLMkDpYHAj8dz6atOwasVIRsAVoposLtPxFoNoLE-QjPK0z2MR8d8K3ksXEyDZnffRX6vW-ihcwLYNhNqPQw2_Mo1rH-IPEM/s1600/psl.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;
     &lt;img border=&quot;0&quot; height=&quot;355&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8h64NGq29XDwUP1pab58OT6hfTCFZ3_7iXi3ce5WiHjpBLMkDpYHAj8dz6atOwasVIRsAVoposLtPxFoNoLE-QjPK0z2MR8d8K3ksXEyDZnffRX6vW-ihcwLYNhNqPQw2_Mo1rH-IPEM/s400/psl.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;
   &lt;/tr&gt;
&lt;tr&gt;
    &lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;The Paymentshield Intermediary website&lt;/span&gt;&lt;/td&gt;
   &lt;/tr&gt;
&lt;/tbody&gt;
 &lt;/table&gt;
&lt;br /&gt;
Whilst at Paymentshield I met a couple of developers that I got along with pretty well. One in particular - a guy called Stephen - inspired me to really push myself technically; we had plenty of geeky discussions around bleeding-edge tech, built up a bit of a rapport (mainly surrounding his disgust in my placement of curly brackets in code :\), and I learned a hell of a lot from him. Anyway, man-crush aside, and not wishing to do myself out of a potential job, if you&#39;re looking for a particularly gifted and knowledgeable Microsoft / web developer, you can get hold of him through his &lt;a href=&quot;http://www.rowanbeach.com/&quot; target=&quot;_blank&quot;&gt;website / blog&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
As to what I learned; dare I admit that I&#39;d never even heard of Dependency Injection and Inversion of Control before I started at Paymentshield, and although I&#39;d touched upon it, WCF was still a bit of a mystery to me. I came away with a good, rounded knowledge of everything I worked on, and I&#39;ve been consistently using and improving those skills ever since - in fact, I often advocate the use of DI / IoC, SOA, and a number of design patterns; I can&#39;t see how I managed without them!&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Love Code&lt;/h3&gt;
&lt;br /&gt;
In May, I took on a project at webuyanycar.com, architecting and developing a new website they had in the pipeline. Even though I&#39;ve put together a few smaller MVC apps over the years, this was my first commercial MVC focused role - and it&#39;s something I&#39;ve been interested in for quite some time. Prior to this I&#39;d been developing with MVC3 almost every day since it was released in January 2011 - spending hours per night on one of my personal projects. I&#39;d been doing some pretty complex stuff too... so when I actually got down to the nitty gritty for the client&#39;s project, I realised that my knowledge was actually quite advanced and current. Suffice to say that I pumped out another bespoke CMS in just 3 months, that integrated in to their existing SOA architecture and CRM system.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
    &lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM8OgTaZqTR2dV-sU1yRh-MNU1ulOA0-UbI3sL6LqeNFnWDLwLAvGseXZNapgwi0wIDMOGC3_QsNml8txQpJ-h4OK83xet6UGCfYSNMQddQmmH1WUdw3habE5qzEZoNvd92M5rQWz6tyc/s1600/wlac.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;
     &lt;img border=&quot;0&quot; height=&quot;258&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM8OgTaZqTR2dV-sU1yRh-MNU1ulOA0-UbI3sL6LqeNFnWDLwLAvGseXZNapgwi0wIDMOGC3_QsNml8txQpJ-h4OK83xet6UGCfYSNMQddQmmH1WUdw3habE5qzEZoNvd92M5rQWz6tyc/s400/wlac.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;
   &lt;/tr&gt;
&lt;tr&gt;
    &lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://www.weloveanycar.com/&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;b&gt;www.weloveanycar.com&lt;/b&gt;&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
   &lt;/tr&gt;
&lt;/tbody&gt;
 &lt;/table&gt;
&lt;br /&gt;
My contract ended a few weeks before the site was supposed to go live, as I took off to get married and spend a month on honeymoon in the States. The website has since launched, though it&#39;s not seeing much activity at the moment; a little birdy has told me they&#39;re in the process of redeveloping it as the focus has changed since I was there, so it looks like the &lt;a href=&quot;http://www.weloveanycar.com/&quot; target=&quot;_blank&quot;&gt;fruit of my labour&lt;/a&gt; might not be there too long.&lt;br /&gt;
&lt;br /&gt;
There were two of us developing the site; the second contractor was in charge of everything front-end, which helped to speed up my back-end development considerably. While I was there I managed to pick up a few things I&#39;d not spent too much time on before; JS / CSS minification and bundling, a little bit of Test Driven Development, mocking, search engine optimisation, and software build management.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Rusty Code&lt;/h3&gt;
&lt;br /&gt;
Whilst at webuyanycar (in my free time, of course), I finally managed to launch my pet project &lt;a href=&quot;http://www.rustyshark.com/&quot; target=&quot;_blank&quot;&gt;rustyshark.com&lt;/a&gt;. I&#39;d spent a couple of years developing it on and off, and at the beginning of 2012 I made a concerted effort to get it up to a point that I could launch a beta version. &lt;a href=&quot;http://spikehd.blogspot.co.uk/2012/06/rustysharkcom-is-finally-online.html&quot; target=&quot;_blank&quot;&gt;Since then&lt;/a&gt;, I&#39;ve been feverishly adding features and fixing bugs, tacking spammers, writing as many reviews as I&#39;ve been able to (considering my time invested elsewhere), and trying to optimise it for the search engines. I can&#39;t say it&#39;s been easy, but I finally feel as if I&#39;ve put something together I can be proud of. When I&#39;ve got a few more of the public facing pages completed (such as the search and the news filtering) I&#39;ll be happy to call it a &quot;release&quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
    &lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyNdLQotXaeESa_hhccVIvTkS88xjJGoI_tVkffwNUx6yqaHzqQd2yB9aIiEZzYbAtmcOGkzrS7-EUMXnxH9w-MhZZRkNUxMKslGishlRBFTL2HON7CkWPMZv1uLhxGMGfzMWuBYgDMg8/s1600/rs.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;
     &lt;img border=&quot;0&quot; height=&quot;285&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyNdLQotXaeESa_hhccVIvTkS88xjJGoI_tVkffwNUx6yqaHzqQd2yB9aIiEZzYbAtmcOGkzrS7-EUMXnxH9w-MhZZRkNUxMKslGishlRBFTL2HON7CkWPMZv1uLhxGMGfzMWuBYgDMg8/s400/rs.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;
   &lt;/tr&gt;
&lt;tr&gt;
    &lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Fig 2. Better looking than your girlfriend.&lt;/span&gt;&lt;/td&gt;
   &lt;/tr&gt;
&lt;/tbody&gt;
 &lt;/table&gt;
&lt;br /&gt;
I did have high hopes for the website; it was never going to be able to compete with the likes of IGN or GameSpot, but I wanted it to be somewhere that me and my geeky friends could shoot the shit about games and films, whilst also serving to teach me a new technology that I&#39;ve been meaning to learn for a while. Whilst the later was extremely successful (and then some), the former suffered due to a number of reasons. The friend I conceived the website with let me down more than a few times, and just couldn&#39;t commit to the project due to personal reasons, and the people who said they&#39;d help out with the odd review here and there all have their own things going on. Whilst I can&#39;t complain (I totally appreciate everything I&#39;ve received from people), unfortunately I can&#39;t do everything myself, meaning there isn&#39;t anywhere near as much content as I&#39;d like there to be. I&#39;m still posting reviews when I can (I&#39;ve got two on the go at the moment), and hopefully it&#39;ll pick up again at some point in the near future.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve managed to apply almost all of the skills and techniques I&#39;ve learned over the last year to the website; only a few weeks ago I updated it to use .Net 4.5, EntityFramework 5.0 (turning off lazy-loading at the same time, which meant I had to test absolutely everything on the website thoroughly for missing data), AutoMapper 2.2.1-ci9000 (pre-release), MVC4, and added RSS feeds and a comment approval system. I&#39;ll continue to update the site, whether I&#39;m posting reviews on there or not, as I enjoy the challenge, and it serves as a good test bed for new technology. One thing I&#39;m very keen on doing is adding a lot of unit and integration tests to my service factories, as my most recent contract has exposed me to the vast benefits of TDD and mocking.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Independent Code&lt;/h3&gt;
&lt;br /&gt;
I just finished at &lt;a href=&quot;http://www.independentgroupltd.co.uk/&quot; target=&quot;_blank&quot;&gt;Independent Group&lt;/a&gt;, a claims management company that are in the process of upgrading all of the hardware and software across the entire group; a vast undertaking that&#39;s being carried out in carefully planned steps. They&#39;ve got a lot of legacy software, which requires staged replacement, and I was tasked with designing and implemented an SOA system that pulls information from various internal sources, and provides it to their suppliers. I got to flex my SSIS, WCF and MVC skills again, but also did a lot of infrastructure; setting up IIS and SQL servers, configuring DNS, installing certificates, and setting up builds and deployment. I&#39;ve not really done much infrastructure for the past few years, as most of my clients have had departments that deal with it, so it was actually quite refreshing to get to grips with IIS7 and Windows Server for a change.&lt;br /&gt;
&lt;br /&gt;
I&#39;m quite proud of the work I&#39;ve done at Independent - everything has been TDD from day one (last time I looked, I was at 89% code coverage), and all components are fully documented. I can&#39;t say I&#39;ve learned all that much while I was there, but I did get a good grip on mocking, and had another opportunity to analyse and design a loosely-coupled, enterprise level piece of software.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
My Code&lt;/h3&gt;
&lt;br /&gt;
Looking back over the year, I really feel like I&#39;ve come a long way. I&#39;ve been learning how to develop for around 16 years, in which time I&#39;ve worked with clients of all shapes and sizes, and designed and developed software from simple web sites to massive, scalable enterprise solutions.&lt;br /&gt;
&lt;br /&gt;
My aim this year it to look in to mobile app development; whether it&#39;s games or tablet apps. Even if I do despair every time I see a 14 year old with their face permanently glued to Angry Birds, it&#39;s the future, and if I don&#39;t start looking in to it soon, I&#39;m gonna be left behind!</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/3719870311069434410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/3719870311069434410'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2013/01/2012-year-world-would-end.html' title='2012: The Year The World Would End'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu4f7phowtNHFUWdHLWFfYDT9y8-ckh9h-rRScdlBo0iuYMeLhCHioe5IgTpKNoRHPelJYKQUVtRHNurABbPRX11hKy7T7zmbYY4InbgS_FGAF8mrPDoft0s7n7ujtrecQvsq_mmuipkA/s72-c/computer-junk-2.jpeg" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-9166841398551129551</id><published>2012-07-02T07:04:00.000+01:00</published><updated>2013-01-05T15:42:51.305+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Windows"/><title type='text'>Windows 7: One Network Adapter, Two Connections; No Internet Connection</title><content type='html'>For the past week, my main PC has been occasionally booting with a lovely little yellow exclamation mark over the network icon in the system tray. The only way to rectify it was to reboot once or twice, which confused me a little bit.

Anyway, to cut a long story short, it&#39;s the Bonjour network service that was recently installed with Skype (I&#39;m currently working at home and we&#39;re using Skype to communicate). It seems that the best way to solve this (without affecting Skype) is to &quot;Delay Start&quot; the service.

The service (and it doesn&#39;t sound like this happens on everyone&#39;s machine) is pretty easy to find, only because it&#39;s got a GUID for a name in the Services snap-in (Start Menu -&amp;gt; Administrative Tools -&amp;gt; Services):

&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcchY1DFbJbWYZhXL1eTl0rwTRHob-dvNXfs5thbF5rKeln2k2BLaz77jb3gxF-Bse9CGW7jDTXPofO5AzTpSqv1ak4h9UlXoiIN7-120Z7CeVtD6clyvDh77NTj1cy0F6o_HsvnZYZ9g/s1600/bonjour.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;150&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcchY1DFbJbWYZhXL1eTl0rwTRHob-dvNXfs5thbF5rKeln2k2BLaz77jb3gxF-Bse9CGW7jDTXPofO5AzTpSqv1ak4h9UlXoiIN7-120Z7CeVtD6clyvDh77NTj1cy0F6o_HsvnZYZ9g/s400/bonjour.png&quot; title=&quot;&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;i&gt;GUIDs: scaring the shit out of advanced computer users since 1998.&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
Suffice to say, it looks dodgy, so it was investigated. Luckily, there&#39;s plenty of info on Google about it. Just change the startup type to &quot;Automatic (Delayed Start)&quot; and everything goes away.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfGyo5DQJ2nhFeMBe53Y6dl1GKKYHq2aXA0Oks1K2CS0nhEREArOAVRwUn9WT-L5YGsDZoej-xNaE_FMWqPDUz2HF2rt3YK9jEuD5S1RqpBdn7SbnDfCuWPishtgC0qvP5lXWmBsxIo08/s1600/bonjour-2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfGyo5DQJ2nhFeMBe53Y6dl1GKKYHq2aXA0Oks1K2CS0nhEREArOAVRwUn9WT-L5YGsDZoej-xNaE_FMWqPDUz2HF2rt3YK9jEuD5S1RqpBdn7SbnDfCuWPishtgC0qvP5lXWmBsxIo08/s1600/bonjour-2.png&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;i&gt;Apple are a pack of bastards&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/9166841398551129551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/9166841398551129551'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2012/07/windows-7-one-network-adapter-two.html' title='Windows 7: One Network Adapter, Two Connections; No Internet Connection'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcchY1DFbJbWYZhXL1eTl0rwTRHob-dvNXfs5thbF5rKeln2k2BLaz77jb3gxF-Bse9CGW7jDTXPofO5AzTpSqv1ak4h9UlXoiIN7-120Z7CeVtD6clyvDh77NTj1cy0F6o_HsvnZYZ9g/s72-c/bonjour.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-1529668572578721499</id><published>2012-06-28T11:15:00.001+01:00</published><updated>2013-12-26T10:42:10.632+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AutoMapper"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><title type='text'>AutoMapper: UseValue vs ResolveUsing vs MapFrom</title><content type='html'>I just hit a confusing mapping bug whilst using &lt;a href=&quot;http://automapper.org/&quot; target=&quot;_blank&quot;&gt;AutoMapper&amp;nbsp;&lt;/a&gt;to map DateTime.Now to a field in my database. Every item that was being added to the database had the same value in the &quot;DateAdded&quot; - to the millisecond. This was because I was using the following mapping expression:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;Mapper.CreateMap&amp;lt;SourceObject, DestObject&amp;gt;()
.ForMember(m =&amp;gt; m.DateAdded, o =&amp;gt; o.UseValue(DateTime.Now));&lt;/pre&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;/pre&gt;
&lt;br /&gt;
UseValue() retrieves a value on first-run and stores it in the mapping (hence the static DateTime value that&#39;s being stored in the database), whereas ResolveUsing() resolves at run-time - which is obviously why it&#39;s called &lt;i&gt;Resolve&lt;/i&gt;Using(). A minor oversight, but confusing&amp;nbsp;nonetheless.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Use ResolveUsing(s =&amp;gt; {}) when you want to resolve a destination field from a derived value. This should be used for any DateTime mappings, and any more complicated mapping functions.&lt;/li&gt;
&lt;li&gt;Use MapFrom(s =&amp;gt; s.MemberName) when you return an actual source object member.&lt;/li&gt;
&lt;li&gt;Use UseValue() if you want to map a static value in the mapping, and you know the value itself won&#39;t change.&lt;/li&gt;
&lt;/ul&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/1529668572578721499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/1529668572578721499'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2012/06/automapper-usevalue-vs-resolveusing-vs.html' title='AutoMapper: UseValue vs ResolveUsing vs MapFrom'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-756665267347878157</id><published>2012-06-24T09:52:00.000+01:00</published><updated>2013-12-26T10:42:47.538+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="JQuery"/><title type='text'>IMDB API Lookup JQuery Plugin</title><content type='html'>I spent a few hours last night writing my first ever JQuery plugin, only to realise today that it&#39;s completely useless to me! I wanted an easy way to populate the &quot;Add medium&quot; form on &lt;a href=&quot;http://www.rustyshark.com/&quot; target=&quot;_blank&quot;&gt;RustyShark&lt;/a&gt;, as it tends to take me a few hours every time I add a new review (and therefore medium) to the website (y&#39;know, looking up information, finding images, finding box art, editing the review etc), and I wanted to increase my production rate :)&lt;br /&gt;
&lt;br /&gt;
IMDB offers its data for free, for non commercial use, but only in text files. I found an API at &lt;a href=&quot;http://www.imdbapi.com/&quot;&gt;http://www.imdbapi.com/&lt;/a&gt;, which has gone a long way to simplifying and serializing the information in to something useful, so I decided to use this opportunity to teach myself how to write JQuery plugins. Below is my resulting plugin, queryable by Title + Year, or IMDB ID:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;; (function ($) {
    $.fn.imdbLookup = function (options) {
        &lt;span class=&quot;rem&quot;&gt;// Default options&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; defaults = {
            complete: function (imdbData) {
            },
            title: &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;,
            date: &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;,
            imdbId: &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;
        };
        &lt;span class=&quot;rem&quot;&gt;// Overwrite defaults with passed options&lt;/span&gt;
        options = $.extend(defaults, options);

        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.each(function () {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; $&lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; = $(&lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;);
            $&lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.click(function () {
                &lt;span class=&quot;rem&quot;&gt;// Get defaults&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; title = (options.title != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt; &amp;amp;&amp;amp; options.title.val().length &amp;gt; 0) ? options.title.val().trim() : &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; date = (options.date != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt; &amp;amp;&amp;amp; options.date.val().length &amp;gt; 0) ? $.parseDate(options.date.val().trim()) : &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; imdbId = (options.imdbId != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt; &amp;amp;&amp;amp; options.imdbId.val().length &amp;gt; 0) ? options.imdbId.val().trim() : &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;

                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; ((title == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt; || date == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) &amp;amp;&amp;amp; imdbId == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; year = date.getFullYear();

                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; qs;

                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (title != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt; &amp;amp;&amp;amp; date != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) {
                    qs = {
                        t: title,
                        y: year
                    };
                } &lt;span class=&quot;kwrd&quot;&gt;else&lt;/span&gt; {
                    qs = {
                        i: imdbId
                    };
                }
                
                $.ajax({
                    url: &lt;span class=&quot;str&quot;&gt;&#39;http://www.imdbapi.com/&#39;&lt;/span&gt;,
                    type: &lt;span class=&quot;str&quot;&gt;&quot;GET&quot;&lt;/span&gt;,
                    dataType: &lt;span class=&quot;str&quot;&gt;&quot;json&quot;&lt;/span&gt;,
                    data: $.extend({
                        r: &lt;span class=&quot;str&quot;&gt;&#39;JSON&#39;&lt;/span&gt;,
                        plot: &lt;span class=&quot;str&quot;&gt;&#39;short&#39;&lt;/span&gt;,
                        tomatoes: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;
                    }, qs),
                    success: function (imdbData) {
                        options.complete(imdbData);
                    }
                });
            });
        });
    };

})(jQuery);&lt;/pre&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;    $(&lt;span class=&quot;str&quot;&gt;&quot;#MyElement&quot;&lt;/span&gt;).imdbLookup({
        complete: function (imdbData) {
            alert(imdbData); &lt;span class=&quot;rem&quot;&gt;// Do something with the resulting object&lt;/span&gt;
        },
        title: $(&lt;span class=&quot;str&quot;&gt;&quot;#Title&quot;&lt;/span&gt;),
        date: $(&lt;span class=&quot;str&quot;&gt;&quot;#ReleaseDate&quot;&lt;/span&gt;)
    });&lt;/pre&gt;
&lt;br /&gt;
Or:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;    $(&lt;span class=&quot;str&quot;&gt;&quot;#MyElement&quot;&lt;/span&gt;).imdbLookup({
        complete: function (imdbData) {
            alert(imdbData); &lt;span class=&quot;rem&quot;&gt;// Do something with the resulting object&lt;/span&gt;
        },
        imdbId: $(&lt;span class=&quot;str&quot;&gt;&quot;#imdbId&quot;&lt;/span&gt;)
    });&lt;/pre&gt;
&lt;br /&gt;
Please read&amp;nbsp;&lt;a href=&quot;http://www.imdbapi.com/&quot;&gt;http://www.imdbapi.com/&lt;/a&gt; for notes on usage.&lt;br /&gt;
&lt;br /&gt;
It seems to work for me at the moment, but treat it as completely untested - I&#39;ve only tried it in Chrome, and I haven&#39;t tested the IMDB ID method at all. I just wanted to put the code somewhere before I removed it from the JS in &lt;a href=&quot;http://www.rustyshark.com/&quot; target=&quot;_blank&quot;&gt;RustyShark &lt;/a&gt;:)</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/756665267347878157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/756665267347878157'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2012/06/imdb-api-lookup-jquery-plugin.html' title='IMDB API Lookup JQuery Plugin'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-6636064405680721626</id><published>2012-06-11T00:39:00.001+01:00</published><updated>2013-01-05T16:03:03.177+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Blog / General / Personal"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><title type='text'>RustyShark.com is finally online!</title><content type='html'>Regular readers will know that I&#39;ve been working on my new game and film review site for a good while now. I&#39;ve been spending my spare time in the past few weeks editing the reviews I&#39;ve written and gathered from friends, which has been a task in itself. Unfortunately, because the site is a bit of a movie and game database as well as a review site, it takes me a while to gather all of the information for each one, so I&#39;ve not been able to launch with too many published! Suffice to say, I&#39;ve got a &lt;i&gt;lot &lt;/i&gt;more to get through, but when I&#39;ve caught up I should be able to edit and publish reviews as they come in. All of the reviews I&#39;ve received will be dealt with ASAP!&lt;br /&gt;
&lt;br /&gt;
I&#39;ve still got a long way to go until version 1 of the site is completely finished. I still have to write the news editing tools and there are lots of additional features I want to implement, like a Facebook login, more products from different sites and RSS feeds. Of course, I&#39;ve still got quite a bit of layout tweaking to do, and quite a few additional niceties like a carousel and new panels.&lt;br /&gt;
&lt;br /&gt;
For those interested, I&#39;ve written the site in MVC3, using SQL Server 2008 and Entity Framework 4.3. I&#39;ve written it from scratch, rather than use a CMS like Joomla or Umbraco, in order to thoroughly teach myself the MVC pattern and all of the tools Microsoft have added to the latest version. All sensitive information is encrypted with SHA256, and I&#39;ve written a load of image manipulation classes and MVC helpers.&lt;br /&gt;
&lt;br /&gt;
My JQuery isn&#39;t the best, so any front-end guys looking at the client-side code might have a chuckle or two. It&#39;s something I aim to improve in future years, as I quite enjoy it, but it&#39;s not something I&#39;ve been involved with too heavily.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve tested as much of the site as I can, with all of the major browsers. I &lt;i&gt;haven&#39;t&lt;/i&gt; spent any time getting it working with older versions (especially not the dreaded IE6); it may be something I look in to in the future, but we&#39;ll see how it goes.&lt;br /&gt;
&lt;br /&gt;
I still consider the site in &quot;alpha&quot;, as I&#39;ve not been able to really hammer the testing. If anyone sees any issues, or has any ideas about how to improve it, all feedback is appreciated!&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.rustyshark.com/&quot;&gt;www.rustyshark.com&lt;/a&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/6636064405680721626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/6636064405680721626'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2012/06/rustysharkcom-is-finally-online.html' title='RustyShark.com is finally online!'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-7747481638737595562</id><published>2012-05-15T10:16:00.000+01:00</published><updated>2013-01-05T15:56:50.287+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AutoMapper"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><title type='text'>AutoMapper 2.1 AfterMap() Fires Multiple Times</title><content type='html'>I&#39;ve been writing some complex mapping for the&amp;nbsp;hierarchical&amp;nbsp;data on my &lt;a href=&quot;http://www.rustyshark.com/&quot; target=&quot;_blank&quot;&gt;RustyShark &lt;/a&gt;site (the Media entities on the site consist of a lot of dynamic meta data, which can be added and removed when edited). I&#39;m&amp;nbsp;using Entity Framework and AutoMapper, and I&#39;ve ran in to an issue where AfterMap() executes multiple times, when it should only really execute once. I just thought I&#39;d post my workaround, which also helps to demonstrate how C# interfaces can be handy. Here&#39;s what my source entity looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Medium : IAutoMapperAfterMapUsage {
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;? MediumID { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Title { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; DateTime ReleaseDate { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; User CreatedBy { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; DateTime CreatedDate { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }

    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; List&amp;lt;Genre&amp;gt; Genres { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; List&amp;lt;MediaFormat&amp;gt; Formats { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; List&amp;lt;MetaData&amp;gt; MetaData { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }

    &lt;span class=&quot;preproc&quot;&gt;#region&lt;/span&gt; IAutoMapperAfterMapUsage

    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; Mapped { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }

    &lt;span class=&quot;preproc&quot;&gt;#endregion&lt;/span&gt;
}&lt;/pre&gt;
&lt;br /&gt;
The destination entity isn&#39;t a concern here, so I won&#39;t post the code. As you can see, I&#39;ve added a&amp;nbsp;custom interface, IAutoMapperAfterMapUsage&amp;nbsp;which has one property:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IAutoMapperAfterMapUsage {
    &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; Mapped { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
}&lt;/pre&gt;
&lt;br /&gt;
The boolean simply acts as a state manager, so whenever you need to use AfterMap(), implement the interface and add a single line of code at the top of your AfterMap method:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;Mapper.CreateMap&amp;lt;Entities.Medium, Medium&amp;gt;()
    .ForMember(m =&amp;gt; m.CreatedDate, o =&amp;gt; o.Condition(s =&amp;gt; (s.MediumID ?? 0) &amp;lt;= 0))
    .ForMember(m =&amp;gt; m.CreatedDate, o =&amp;gt; o.ResolveUsing(s =&amp;gt; DateTime.Now))
    .ForMember(m =&amp;gt; m.CreatedBy, o =&amp;gt; o.Condition(s =&amp;gt; (s.MediumID ?? 0) &amp;lt;= 0))
    .ForMember(m =&amp;gt; m.CreatedBy, o =&amp;gt; o.MapFrom(s =&amp;gt; s.CreatedBy.UserID))
    .ForMember(m =&amp;gt; m.Title, o =&amp;gt; o.ResolveUsing(s =&amp;gt; s.Title.Trim()))
    .ForMember(m =&amp;gt; m.MediaType, o =&amp;gt; o.Ignore())
    .ForMember(m =&amp;gt; m.Genres, o =&amp;gt; o.Ignore())
    .ForMember(m =&amp;gt; m.MediaFormats, o =&amp;gt; o.Ignore())
    .ForMember(m =&amp;gt; m.MediaMetaData, o =&amp;gt; o.Ignore())
    .AfterMap((source, dest) =&amp;gt; {
        &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (source.Mapped) &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/span&gt;&lt;/b&gt;
        &lt;span class=&quot;rem&quot;&gt;// Do complex mapping for Genres, MediaFormats and MediaMetaData&lt;/span&gt;

        source.Mapped = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
    });&lt;/pre&gt;
&lt;br /&gt;
Apparently this has been &lt;a href=&quot;https://github.com/AutoMapper/AutoMapper/issues/105&quot; target=&quot;_blank&quot;&gt;fixed&lt;/a&gt;, though the fix does say &quot;&lt;a class=&quot;message&quot; href=&quot;https://github.com/jbogard/AutoMapper/commit/015aa2ce766e0414bcf6476d5c097ebb30a70a70&quot; style=&quot;background-color: #fbfbfb; border-bottom-width: 0px; border-color: initial; border-image: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; color: #333333; font-family: Monaco, &#39;Courier New&#39;, &#39;DejaVu Sans Mono&#39;, &#39;Bitstream Vera Sans Mono&#39;, monospace; font: inherit; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-decoration: none;&quot;&gt;Moved after map to execute &lt;b&gt;less often&lt;/b&gt;, fixes&amp;nbsp;&lt;/a&gt;&lt;a class=&quot;issue-link&quot; href=&quot;https://github.com/AutoMapper/AutoMapper/issues/105&quot; style=&quot;background-color: #fbfbfb; border-bottom-width: 0px; border-color: initial; border-image: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; color: #333333; font-family: Monaco, &#39;Courier New&#39;, &#39;DejaVu Sans Mono&#39;, &#39;Bitstream Vera Sans Mono&#39;, monospace; font: inherit; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-decoration: none;&quot; title=&quot;Multiple calls to AfterMap for bidirectional relationships&quot;&gt;#105&lt;/a&gt;&quot;, which isn&#39;t that reassuring. I also use this interface to expose my DbContext to the AfterMap() method, which is very handy for the complex scenarios I&#39;m working with.</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/7747481638737595562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/7747481638737595562'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2012/05/automapper-21-aftermap-fires-multiple.html' title='AutoMapper 2.1 AfterMap() Fires Multiple Times'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-8674883598729366121</id><published>2012-04-20T11:57:00.000+01:00</published><updated>2013-01-05T15:57:02.442+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="async"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio"/><title type='text'>Long running processes: C# 5, Visual Studio 11, async and await; updating a Winforms UI asynchronously</title><content type='html'>I recently downloaded &lt;a href=&quot;https://msdn.microsoft.com/en-gb/subscriptions/securedownloads/#FileId=48571&quot; target=&quot;_blank&quot;&gt;Visual Studio 11 Beta&lt;/a&gt;&amp;nbsp;in order to take a look at the new 4.5 .Net Framework and play around with its new features. I decided to take the opportunity to build a &quot;quick&quot; app that I&#39;ve been meaning to build for a few years; a single form Windows Client that allows me to send out an email merge to the 1,400 agents I have in my outlook contacts list, to let them know I&#39;m available for work.&amp;nbsp;Before now, every time I&#39;ve needed to send an &quot;I&#39;m available!&quot; email, I&#39;ve copied + pasted the same email a number of times, attached my CV and BCC&#39;d 100 or so agents at a time (too many and Outlook just falls over). Not only is it a massive waste of my time, but it&#39;s very error prone and not a very friendly way of doing things. Unfortunately, the mail merge feature of Word has its limitations, so I&#39;ve had to look in to my own solution.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Anyone who&#39;s worked with bulk email systems before knows fine well that any kind of mass emailing (solicited or unsolicited) is seen as &quot;spam&quot; by many email servers and ISPs. Some servers are clever enough to spot a mail merge, but most still work on limits. My current server host allows me to send 300 email per hour, which is way more than I&amp;nbsp;intend to send, but I&#39;ve still got to consider the receiving servers; I have 100+ agent email addresses per agency / domain, so I&#39;m likely to be black listed if I sent them all at once. So, with this in mind, I decided to build an email system that I could configure to fire off emails asynchronously, over a configurable period of time. Here&#39;s a quick screenshot - it&#39;s not exactly pretty, but it does what I need it to :)&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnqSL9jhUGoBd1qo82-6SUT3BBtMNJLYxvg_zAY8R-geY7jHHntfdtMv5UrvgrH07SqDinbWr5ilnBJTZk5_7FikAnEYW3-OUwLABV6P1aK_ornL4neaQgsqzJ8jiJ9lDbecELsY6yeKA/s1600/AgentMailer.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;408&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnqSL9jhUGoBd1qo82-6SUT3BBtMNJLYxvg_zAY8R-geY7jHHntfdtMv5UrvgrH07SqDinbWr5ilnBJTZk5_7FikAnEYW3-OUwLABV6P1aK_ornL4neaQgsqzJ8jiJ9lDbecELsY6yeKA/s640/AgentMailer.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div&gt;
The Email Template drop down requires a little bit of&amp;nbsp;explanation; I&#39;d already written a emailer class for my &lt;a href=&quot;http://www.rustyshark.com/&quot; target=&quot;_blank&quot;&gt;RustyShark&lt;/a&gt; project that accepts XML templates and replaces place holders (wrapped in {curly brackets}) with any data I so wish. All I had to do was build the forms, add in some configuration options and write the threading code.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In my app, I wanted to be able to select a CSV of email addresses and names, then click a button to send the selected template to everyone in the list at various increments. All of this is pretty each to achieve, but as always, long running processes (the app will be running over a number of hours; 1400 contacts x 20 second intervals = 7.8 hours) lock up the UI thread, meaning it&#39;s very difficult to monitor their progress. Obviously there&#39;s the System.Threading namespace, and the various BeginInvoke() methods scattered around the Framework, but I downloaded the VS11 Beta to learn something, and learn something I did!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Enter the new &quot;async&quot; and &quot;await&quot; C# language features. I spent a while in the &lt;a href=&quot;http://msdn.microsoft.com/en-us/vstudio/gg316360&quot; target=&quot;_blank&quot;&gt;Visual Studio Developer Centre&lt;/a&gt; watching videos, reading whitepapers and trying examples, then I delved in to my specific requirement.&amp;nbsp;Asynchrony is not an easy task in any language or framework, but the new keywords (as long as you understand what they mean) &lt;i&gt;do &lt;/i&gt;help to simplify your code, and help with debugging. Let&#39;s jump straight in to an example.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
When I click &quot;Send&quot; at the bottom right of the app, I wanted to fire off a foreach() loop, which sends an email, updates the DataGrid, the label next to the send button, and a progress bar, which is not visible in the screenshot above. Though my form has a lot more code (error handling, logging etc), normal, synchronous code would look like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; btnSend_Click(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; sender, EventArgs e) {
    &lt;span class=&quot;rem&quot;&gt;// Set up progress bar&lt;/span&gt;
    progressBar.Maximum = recipients.Count;
    progressBar.Value = 0;
    progressBar.Step = 1;
    progressBar.Visible = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
    &lt;span class=&quot;rem&quot;&gt;// Disable form&lt;/span&gt;
    ToggleForm(&lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;);

    &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; r &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; recipients) {
        &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt; {
            &lt;span class=&quot;rem&quot;&gt;// Send email&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; msg = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Email();
            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!msg.Send()) {
                &lt;span class=&quot;rem&quot;&gt;// Email Failure&lt;/span&gt;
                r.Error = &lt;span class=&quot;str&quot;&gt;&quot;Unknown&quot;&lt;/span&gt;;
                &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;
            }
            &lt;span class=&quot;rem&quot;&gt;// Update recipient&lt;/span&gt;
            r.Success = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
        } &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt; (Exception ex) {
            r.Error = ex.Message;
            &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;
        } &lt;span class=&quot;kwrd&quot;&gt;finally&lt;/span&gt; {
            &lt;span class=&quot;rem&quot;&gt;// Update progress&lt;/span&gt;
            progressBar.PerformStep();
            progressBar.Refresh();
            &lt;span class=&quot;rem&quot;&gt;// Refresh grid&lt;/span&gt;
            r.Processed = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
            dgvRecipients.Refresh();
            &lt;span class=&quot;rem&quot;&gt;// Update label&lt;/span&gt;
            UpdateSummaryMessage();
        }

        &lt;span class=&quot;rem&quot;&gt;// Do not wait if there are no more recipients to process&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (recipients.All(x =&amp;gt; x.Success)) &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;

        &lt;span class=&quot;rem&quot;&gt;// Wait this thread for the specified amount of time&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; waitTime = (&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)(udSeconds.Value*1000);
        Thread.Sleep(waitTime);
    }
    &lt;span class=&quot;rem&quot;&gt;// Enable form&lt;/span&gt;
    ToggleForm(&lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;);

    progressBar.Visible = &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Recipients&lt;/i&gt; is a &lt;i&gt;List&amp;lt;Recipient&amp;gt;&lt;/i&gt;, which is data bound to the DataGridView. It contains the contact information loaded from the contacts CSV. &lt;i&gt;udSeconds &lt;/i&gt;is the Up Down Control on the form that selects the number of seconds to wait between emails. The &lt;i&gt;var msg = Email()&lt;/i&gt; line uses my custom &lt;i&gt;Email &lt;/i&gt;templating class, and actually needs a lot more code to work, but you get the general idea.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
As you can see, I&#39;m using &lt;i&gt;Thread.Sleep()&lt;/i&gt; to wait the thread for the number of seconds I&#39;ve specified with the Up Down Control. I experimented with a timer at this point, but using one would have pretty much negated the need for the async / await keywords I wanted to play with (and required me to use callbacks and invokes to update the UI thread), so I avoided it.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: orange; padding: 10px;&quot;&gt;
&lt;b&gt;UPDATE: 2nd May 2011&lt;/b&gt; - Since I wrote this post, I found out that &lt;i&gt;Thread.Sleep()&lt;/i&gt;&amp;nbsp;&lt;a href=&quot;https://msmvps.com/blogs/peterritchie/archive/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-program.aspx&quot; target=&quot;_blank&quot;&gt;should not be used for exact timing&lt;/a&gt;. The thread is blocked for a &lt;i&gt;&lt;b&gt;minimum &lt;/b&gt;&lt;/i&gt;of &lt;i&gt;{n}&lt;/i&gt; seconds, after which, control is then passed back to the OS to be scheduled back in for execution. Each version of each OS has it&#39;s own idea of what a processor time slice is, so there is no guarantee that the thread will continue execution after the time you have specified. My examples below are still valid, but only as &lt;i&gt;examples&lt;/i&gt;. Neither &lt;i&gt;Thread.Sleep()&lt;/i&gt;, &lt;i&gt;await Task.Delay()&lt;/i&gt; (also new to the Developer Preview) or &lt;i&gt;Task.Wait()&lt;/i&gt; should be used for precise scheduling. Contrary to my comment above, there are various timers available in the .Net Framework that are much more reliable than trying to control the thread directly, and should be used for this type of scenario.&lt;br /&gt;
&lt;br /&gt;
In my example, each call to&amp;nbsp;&lt;i&gt;Thread.Sleep()&lt;/i&gt;&amp;nbsp;took exponentially longer than the last. As you can imagine, over a number of hours, this built up to quite a lot of additional time. This would be totally&amp;nbsp;unacceptable&amp;nbsp;in a mission critical application.&lt;/div&gt;
&lt;br /&gt;
When the above code is implemented, the UI hangs for however long the task is running (in this case, nearly 8 hours). Even for a small, personal application, this is an unacceptable situation. Making this code asynchronous would normally require quite a bit of refactoring, but the new async / await keywords really speed it up:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;async &lt;/span&gt;&lt;/b&gt;&lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; btnSend_Click&lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;Async&lt;/span&gt;&lt;/b&gt;(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; sender, EventArgs e) {
    &lt;span class=&quot;rem&quot;&gt;// Set up progress bar&lt;/span&gt;
    progressBar.Maximum = recipients.Count;
    progressBar.Value = 0;
    progressBar.Step = 1;
    progressBar.Visible = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
    &lt;span class=&quot;rem&quot;&gt;// Disable form&lt;/span&gt;
    ToggleForm(&lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;);

  &lt;span style=&quot;color: red;&quot;&gt; &lt;b&gt; await Task.Run(() =&amp;gt; {&lt;/b&gt;&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; r &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; recipients) {
            &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt; {
                &lt;span class=&quot;rem&quot;&gt;// Send email&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; msg = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Email();
                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(!msg.Send()) {
                    &lt;span class=&quot;rem&quot;&gt;// Email Failure&lt;/span&gt;
                    r.Error = &lt;span class=&quot;str&quot;&gt;&quot;Unknown&quot;&lt;/span&gt;;
                    &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;
                }
                &lt;span class=&quot;rem&quot;&gt;// Update recipient&lt;/span&gt;
                r.Success = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
            } &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt;(Exception ex) {
                r.Error = ex.Message;
                &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;
            } &lt;span class=&quot;kwrd&quot;&gt;finally&lt;/span&gt; {
                &lt;span class=&quot;rem&quot;&gt;// Update progress&lt;/span&gt;
                r.Processed = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
               &lt;b&gt; &lt;span style=&quot;color: red;&quot;&gt;Report(r);&lt;/span&gt;&lt;/b&gt;
            }

            &lt;span class=&quot;rem&quot;&gt;// Do not wait if there are no more recipients to process&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(recipients.All(x =&amp;gt; x.Success)) &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;

            &lt;span class=&quot;rem&quot;&gt;// Wait this thread for the specified amount of time&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; waitTime = (&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)(udSeconds.Value * 1000);
            Thread.Sleep(waitTime);
        }
   &lt;b&gt; &lt;span style=&quot;color: red;&quot;&gt;});&lt;/span&gt;&lt;/b&gt;
    &lt;span class=&quot;rem&quot;&gt;// Enable form&lt;/span&gt;
    ToggleForm(&lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;);

    progressBar.Visible = &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;
}&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&quot;That&#39;s it?!&quot; I hear you scream? Well, almost. Most examples you&#39;ll see online just show you the addition of the two new keywords, and usually have a second method (tagged with the &lt;i&gt;async &lt;/i&gt;keyword), called in place of my &lt;i&gt;await Task.Run()&lt;/i&gt; line. &lt;a href=&quot;http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx&quot; target=&quot;_blank&quot;&gt;Task.Run() is new in the .Net 4.5 Developer Preview&lt;/a&gt;, and is basically a shortcut to the &lt;i&gt;Task.Factory.StartNew()&lt;/i&gt; method from .Net 4.0, only much simpler to use.&lt;br /&gt;
&lt;br /&gt;
So, what&#39;s this await keyword all about?&amp;nbsp;In order for any method to use the&amp;nbsp;&lt;i&gt;await&amp;nbsp;&lt;/i&gt;keyword within its body, it must be&amp;nbsp;&lt;i&gt;awaitable&lt;/i&gt;. In order to make a &amp;nbsp;method&amp;nbsp;&lt;i&gt;awaitable&lt;/i&gt;, you have to tag the&amp;nbsp;&lt;i&gt;async&lt;/i&gt;&amp;nbsp;keyword on to the method signature. If you tag&amp;nbsp;&lt;i&gt;async&amp;nbsp;&lt;/i&gt;on to a method and do not include the&amp;nbsp;&lt;i&gt;await&amp;nbsp;&lt;/i&gt;keyword in the body, the method is always executed&amp;nbsp;&lt;b&gt;&lt;i&gt;synchronously&lt;/i&gt;&lt;/b&gt;. The &lt;i&gt;await &lt;/i&gt;keyword simply tells the compiler that asynchronous code is to be executed, somewhere within the body of the method. Because the code is asynchronous, the method immediately returns to the UI thread and the code inside the &lt;i&gt;Task.Run()&lt;/i&gt; block is started on another thread. The interesting thing to understand here, is that the rest of the &lt;i&gt;btnSend_ClickAsync&lt;/i&gt; method &lt;i&gt;waits for&lt;/i&gt;&amp;nbsp;the asynchronous code to be executed before it is executed itself. This is immensely clever, considering everything looks perfectly synchronous, there are no callbacks specified, and we&#39;ve hardly changed any code.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
I&#39;ve not only used&lt;i&gt; Task.Run()&lt;/i&gt; because it has a cool lambda&amp;nbsp;implementation and I dislike&amp;nbsp;superfluous&amp;nbsp;methods, I&#39;ve used it to demonstrate that the &lt;i&gt;await &lt;/i&gt;keyword can be applied to any method that returns a &lt;i&gt;Task&lt;/i&gt;, as well as those that use the &lt;i&gt;async&lt;/i&gt; keyword. The &lt;i&gt;Task.Run()&lt;/i&gt; method does &lt;b&gt;&lt;i&gt;not &lt;/i&gt;&lt;/b&gt;use the &lt;i&gt;async &lt;/i&gt;keyword, it simply returns a &lt;i&gt;Task&lt;/i&gt;. The &lt;i&gt;Task &lt;/i&gt;class implements &lt;i&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.iasyncresult(v=vs.110).aspx&quot; target=&quot;_blank&quot;&gt;IAsyncResult&lt;/a&gt;&lt;/i&gt;, which proves that the compiler still uses callbacks in the background, even though you don&#39;t have to deal with them yourself.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So, where&#39;s this callback? Well, the compiler puts everything that comes after the &lt;i&gt;await Task.Run()&lt;/i&gt;&amp;nbsp;line in to a callback (everything under the &lt;i&gt;&lt;span style=&quot;color: #6aa84f;&quot;&gt;// Enable form&lt;/span&gt;&lt;/i&gt; comment), so it&#39;s only executed once the asynchronous code is finished. I don&#39;t fully understand this bit yet, but notice that the code I&#39;ve written accesses the UI controls directly, as if they were being executed in the UI thread; the code looks synchronous, but I imagine the callback that&#39;s created by the compiler also rewrites these UI calls in a thread-safe manner (possibly using invokes).&lt;br /&gt;
&lt;br /&gt;
The &quot;Async&quot; suffix on the method name does not seem to be required, but is used consistently in examples, blogs and whitepapers. Of course, this makes sense, as you may want to implement both synchronous and asynchronous methods for a single task.
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It&#39;s also worth briefly mentioning that you can use the result of the &lt;i&gt;Task.Run()&lt;/i&gt;&amp;nbsp;method in the callback, to determine a&amp;nbsp;return value from the asynchronous code. Apparently, you&#39;re supposed to be able to return a Task&amp;lt;T&amp;gt;, but I&#39;ve not yet been able to figure out how to do that. The best I&#39;ve been able to figure out is that I can return a value from the&lt;i&gt; Task.Run() &lt;/i&gt;method. Take a look at the following simple example:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; asyncResult = &lt;/span&gt;&lt;/b&gt;await Task.Run(() =&amp;gt; {
        &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; r &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; recipients) {
            &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt; {
                &lt;span class=&quot;rem&quot;&gt;// Send email&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; msg = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Email();
                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(!msg.Send()) {
                    &lt;span class=&quot;rem&quot;&gt;// Email Failure&lt;/span&gt;
                    r.Error = &lt;span class=&quot;str&quot;&gt;&quot;Unknown&quot;&lt;/span&gt;;
                    &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;
                }
                &lt;span class=&quot;rem&quot;&gt;// Update recipient&lt;/span&gt;
                r.Success = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
            } &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt;(Exception ex) {
                r.Error = ex.Message;
                &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;
            } &lt;span class=&quot;kwrd&quot;&gt;finally&lt;/span&gt; {
                &lt;span class=&quot;rem&quot;&gt;// Update progress&lt;/span&gt;
                r.Processed = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
                Report(r);
            }
            &lt;span class=&quot;rem&quot;&gt;// Do not wait if there are no more recipients to process&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(recipients.All(x =&amp;gt; x.Success)) &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;

            &lt;span class=&quot;rem&quot;&gt;// Wait this thread for the specified amount of time&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; waitTime = (&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)(udSeconds.Value * 1000);
            Thread.Sleep(waitTime);
        }
       &lt;span style=&quot;color: red;&quot;&gt; &lt;b&gt;&lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;&lt;/b&gt;&lt;/span&gt;
    });

   &lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt; &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(asyncResult) {&lt;/span&gt;&lt;/b&gt;
        &lt;span class=&quot;rem&quot;&gt;// Enable form&lt;/span&gt;
        ToggleForm(&lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;);

        progressBar.Visible = &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;
&lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;    }&lt;/span&gt;&lt;/b&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;
I&#39;ve no use for it in my example, but I&#39;m sure I&#39;ll need it in the future :)&lt;br /&gt;
&lt;br /&gt;
So, on to the rest of the changes I&#39;ve made to the above example. The UI update code that was in the &lt;i&gt;finally()&lt;/i&gt;&amp;nbsp;block has been moved to the&amp;nbsp;&lt;i&gt;Report()&lt;/i&gt; method. This method is provided by the&amp;nbsp;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/hh138298(v=vs.110).aspx&quot; target=&quot;_blank&quot;&gt;IProgress&amp;lt;T&amp;gt;&lt;/a&gt;&amp;nbsp;interface, which is&amp;nbsp;another new interface available in .Net 4.5 Developer Preview. I&#39;m using it here to post to a &lt;i&gt;SynchronizationContext &lt;/i&gt;object I created on the main form. I might be missing something, but I think it&#39;s provided for convenience and separation only; I don&#39;t *think* you need to use the &lt;i&gt;IProgress&amp;lt;T&amp;gt;&lt;/i&gt; interface to update the&amp;nbsp;&lt;i&gt;SynchronizationContext&amp;nbsp;&lt;/i&gt;, it just makes it a bit neater. An example of the implementation is below:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; AsyncTest : Form, IProgress&amp;lt;Recipient&amp;gt; {
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; SynchronizationContext sc;

    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; AsyncTest() {
        InitializeComponent();
        sc = SynchronizationContext.Current;
    }

    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Report(Recipient value) {
        sc.Post(x =&amp;gt; {
            value.Success = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
            progressBar.PerformStep();
            progressBar.Refresh();
            &lt;span class=&quot;rem&quot;&gt;// Refresh grid&lt;/span&gt;
            dgvRecipients.Refresh();
            &lt;span class=&quot;rem&quot;&gt;// Update label&lt;/span&gt;
            UpdateSummaryMessage();
        }, value);
    }
}&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;SynchronizationContext&lt;/i&gt;&amp;nbsp;has been in .Net since version 2.0, and allows you to post (asynchronous) or send (synchronous) information back to the UI thread. &lt;i&gt;Report()&lt;/i&gt; is being called in place of the UI update code (which would have broken at runtime if we&#39;d left it within the &lt;i&gt;Task.Run()&lt;/i&gt; block), which in turn posts the data. I&#39;m fairly confident that you could remove the &lt;i&gt;IProgress&amp;lt;T&amp;gt;&lt;/i&gt; implementation and put the &lt;i&gt;sc.Post()&lt;/i&gt; code in to the&lt;i&gt; finally() &lt;/i&gt;block without it causing too much trouble, though I&#39;ve not tried it yet.&lt;br /&gt;
&lt;br /&gt;
Within .Net 4.5 there are a number of new Async methods built in to classes for potentially long-running operations, such as reading a &lt;i&gt;Stream &lt;/i&gt;or sending an email with &lt;i&gt;System.Net.Mail.SmtpClient()&lt;/i&gt;, which are all welcome additions. I imagine they&#39;re all just wrappers, though in theory you can create your own Async method for any method in the framework, which is quite exciting.&lt;br /&gt;
&lt;br /&gt;
So, here&#39;s a full example of the code above. Please bear in mind that this is a cut-down version of my form code, so it won&#39;t work out of the box. It&#39;s intended to show you how to implement an asynchronous Winform button using the new async and await keywords, and carry out progress updates without having to specify callbacks:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; AsyncTest : Form, IProgress&amp;lt;Recipient&amp;gt; {
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; SynchronizationContext sc;
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; List&amp;lt;Recipient&amp;gt; recipients;

    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; AsyncTest() {
        InitializeComponent();
        sc = SynchronizationContext.Current;
    }

    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Report(Recipient value) {
        sc.Post(x =&amp;gt; {
            value.Success = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
            progressBar.PerformStep();
            progressBar.Refresh();
            &lt;span class=&quot;rem&quot;&gt;// Refresh grid&lt;/span&gt;
            dgvRecipients.Refresh();
            &lt;span class=&quot;rem&quot;&gt;// Update label&lt;/span&gt;
            UpdateSummaryMessage();
        }, value);
    }


    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; UpdateSummaryMessage() {
        &lt;span class=&quot;rem&quot;&gt;// update summary message code&lt;/span&gt;
    }

    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ToggleForm(&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; enabled) {
        &lt;span class=&quot;rem&quot;&gt;// enable / disable relevant form controls&lt;/span&gt;
    }

    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; async &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; btnSend_ClickAsync(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; sender, EventArgs e) {
        &lt;span class=&quot;rem&quot;&gt;// Set up progress bar&lt;/span&gt;
        progressBar.Maximum = recipients.Count;
        progressBar.Value = 0;
        progressBar.Step = 1;
        progressBar.Visible = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
        &lt;span class=&quot;rem&quot;&gt;// Disable form&lt;/span&gt;
        ToggleForm(&lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;);

        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; asyncResult = await Task.Run(() =&amp;gt; {
            &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; r &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; recipients) {
                &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt; {
                    &lt;span class=&quot;rem&quot;&gt;// Send email&lt;/span&gt;
                    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; msg = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Email();
                    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(!msg.Send()) {
                        &lt;span class=&quot;rem&quot;&gt;// Email Failure&lt;/span&gt;
                        r.Error = &lt;span class=&quot;str&quot;&gt;&quot;Unknown&quot;&lt;/span&gt;;
                        &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;
                    }
                    &lt;span class=&quot;rem&quot;&gt;// Update recipient&lt;/span&gt;
                    r.Success = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
                } &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt;(Exception ex) {
                    r.Error = ex.Message;
                    &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;
                } &lt;span class=&quot;kwrd&quot;&gt;finally&lt;/span&gt; {
                    &lt;span class=&quot;rem&quot;&gt;// Update progress&lt;/span&gt;
                    r.Processed = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
                    Report(r);
                }
                &lt;span class=&quot;rem&quot;&gt;// Do not wait if there are no more recipients to process&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(recipients.All(x =&amp;gt; x.Success)) &lt;span class=&quot;kwrd&quot;&gt;continue&lt;/span&gt;;

                &lt;span class=&quot;rem&quot;&gt;// Wait this thread for the specified amount of time&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; waitTime = (&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)(udSeconds.Value * 1000);
                Thread.Sleep(waitTime);
            }
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
        });

        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(asyncResult) {
            &lt;span class=&quot;rem&quot;&gt;// Enable form&lt;/span&gt;
            ToggleForm(&lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;);

            progressBar.Visible = &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;
        }
    }
}&lt;/pre&gt;
&lt;br /&gt;
I&#39;m afraid I&#39;m no expert with asynchrony, and my understanding is limited - still, I&#39;ve done my research, so I&#39;m hoping that all of the information I&#39;ve posted is accurate. If you spot anything that&#39;s incorrect, please let me know and I&#39;ll update it.&lt;br /&gt;
&lt;br /&gt;
My next task is to put an example together for MVC and / ASP.Net Webforms, to see how useful it&#39;ll be. I&#39;ve been using AJAX for asynchrony for years, so I&#39;m not sure how these methods will fit in the web world at the moment.&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/8674883598729366121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/8674883598729366121'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2012/04/long-running-processes-c-5-visual.html' title='Long running processes: C# 5, Visual Studio 11, async and await; updating a Winforms UI asynchronously'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnqSL9jhUGoBd1qo82-6SUT3BBtMNJLYxvg_zAY8R-geY7jHHntfdtMv5UrvgrH07SqDinbWr5ilnBJTZk5_7FikAnEYW3-OUwLABV6P1aK_ornL4neaQgsqzJ8jiJ9lDbecELsY6yeKA/s72-c/AgentMailer.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-9146166892468370360</id><published>2012-02-29T11:51:00.000+00:00</published><updated>2013-01-05T15:58:41.876+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Blog / General / Personal"/><category scheme="http://www.blogger.com/atom/ns#" term="Contracting"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><title type='text'>A learned journey</title><content type='html'>As a mercenary developer, I come across programmers from many different walks of life; of all skill levels and abilities with varying levels of enthusiasm. Whilst I&#39;m certainly not perfect (and am &lt;i&gt;always&lt;/i&gt; learning), I encounter some who are yet to grasp some of the more basic programming concepts. It&#39;s very easy to take a blinkered view of the technologies you&#39;re familiar with and to become complacent in your current role or too comfortable with your existing skills. On the other hand, some developers I encounter are far keener than I, and therefore usually far exceed my skill; two things which are directly related.&lt;br /&gt;
&lt;br /&gt;
I speak from first hand experience when I say that by taking a step outside of your comfort zone and making even one or two small changes to your daily routine as a developer could seriously improve your general programming knowledge and overall productivity. Although not quite ad-verbatim, I think it was &lt;a href=&quot;http://www.hanselman.com/&quot; target=&quot;_blank&quot;&gt;Scott Hanselmann&lt;/a&gt; who recently blogged that simply stating that you are a developer with 20 years experience means very little; having 20 years experience writing the same code over and over is very different to going a little bit out of your way to learn something new with every project (or even every day - there&#39;s really no excuse!); (20 years x 1 years experience) &amp;gt; (1 years experience x 20 years). The fact is that if you do not look at what you&#39;re writing and constantly want to improve it, or at least to investigate new technologies and employ new techniques and patterns to your existing knowledge, you&#39;re digging yourself a career-swallowing hole.&lt;br /&gt;
&lt;br /&gt;
I often see code written by senior developers that doesn&#39;t even follow some of the more simple programming principles. I appreciate that code can get &quot;in a state&quot; over time (especially in environments that aren&#39;t tightly managed), but it&#39;s rare that I ever need to &quot;hack&quot; code to get it to work - hacks are usually a result of bad planning or just because a developer doesn&#39;t know a right way to do things. Of course, new technologies are sometimes lacking in various areas, but most are extensible, and with a little bit of work can be neatly expanded to include functionality you require, whilst avoiding those nasty code smells.&lt;br /&gt;
I can forgive junior developers not understanding some of the more advanced techniques, but when I see senior developers (&lt;em&gt;especially&lt;/em&gt; contractors) who still blindly copy &amp;amp; paste code segments from the web, constantly use WYSIWYG editors or hack their way around a language without making use of it&#39;s features and tools, it baffles and infuriates me. All it takes is to spend as little as 20 minutes a day researching the &lt;em&gt;right&lt;/em&gt; things to keep your skills fresh and brain active. You can even fit things in and around work, which is a healthier way to approach it than taking time out of your personal life, if you&#39;re as busy as I can sometimes get.&lt;br /&gt;
&lt;br /&gt;
I appreciate this post won&#39;t be very popular with the search engines - no developer I know (whether they are good or bad) is going to search for &quot;how do I stop being a complete ball-bag at programming&quot;, mainly due to the fact that the people this blog is aimed at are, whilst being intelligent, usually ignorant to the fact they can do things better... or they simply don&#39;t care how terrible their code is. This isn&#39;t just me having a winge; developing better code (and understanding it) is the first step to a more rewarding and interesting daily work life, whether you&#39;ve been somewhere for 30 years, or you move around from client to client like me. It certainly helps me land work - a breadth of knowledge is generally much more important to my clients than specialising in one particular area, though of course there are arguments for both.&lt;br /&gt;
So, I shall attempt to compile a list of &quot;Dos and Don&#39;ts&quot; for those programmers who wish to become wiser in the world of development. Some of the items below are platform / language agnostic, whereas others are .Net / C# specific. I am, after all, a .Net developer :) I&#39;m more than open to additional suggestions; as previously mentioned, I&#39;m far from perfect, and my quest for knowledge is never ending.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Once and Only Once / Don&#39;t repeat yourself (DRY)&lt;/b&gt; - Two similar programming principals stating that &quot;Every piece of knowledge must have a single, unambiguous, authoritative representation within a system&quot;. Hard to follow in their purest form, but in an ideal world, you would never write the same line of code more than once, nor would you ever copy + paste code from another part of your application; if you need to output the same error message on multiple web pages, store it in a class or a configuration file. If you need to log different levels of error, write a number of objects to do the complicated work, and a helper method to call and manipulate the objects etc.&lt;br /&gt;&lt;br /&gt;

I often see code that repeats itself, even within the same method; create directory A, create directory B, create sub-directory B-A etc... applying this principal (or at least having it in mind) will greatly improve maintenance of your code, and make your code more predictable.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Use the correct type&lt;/b&gt; - Please, for the love of Zeus, don&#39;t just use &quot;int&quot; and &quot;string&quot; for everything, and avoid using base types like &quot;object&quot; unless absolutely necessary. E.g. use boolean types for boolean data; if you&#39;re storing a CHAR(1) in a database that only has two potential values (&quot;Y&quot; and &quot;N&quot; or &quot;0&quot; and &quot;1&quot;, for example), store as a boolean. Not only do you save memory / disk space (in the above example, CHAR(1) stores 1 byte, whereas you can have up to 8 BIT columns in a single table occupying 1 byte), but the column is naturally constrained to two possible values, reducing the possibility of a data error.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Code Formatting&lt;/b&gt; - Most IDEs will format for you these days, but there are still some that don&#39;t. Those that format should give you plenty of options on how to display your code, and a little bit of fiddling should do the trick. Well formatted code is easier to read and modify, for you and other developers that may need to access it.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Subscribe to blogs&lt;/b&gt; - One of the most productive things I ever did was starting using RSS to subscribe to tech blogs. Subscribing to the right blogs (it took me a while to filter down to the ones that are useful to me) gives you instant access to the latest tech releases and insider info. I&#39;m always adding and changing my blog subscriptions - but there are a few .Net guys I will mention by name, due to the fact they provide consistent quality in their updates. &lt;a href=&quot;http://www.hanselman.com/blog/&quot; target=&quot;blank&quot;&gt;Scott Hanselman&lt;/a&gt;, &lt;a href=&quot;http://weblogs.asp.net/scottgu/&quot; target=&quot;blank&quot;&gt;Scott Guthrie&lt;/a&gt; and &lt;a href=&quot;http://haacked.com//&quot; target=&quot;blank&quot;&gt;Phil Haack&lt;/a&gt;. I enjoy reading their blogs more than most, though I am subscribed to quite a number of other developers too.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Expand (and understand) your toolset&lt;/b&gt; - I recently posted a &lt;a href=&quot;http://spikehd.blogspot.com/2011/05/tools-roundup.html&quot; target=&quot;blank&quot;&gt;Tools Roundup&lt;/a&gt; listing the apps and programs that I use on a daily basis. I have to admit, I don&#39;t know all of the tools I use inside-out, but I sure as hell know that what little I do know about them has improved my productivity unfathomably. I used to shun tools, until I grew out of it :)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Read whitepapers&lt;/b&gt; - As with blog subscriptions, another thing that I&#39;ve been doing for the past few years is actually &lt;em&gt;reading through&lt;/em&gt; online articles, instead of skipping through to find code examples. None of us have the time for that though, do we? By reading the full article, you have a better chance of understanding a concept, and taking away from it much more than just what you&#39;re looking for. They help you make informed decisions and give you all kinds of facts that you didn&#39;t know or think about. Online whitepapers can be written by individual developers, or sponsored by corporations - both can be full of relevant information, but beware - they can also be full of rubbish, just like blogs (ahem).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Embrace new technologies&lt;/b&gt; - It&#39;s hard to keep up, but it&#39;s definitely possible. I have a lot on my plate (see my &quot;bio&quot; section), but I still manage to fit in the odd example project now and then. At the time of writing, MVC4 is in Beta and not far off RC - I&#39;ve already played around with the new MVC4 framework, but I&#39;ve not spent too long on it. It doesn&#39;t hurt to download example projects or follow blog posts to at least see what a tech&#39;s new features are capable of.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Inform Yourself of Popular Design Patterns&lt;/b&gt; - Pretty much every developer uses at least one design pattern, whether they know it or not. Different patterns can be used to make your development quicker and easier, as long as you know where to apply each one. I&#39;m no expert by any means, but since I started reading about and understanding different design patterns, I&#39;ve come a long way. Take a look at &lt;a href=&quot;http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller&quot; target=&quot;blank&quot;&gt;MVC&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Model_View_ViewModel&quot; target=&quot;blank&quot;&gt;MVVM&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Multitier_architecture&quot; target=&quot;blank&quot;&gt;nTier&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Factory_method_pattern&quot; target=&quot;blank&quot;&gt;Factory&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Singleton_pattern&quot; target=&quot;blank&quot;&gt;singleton&lt;/a&gt; to get you started.&lt;/li&gt;
&lt;/ul&gt;
The Internet is a wonderful place that can answer almost any question you have, as long as you &lt;a href=&quot;http://mashable.com/2011/11/24/google-search-infographic/&quot; target=&quot;blank&quot;&gt;know how to search&lt;/a&gt;, and you&#39;re willing to read through the information available. If you&#39;ve read this far, there&#39;s hope for you yet - if you haven&#39;t, then I wish you luck travelling down that long and unrewarding road.</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/9146166892468370360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/9146166892468370360'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2012/02/learned-journey.html' title='A learned journey'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-8769888932905418267</id><published>2012-01-19T10:46:00.000+00:00</published><updated>2013-01-05T15:53:48.880+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="MVC"/><title type='text'>MVC3: Redirect Action to HTML Bookmark</title><content type='html'>I&#39;m currently in the process of writing my next personal project,&amp;nbsp;&lt;a href=&quot;http://www.rustyshark.com/&quot; target=&quot;_blank&quot;&gt;RustyShark&lt;/a&gt;&amp;nbsp;in .Net MVC3. It&#39;s a game and films review site, and will hopefully generate a bit of a community. Each review on the website has a comments form at the bottom that readers can use to post their own mini review, or just a simple comment. I&#39;m using unobtrusive client side validation, but (as it should) the validation also occurs on the server side. This means that the user could potentially receive an error message on the comments form after a post-back but not notice it, as they will be redirected to the top of the page, rather than the comments form.&lt;br /&gt;
&lt;br /&gt;
The &quot;read review&quot; page is accessed via the fairly standard route /Reviews/Read/{titleURL}, which means the reviews controller exposes the Read action method. The Read method has a single override which is tagged with the [HttpPost] attribute as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ReviewsController : Controller {

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ActionResult Read(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; titleURL) {
            &lt;span class=&quot;rem&quot;&gt;// Get review by SEO friendly url&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; model = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ReadReviewModel();
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; View();
        }

        [HttpPost]
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ActionResult Read(ReadReviewModel model, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; titleURL) {
            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(ModelState.IsValid) {
                &lt;span class=&quot;rem&quot;&gt;// Add user review comment&lt;/span&gt;
            }

            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; View(model);
        }
    }&lt;/pre&gt;
&lt;br /&gt;
Fairly standard so far, yeah? Well, also pretty standard is applying a bookmark (e.g. /Reviews/Read/#comments) to a URL, which is especially useful when target content is located a good way down a page, such as in my example. MVC provides no built-in way to append a bookmark to your URL, and because bookmarks are not sent in the HTTP Header (browsers themselves implement the code to &quot;scroll down&quot; to a bookmark), its not possible to do this on the server side, unless I&#39;m missing something fundamental.&lt;br /&gt;
&lt;br /&gt;
Initially I went down the route of trying to modify the output route string on the fly, but I couldn&#39;t figure anything out. I&#39;d be interested in if this is possible or not, though I don&#39;t imagine it would be easy or recommended.&lt;br /&gt;
&lt;br /&gt;
So, after quite a bit of digging, I&#39;ve managed to implement a fairly elegant solution (at least on the server side). I created an ActionFilter that modifies the HTTP buffer by adding a small amount of JavaScript just after the  tag, after it&#39;s been rendered, but before the buffer is sent to the client. The ActionFilter is then applied it to the action method tagged with the HttpPost attribute (or any other action method, though I don&#39;t really see a good use for it anywhere else). The end result for the developer, is that you simply need to tag an additional attribute on to any action methods that you&#39;d like to redirect to a bookmark, as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ReviewsController : Controller {

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ActionResult Read(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; titleURL) {
            &lt;span class=&quot;rem&quot;&gt;// Get review by SEO friendly url&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; model = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ReadReviewModel();
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; View();
        }

        [HttpPost, &lt;b&gt;AppendAnchor(&quot;commentForm&quot;)&lt;/b&gt;]
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ActionResult Read(ReadReviewModel model, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; titleURL) {
            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt;(ModelState.IsValid) {
                &lt;span class=&quot;rem&quot;&gt;// Add user review comment&lt;/span&gt;
            }

            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; View(model);
        }
    }&lt;/pre&gt;
&lt;br /&gt;
The AppendAnchorAttribute and its dependant classes are quite simple. First, the action filter:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System;
&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System.Web.Mvc;

&lt;span class=&quot;kwrd&quot;&gt;namespace&lt;/span&gt; ShadowMoses.Core.Mvc.ActionFilters {
    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;rem&quot;&gt;/// Includes a small section of JavaScript in the response buffer that redirects the user to the desired page bookmark.&lt;/span&gt;
    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;, Inherited = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;)]
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; AppendAnchorAttribute : ActionFilterAttribute {
        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; _bookmark;

        &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;rem&quot;&gt;/// Includes a small section of JavaScript in the response buffer that redirects the user to the desired page bookmark.&lt;/span&gt;
        &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;param name=&quot;bookmark&quot;&amp;gt;The bookmark to redirect to.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; AppendAnchorAttribute(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; bookmark) {
            _bookmark = bookmark;
        }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; OnResultExecuted(ResultExecutedContext filterContext) {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; r = filterContext.HttpContext.Response;
            r.Filter = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; IncludeAnchorScriptFilter(r.Filter) {
                Anchor = _bookmark
            };
            &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;.OnResultExecuted(filterContext);
        }
    }
}&lt;/pre&gt;
&lt;br /&gt;
The OnResultExecuted event stub takes the current HttpResponse (which has been rendered by this point) and applies a custom filter to it. The IncludeAnchorScriptFilter class inherits from Stream and does some simple string manipulation (made simple by a Regular Expression pattern):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System.IO;
&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System.Text;
&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System.Text.RegularExpressions;

&lt;span class=&quot;kwrd&quot;&gt;namespace&lt;/span&gt; ShadowMoses.Core.Mvc.ActionFilters {
    &lt;span class=&quot;kwrd&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; IncludeAnchorScriptFilter : Stream {
        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Regex RegEx = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Regex(&lt;span class=&quot;str&quot;&gt;&quot;(&amp;lt;body([^&amp;gt;]*)&amp;gt;)&quot;&lt;/span&gt;, RegexOptions.Singleline);

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Anchor { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }

        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Stream _filter;

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; IncludeAnchorScriptFilter(Stream originalFilter) {
            _filter = originalFilter;
        }

        &lt;span class=&quot;preproc&quot;&gt;#region&lt;/span&gt; Overrides of Stream

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Flush() {
            _filter.Flush();
        }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;long&lt;/span&gt; Seek(&lt;span class=&quot;kwrd&quot;&gt;long&lt;/span&gt; offset, SeekOrigin origin) {
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _filter.Seek(offset, origin);
        }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; SetLength(&lt;span class=&quot;kwrd&quot;&gt;long&lt;/span&gt; value) {
            _filter.SetLength(value);
        }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Write(&lt;span class=&quot;kwrd&quot;&gt;byte&lt;/span&gt;[] buffer, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; offset, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; count) {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; html = Encoding.UTF8.GetString(buffer, offset, count);
            html = RegEx.Replace(html, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Concat(&lt;span class=&quot;str&quot;&gt;&quot;$1&quot;&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Format(&lt;span class=&quot;str&quot;&gt;@&quot;&amp;lt;script type=&quot;&lt;/span&gt;&lt;span class=&quot;str&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span class=&quot;str&quot;&gt;&quot;&amp;gt;document.location = &#39;#{0}&#39;;&amp;lt;/script&amp;gt;&quot;&lt;/span&gt;, Anchor)), 1);

            buffer = Encoding.UTF8.GetBytes(html);

            _filter.Write(buffer, offset, buffer.Length);
        }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; CanRead {
            &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt; {
                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _filter.CanRead;
            }
        }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; CanSeek {
            &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt; {
                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _filter.CanSeek;
            }
        }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; CanWrite {
            &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt; {
                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _filter.CanWrite;
            }
        }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;long&lt;/span&gt; Length {
            &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt; {
                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _filter.Length;
            }
        }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;long&lt;/span&gt; Position {
            &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt; {
                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _filter.Position;
            }
            &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt; {
                _filter.Position = value;
            }
        }

        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; Read(&lt;span class=&quot;kwrd&quot;&gt;byte&lt;/span&gt;[] buffer, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; offset, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; count) {
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _filter.Read(buffer, offset, count);
        }

        &lt;span class=&quot;preproc&quot;&gt;#endregion&lt;/span&gt;
    }
}&lt;/pre&gt;
&lt;br /&gt;
The Anchor property is populated when instantiating the filter in AppendAnchorAttribute. The RegEx pattern allows for multi-line  tags with as many attributes as you&#39;d like, unless an attribute value contains a right angle bracket. This minor issue can be rectified if you need it to be, but I have no use for that level of regular expression checking.&lt;br /&gt;
&lt;br /&gt;
The Write() method reads the HTML buffer and inserts the specified JavaScript just after the HTML &amp;lt;body&amp;gt; tag in the response. The JavaScript is executed on page load, and simply instructs the browser to redirect itself to the bookmark. There is no HTTP POST or HTTP GET; the browser deals with the redirect on the client side, and because there is no&amp;nbsp;post-back, the JavaScript only executes once.&lt;br /&gt;
&lt;br /&gt;
The resulting URL will be /Reviews/Read/#commentForm, which will scroll down to my related anchor tag in my partial view:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;a id=&quot;commentForm&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &quot;name&quot; attribute of the anchor tag has been depreciated, and the id attribute seems to work just as well. I think you can also use the id attribute of an existing tag (such as &amp;lt;div id=&quot;commentForm&quot;&amp;gt;&amp;lt;/div&amp;amp;gt&amp;gt;), though I haven&#39;t tested this yet.&lt;br /&gt;
&lt;br /&gt;
Although I&#39;ve tested this with Chrome, IE9, FireFox and Opera, I&#39;m a little concerned that older browsers may not have implemented document.location in the same way over the years, and a post-back &lt;i&gt;may&lt;/i&gt; occur.&lt;br /&gt;
&lt;br /&gt;
It&#39;s not the cleanest solution to a problem I&#39;ve come up with, but given the circumstances, I think it works quite well. Hope it helps people out :)</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/8769888932905418267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/8769888932905418267'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2012/01/mvc3-redirect-action-to-html-bookmark.html' title='MVC3: Redirect Action to HTML Bookmark'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-3641026944164213727</id><published>2011-11-17T14:25:00.001+00:00</published><updated>2013-01-05T15:54:20.655+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="SSIS"/><title type='text'>Debugging the SSIS Script Component</title><content type='html'>I&#39;ve been doing a lot of work with SSIS recently, and learning a lot on the way. One of my tasks over the last week was to convert each row of a result set in to XML and post it to a web service. The web service only accepted one row at a time, and generating XML in SSIS is not the most intuitive of tasks, so I wrote a script component to do the conversion work.&lt;br /&gt;
&lt;br /&gt;
Anyone who&#39;s tried anything more advanced than a &quot;Hello World&quot; example in a script component will be able to tell you that you cannot use breakpoints in them - making it quite difficult to debug even the simplest of code. For a developer such as myself, it&#39;s like having an arm removed in a horrific train accident. I had a bit of a task ahead of me - I had to create an XML document with tags containing attributes and values, attributes and child elements, child elements and values, attributes, child elements and values, then self-closing tags with some of the above... whilst not exactly a daunting task, it certainly required a bit of debugging to get right.&lt;br /&gt;
&lt;br /&gt;
MSDN suggests that you should use System.Windows.Forms.MessageBox.Show() to show any debugging information.&amp;nbsp;Aside&amp;nbsp;from the obvious ugliness of this method, it stops the package flow, and if the code is left in the package when deployed, you can lock up the package execution at runtime. Now... I&#39;m not entirely sure why this hadn&#39;t came to me before now, but in a flash of super-hero-esq inspiration and inside-out underpants, I remembered a similar issue I had a few years ago...&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYl6XxrKcoYozr7fb4tF-BHux-o6BMsazDn8NzzYuC4K2Dhk8nrQ6eLrEIaRHN_FEZ52wUlWhOwtf40bEcG2WAVW8PMRtbFftQyzqZNTMP3Gq2jxcd3YVnitNOyfjRZKmJIpj_fmpIC6s/s1600/popup.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;175&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYl6XxrKcoYozr7fb4tF-BHux-o6BMsazDn8NzzYuC4K2Dhk8nrQ6eLrEIaRHN_FEZ52wUlWhOwtf40bEcG2WAVW8PMRtbFftQyzqZNTMP3Gq2jxcd3YVnitNOyfjRZKmJIpj_fmpIC6s/s320/popup.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;System.Diagnostics.Debug.BloodyHorrible()&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
DebugView to the rescue!&lt;br /&gt;
&lt;br /&gt;
I used DebugView extensively when I was developing a SharePoint 2007 site a few years ago. It&#39;s a tiny little app from the SysInternals suite (god bless Cogswell and &lt;a href=&quot;http://en.wikipedia.org/wiki/Mark_Russinovich&quot; title=&quot;Mark Russinovich&quot;&gt;Russinovich&lt;/a&gt;) which monitors the Win32 OutputDebugString, which is exactly what System.Diagnostics.Trace.Write writes to by default.&lt;br /&gt;
&lt;br /&gt;
So. here&#39;s the main bulk of my Script Component code, along with the very simple tracing code:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Input0_ProcessInputRow(Input0Buffer Row)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// For each row, compile XML and submit to the web service&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        var sb = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; StringBuilder();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (var writer = XmlWriter.Create(sb, &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; XmlWriterSettings()&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            Indent = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        }))&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;rem&quot;&gt;// Write to the XML Writer&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            writer.WriteStartElement(&lt;span class=&quot;str&quot;&gt;&quot;request&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;            writer.WriteAttributeString(&lt;span class=&quot;str&quot;&gt;&quot;action&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;insert&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            writer.WriteAttributeString(&lt;span class=&quot;str&quot;&gt;&quot;database&quot;&lt;/span&gt;, Variables.MDatabase);&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            writer.WriteStartElement(&lt;span class=&quot;str&quot;&gt;&quot;credentials&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;            writer.WriteAttributeString(&lt;span class=&quot;str&quot;&gt;&quot;server&quot;&lt;/span&gt;, Variables.Server);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            writer.WriteAttributeString(&lt;span class=&quot;str&quot;&gt;&quot;layout&quot;&lt;/span&gt;, Variables.ClaimsLayout);&lt;/pre&gt;
&lt;pre&gt;            writer.WriteAttributeString(&lt;span class=&quot;str&quot;&gt;&quot;username&quot;&lt;/span&gt;, Variables.Username);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            writer.WriteAttributeString(&lt;span class=&quot;str&quot;&gt;&quot;password&quot;&lt;/span&gt;, Variables.Password);&lt;/pre&gt;
&lt;pre&gt;            writer.WriteEndElement(); &lt;span class=&quot;rem&quot;&gt;// &amp;lt;credentials&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;            writer.WriteStartElement(&lt;span class=&quot;str&quot;&gt;&quot;columns&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;rem&quot;&gt;// Data columns&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            writer.WriteColumn(&lt;span class=&quot;str&quot;&gt;&quot;NCDAffected&quot;&lt;/span&gt;, Row.NCDAffected);&lt;/pre&gt;
&lt;pre&gt;            writer.WriteColumn(&lt;span class=&quot;str&quot;&gt;&quot;PolicyReference&quot;&lt;/span&gt;, Row.PolicyReference);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            writer.WriteColumn(&lt;span class=&quot;str&quot;&gt;&quot;Status&quot;&lt;/span&gt;, Row.Status);&lt;/pre&gt;
&lt;pre&gt;            writer.WriteColumn(&lt;span class=&quot;str&quot;&gt;&quot;TypeOfClaim&quot;&lt;/span&gt;, Row.TypeOfClaim);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            writer.WriteColumn(&lt;span class=&quot;str&quot;&gt;&quot;FileID&quot;&lt;/span&gt;, Row.FileID);&lt;/pre&gt;
&lt;pre&gt;            writer.WriteColumn(&lt;span class=&quot;str&quot;&gt;&quot;TotalOutstandingReserves&quot;&lt;/span&gt;, Row.TotalOutstandingReserves);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            writer.WriteColumn(&lt;span class=&quot;str&quot;&gt;&quot;TotalPaymentsRecoveries&quot;&lt;/span&gt;, Row.TotalPaymentsRecoveries);&lt;/pre&gt;
&lt;pre&gt;            writer.WriteColumn(&lt;span class=&quot;str&quot;&gt;&quot;ClaimDate&quot;&lt;/span&gt;, Row.ClaimDate.ToString(&lt;span class=&quot;str&quot;&gt;&quot;dd/MM/yyyy&quot;&lt;/span&gt;));&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            writer.WriteColumn(&lt;span class=&quot;str&quot;&gt;&quot;NotificationDate&quot;&lt;/span&gt;, Row.NotificationDate.ToString(&lt;span class=&quot;str&quot;&gt;&quot;dd/MM/yyyy&quot;&lt;/span&gt;));&lt;/pre&gt;
&lt;pre&gt;            writer.WriteColumn(&lt;span class=&quot;str&quot;&gt;&quot;TransactionDate&quot;&lt;/span&gt;, Row.TransactionDate.ToString(&lt;span class=&quot;str&quot;&gt;&quot;dd/MM/yyyy&quot;&lt;/span&gt;));&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;            writer.WriteEndElement(); &lt;span class=&quot;rem&quot;&gt;// &amp;lt;columns&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;            writer.WriteEndElement(); &lt;span class=&quot;rem&quot;&gt;// &amp;lt;request&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;//System.Windows.Forms.MessageBox.Show(sb.ToString());&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;b&gt;System.Diagnostics.Trace.Write(sb.ToString());&lt;/b&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Extensions&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; WriteColumn(&lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; XmlWriter writer, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; columnName, &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;value&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        writer.WriteStartElement(&lt;span class=&quot;str&quot;&gt;&quot;column&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        writer.WriteAttributeString(&lt;span class=&quot;str&quot;&gt;&quot;name&quot;&lt;/span&gt;, columnName);&lt;/pre&gt;
&lt;pre&gt;        writer.WriteValue(&lt;span class=&quot;kwrd&quot;&gt;value&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        writer.WriteEndElement();&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The bold line is the one we&#39;re interested in - it&#39;s&amp;nbsp;transparent to the user&amp;nbsp;and won&#39;t affect performance if deployed with the application. In fact, it may even aid debugging on a production environment. Of course, it may expose a security hole if used incorrectly, but it does a much neater job of posting debug output that using MessageBox.Show(). It posts the following to DebugView:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCTGrIjBSVYBrDHZ5PJvLnHEdc9MaWs3porxEJKVkmXXKdqmKuP0CBCRQd4uiX25bDPfmHsG-Evoc1uQtNE1a35QuiLBlDK6tMEh2NZFPoPG-wSedrLGBSf_OVEH_3k7UOvNl6JvCowuE/s1600/debugview.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;216&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCTGrIjBSVYBrDHZ5PJvLnHEdc9MaWs3porxEJKVkmXXKdqmKuP0CBCRQd4uiX25bDPfmHsG-Evoc1uQtNE1a35QuiLBlDK6tMEh2NZFPoPG-wSedrLGBSf_OVEH_3k7UOvNl6JvCowuE/s640/debugview.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;System.Diagnostics.Debug.Trace.MuchCleaner()&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
So, until MS make SSIS Script Components easier to debug, I&#39;ll be sticking with this method :)</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/3641026944164213727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/3641026944164213727'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2011/11/debugging-ssis-script-component.html' title='Debugging the SSIS Script Component'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYl6XxrKcoYozr7fb4tF-BHux-o6BMsazDn8NzzYuC4K2Dhk8nrQ6eLrEIaRHN_FEZ52wUlWhOwtf40bEcG2WAVW8PMRtbFftQyzqZNTMP3Gq2jxcd3YVnitNOyfjRZKmJIpj_fmpIC6s/s72-c/popup.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-566920994700408061</id><published>2011-11-09T14:30:00.000+00:00</published><updated>2013-01-05T15:57:20.763+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".Net"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio"/><title type='text'>Tools Round-up</title><content type='html'>The development world has been coming up with ways to improve productivity for years. However since Visual Studio 2010 was released, with its fully extensible model, things have seriously changed. Most tools have been modified to extend VS2010&#39;s already pretty awesome IDE. With just a few extensions, you can fill in almost all of the gaps the Visual Studio team have left in the VS experience.&lt;br /&gt;
&lt;br /&gt;
I&#39;m not a massive fan of NuGet; I use it, but not for production sites. It&#39;s good for quickly implementing a library in a test project, but I just don&#39;t like the &quot;bloat&quot; you end up with. I like to know what every single file does and why its there. The same goes for WebMatrix; although handy, I much prefer to manually create projects... I somehow feel like it makes it easier in the long run, even if it takes you a while to set them up in the first place.&lt;br /&gt;
&lt;br /&gt;
I recently purchased ReSharper (after trying trials a number of times over the years and not getting along with it) and I&#39;ve finally started to appreciate how awesome it actually is. I&#39;ve already come to rely on a lot of the features - I find myself a bit lost when I use a version of VS without it installed these days!&lt;br /&gt;
&lt;br /&gt;
So, after spending the duration of my career looking at new tools,&amp;nbsp;plug-ins&amp;nbsp;and libraries, I thought it was about time that I posted a&amp;nbsp;round-up&amp;nbsp;list of the ones I&#39;ve found über useful. I&#39;ve been using some for over a decade, though most have been&amp;nbsp;superseded&amp;nbsp;with better products. Note that a lot of these aren&#39;t Visual Studio specific - they&#39;re just good tools that I&#39;ve found over the years to help me in my work.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://haacked.com/archive/2011/04/13/routedebugger-2.aspx&quot; target=&quot;_blank&quot;&gt;RouteDebugger 2.0&lt;/a&gt; - A nice little NuGet package that allows you to debug MVC routes - helps when you&#39;re starting out with MVC projects. Written by &lt;a href=&quot;http://haacked.com/&quot; target=&quot;_blank&quot;&gt;Phil Haack&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.sqldbatips.com/showarticle.asp?ID=78&quot; target=&quot;_blank&quot;&gt;SortSQLFilesInProject&lt;/a&gt; - Very useful MSSQLMS plugin that allows you to reorder the .sql files contained in your MSSQLMS project. Not perfect (sometimes you have to reorder and reload the solution a number of times for it to work), but the best solution to get your sql scripts in any kind of order,&amp;nbsp;aside&amp;nbsp;from manually editing the project file.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.linqpad.net/&quot; target=&quot;_blank&quot;&gt;LINQPad &lt;/a&gt;- I was having trouble with one particular LINQ statement I needed to write a few months ago, and I found this little beauty. I must admit, I&#39;ve not used it too much, but it did the job when I needed it.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.dnolan.com/portfolio_nadger.php&quot; target=&quot;_blank&quot;&gt;Nadger &lt;/a&gt;- I&#39;ve been using this since the 90&#39;s. Developed by a guy I used to interact with regularly when I was heavily involved in the Quake II clan scene. Extremely handy, standalone colour picker written in Delphi. The only issue I&#39;ve had with it is that it doesn&#39;t work over multi-monitors, much like many screen based tools.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://wisdom-soft.com/products/screenhunter_free.htm&quot; target=&quot;_blank&quot;&gt;ScreenHunter &lt;/a&gt;- Handy, free screenshot tool. I use it for documentation and user guides (I tend to write a lot as I&#39;m always moving from company to company). It&#39;s the best FREE screenshot manager I could find, though I&#39;m sure there are better ones if you&#39;re willing to cash up :) As with Nadger, this seems to only work on the main monitor.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.abstractpath.com/powermenu/&quot; target=&quot;_blank&quot;&gt;Powermenu &lt;/a&gt;- Doesn&#39;t work so well with Windows 7, but saved me a huge amount of time in XP. Allows you to set any window &quot;On Top&quot;. Also allows you to set the window&#39;s process priority and transparency. Aero has replaced many of the features, and the new Windows 7 shell disables the context menu, but you can still use the command line interface (I&#39;ve set up some batch files to execute various commands for me) to set windows &quot;On Top&quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/7c8341f1-ebac-40c8-92c2-476db8d523ce&quot; target=&quot;_blank&quot;&gt;Spellchecker &lt;/a&gt;- A Visual Studio 2010 extension written by Microsoft that simply applies a spellchecker to any strings and comments within your code files. Even if you can spell well, I would recommend it... because none of us are perfect :) You can download it via Tools -&amp;gt; Extension Manager.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/e5f41ad9-4edc-4912-bca3-91147db95b99&quot; target=&quot;_blank&quot;&gt;PowerCommands &lt;/a&gt;- Adds some handy shell commands to Visual Studio, such as &quot;Open Command Prompt&quot;, which starts a VS Command Prompt in the directory you&#39;re pointing at in Solution Explorer, Clear Recent Files List, Copy Path, Copy Class and many more... very handy indeed.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://notepad-plus-plus.org/&quot; target=&quot;_blank&quot;&gt;NotePad++&lt;/a&gt; - A free text editor, useful for regular expression matching and quick editing. I used to use UltraEdit, until it became slow-ass bloat-ware.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://visualstudiogallery.msdn.microsoft.com/6ed4c78f-a23e-49ad-b5fd-369af0c2107f&quot; target=&quot;_blank&quot;&gt;Web Essentials&lt;/a&gt; - Adds various editor features, such as CSS colour glyphs, JavaScript regions, outlining, JS minifying and CSS image embedding to the VS editor. In beta, but very handy.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://t4toolbox.codeplex.com/&quot; target=&quot;_blank&quot;&gt;T4 Tookbox&lt;/a&gt; - Essential if you&#39;re writing a lot of code-generator files. Provides ready built templates for your consumption, which greatly simplifies the process. There is lots of support on this, especially from &lt;a href=&quot;http://www.olegsych.com/&quot; target=&quot;_blank&quot;&gt;Oleg Sych&lt;/a&gt;, who&#39;s blog saved me a considerable amount of time when generating templates.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx&quot; target=&quot;_blank&quot;&gt;Process Monitor&lt;/a&gt; - I keep forgetting about the Sysinternals suite - every now and then it comes up in conversation, and I remember how awesome it is. I&#39;m a bit of a task manager whore, especially when developing, and the Sysinternals&#39; Process Monitor gives me that little bit extra information when I need it.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://t4-editor.tangible-engineering.com/T4-Editor-Visual-T4-Editing.html&quot; target=&quot;_blank&quot;&gt;T4 Editor&lt;/a&gt; - Another useful tool when working with T4 code generation. I had a few issues when installing it on WinXP, but the support is fairly good so I was sorted out quickly. This extension basically enabled highlighting and intellisense in .tt files. It&#39;s a bit of a disappointment that Visual Studio doesn&#39;t support this by default... though I&#39;m sure it will in the future.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://t4-editor.tangible-engineering.com/T4-Editor-Visual-T4-Editing.html&quot; target=&quot;_blank&quot;&gt;ReSharper&lt;/a&gt; - If you decide to spend money on a Visual Studio extension, this is the one to go for. Improves everything from productivity to coding practices. It has more features than I&#39;ll ever use, but the ones I do use have already improved my life as a developer tenfold. Highly recommended, even if it can be a bit buggy and laggy at times.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.jetbrains.com/decompiler/&quot; target=&quot;_blank&quot;&gt;DotPeek&lt;/a&gt; - The new (and currently free!) .Net Reflector. I&#39;ve not needed to use this much yet, but it&#39;s handy to have around. It only works with .Net 4.0 unfortunately,&amp;nbsp;but whose still using &amp;lt;= 3.5 eh?&amp;nbsp;Developed by JetBrains (the same developer as ReSharper).&lt;br /&gt;
&lt;br /&gt;
So, there it is... the apps that make my life a lot easier than it could be. I&#39;m sure there are more I use (there are definitely other small, free apps I use for other purposes such as the &lt;a href=&quot;http://www.cccp-project.net/&quot; target=&quot;_blank&quot;&gt;CCCP&lt;/a&gt;, Windows Media Player Classic and &lt;a href=&quot;http://www.irfanview.com/&quot; target=&quot;_blank&quot;&gt;IrfanView&lt;/a&gt;), but I think that about does it for development-based apps and extensions.&lt;br /&gt;
&lt;br /&gt;
Are there any development apps you use regularly that I&#39;ve not listed? Or are there any better implementations of the above apps out there?</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/566920994700408061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/566920994700408061'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2011/05/tools-roundup.html' title='Tools Round-up'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-8543775540244531677</id><published>2011-05-26T09:52:00.001+01:00</published><updated>2013-01-05T16:05:03.958+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio"/><title type='text'>Getting Visual Studio 2008 to work with Team Foundation Server 2010</title><content type='html'>Recently I&#39;ve been collaborating via Team Foundation Server 2010 - it&#39;s my first time, and I&#39;ll be honest... it was very gentle. It eased me in with its promise of improved Source Control (improved over Source Safe, that is) and toyed with me, sporting its ideals surrounding automated builds and work item collaboration.&lt;br /&gt;
&lt;br /&gt;
Whilst I&#39;ve not been directly involved with the set up, using it on a daily basis has been a refreshing change. I&#39;m one of those developers who obsessively refactors code, renames and moves files around until I&#39;m happy everything is in the right place, so when using Source Safe, CVS or SVN, there&#39;s quite a bit of repeat work involved when it comes to making sure the source control server is also updated. Suffice to say that TFS 2010 works beautifully in this area, keeping the local, server and project file structure the same as each other.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve been exclusively working in Visual Studio 2010 for a while now, as I&#39;ve been creating new systems rather than maintaining old ones. I recently needed to revert back to Visual Studio 2008 in order to create some SSIS packages for some good old ETL. I&#39;ve not used TFS with any other version of Visual Studio, but I wasn&#39;t surprised to find out that VS 2008 doesn&#39;t let you connect to TFS (any version) out of the box. There were a few gotchas, but after installing a few updates and patches, I managed to get Visual Studio 2008 working with TFS 2010 so I could store my BI projects in the same source control system as my VS2010 solutions. Although I&#39;m sure there&#39;s a distribution / version available with TFS support out of the box, here are the steps I took to get my vanilla Visual Studio 2008 working with TFS 2010:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Install Visual Studio 2008&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.microsoft.com/downloads/en/details.aspx?FamilyID=0ed12659-3d41-4420-bbb0-a46e51bfca86&quot;&gt;Install Visual Studio 2008 Team Explorer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.microsoft.com/downloads/en/details.aspx?familyid=fbee1648-7106-44a7-9649-6d9f6d58056e&amp;amp;displaylang=en&quot;&gt;Install Visual Studio 2008 Service Pack 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.microsoft.com/downloads/en/details.aspx?displaylang=en&amp;amp;FamilyID=cf13ea45-d17b-4edc-8e6c-6c5b208ec54d&quot;&gt;Install Visual Studio Team System 2008 SP1 Forward Compatibility Update for TFS 2010&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Open Visual Studio 2008 and connect to your Team Foundation Server 2010 as you would normally.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
I already had VS 2008 installed, but because I haven&#39;t used it since my last reinstall, I didn&#39;t have SP1. If you install Team Explorer before SP1 (as per my instructions) and try to add a TFS 2010 server, you&#39;ll fist receive errors stating that you can&#39;t use forward slash characters etc. When I tried to add a server manually, via the below registry key:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Calibri, sans-serif; font-size: 15px;&quot;&gt;HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\TeamFoundation\Servers&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
... I just received another error stating that the server was an older version than was compatible with VS2008, which is obviously a load of rubbish. The key here is the &quot;Forward Compatibility Update&quot; listed above. Once I installed that, the UI started to act more like I would have expected it to.&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/8543775540244531677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/8543775540244531677'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2011/05/getting-visual-studio-2008-to-work-with.html' title='Getting Visual Studio 2008 to work with Team Foundation Server 2010'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-6935909766549467205.post-607897067655549429</id><published>2011-05-08T17:48:00.001+01:00</published><updated>2013-01-05T16:04:18.273+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="MVC"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio"/><title type='text'>Visual Studio 2010 defaults to an undesired browser when opening MVC projects</title><content type='html'>A while ago, I set my default browser in Visual Studio 2010 to Google Chrome by using the &quot;Browse With...&quot; trick, and I&#39;ve been happy with it for some time. Recently I&#39;ve found that I&#39;ve needed to do quite a bit of testing in IE, so I wanted to change it back. I went down the &quot;Browse With...&quot; route again, which seemed to work... but every time I close and re-opened Visual Studio, it reset itself back to Chrome.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve been living with it for a while, as I tend to do extended sessions anyway, so it&#39;s not been too much of a hassle... but today I&#39;ve needed to close and restart Visual Studio a few times, so it&#39;s become a bit annoying. Anyway, to cut a long story short, it seems that when setting the &quot;Browse With...&quot; option in an MVC project, the settings aren&#39;t saved to the configuration file, probably because MVC projects don&#39;t actually have physical files to be &quot;Browsed&quot;, unlike an ASP.Net project. I&#39;m not making excuses for the bug, but its understandable how it&#39;s been missed. I&#39;ve not worked on an ASP.Net project at home for a while, it&#39;s all been MVC.&lt;br /&gt;
&lt;br /&gt;
Anyway, for anyone having the same issue as me - all you need to do is create a blank &lt;b&gt;Web Application&lt;/b&gt; project, right click one of the generated .aspx files and click &quot;Browse With...&quot;, then set the default browser as per normal; voila, your MVC projects will now open with your new default browser setting.&lt;br /&gt;
&lt;br /&gt;
If that&#39;s not enough, Scott Hanselman, in his infinite geekiness put together a &lt;a href=&quot;http://www.hanselman.com/blog/HowToChangeTheDefaultBrowserInVisualStudioProgrammaticallyWithPowerShellAndPossiblyPokeYourselfInTheEye.aspx&quot;&gt;blog post&lt;/a&gt;&amp;nbsp;a while ago outlining a workaround to give you a bit more control over the browser you run your pages in. I don&#39;t need this flexibility at the moment, but if you want to put a bit of effort in, its a pretty good solution considering the current options in Visual Studio.&lt;br /&gt;
&lt;br /&gt;
The bug has been &lt;a href=&quot;http://connect.microsoft.com/VisualStudio/feedback/details/568469&quot;&gt;reported to Microsoft&lt;/a&gt;, and will hopefully be fixed in a future service pack, even though it was reported quite some time ago.</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/607897067655549429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6935909766549467205/posts/default/607897067655549429'/><link rel='alternate' type='text/html' href='http://blog.shadowmoses.co.uk/2011/05/visual-studio-2010-defaults-to.html' title='Visual Studio 2010 defaults to an undesired browser when opening MVC projects'/><author><name>Chris &quot;Spikeh&quot; Sebok</name><uri>http://www.blogger.com/profile/06403874631055393888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitW7Zo-Qed41iYZn1Jc-euULTUSqQQowDEn0WijENCnMisL_wdD_Fv1unxsm4Dcoa4y2NFsaWONpQyVj2PC7vXxE9wPY6uFnKKkH-1Y1Pi48Cje8q8ZQyt-gpIKWVQ6ps/s220/Avatar_Professional.jpg'/></author></entry></feed>