<?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:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-28989665</id><updated>2009-11-11T08:31:56.291Z</updated><title type='text'>The blog of the software development team at Compsoft</title><subtitle type='html'>In creating bespoke software solutions, websites and custom solutions, our developers come across problems. In this blog they discuss issues experienced and how they got around them. As Microsoft Gold Certified Partners our developers go to the TechEd conference - read about their experiences and thoughts on emerging technologies!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default?start-index=26&amp;max-results=25'/><author><name>Phil Lenton</name><uri>http://www.blogger.com/profile/03854036326283622134</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>103</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-28989665.post-3676388317904032360</id><published>2009-11-10T16:55:00.001Z</published><updated>2009-11-10T17:02:37.492Z</updated><title type='text'>Tim Jeanes - TechEd 2009 - Day 2</title><content type='html'>&lt;h4&gt;Coincidentally in Berlin for the 20th anniversary of the fall of the Berlin wall.&lt;/h4&gt;  &lt;p&gt;20 years ago today a bunch of us got away without doing our German homework because our teacher was in such a good mood.&lt;/p&gt;  &lt;h4&gt;WIA203 - Streaming With IIS and Windows Media Services&lt;/h4&gt;  &lt;p&gt;IIS and WMS are two quite separate products, and which you use depends largely on your specific requirements and your available architecture.&lt;/p&gt;  &lt;p&gt;WMS2008 sits best on its own server, separate from the server holding the original content. It then does all its own smart caching, automatically dumping the less-viewed content from the cache, and preserving the media that is more on demand. A raft of recent improvements mean it can handle more than twice as many simultaneous connections as could WMS2003.&lt;/p&gt;  &lt;p&gt;On the other hand, if you're just delivering media from a web server, IIS Media Services may well be enough. It's a freely-available downloadable add-on to IIS that gives a bunch of features to improve media delivery.&lt;/p&gt;  &lt;p&gt;It has some nice settings to give more efficient usage of the available bandwidth. Typically users only watch 20% of the video media that they actually download, so the other 80% is wasted bandwidth that the media provider still has to pay for. You can configure IIS to treat media and other data files differently dependent on their file type. Typically you'd set it to download as fast as possible for the first 5-20 seconds, then drop to a proportion of the required bit rate for the rest of the video. This gives a quick spike on bandwidth initially followed by a constant rate of just enough to ensure the user doesn't experience any delays in the media they're viewing.&lt;/p&gt;  &lt;p&gt;If you need to control how and what the end user watches (for example, they may need to be forced to watch an advert before they can see the main content), you can control how they can stream and download the content. In the playlist you define on the server you can enable or disable the user's ability to skip videos or to seek within them. The URLs of the actual videos being sent are automatically obfuscated to ensure that the URL of the main content isn't guessable by the end user.&lt;/p&gt;  &lt;p&gt;Smooth streaming is now supported. This monitors the user's bandwidth and adapts the stream quality in almost-real time. This is achieved by splitting the original media into many 2-4 second long chunks and encoding each at several different qualities. IIS then delivers each chunk in succession, switching between qualities as the bandwidth allows. As it's monitored continuously, if the user experiences a temporary glitch, their video returns to its better quality within a few moments.&lt;/p&gt;  &lt;p&gt;Encoding at many bitrates is very CPU intensive, so doing this live is much harder work. Currently Microsoft has no offering that can manage this in real-time, so you'd need some third party hardware to do the hard work.&lt;/p&gt;  &lt;h4&gt;DEV317 - Agile Patterns: Agile Estimation&lt;/h4&gt;  &lt;p&gt;I suck at estimating timescales, and Getting Better At It has been on my list of tasks for the next period on every performance review I've had for the past 11 years. I'm glad to hear that I'm not alone - this was a very well-attended session where we commiserated together about how estimates (which are by definition based on incomplete information) becomes a hard deadline.&lt;/p&gt;  &lt;p&gt;A key concept is the Cone Of Uncertainty. This measures how inaccurate your estimates are as time goes by.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_zsifaW4TiJo/SvmbHeDdkmI/AAAAAAAAAB8/orUomC4pzkM/s1600-h/ConeOfUncertainty%5B2%5D.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ConeOfUncertainty" border="0" alt="ConeOfUncertainty" src="http://lh3.ggpht.com/_zsifaW4TiJo/SvmbHreLWhI/AAAAAAAAACA/DDovsxlsTwQ/ConeOfUncertainty_thumb.jpg?imgmax=800" width="244" height="180" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;A couple of points to note are that initial project estimates, based on the loosest information, are often out by a factor of 4 - either too long or too short; even when you have a clear idea of what the customer wants, estimates are still out by a factor of 2. Also notably, we can't guess with 100% accuracy when the software will be delivered until it's totally complete. Asked for a show of hands, the vast majority of the room said they've woken in the morning expecting to release a product today, end then haven't: even on the last day, we can't guess how long we've got left.&lt;/p&gt;  &lt;p&gt;As we can't avoid this, it's better to be honest about it and work with it.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;User stories&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;The customer specifies a list of stories - items that must be in the product.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;Planning poker&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;From user stories, we make estimates of difficulty. This is to do with priorities - not time estimation. The estimates should be based on difficulty. Planning poker cards represent order of magnitude compared with baseline. Each person places their estimates simultaneously. Disagreements lead to discussions.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000"&gt;Take a baseline: a task you know well (such as a login page), then compare the complexity of each other item with this (this is twice as hard as that, etc.). &lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;Story points&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;Break down stories into smaller pieces (that will later become your individual work items). Give each a number of story points: a number of units of relative size - multiples of say a notional hour or day, depending on the scale of the project. These aren't still really your time estimates as you don't really know yet how quickly you're going to work through them.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000"&gt;Play planning poker again to decide the number of story points for each item.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;Product backlog&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;The list of work items becomes your backlog, each with an estimate attached to it. At this point you meet with the customer to prioritise the items in the backlog.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;Velocity&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;Developers commit to a number of story points for the first sprint. At the end of the first sprint, the number of completed story points is your velocity.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000"&gt;TFS has some plugins that help to monitor and calculate this.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;Re-estimation&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;After each sprint, the customer may add more stories to the backlog, and can re-prioritise the backlog. The developers may also add bugs to the backlog.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000"&gt;Each sprint gives you increasingly accurate predictions of future delivery.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;h4&gt;DEV303 - Source Code Management with Microsoft Visual Studio 2010&lt;/h4&gt;  &lt;p&gt;Branching has been improved: it's now a more first-class part of TFS. Branches have permissions associated with them to allow or prevent certain users from creating or merging branches. It's a faster process now as no files have to be checked out (or even copied to your local machine) to create a branch in TFS.&lt;/p&gt;  &lt;p&gt;You can create private branches by branching code and setting permissions on the new branch. Also, there's a graphical tool that shows how branches have been created and how they relate to one another. This is interactive, so branches can be created or merged from here.&lt;/p&gt;  &lt;p&gt;When viewing the history of a file or project, changesets that were branches can be drilled into to show the changes that happened in the main branch, prior to it being branched into your project.&lt;/p&gt;  &lt;p&gt;Changesets can be tracked visually through branches and merges - you can show where a change has been migrated between branches - either on the hierarchical diagram of changesets or on a timeline.&lt;/p&gt;  &lt;p&gt;It was always a pain to merge changes where there are conflicting file renames. Fortunately this has been significantly cleaned up. The conflict is now correctly detected and you're told the original name of the file as well as the two conflicting new names.&lt;/p&gt;  &lt;p&gt;Similar fixes have been implemented for the problem areas of moving files, making edits within renamed files, renaming folders, etc.&lt;/p&gt;  &lt;p&gt;These version model changes make it a whole lot clearer what's going on if you view the history for a file that's been renamed - even if it's renamed to the same name as a file that was previously deleted. If you're using VS2005/2008 with TFS2010, you'll need a patch to ensure this works.&lt;/p&gt;  &lt;p&gt;Rollbacks are now a proper feature - you don't have to resort to the command line power tool to do these. Also they now properly rollback merges (previously it would forget that the merge now hadn't taken place, so re-merging would be very difficult).&lt;/p&gt;  &lt;p&gt;A single TFS server can now have multiple Team Project Collections. These are sets of projects with their own permissions, meaning that different teams can use the same TFS installation without access to one another's projects.&lt;/p&gt;  &lt;h4&gt;WIA403 - Tips and Tricks for Building High Performance Web Applications and Sites&lt;/h4&gt;  &lt;p&gt;This was a fast-paced session with lots of quick examples. I've not listed them all, but a few of them are here:&lt;/p&gt;  &lt;p&gt;Simplifying the CSS can improve the performance of the browser. Basically speaking, the simpler the CSS rule, the more performant it will be. Also, using "ul &amp;gt; li" to specify immediate children is much more efficient than catching all descendents with "ul li".&lt;/p&gt;  &lt;p&gt;Javascript performance can be improved by making sure you use variables that are as local as possible. Similarly, the more local the property on an object (i.e. on the object itself or on its prototype), the quicker it can be accessed.&lt;/p&gt;  &lt;p&gt;A powerful feature of javascript is that it can evaluate and execute code in strings at runtime. However, this can be very slow. It's often used to run code with setTimeout - it's much better to use an anonymous function instead.&lt;/p&gt;  &lt;p&gt;Getters and setters for properties are generally good programming practice. However, as javascript isn't compiled, the slight overhead of traversing the setter/ getter method can double the time taken to access the property.&lt;/p&gt;  &lt;p&gt;The length property on a string or array is not fast: it has to count all the items in it. Thus saying for (var i = 0; i &amp;lt; myArray.length; i++) is very inefficient. Caching the length in a variable makes it faster. Or if you're iterating over DOM elements, you can use the firstChild and nextSibling properties instead: for (var el = this.firstChild; el != null; el = el.nextSibling)&lt;/p&gt;  &lt;p&gt;Having a lot of cases in a switch statement is also slow: each case has to be checked in turn. A sneaky trick that can be employed is to build an array of functions instead, and just call the appropriate one. Obviously this doesn't apply in every situation.&lt;/p&gt;  &lt;p&gt;Rather than having many small images on your page, it's better to have one large image and specify offsets for each one you want to show. SpriteMe is a handy tool that will make this mosaic for you: it scans your page for images and then glues them all together.&lt;/p&gt;  &lt;p&gt;Doloto is a tool that monitors your javascript and tracks which functions are called. It can then generate javascript library files that are dynamically loaded in the page as they are needed. It ensures that the most common functions are available immediately and others are loaded later. A quick demo on Google maps showed that it could reduce its bandwidth spent on retrieving javascript files by 89%. Impressive stuff!&lt;/p&gt;  &lt;p&gt;Microsoft Expression SuperPreview can render a page as it would appear in different versions of different browsers (Firefox, IE6, 7, and 8). It will show the results side-by-side (or even superimposed on one another) and even spot the differences for you (and highlight them).&lt;/p&gt;  &lt;h4&gt;WIA305 - What's New in ASP.NET MVC&lt;/h4&gt;  &lt;p&gt;A new feature is to be able to compose a view out of multiple calls to actions. This appears as &amp;lt;% Html.RenderAction() %&amp;gt;. This is a little smarter than Html.RenderPartial as you can perform any necessary business logic where it belongs in the correct controller instead of having to shoe-horn it in elsewhere.&lt;/p&gt;  &lt;p&gt;Areas allow you to group parts of your application into logical groups. It behaves like a folder in your project, with subfolders for models, views and controllers. There's also an AreaRegistration class that registers routes for the Area. Global.asax has to call AreaRegistration.RegisterAllAreas to activate these. By default, the area appears at the top level of its views' URLs.&lt;/p&gt;  &lt;p&gt;An exception is thrown at runtime if Areas contain controllers with the same name. This can be circumvented by specifying which namespace should be used for the controller, when you register the route.&lt;/p&gt;  &lt;p&gt;Working with ASP.NET MVC 1, I've felt frustrated with the validation. A new model allows you to specify your validation once and have it applied to each layer. Your validation rules can be specified by using Data Annotation attributes, or in an XML file, or elsewhere if you write your own provider. To enable client-side validation you only need to include a couple of Microsoft javascript libraries and add the helper method &amp;lt;% Html.EnableClientValidation(); %&amp;gt; to your page. If you invent your own validation rules, you'll also have to write your own javascript version of that validation logic - the built in framework passes the rules as JSON that you can intercept on the client.&lt;/p&gt;  &lt;p&gt;There are some new helper methods - Html.Display, Html.DisplayFor, Html.DisplayForModel, HtmlEditor, Html.EditorFor and Html.EditorForModel. Given a model, these display read-only or input field versions of all the fields on the model. You can define your own templates for these - either by type (to implement your own date picker, for example), or by giving a name of a partial view that renders an editor for the whole model. This respects inheritance too: if no template has been defined for Employee, it will fall back to the template defined for Person.&lt;/p&gt;  &lt;p&gt;A nice little tweak is that by default, JsonResult now won't allow HTTP GETs. This dodges a cross-site scripting vulnerability, though you can override it if you really want.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-3676388317904032360?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/3676388317904032360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=3676388317904032360' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3676388317904032360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3676388317904032360'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tim-jeanes-teched-2009-day-2.html' title='Tim Jeanes - TechEd 2009 - Day 2'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15336493667160399642'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7084217638402948271</id><published>2009-11-09T15:24:00.001Z</published><updated>2009-11-09T15:24:34.829Z</updated><title type='text'>Tim Jeanes - TechEd 2009 - Day 1</title><content type='html'>&lt;h4&gt;ARC201 - The Windows Azure Platform - How and When to Use It&lt;/h4&gt;  &lt;p&gt;The pricing for Windows Azure has been out for a little while, but I found it unclear exactly what you were paying for - especially for hosting web applications. What does $0.12 per hour really mean? That's CPU hours, surely? Well no - it turns out it's bad news: that's $0.12 per hour per web role or per worker role. And an hour is an hour: for every hour that goes by on your watch, you pay $0.12 for each role you have running.&lt;/p&gt;  &lt;p&gt;That makes things very expensive very quickly if you're hosting a small web site, but this isn't what Azure is for. This gets very cheap very quickly if you're running Facebook.&lt;/p&gt;  &lt;p&gt;This is also a great pricing model if your site has massive spikes in usage: ticket sales apps or tax service sites for example. You can basically turn your site off for 95% of the time, then spin up 20 servers in the space of a minute just before the tickets go on sale and drop back to zero just after they're sold out.&lt;/p&gt;  &lt;p&gt;I think a more common route into using Azure will be for data storage. Data storage of Blob data is only $0.15 per GB per month (plus $0.15 per GB downloaded). If you've got a whole load of video or other media that you want to be constantly available, Azure could be a great dumping ground for it all: it's reliably available and isn't going to use up your bandwidth, and you can leave the rest of your app running outside Azure in an environment you're more comfortable with.&lt;/p&gt;  &lt;p&gt;Using SQL in the cloud, however, is far more expensive than raw data storage: though prices are measured by the size of your database ($9.99 per month for a database up to 1GB; $99.99 for up to 10GB), what you're really paying for is all the functionality (and CPU time) of having a structured database. You've got to know that your database is going to be used regularly before this becomes worthwhile.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;DAT204 - What's new in Microsoft SQL Azure&lt;/h4&gt;  &lt;p&gt;Oh thank goodness! Microsoft listened to everyone last year saying that accessing SQL Azure via REST was a major pain in the body part. We also now have everything you'd expect in a proper fully-functioning SQL database: gone are the days where you just have basic tables with string keys, partitioned by rules you specify.&lt;/p&gt;  &lt;p&gt;Instead now you access SQL Azure via SQL Server Management Studio: you just connect to [database name].database.windows.net, and very nearly all the functionality you'd expect from SQL Server is right there. There are a few exceptions: for example you can't use the USE keyword, as they can't guarantee your two databases are on the same physical server (though they are on the same logical server) - in fact they probably won't be, to optimise performance.&lt;/p&gt;  &lt;p&gt;A server is only a logical server - not a physical box. It's a unit of authority and a unit of geo-location, so this should be what drives the point at which you make another server. As you get to choose which datacentre's hosting your database, you can also get best performance by ensuring your application runs in the same datacentre as your database. And as data transfer within a datacentre is free, so you won't be eating into that $0.15 per GB download cost.&lt;/p&gt;  &lt;p&gt;There's a nice improvement to security too: your server now comes with a firewall, allowing you to restrict access to by IP address range. Somewhat novelly, you can't create accounts called sa, admin or root, just because those are most commonly hacked.&lt;/p&gt;  &lt;p&gt;(And next week they'll announce that you can replicate from Azure to SQL Server but shh! - you're not allowed to know that yet!)&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;DEV-GEN - Developer General Session&lt;/h4&gt;  &lt;p&gt;The Developer General Sessions at TechEd are attended by pretty much every developer at the conference, so they're held in the largest hall on site.&lt;/p&gt;  &lt;p&gt;"Wi-fi access is not available in this hall&amp;quot;," said the sign outside. A shame, because the main part of the talk was really quite dull, very high-level and largely uninformative. "VS2010's made of WPF!" My cat knew that - and I haven't even got a cat.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7084217638402948271?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7084217638402948271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=7084217638402948271' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7084217638402948271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7084217638402948271'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tim-jeanes-teched-2009-day-1.html' title='Tim Jeanes - TechEd 2009 - Day 1'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15336493667160399642'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7316922388520873575</id><published>2009-11-09T08:43:00.020Z</published><updated>2009-11-10T14:34:24.264Z</updated><title type='text'>Tech Ed 2009 - Monday - Neil Bostrom</title><content type='html'>&lt;span style="font-weight: bold;"&gt;What's new in Windows Communication Foundation 4.0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I've recently started using WCF in anger on one of our projects, which is why this session interested me. The first major feature that was discussed is the new routing functionality. This feature allows a single end point to publish multiple services &amp;amp; protocols. This single end point will forward the request to the correct service based on path / content type.&lt;br /&gt;&lt;br /&gt;The next sexy feature was auto discovery of services. At the moment you always need to put the connection information into your client. By using discovery we can just create a service of a contract and it will go and attempt to discover if anything is hosting that contract. This means you can easily do load balancing just by putting up more services offering that contract and the client will just pick the first one it finds. Bonus feature with this is that you can take services out without affecting the clients.&lt;br /&gt;&lt;br /&gt;To publish your service as discoverable, you create a UdpDiscoveryEndpoint. This will use UDP packets to make the service available to clients.&lt;br /&gt;&lt;br /&gt;Christian suggested that using ChannelFactory.CreateChannel() is better than storing the configuration in the web.config. I hadn't really got around to looking into using CreateChannel, will definitely look at making use of it.&lt;br /&gt;&lt;br /&gt;WCF 4.0 has better REST support including JSON-P features.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Microsoft Visual Studio Team Suite 2010: A lap around the developer and tester experience&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Brian Harry did a good whirlwind tour of the new features coming in TFS and VS 2010. He started off with showing the new tester experience. They have a new product coming out called Lab Management. This product is built for testers to do all types of testing including, manual testing and integration testing.&lt;br /&gt;&lt;br /&gt;The sexy part of the TFS / Labs is that during test runs, it will record all sorts of information about what is happening. Screenshots, a live video is recorded, all the system information, historic debugging saved. All of this just happens in the background and get attached to any bugs you create. This gives the developers the maximum information about the bugs.&lt;br /&gt;&lt;br /&gt;Another cute feature is that the tests know the code that they cover. This means when a new build gets produced, it can notify the tester of the manual test that would need to be run that have been effected by that build.&lt;br /&gt;&lt;br /&gt;Brian moved on to TFS features next. Showing nice branch visualization, allowing you to track changes across branches and show where changes have been applied. Brian also mentioned that the conflict resolution has been improved which should be interesting to try.&lt;br /&gt;&lt;br /&gt;TFS finally has rollback support built into the interface, meaning I don't have to use the command line to rollback changes.&lt;br /&gt;&lt;br /&gt;One feature I'm really excited about is that TFS Build has been updated to use Workflow foundation on top of MSBuild to make building build scripts much easier. This should give us loads more power in the build script. Its been really painful up to this point building complex build scripts.&lt;br /&gt;&lt;br /&gt;The new version of the TFS product will have three versions, Basic, Standard and Advanced. Basic gives you the base level functionality of source control. Standard includes the share point sites and sql reporting features. Advanced version allows you to tweak pretty much any configuration so you can run on a web farm or an existing SQL cluster etc.&lt;br /&gt;&lt;br /&gt;The server version of TFS will finally come with an admin console meaning you don't have to use command line to make changes. It also includes lots of improvements for scaling out your installation by load balancing any layer, web, business or data access.&lt;br /&gt;&lt;br /&gt;Microsoft Office System 2010 Client Overview&lt;br /&gt;This was a bit of an eye opener for me as I knew very little of the latest office buzz. The guys presentation just steamed straight into new features and changes in the office products. The interesting part of this was they kinda just assumed you knew there was online versions of all the office products. That work in any browser on any platform! OMG! I was not aware of this!&lt;br /&gt;&lt;br /&gt;It seemed like the web version would use Silverlight if its installed to give a sexier interaction but will fall back to a html / javascript version if you don't have SL installed. JS version was still fully featured and worked in every major browser!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tech Ed Keynote&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Usually the keynotes at Tech Ed are sexy and sell harder than the Berlin wall! However today's keynote seems to just be a big flop. A few random videos with no content and a long speech that seems to lack any information. The small bits I did get out of the keynote was BitLocker to go, vague cloud computing. Even the exchange demo seems to just be some random side feature.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7316922388520873575?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7316922388520873575/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=7316922388520873575' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7316922388520873575'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7316922388520873575'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tech-ed-2009-monday-neil-bostrom.html' title='Tech Ed 2009 - Monday - Neil Bostrom'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16236226257094048772'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-3122156634807437707</id><published>2009-10-15T12:56:00.004Z</published><updated>2009-10-20T10:26:07.758Z</updated><title type='text'>CDNs (CD what nows?)</title><content type='html'>&lt;p&gt;With the ever increasing demands that come with scale on popular websites, site owners are always looking for ways to move resource demands away from their traffic inundated servers.&lt;/p&gt;  &lt;p&gt;There are a number of ways of offsetting or distributing demand, I'm going to cover just one, Content Delivery Networks (CDNs).&lt;/p&gt;  &lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Content_delivery_network" target="_blank"&gt;Content Delivery Networks&lt;/a&gt; are servers which host duplicate copies of a given resource or resources, this might be your site's images, javascript or media.&lt;/p&gt;  &lt;p&gt;Why might you need to move your resources to a CDN?&lt;/p&gt;  &lt;p&gt;When your browser downloads a web page, it has a limited number of active connections it can make to a domain, typically around 2. &lt;/p&gt;  &lt;p&gt;This means that if it's busy downloading images on one, and media on another, you're not going to see the page until both have finished downloading.&lt;/p&gt;  &lt;p&gt;Pushing those resources to other domains via a CDN means you get:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;More active connections available so the page can load quicker.&lt;/li&gt;    &lt;li&gt;Resources can be pulled down from locations geographically closer to the user, resulting in even faster page speeds.&lt;/li&gt;    &lt;li&gt;A reduced load on your server, no bandwidth cost on your server.&lt;/li&gt;    &lt;li&gt;Duplication of your resources gives you redundancy failovers if servers are down.&lt;/li&gt;    &lt;li&gt;Sites that use the same resources, which a user has previously downloaded, will not need to download them again, giving big speed gains.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;You can see how there are some immediate benefits to using them.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Want to use one now?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Google and Microsoft have somewhat closed CDNs meaning they won't host your content, but they do host some common files you might need, such as &lt;a href="http://jquery.com/" target="_blank"&gt;jQuery&lt;/a&gt;.&lt;/p&gt;  &lt;div   style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; direction: ltr; max-height: 200px; cursor: text;font-family:'Courier New',courier,monospace;font-size:8pt;" id="codeSnippetWrapper"&gt;   &lt;div    style="border-style: none; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;" id="codeSnippet"&gt;     &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum1"&gt;   1:&lt;/span&gt; &amp;lt;script src=&lt;span style="color: rgb(0, 96, 128);"&gt;"http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js"&lt;/span&gt; type=&lt;span style="color: rgb(0, 96, 128);"&gt;"text/javascript"&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Or:&lt;/p&gt;&lt;div   style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; direction: ltr; max-height: 200px; cursor: text;font-family:'Courier New',courier,monospace;font-size:8pt;" id="codeSnippetWrapper"&gt;&lt;div    style="border-style: none; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;" id="codeSnippet"&gt;&lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum1"&gt;   1:&lt;/span&gt; &amp;lt;script src=&lt;span style="color: rgb(0, 96, 128);"&gt;"http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&lt;/span&gt; type=&lt;span style="color: rgb(0, 96, 128);"&gt;"text/javascript"&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;So why wouldn't you use them?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;u&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/u&gt;, there are a whole lot of ways you can customise your requirements, number of servers, redundancy, global availability etc. Akamai, Amazon, CacheFly and Limelight Networks all have offerings in this space.&lt;/p&gt;&lt;p&gt;Having issues with scale or need a high demand, high availability site and need help? contact &lt;a href="http://www.compsoft.co.uk/ContactUs" target="_blank"&gt;Compsoft&lt;/a&gt; today.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-3122156634807437707?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/3122156634807437707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=3122156634807437707' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3122156634807437707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3122156634807437707'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/10/cdns-cd-what-nows.html' title='CDNs (CD what nows?)'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04912185286940984148'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-5696822698110321600</id><published>2009-10-06T09:40:00.001Z</published><updated>2009-10-06T09:49:03.590Z</updated><title type='text'>Mail merging with PDF documents</title><content type='html'>&lt;p&gt;We tend to find that mail merge with word documents is a flexible mechanism for customers to control the output of their applications. Be that invoices, emails or reports. Using simple merge merge documents allows the customers to modify the output of the system without having to contact us. We find that the word mail merge solution provided by &lt;a href="http://www.aspose.com/categories/.net-components/aspose.words-for-.net/default.aspx"&gt;ASPOSE Words&lt;/a&gt; is simple and reliable.&lt;/p&gt;  &lt;p&gt;We recently had a customer that required pre made PDF forms to be source of the outputs from their system. After a quick search of the ASPOSE solutions, we found that the &lt;a href="http://www.aspose.com/categories/.net-components/aspose.pdf.kit-for-.net/default.aspx"&gt;ASPOSE PDF Kit&lt;/a&gt; had exactly what we needed.&lt;/p&gt;  &lt;p&gt;10 lines of code later, we could as easily mail merge against PDF documents as we could against word documents.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="var"&gt;MemoryStream&lt;/span&gt; outputStream = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="var"&gt;MemoryStream&lt;/span&gt;();&lt;br /&gt;&lt;span class="var"&gt;MemoryStream&lt;/span&gt; pdfForm = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="var"&gt;MemoryStream&lt;/span&gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Binary.Data);&lt;br /&gt;&lt;span class="var"&gt;Form form&lt;/span&gt; = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="var"&gt;Form&lt;/span&gt;(pdfForm, outputStream);&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; fieldName &lt;span class="kwrd"&gt;in&lt;/span&gt; form.FieldsNames)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;object&lt;/span&gt; fieldValue = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (mailMergeDataSource.GetValue(fieldName, &lt;span class="kwrd"&gt;out&lt;/span&gt; fieldValue))&lt;br /&gt;        form.FillField(fieldName, fieldValue.ToString());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;form.FlattenAllFields();&lt;br /&gt;form.Save();&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; outputStream;&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt; .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre  margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .var { color: #006080; } .csharpcode .str { color: #8B0000; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt  { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } &lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Thank you &lt;a href="http://www.aspose.com/"&gt;ASPOSE&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-5696822698110321600?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/5696822698110321600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=5696822698110321600' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5696822698110321600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5696822698110321600'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/10/mail-merging-with-pdf-documents.html' title='Mail merging with PDF documents'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16236226257094048772'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-4343960492735780968</id><published>2009-10-05T16:11:00.007Z</published><updated>2009-10-05T16:28:01.793Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='JSONP'/><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='Cross site'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>This week, I have been mostly getting JSONP</title><content type='html'>&lt;p&gt;I've just finished writing a test harness for a sms texting service. While writing this little tool I ran into a problem with cross site scripting issues.&lt;/p&gt;  &lt;p&gt;Essentially its a form that is submitted to a page which then invokes methods to deal with the faked sms. It actually plays the part of the sms gateway host and saves me 50pence a shot!&lt;/p&gt;  &lt;p&gt;The form submission is via AJAX, but because its on a different domain I get no success or useful error responses. This is where JSONP comes in.&lt;/p&gt;  &lt;p&gt;As of jQuery 1.2 you can get JSON data from another domain if you add a JSONP callback and a little bit of handling on the server.&lt;/p&gt;  &lt;p&gt;You also get the proper success and error responses.&lt;/p&gt;  &lt;p&gt;The form looks a little like this: &lt;/p&gt;  &lt;pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;form&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;action&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"http://someOtherDomain/cross-site.php"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;method&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"get"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#000000;"&gt; input1:&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;input&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;id&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"input1"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"input1"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;value&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"suits you sir"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;form&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;button&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;type&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"button"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;id&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"btnsubmitjson"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;jsonp submit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;button&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;div&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;id&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"response"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;div&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The javascript that handles the button click event appends the JSON callback to the url and then submits the form with the power of jQuery:&lt;/p&gt;&lt;pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt; &lt;span style="color:#000000;"&gt;submitjson(){&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;   &lt;span style="color:#000000;"&gt; posturl = $("&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;form&lt;/span&gt;&lt;span style="color:#000000;"&gt;").attr('action');&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;    &lt;span style="color:#000000;"&gt;posturl += "&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;&lt;span style="color:#000000;"&gt;?&lt;/span&gt;jsoncallback=?&lt;/span&gt;&lt;span style="color:#000000;"&gt;"; &lt;/span&gt;&lt;span style="color:#008000;"&gt;//append the JSON call back&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;    &lt;span style="color:#000000;"&gt;$.getJSON(posturl, $("&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;form&lt;/span&gt;&lt;span style="color:#000000;"&gt;").serialize(),&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="color:#000000;"&gt;(data) {&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;      &lt;span style="color:#000000;"&gt;  $('#response').text(data.&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;name&lt;/span&gt;&lt;span style="color:#000000;"&gt;);&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#000000;"&gt;    });&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#000000;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;And the final part (which is not so obvious) is the response required, generated by the server:&lt;/p&gt;&lt;pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#000000;"&gt;php&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#000000;"&gt;$data = '&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;{"name" : "&lt;/span&gt;&lt;span style="color:#000000;"&gt;'.$_GET['&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;input1&lt;/span&gt;&lt;span style="color:#000000;"&gt;'].'&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;"}&lt;/span&gt;&lt;span style="color:#000000;"&gt;';&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" color="#ffffff" style="width: 100%;"&gt;&lt;a style="color: #0000ff" href="http://www.php.net/echo"&gt;echo&lt;/a&gt; &lt;span class="Apple-style-span"  style="color:#000000;"&gt;$_GET['&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;jsoncallback&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#000000;"&gt;'].'&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;(&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#000000;"&gt;'.$data.'&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;);&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#000000;"&gt;';&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;?&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;And its this last magic bit in the responding with $_GET['&lt;span style="color:#8b0000;"&gt;jsoncallback&lt;/span&gt;'] which makes it all work!&lt;/p&gt;&lt;p&gt;Now I can point my tool where ever I like, AND get the right responses (ah yeah).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-4343960492735780968?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/4343960492735780968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=4343960492735780968' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4343960492735780968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4343960492735780968'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/10/this-week-i-have-been-mostly-getting.html' title='This week, I have been mostly getting JSONP'/><author><name>John Green</name><uri>http://www.blogger.com/profile/00454091456869602396</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='05522198464570262162'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-9153358861610097878</id><published>2009-09-10T15:28:00.001Z</published><updated>2009-09-10T15:41:47.222Z</updated><title type='text'>Save XDocument to string as UTF-8</title><content type='html'>&lt;p&gt;I love LINQ to XML, I'll admit it. It has changed the way I work with XML forever, in a great way!&lt;/p&gt;  &lt;p&gt;I did however run into my first issue with using it that I felt should have been simpler than it turned out to be. I had created my uber XDocument containing all the data in the world including an XDecleration saying UTF-8 on the encoding.&lt;/p&gt;  &lt;p&gt;However, whenever I did a ToString() or Save to StringBuilder it would always come out with:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;&amp;lt;?&lt;/font&gt;&lt;/span&gt;&lt;font color="#5f0513"&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;/font&gt;&lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;version&lt;/font&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;=&amp;quot;1.0&amp;quot;&lt;/font&gt;&lt;/span&gt; &lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;encoding&lt;/font&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;=&amp;quot;utf-16&amp;quot;&lt;/font&gt;&lt;/span&gt; &lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;standalone&lt;/font&gt;&lt;/span&gt;&lt;font color="#0000ff"&gt;&lt;span class="kwrd"&gt;=&amp;quot;yes&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;  &lt;p&gt;Trying all sorts of combinations got me nowhere. The reason behind this is that strings internally to .net are stored as UTF-16. This meant the XDocument was always picking up the destination of the xml and encoding it appropriately.&lt;/p&gt;  &lt;p&gt;In the end I had to go via a MemoryStream to trick XDocument into giving me the correct declaration:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;// codesnippet:20B728DE-9E20-11DE-AFE0-B04D56D89593&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;private static string&lt;/font&gt; GetDocumentAsString(&lt;font color="#008080"&gt;XDocument&lt;/font&gt; document)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160; &lt;font color="#008000"&gt; // Crazy way to get UTF8 encoding out to a string       &lt;br /&gt;&lt;/font&gt;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#008080"&gt;MemoryStream&lt;/font&gt; ms = &lt;font color="#0000ff"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;MemoryStream&lt;/font&gt;();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;using&lt;/font&gt; (&lt;font color="#008080"&gt;XmlWriter&lt;/font&gt; xw = &lt;font color="#0000ff"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;XmlTextWriter&lt;/font&gt;(ms, &lt;font color="#008080"&gt;Encoding&lt;/font&gt;.UTF8))      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; document.Save(xw);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; xw.Flush(); &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#008080"&gt;StreamReader&lt;/font&gt; sr = &lt;font color="#0000ff"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;StreamReader&lt;/font&gt;(ms);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ms.Seek(0, &lt;font color="#008080"&gt;SeekOrigin&lt;/font&gt;.Begin);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt; return&lt;/font&gt; sr.ReadToEnd();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;This now produces:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;&amp;lt;?&lt;/font&gt;&lt;/span&gt;&lt;font color="#5f0513"&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;/font&gt;&lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;version&lt;/font&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;=&amp;quot;1.0&amp;quot;&lt;/font&gt;&lt;/span&gt; &lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;encoding&lt;/font&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;=&amp;quot;utf-8&amp;quot;&lt;/font&gt;&lt;/span&gt; &lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;standalone&lt;/font&gt;&lt;/span&gt;&lt;font color="#0000ff"&gt;&lt;span class="kwrd"&gt;=&amp;quot;yes&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt; &lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-9153358861610097878?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/9153358861610097878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=9153358861610097878' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/9153358861610097878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/9153358861610097878'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/09/save-xdocument-to-string-as-utf-8.html' title='Save XDocument to string as UTF-8'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16236226257094048772'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-8968168860881759000</id><published>2009-08-24T10:26:00.001Z</published><updated>2009-08-24T10:26:43.157Z</updated><title type='text'>JavaScript string handling - oh come on, IE!</title><content type='html'>&lt;p&gt;Anyone want to guess what the result of this bit of javascript is?&lt;/p&gt;  &lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; myString = &amp;quot;&lt;span style="color: #8b0000"&gt;abc&lt;/span&gt;&amp;quot;;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #0000ff"&gt;alert&lt;/span&gt;(myString[2]);&lt;br /&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Let's see, shall we?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Firefox:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://www.compsoft.co.uk/Files/tgj_Firefox.png" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Google Chrome:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://www.compsoft.co.uk/Files/tgj_Chrome.png" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Safari:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://www.compsoft.co.uk/Files/tgj_Safari.png" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;IE7:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://www.compsoft.co.uk/Files/tgj_IE7.png" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Admittedly IE8 treats strings the same way everyone has been treating them since the 1970s, but at the rate users pick up the newer versions, we're going to have to carry this around for a good many years yet.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Sigh.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-8968168860881759000?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/8968168860881759000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=8968168860881759000' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8968168860881759000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8968168860881759000'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/08/javascript-string-handling-oh-come-on.html' title='JavaScript string handling - oh come on, IE!'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15336493667160399642'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-492198220112739204</id><published>2009-08-14T12:40:00.004Z</published><updated>2009-08-14T16:55:24.587Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='stateful web'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><title type='text'>One reason ASP.NET MVC can only be a good thing</title><content type='html'>&lt;p&gt;&lt;strong&gt;ASP.NET Webforms &lt;/strong&gt;has been the standard web development model on the Microsoft .NET platform since its release in 2002. One of the key web development aims, is making the stateless nature of the internet easier to develop for.&lt;/p&gt;  &lt;p&gt;It does this by wrapping up all the things you might expect if you're coming from Windows programming:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Input controls having the same content as when you last interacted with the page (via mechanisms like ViewState).&lt;/li&gt;    &lt;li&gt;Event driven architecture (btnDoStuff.Click += new .)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;It does a great job of abstracting away the details of what's going on, it makes it easy to pick up and work with. &lt;/p&gt;  &lt;p&gt;It makes you really productive create a form, add some text box controls, add a button, wire up to the click event, grab the data from the form via a full control hierarchy. &lt;/p&gt;  &lt;p&gt;&lt;span style="font-weight: bold;"&gt;Bing, bang, bosh!&lt;/span&gt; you've got a contact form.&lt;/p&gt;  &lt;p&gt;The thing is though, the web &lt;strong&gt;isn't &lt;/strong&gt;stateful, and working with the comfy blanket of Webforms makes you forget that.&lt;/p&gt;  &lt;p&gt;&lt;span style="font-weight: bold;"&gt;ASP.NET MVC &lt;/span&gt;was released this year, it's an alternative web framework that takes you back to the truth. It runs on the same .NET platform but takes you back to thinking of pages in terms of resource request / response.&lt;/p&gt;  &lt;p&gt;We love Webforms, we've got a big investment in them and it's one of the things that enables us to build great web applications.&lt;/p&gt;  &lt;p&gt;What's the one reason &lt;span style="font-weight: bold;"&gt;ASP.NET MVC &lt;/span&gt;can only be a good thing? because it makes you remember the truth. &lt;/p&gt;  &lt;p&gt;Take the blue pill, go with the programmatic illusion of the stateful web, or take the &lt;a href="http://en.wikipedia.org/wiki/Redpill" target="_blank"&gt;red pill&lt;/a&gt; and see how deep the rabbit hole goes. I'll always take knowledge over ignorance.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-492198220112739204?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/492198220112739204/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=492198220112739204' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/492198220112739204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/492198220112739204'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/08/one-reason-aspnet-mvc-can-only-be-good.html' title='One reason ASP.NET MVC can only be a good thing'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04912185286940984148'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-1824393015119018455</id><published>2009-07-20T09:09:00.004Z</published><updated>2009-07-20T09:15:57.422Z</updated><title type='text'>C# coalesce operator (double question mark) gotcha</title><content type='html'>&lt;p&gt;I'm sure you've met the C# coalesce operator, where you can use a double question mark to check for null:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;x = y ?? z;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;... being equivalent to:&lt;/p&gt;&lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (y != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    x = y;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    x = z;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;It's a handy shortcut, but sometimes it doesn't behave quite as &lt;strike&gt;you&lt;/strike&gt; I might expect.&lt;/p&gt;&lt;p&gt;Here's an example:&lt;/p&gt;&lt;p&gt;I wanted to combine the elements of an address to make a field that was searchable with a SQL LIKE statement. As we use LINQ to SQL, I needed an expression that LINQ to SQL could translate into SQL syntax. I wrote this:&lt;/p&gt;&lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;...&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;font color="#0000ff"&gt;select&lt;/font&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;{&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    SearchableAddress = c.Address.HouseName   ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + c.Address.HouseNumber ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + c.Address.Road        ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + c.Address.Town        ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + c.Address.County      ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + c.Address.Postcode    ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;I'm using the coalesce operator to replace nulls with empty strings - otherwise SQL returns NULL for the whole expression if a single element is NULL.&lt;/p&gt;&lt;p&gt;However, I found my search was rarely getting any matches, and a little digging isolated the above expression as the culprit.&lt;/p&gt;&lt;p&gt;It turns out that the coalesce operator takes lower precedence than the concatenation operator. What I meant (and what I should have written) was this:&lt;/p&gt;&lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;...&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;font color="#0000ff"&gt;select&lt;/font&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;{&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    SearchableAddress = (c.Address.HouseName   ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;) + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + (c.Address.HouseNumber ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;) + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + (c.Address.Road        ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;) + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + (c.Address.Town        ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;) + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + (c.Address.County      ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;) + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + (c.Address.Postcode    ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;)&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;... but my version without any parentheses was equivalent to this:&lt;/p&gt;&lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;...&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;font color="#0000ff"&gt;select&lt;/font&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;{&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    SearchableAddress =             c.Address.HouseName    ?? &lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                        (&amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot; + c.Address.HouseNumber) ?? &lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                        (&amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot; + c.Address.Road)        ?? &lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                        (&amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot; + c.Address.Town)        ?? &lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                        (&amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot; + c.Address.County)      ?? &lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                        (&amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot; + c.Address.Postcode)    ??&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                         &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Getting back the first non-null element, padded with a superfluous space, was enough to make the search work occasionally enough to be confusing.&lt;/p&gt;&lt;p&gt;Maybe I should have seen it coming, as I'd happily use:&lt;/p&gt;&lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;a = b ?? c ?? d ?? e;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;to get the first non-null value, but that string concatenation threw me off the scent.&lt;/p&gt;&lt;p&gt;I dunno - to me coalesce feels like a unary operator, so I'd expect it to be evaluated first; it turns out it gets evaluated &lt;a href="http://en.csharp-online.net/ECMA-334:_14.2.1_Operator_precedence_and_associativity"&gt;almost last&lt;/a&gt;. What do you think?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-1824393015119018455?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/1824393015119018455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=1824393015119018455' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1824393015119018455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1824393015119018455'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/07/c-coalesce-operator-double-question.html' title='C# coalesce operator (double question mark) gotcha'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15336493667160399642'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-1828171746674685785</id><published>2009-07-06T10:41:00.004Z</published><updated>2009-07-06T15:15:21.482Z</updated><title type='text'>Silverlight 3 And Blend 3</title><content type='html'>&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_0"&gt;Rumour&lt;/span&gt; has it, that &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Silverlight&lt;/span&gt; 3 isn't far from release.&lt;br /&gt;&lt;br /&gt;Here is a quick list of features I'm really excited about in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Silverlight&lt;/span&gt; 3 and Blend 3:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Element Property Binding&lt;/span&gt;&lt;br /&gt;You won't believe how much I need this in my life! I've written so much back end code to replicate this feature. Now it's all available &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Silverlight&lt;/span&gt; (as it has been in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;WPF&lt;/span&gt; since the start). It means I can wire up one controls property to another controls property. You'll be &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_5"&gt;surprised&lt;/span&gt; how much you'll use this!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Behaviors&lt;/span&gt;&lt;br /&gt;Another feature that massively increases code reuse. Write that &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_6"&gt;full screen&lt;/span&gt; code once and wire it up to anything you can think of!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Team System Source Control &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_7"&gt;Integration&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Finally! I won't need to keep checking out files in Visual Studio to modify them in blend! All the usual (not all but most) source control features will be available through Blend.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Samples Data&lt;/span&gt;&lt;br /&gt;Cute feature inside Blend to generate sample data so you are able to see what your designs will look like with some close to real world data in your controls.&lt;br /&gt;&lt;br /&gt;As of yet, there has been no &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_8"&gt;official&lt;/span&gt; Microsoft press on when &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;Silverlight&lt;/span&gt; 3 is due but I've seen some hints lying around on the net that July is the month.&lt;br /&gt;&lt;br /&gt;If you &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_10"&gt;haven't&lt;/span&gt; guessed it yet, I'm excited... bring it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-1828171746674685785?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/1828171746674685785/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=1828171746674685785' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1828171746674685785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1828171746674685785'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/07/silverlight-3-and-blend-3.html' title='Silverlight 3 And Blend 3'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16236226257094048772'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-264562326634082074</id><published>2009-06-26T13:20:00.010Z</published><updated>2009-06-26T15:06:39.711Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='microformats'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Winning with Microformats and JQuery</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Microformat"&gt;Microformats&lt;/a&gt; are a nice way to get semantic data onto a page, and here at Compsoft we have had a maptacular week which has given us the chance to use some with a little JQuery to make things nice.&lt;br /&gt;&lt;br /&gt;So on a map we are plotting locations. We are also listing these locations next to the map. You can drag and drop a selection of locations from the main list, into a short list. You can then get Google maps to create us a route based on this short list.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nyW099dZ_Zg/SkTYEQpC6vI/AAAAAAAAAAM/ZYf7JP29UXg/s1600-h/routemap.png"&gt;&lt;img id="BLOGGER_PHOTO_ID_5351639824921193202" style="margin: 0pt 10px 10px 0pt; float: left; width: 320px; cursor: pointer; height: 146px;" alt="" src="http://2.bp.blogspot.com/_nyW099dZ_Zg/SkTYEQpC6vI/AAAAAAAAAAM/ZYf7JP29UXg/s320/routemap.png" border="0" /&gt;&lt;/a&gt;But the cool thing is, you can drag items in the short list to rearrange the route!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How though, do you know the order of the items in the short list once they have been reordered?&lt;br /&gt;&lt;br /&gt;With the magic of JQuery and microformats of course!&lt;br /&gt;&lt;br /&gt;The markup used to present also defines the data that is being displayed. CSS styling then allows us to make it look nice. This is what the markup looks like:   &lt;pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;id&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"location628"&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;class&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"location"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;class&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"name"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Geodis UK Limited&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;class&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"address"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Warren Farm Transfer Station&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;class&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"detail"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;1 mile&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;class&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"latlng"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;(50.8915618, -1.1965132)&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;We can make the lists sortable and allow drag and drop between them with JQuery like this: &lt;/p&gt;&lt;pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;$(&lt;span style="color: rgb(0, 0, 255);"&gt;document&lt;/span&gt;).ready(&lt;span style="color: rgb(0, 0, 255);"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    $("&lt;span style="color: rgb(139, 0, 0);"&gt;#locations&lt;/span&gt;").sortable({ connectWith: "&lt;span style="color: rgb(139, 0, 0);"&gt;#selectedLocations&lt;/span&gt;" });&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    $("&lt;span style="color: rgb(139, 0, 0);"&gt;#selectedLocations&lt;/span&gt;").sortable({ connectWith: "&lt;span style="color: rgb(139, 0, 0);"&gt;#locations&lt;/span&gt;" });&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;});&lt;/pre&gt;&lt;/pre&gt;and listen for the sorting to finish with this:&lt;br /&gt;&lt;pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;$("&lt;span style="color: rgb(139, 0, 0);"&gt;#selectedLocations&lt;/span&gt;").bind('sortupdate', &lt;span style="color: rgb(0, 0, 255);"&gt;function&lt;/span&gt;(event, ui) {&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    getRoute();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255); font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;/pre&gt;And because we are using JQuery, and microformatting makes it clear what the data means, we can use a JQuery selector to get the data stored on the page in the order they are displayed! This makes it so simple to grab the ordered data.&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;function&lt;/span&gt; getRoutes() {&lt;br /&gt;&lt;pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;var&lt;/span&gt; waypoints = [];&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255); font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;var&lt;/span&gt; stops = $("&lt;span style="color: rgb(139, 0, 0);"&gt;#selectedLocations .latlng&lt;/span&gt;");&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255); font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;for&lt;/span&gt; (&lt;span style="color: rgb(0, 0, 255);"&gt;var&lt;/span&gt; i = 0; i &amp;lt; stops.&lt;span style="color: rgb(0, 0, 255);"&gt;length&lt;/span&gt;; i++) {&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);"&gt;        &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (divs[i])&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);"&gt;            waypoints.push(stops[i].innerHTML);&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);"&gt;    &lt;span style="color: rgb(0, 128, 0);"&gt;//GDirections object connected to GMap on page to display the route&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; font-size: 12px; width: 100%; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(255, 255, 255);"&gt;    directions.loadFromWaypoints(waypoints);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; font-size: 12px; width: 100%; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(255, 255, 255);"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-264562326634082074?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/264562326634082074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=264562326634082074' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/264562326634082074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/264562326634082074'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/06/winning-with-microformats-and-jquery.html' title='Winning with Microformats and JQuery'/><author><name>John Green</name><uri>http://www.blogger.com/profile/00454091456869602396</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='05522198464570262162'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nyW099dZ_Zg/SkTYEQpC6vI/AAAAAAAAAAM/ZYf7JP29UXg/s72-c/routemap.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7760179028417385983</id><published>2009-06-15T08:37:00.001Z</published><updated>2009-06-15T08:37:13.844Z</updated><title type='text'>Animated gifs stop animating in IE</title><content type='html'>&lt;p&gt;An annoying bug/ feature of Internet Explorer is that animated gifs stop animating the moment you click a link to navigate to another page. Other things can stop them animating too: I recently found that a flash-based file uploader that we use triggers this bug when it finishes the upload.&lt;/p&gt;  &lt;p&gt;Fortunately it's not to hard to work around. If you reassign the value of the src attribute of the &amp;lt;img&amp;gt; tag, the animation starts again.&lt;/p&gt;  &lt;p&gt;jQuery makes it easy to reassign all such tags in one fell swoop:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #008000"&gt;//codesnippet:7660712A-6D8A-4820-A99F-751F44A57AD2&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; fixAnimatedGifsDamnYouInternetExplorer()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;{&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    $(&amp;quot;&lt;span style="color: #8b0000"&gt;img&lt;/span&gt;&amp;quot;).each(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.src = &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.src;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    });&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;In my case, I called this function when my upload completed, but you could easily attach it to the click event of every link on your page. &lt;br /&gt;&lt;br /&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7760179028417385983?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7760179028417385983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=7760179028417385983' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7760179028417385983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7760179028417385983'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/06/animated-gifs-stop-animating-in-ie.html' title='Animated gifs stop animating in IE'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15336493667160399642'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-3856198214148559431</id><published>2009-06-08T10:53:00.002Z</published><updated>2009-06-10T14:06:48.357Z</updated><title type='text'>Microsoft release SEO Tools</title><content type='html'>&lt;p&gt;SEO (search engine optimisation) is debatably one of the most important things to get right in a website that needs web traffic. If your web traffic is driven by search engines, you want to give the search engines anything and everything they could need to connect someone's query with your site. Especially as traffic from search is effectively free traffic.&lt;/p&gt;  &lt;p&gt;Google have webmaster tools available which give you access to stats about your site (assuming you have tracking on your site),  crawling errors etc. They have associated help sections and even have an &lt;a href="http://www.google.com/webmasters/docs/search-engine-optimization-starter-guide.pdf" target="_blank"&gt;SEO guide available&lt;/a&gt; for download.&lt;/p&gt;  &lt;p&gt;What Microsoft have released is an IIS add in that gives you a huge amount of stats, finds issues and provides diagnostic information about any site you point it at. We pointed it at the W3C (World Wide Web Consortium - Home of Web Standards), limited the tool to 5000 links and set it running.&lt;/p&gt;  &lt;p&gt;It found more than 19,000 violations:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_gPRWTjkTHUU/SiztoCxA2FI/AAAAAAAAADY/g154sf-J2k4/s1600-h/w3c%5B3%5D.png"&gt;&lt;img style="border-width: 0px; display: inline;" title="w3c" alt="w3c" src="http://lh4.ggpht.com/_gPRWTjkTHUU/Sizto_4QYYI/AAAAAAAAADc/inTouEQhTmc/w3c_thumb%5B1%5D.png?imgmax=800" border="0" height="351" width="467" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;It ranks these by SEO, Content, Performance and Standards and gives an indication of the severity.&lt;/p&gt;  &lt;p&gt;The thing you notice when you get going with the tool is the extent to which you can drill down and the immense utility of the information it exposes.&lt;/p&gt;  &lt;p&gt;Did you know the content of the &amp;lt;title&amp;gt; tag shouldn't exceed 65 characters? search engines generally truncate the text after that.&lt;/p&gt;  &lt;p&gt;Here's a hastily thrown together image of the other menu options:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_gPRWTjkTHUU/Siztpeg8fLI/AAAAAAAAADg/ca6zBpQ8EJk/s1600-h/menuoptions%5B3%5D.png"&gt;&lt;img style="border-width: 0px; display: inline;" title="menuoptions" alt="menuoptions" src="http://lh5.ggpht.com/_gPRWTjkTHUU/SiztqDuME_I/AAAAAAAAADk/K6CdhqPVds8/menuoptions_thumb%5B1%5D.png?imgmax=800" border="0" height="343" width="529" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;It's currently in beta and only works in IIS 7 so that means it's limited to Windows Vista and Windows Server 2008. I think it'll quickly become a mainstay of the SEO optimiser's arsenal. Find out more here: &lt;a href="http://weblogs.asp.net/scottgu/archive/2009/06/03/iis-search-engine-optimization-toolkit.aspx" target="_blank"&gt;Scott Guthries blog&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-3856198214148559431?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/3856198214148559431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=3856198214148559431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3856198214148559431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3856198214148559431'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/06/microsoft-release-seo-optimisation.html' title='Microsoft release SEO Tools'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04912185286940984148'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-5699213877530422312</id><published>2009-06-01T15:06:00.002Z</published><updated>2009-06-01T15:21:22.436Z</updated><title type='text'>Speeding up deployment by zipping drop files in TFS</title><content type='html'>&lt;p&gt;As most of the projects we produce are web based, we use the file copy feature of ASP.NET heavily. It makes for wonderfully simple deployment. Using this feature does however mean that we zip the files up before sending them over to the live server.&lt;/p&gt;  &lt;p&gt;To speed up deployment even further, we added a zip command to our build job in Team Foundation Server Build that zips the files in the drop location, ready for copy.&lt;/p&gt;  &lt;p&gt;Zipping is not supported out of the box in TFS but the &lt;a href="http://msbuildtasks.tigris.org/"&gt;MSBuild Community Tasks Project&lt;/a&gt; has a lovely one. &lt;/p&gt;  &lt;p&gt;To use the zip command in the community tasks library you need to add a reference to it.&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Import&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Project&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;Once this has been imported you can then use the zip command in your script. We tend to use the zip command in the AfterDropBuild event.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;CreateItem&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Include&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;$(DropLocation)\$(BuildNumber)\Release\**\*.*&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Exclude&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;$(DropLocation)\$(BuildNumber)\Release\**\*.config&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Output&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ItemName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;ZipFiles&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TaskParameter&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Include&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;CreateItem&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Time&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Format&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;yyyy-MM-dd&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Output&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TaskParameter&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;FormattedTime&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;PropertyName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;buildDate&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Time&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Zip&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Files&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;@(ZipFiles)&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;WorkingDirectory&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;$(DropLocation)\$(BuildNumber)\Release&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ZipFileName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;$(DropLocation)\$(BuildNumber)\NBR Release $(buildDate).zip&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;We also tend to put the date into the release and we do that by using the Time command. This now gives us a prepped zip file with all the release files in it. &lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-5699213877530422312?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/5699213877530422312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=5699213877530422312' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5699213877530422312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5699213877530422312'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/06/speeding-up-deployment-by-zipping-drop.html' title='Speeding up deployment by zipping drop files in TFS'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16236226257094048772'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-1435863670387469718</id><published>2009-05-21T13:38:00.002Z</published><updated>2009-05-21T13:46:14.214Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='viewstate'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><title type='text'>Size of data in the ViewState</title><content type='html'>&lt;p&gt;I love the ViewState.&lt;/p&gt;  &lt;p&gt;I know it's a much-maligned technology. I know it can bloat out of all control. I know it can be an effort to tame it, but spend an afternoon reading up on it and it can really be your friend.&lt;/p&gt;  &lt;p&gt;It can be a handy place to store all sorts of state data that you don't want to (or can't) track on the server. It's dead easy to add values to it programmatically and retrieve them after a postback.&lt;/p&gt;  &lt;p&gt;You can serialize pretty much anything into the ViewState. Though putting an instance of your Customer class in there would blatantly be a bad idea - it would be vast once serialized - storing smaller constructs is feasible, and usually holding a few flags is sufficient to maintain the state of your page.&lt;/p&gt;  &lt;p&gt;What can be a little surprising, though, is how big some data items are compared with others when they're serialised to the ViewState.&lt;/p&gt;  &lt;p&gt;I spent an afternoon putting all sorts of items into the ViewState and seeing how much it made the ViewState grow. The results are in the graph below. (Click to see a legible-sized version.)&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.compsoft.co.uk/Files/ViewState.gif" target="_blank"&gt;&lt;img title="ViewState Graph" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="315" alt="ViewState Graph" src="http://www.compsoft.co.uk/Files/ViewState.gif" width="409" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Note that all the figures are multiples of four - this is because the ViewState is base 64 encoded. Unfortunately it means the figures aren't quite spot-on to the byte, but they're good enough for our purposes.&lt;/p&gt;  &lt;p&gt;The most important thing to notice is the long bar at the bottom. A List&amp;lt;string&amp;gt; containing only two three-letter strings took a whopping 312 bytes! Compare this with the array of strings holding the same values, which took only 24 bytes. An easy lesson: if you're putting a set of objects into the ViewState, turn that list into an array first.&lt;/p&gt;  &lt;p&gt;In fact, arrays perform pretty well. Arrays of arrays carry a bit of overhead but aren't too bad, all things considered.&lt;/p&gt;  &lt;p&gt;Surprisingly, int.MaxValue takes more space than the integer 1. Storing int.MaxValue.ToString() took more again, but these figures are still pretty small so it doesn't make much difference.&lt;/p&gt;  &lt;p&gt;Converting a DateTime to a string took rather more space than the raw DateTime itself.&lt;/p&gt;  &lt;p&gt;On the other hand, decimals take a vast amount of space for what they are (and decimal.MinValue took significantly more than decimal.One); but converting them to strings dropped the space right back down again.&lt;/p&gt;  &lt;p&gt;I'm surprised that storing a Guid takes three times as much space as its string representation - I can't imagine what extra information is being serialized there.&lt;/p&gt;  &lt;p&gt;Similarly, types take quite a bit of space; storing their full names is sufficient to regain the class object later and takes only about a third of the space. (Though to be fair I can't imagine what circumstances would lead you to putting a Type into the ViewState.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-1435863670387469718?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/1435863670387469718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=1435863670387469718' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1435863670387469718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1435863670387469718'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/05/size-of-data-in-viewstate.html' title='Size of data in the ViewState'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15336493667160399642'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7304194194178188652</id><published>2009-05-18T10:29:00.003Z</published><updated>2009-05-18T10:32:43.418Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='sql ce'/><category scheme='http://www.blogger.com/atom/ns#' term='bug fix'/><title type='text'>Combatting "Unspecified error"</title><content type='html'>&lt;p&gt;In one of our Windows Mobile applications we've been noticing some bizarre exceptions where we're logging a rare exception of "Unspecified Error".&lt;/p&gt;  &lt;p&gt;It's always a pain getting this kind of error, you really have no clue where to turn. Pin pointing the general area and finding the point at which the application fails tends to be the only route and led us to find it was database related.&lt;/p&gt;  &lt;p&gt;Further research into the error implies that the issue lies in SQL CE (we're using SQL CE 3.5 SP1). It's at the point we're touching the database but ONLY after the device has come out of stand by mode and ONLY if the database file is located on the storage / memory card. Database files stored on the internal memory are fine.&lt;/p&gt;  &lt;p&gt;It turns out that the SQL Server Mobile engine has a bug when the database file is accessed before the block device driver (that allows you to access the database file) has started up after the device is restored from suspend mode.&lt;/p&gt;  &lt;p&gt;There's a &lt;a href="http://support.microsoft.com/kb/919150/en-us" target="_blank"&gt;hotfix available&lt;/a&gt; for previous versions but not the latest and it only seems to give a more intelligible error message of "The disk is not ready" or "The OS storage system (RAM, CF, SD, or IPSM) is not responding. Retry the operation".&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Which leaves us with the choice of what to do in this instance.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Handle database access exceptions until the device is ready again.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Wire up to the device's power events and handle the Power up event.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Move the database file to the Internal memory.&lt;/p&gt;  &lt;p&gt;I decided to go with option 2. A significant amount of work would have been required for option 1.  The devices we're working against have a 2GB storage card versus a 64mb internal memory so I felt this wouldn't work for us without impacting performance so I didn't go for option 3. &lt;/p&gt;  &lt;p&gt;The easiest way to go with option 2 is by using the &lt;a href="http://www.opennetcf.com/Products/SmartDeviceFramework/tabid/65/Default.aspx" target="_blank"&gt;opennetcf smart device framework&lt;/a&gt; framework which in the OpenNETCF.WindowsCE.PowerManagement namespace allows you to wire up to all the Power related states and their changes.&lt;/p&gt;  &lt;p&gt;Here's one possible solution:&lt;/p&gt;  &lt;div   style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; direction: ltr; max-height: 200px; cursor: text;font-family:'Courier New',courier,monospace;font-size:8pt;" id="codeSnippetWrapper"&gt;   &lt;div    style="border-style: none; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;" id="codeSnippet"&gt;     &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; Main()&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum3"&gt;   3:&lt;/span&gt;     OpenNETCF.WindowsCE.PowerManagement.PowerUp += &lt;span style="color: rgb(0, 0, 255);"&gt;new&lt;/span&gt; &lt;/pre&gt;&lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;OpenNETCF.WindowsCE.DeviceNotification(PowerManagement_PowerUp);&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum5"&gt;   4:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;//Run the app&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum6"&gt;   5:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum7"&gt;   6:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr; font-family: 'Courier New',courier,monospace; font-size: 8pt; color: black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum8"&gt;   7:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; PowerManagement_PowerUp()&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum9"&gt;   8:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre face="'Courier New',courier,monospace" size="8pt" color="black" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum10"&gt;   9:&lt;/span&gt;     System.Windows.Forms.Application.Exit();&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum11"&gt;  10:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;OpenNetCF has some great products, their download count is at 3/4 million at the time of writing. They have good customer service too.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7304194194178188652?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7304194194178188652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=7304194194178188652' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7304194194178188652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7304194194178188652'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/05/combatting-error.html' title='Combatting &amp;quot;Unspecified error&amp;quot;'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04912185286940984148'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-8345489597713496334</id><published>2009-05-05T09:21:00.009Z</published><updated>2009-05-08T13:20:44.093Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='debug'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='Compsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='Neil Bostrom'/><title type='text'>Making sure your application is not left in debug="true"</title><content type='html'>You will find loads of articles around the web reminding us all that running your production ASP.NET website in complication debug=true mode is a BAD THING!  &lt;br /&gt; &lt;ul&gt;   &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/04/11/Don_1920_t-run-production-ASP.NET-Applications-with-debug_3D001D20_true_1D20_-enabled.aspx"&gt;Don't run production ASP.NET Applications with debug="true" enabled&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://aspnetresources.com/articles/debug_code_in_production.aspx"&gt;Beware Of Deploying Debug Code In Production&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://daptivate.com/archive/2008/02/12/top-10-best-practices-for-production-asp-net-applications.aspx"&gt;Top 10 Best Practices for Production ASP.NET Applications&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; To make sure we avoid this problem we have added a start up check in our application that will make sure that the build mode (debug or release) of our binaries match that of the web.config. As all releases are done via our build server all our binaries will be in release mode. However we tend to make major changes to the web.config on the live servers so deploying the web.config is usually not an option.  &lt;br /&gt;&lt;br /&gt;To check if the web.config has debug enabled you can use HttpContext.Current.IsDebuggingEnabled.  &lt;br /&gt;&lt;br /&gt;To check what mode a binary is in, we use the #DEBUG Preprocessor Directive:  &lt;br /&gt; &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div   style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; direction: ltr; max-height: 200px; cursor: text;font-family:'Courier New',courier,monospace;font-size:8pt;" id="codeSnippetWrapper"&gt;   &lt;div    style="border-style: none; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;" id="codeSnippet"&gt;     &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 128, 0);"&gt;// codesnippet:ADB0358E-3BD1-11DE-B2D2-764056D89593&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;static&lt;/span&gt; BuildModeEnum BuildMode&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum3"&gt;   3:&lt;/span&gt; {    &lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum4"&gt;   4:&lt;/span&gt;     get    &lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum5"&gt;   5:&lt;/span&gt;     {        &lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum6"&gt;   6:&lt;/span&gt;         &lt;span style="color: rgb(204, 102, 51);"&gt;#if&lt;/span&gt; (DEBUG)&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum7"&gt;   7:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; BuildModeEnum.Debug;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum8"&gt;   8:&lt;/span&gt;         &lt;span style="color: rgb(204, 102, 51);"&gt;#else&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum9"&gt;   9:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; BuildModeEnum.Release;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum10"&gt;  10:&lt;/span&gt;         &lt;span style="color: rgb(204, 102, 51);"&gt;#endif&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum11"&gt;  11:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum12"&gt;  12:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-8345489597713496334?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/8345489597713496334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=8345489597713496334' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8345489597713496334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8345489597713496334'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/05/making-sure-your-application-is-not.html' title='Making sure your application is not left in debug=&amp;quot;true&amp;quot;'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16236226257094048772'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7296868850169548975</id><published>2009-04-27T16:17:00.005Z</published><updated>2009-04-28T09:09:44.912Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='MIGRATIING'/><category scheme='http://www.blogger.com/atom/ns#' term='UNIX TIME'/><category scheme='http://www.blogger.com/atom/ns#' term='UNIX EPOCH'/><category scheme='http://www.blogger.com/atom/ns#' term='MSSQL'/><title type='text'>Migrating MySQL Unix timestamps to MSSQL date time</title><content type='html'>Just this week I've been migrating data held in a MySQL database to a Microsoft SQL database, and I've run into a bit of a headache with temporal values being stored as integers.&lt;br /&gt;&lt;br /&gt;MySQL is a great database for the web. It has some nice features, one of which being the ability to export the table structure and all the data into one script you can download. It can even be zipped on the way. This makes transfering data super simple.&lt;br /&gt;&lt;br /&gt;Super simple that is unless dates and times are stored as Unix timestamps, and its going into a MSSQL database.&lt;br /&gt;&lt;br /&gt;Okay, so there is a certain amount of cleanup needed in the scripts going from one database to the other, but thats fairly easily done with an amount of regex.&lt;br /&gt;&lt;br /&gt;However, dates and times stored as int are in Unix time (or POSIX time). So to get the actual date time of the value in MySQL you need to do something like:&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 SELECT \cf0 FROM_UNIXTIME(date_added) \cf1 FROM \cf0 NewsStory } --&gt; &lt;div style="background: white none repeat scroll 0% 0%; font-family: Consolas; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;SELECT &lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;FROM_UNIXTIME&lt;/span&gt;(date_added) &lt;span style="color: blue;"&gt;FROM &lt;/span&gt;NewsStory &lt;/p&gt; &lt;/div&gt; &lt;br /&gt;There isn't an equivalent of FROM_UNIXTIME in MSSQL so to get at the date time value from there you need to add to the value the number of seconds since the Unix epoch (1st January 1970 00:00:00), like this:&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red163\green21\blue21;}??\fs20 \cf1 SELECT DateAdd\cf0 (ss, date_added, \cf4 '1970-01-01'\cf0 ) \cf1 FROM \cf0 NewsStory\par ??} --&gt; &lt;div style="background: white none repeat scroll 0% 0%; font-family: Consolas; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;SELECT &lt;span style="color: rgb(204, 51, 204);"&gt;DateAdd&lt;/span&gt;&lt;/span&gt;(ss, date_added, &lt;span style="color: rgb(163, 21, 21);"&gt;'1970-01-01'&lt;/span&gt;) &lt;span style="color: blue;"&gt;FROM &lt;/span&gt;NewsStory&lt;/p&gt; &lt;/div&gt; &lt;br /&gt;Et viola! Something sensible you can use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7296868850169548975?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7296868850169548975/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=7296868850169548975' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7296868850169548975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7296868850169548975'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/04/migrating-mysql-unix-timestamps-to.html' title='Migrating MySQL Unix timestamps to MSSQL date time'/><author><name>John Green</name><uri>http://www.blogger.com/profile/00454091456869602396</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='05522198464570262162'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-4921589905915764577</id><published>2009-04-23T13:25:00.002Z</published><updated>2009-04-23T13:27:03.239Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='query'/><category scheme='http://www.blogger.com/atom/ns#' term='log'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq to SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Logging all LINQ to SQL queries used in a single page lifecycle</title><content type='html'>&lt;p&gt;We absolutely love LINQ to SQL here at Compsoft. It's the best ORM we've used and it's made a marked speed increase in both our application development and application performance.&lt;/p&gt;  &lt;p&gt;A concern we had initially was the amount of &amp;quot;magic&amp;quot; involved. Occasionally we'd find that LINQ was running rather more queries than we'd expected (the DataLoadOptions weren't always behaving quite as we'd anticipated), or the queries were unexpectedly complicated. Also, with all the ease of data access that LINQ gives you, it's easy to get lazy and forget quite how many trips you're making to the database to generate a single web page.&lt;/p&gt;  &lt;p&gt;We felt we needed an easy way to see what was going on under the hood. We didn't want to have to go a long way out of our way to find out which pages took a lot of database effort: we wanted to be warned about this up-front.&lt;/p&gt;  &lt;p&gt;So here's what we made: when in debug mode, this appears in the top corner of every page we're working on:&lt;/p&gt;  &lt;p&gt;&lt;img alt="" src="http://1.bp.blogspot.com/_zsifaW4TiJo/SfBJeLAqHkI/AAAAAAAAAAw/sVrNIh3A5uA/s400/DbHitCountClosed.gif" border="0" /&gt;&lt;/p&gt;  &lt;p&gt;... which expands to this when clicked:&lt;/p&gt;  &lt;p&gt;&lt;img alt="" src="http://4.bp.blogspot.com/_zsifaW4TiJo/SfBJr-KOW2I/AAAAAAAAAA4/hILhbJLGkWs/s400/DbHitCountOpen.gif" border="0" /&gt;&lt;/p&gt;  &lt;p&gt;The more queries it takes to make the page, the redder the little &amp;quot;DB hits&amp;quot; box appears, drawing our attention to pages that accidentally take a lot of work to produce.&lt;/p&gt;  &lt;p&gt;LINQ to SQL makes it easy to capture this sort of information. The Log property of DataContext is a TextWriter to which all queries are written, together with the values of any query parameters. Setting this to a new StringWriter in the constructor of our application's DataContext catches all the queries it performs.&lt;/p&gt;  &lt;p&gt;We typically use one DataContext per page lifecycle, so it would seem it would be sufficient to dump the contents of the log to the page late in the page lifecycle. However there are occasions where we create additional DataContexts for particular tasks, and we want to know what they are up to too.&lt;/p&gt;  &lt;p&gt;Here's the solution we came up with:&lt;/p&gt;  &lt;p&gt;The data context class for the application inherits from this BaseDataContext class, which lives in our reusable code libraries:&lt;/p&gt;  &lt;div style="font-size: 10px; background: white; color: black; font-family: couriernew"&gt;   &lt;p style="margin: 0px"&gt;&lt;span style="color: green"&gt;&lt;font face="Courier New" size="2"&gt;// codesnippet:4963E640-80C0-4577-A2B2-F0F6A8D41E56&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;BaseDataContext&lt;/span&gt; : &lt;span style="color: #2b91af"&gt;DataContext&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;{&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: #e000e0"&gt;#if&lt;/span&gt; (DEBUG)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;TextWriter&lt;/span&gt; logWriter;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringBuilder&lt;/span&gt; _Logger;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringBuilder&lt;/span&gt; Logger&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; {&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;get&lt;/span&gt; { &lt;span style="color: blue"&gt;return&lt;/span&gt; _Logger; }&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;set&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _Logger = &lt;span style="color: blue"&gt;value&lt;/span&gt;;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; logWriter = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringWriter&lt;/span&gt;(&lt;span style="color: blue"&gt;value&lt;/span&gt;);&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;static&lt;/span&gt; BaseDataContext()&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; {&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #2b91af"&gt;BaseDataContext&lt;/span&gt;.Logger = &lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringBuilder&lt;/span&gt;();&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;span style="color: #e000e0"&gt;&lt;font face="Courier New" size="2"&gt;#endif&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;public&lt;/span&gt; BaseDataContext(&lt;span style="color: blue"&gt;string&lt;/span&gt; connectionString)&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : &lt;span style="color: blue"&gt;base&lt;/span&gt;(connectionString)&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; {&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: #e000e0"&gt;#if&lt;/span&gt; (DEBUG)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;this&lt;/span&gt;.Log = logWriter;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;span style="color: #e000e0"&gt;&lt;font face="Courier New" size="2"&gt;#endif&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;[Aside: we like &lt;a href="http://www.codinghorror.com/blog/archives/001257.html"&gt;Jeff Attwood's idea for flagging code snippets with GUIDs&lt;/a&gt;.]&lt;/p&gt;  &lt;p&gt;As you can see, the log is static, so all queries from all DataContexts will be written to the same log. This would be nightmarish if the server were handling numerous requests concurrently, but this is just a development tool for when the application is running on your local machine (which is partly why the logging only happens when the application's in debug mode).&lt;/p&gt;  &lt;p&gt;That takes care of logging the queries; next we have to display them. We have this in the class that all our pages inherit from:&lt;/p&gt;  &lt;div style="font-size: 12pt; background: white; color: black; font-family: couriernew"&gt;   &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: #e000e0"&gt;#if&lt;/span&gt; (DEBUG)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: blue"&gt;protected&lt;/span&gt; &lt;span style="color: blue"&gt;override&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Render(&lt;span style="color: #2b91af"&gt;HtmlTextWriter&lt;/span&gt; writer)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;{&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: green"&gt;// Snip - write the contents of the log&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: green"&gt;&amp;#160;&amp;#160;&amp;#160; // to the page&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;base&lt;/span&gt;.Render(writer);&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #2b91af"&gt;BaseDataContext&lt;/span&gt;.Logger = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringBuilder&lt;/span&gt;();&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;}&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;span style="color: #e000e0"&gt;&lt;font face="Courier New" size="2"&gt;#endif&lt;/font&gt;&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;This ensures the log is cleared down right at the very end of the page lifecycle, ready to start logging queries for the next page. Also, as the log is only cleared after it's written out, no queries get lost if the page lifecycle ends prematurely in a redirect.&lt;/p&gt;  &lt;p&gt;The snipped code is a bit lengthy, but it basically renders the database hit count with a little jQuery to expand the full details of the queries when clicked, as in the screenshots above.&lt;/p&gt;  &lt;p&gt;Astonishingly you can't do this sort of thing at all in LINQ to Entities - it doesn't have this logging support - so for all the flexibility that it offers, it's still missing some features that seem pretty crucial to us.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-4921589905915764577?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/4921589905915764577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=4921589905915764577' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4921589905915764577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4921589905915764577'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/04/logging-all-linq-to-sql-queries-used-in_23.html' title='Logging all LINQ to SQL queries used in a single page lifecycle'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15336493667160399642'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_zsifaW4TiJo/SfBJeLAqHkI/AAAAAAAAAAw/sVrNIh3A5uA/s72-c/DbHitCountClosed.gif' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-1837721630371821350</id><published>2009-04-20T15:07:00.003Z</published><updated>2009-04-28T09:36:25.862Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='interactivity'/><category scheme='http://www.blogger.com/atom/ns#' term='plugin'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>jQuery plugins - A treasure trove of awesome</title><content type='html'>&lt;span style=";font-family:verdana;font-size:85%;"  &gt;In order to provide a richer, cross-browser, more interactive experience for our client web applications, we make use of &lt;a href="http://www.jquery.com/"&gt;jQuery&lt;/a&gt;. jQuery is a robust javascript framework that takes a lot of the complexity out of writing client side javascript.&lt;br /&gt;&lt;br /&gt;One of the most powerful features of the framework is that it's been developed with a highly extensible plugin model.&lt;br /&gt;&lt;br /&gt;We recently decided to add some interactivity to our partner site &lt;a href="http://www.bluesulphur.com/"&gt;Bluesulphur&lt;/a&gt; to replace some of the flash content we currently have. As part of that, I looked at some of the plugins currently available.&lt;br /&gt;These are some of the nicest plugins I found.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gPRWTjkTHUU/Seyc6EF0dQI/AAAAAAAAABo/T_25M8zzSw0/s1600-h/autosuggest.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: right; cursor: pointer; width: 198px; height: 272px;" src="http://3.bp.blogspot.com/_gPRWTjkTHUU/Seyc6EF0dQI/AAAAAAAAABo/T_25M8zzSw0/s320/autosuggest.png" alt="" id="BLOGGER_PHOTO_ID_5326804980616951042" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;a href="http://web2ajax.fr/examples/facebook_searchengine/"&gt;Facebook search engine&lt;/a&gt; - A Facebook style autosuggest plugin using jQuery. It's particularly pretty and although it currently uses a php source for data, this isn't a big limitation, these can be swapped out to use .NET web services as a provider quite easily.&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeygJ5eEJFI/AAAAAAAAABw/Q-nz3xi4YrU/s1600-h/codabubble.png"&gt;&lt;img style="margin: 10px 0pt 10px 10px; float: left; cursor: pointer; width: 279px; height: 194px;" src="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeygJ5eEJFI/AAAAAAAAABw/Q-nz3xi4YrU/s320/codabubble.png" alt="" id="BLOGGER_PHOTO_ID_5326808551178642514" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;&lt;br /&gt;&lt;a href="http://jqueryfordesigners.com/demo/coda-bubble.html"&gt;coda bubble&lt;/a&gt; is a mac like popup that could be put to use in many situations.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeyiqMrLe2I/AAAAAAAAACA/5vS4Jz6BmwM/s1600-h/tablesorter.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 113px;" src="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeyiqMrLe2I/AAAAAAAAACA/5vS4Jz6BmwM/s400/tablesorter.png" alt="" id="BLOGGER_PHOTO_ID_5326811305112992610" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;&lt;br /&gt;&lt;a href="http://tablesorter.com/docs/#demo"&gt;jQuery Tablesorter&lt;/a&gt; is a cute little plugin that makes any table sortable&lt;/p&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gPRWTjkTHUU/SeyjddcFgCI/AAAAAAAAACI/hmiCvcUsr3w/s1600-h/fancybox.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: left; cursor: pointer; width: 316px; height: 400px;" src="http://1.bp.blogspot.com/_gPRWTjkTHUU/SeyjddcFgCI/AAAAAAAAACI/hmiCvcUsr3w/s400/fancybox.png" alt="" id="BLOGGER_PHOTO_ID_5326812185786417186" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;&lt;a href="http://fancy.klade.lv/example"&gt;Fancybox &lt;/a&gt;is a popup plugin that you can use for popup image galleries, the popups have nice transition effects as well as inbuilt navigation and grouping functionality.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeykZ8HE78I/AAAAAAAAACQ/wkSBJcq0pdA/s1600-h/markitup.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 385px;" src="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeykZ8HE78I/AAAAAAAAACQ/wkSBJcq0pdA/s400/markitup.png" alt="" id="BLOGGER_PHOTO_ID_5326813224811950018" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;I thought for the last example, I'd show an html editor and I really like markitup, it's both simple and sexy. It looks like it's an easy integrator too, which is always a plus.&lt;/p&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;So, to sum up, there are a lot jQuery plugins out there, more than 2500 just on the &lt;a href="http://plugins.jquery.com/"&gt;jQuery plugin site&lt;/a&gt; alone. New and awesome plugins are being released every day, check them out!&lt;/p&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;Oh, and &lt;a href="http://www.compsoft.co.uk/"&gt;Compsoft &lt;/a&gt;are a great choice for integrating jQuery interactivity and plugins into your site too! *wink*&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-1837721630371821350?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/1837721630371821350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=1837721630371821350' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1837721630371821350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1837721630371821350'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/04/jquery-plugins-treasure-trove-of.html' title='jQuery plugins - A treasure trove of awesome'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04912185286940984148'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_gPRWTjkTHUU/Seyc6EF0dQI/AAAAAAAAABo/T_25M8zzSw0/s72-c/autosuggest.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7978070243187532844</id><published>2009-04-09T14:43:00.005Z</published><updated>2009-04-09T15:10:14.294Z</updated><title type='text'>SQL Server Express Automated Backup</title><content type='html'>SQL Server Express does not come with the SQL agent support which means there is no easy way to schedule backups of databases.&lt;br /&gt;&lt;br /&gt;After some googling, a &lt;a href="http://www.sqldbatips.com/showarticle.asp?ID=27"&gt;great article by Jasper Smith&lt;/a&gt; came up. He has built a wonderful stored procedure that backups all the databases on the instance and even produces a report for the backup.&lt;br /&gt;&lt;br /&gt;Really nice feature of the script is that it will even allows you to manage how long the backups are kept for!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sqldbatips.com/showarticle.asp?ID=27"&gt;Read the original article&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7978070243187532844?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='related' href='http://www.sqldbatips.com/showarticle.asp?ID=27' title='SQL Server Express Automated Backup'/><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7978070243187532844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=7978070243187532844' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7978070243187532844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7978070243187532844'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/04/sql-server-express-automated-backup.html' title='SQL Server Express Automated Backup'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16236226257094048772'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-9196743555093743014</id><published>2009-03-30T08:08:00.008Z</published><updated>2009-04-23T08:35:55.644Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='new id'/><category scheme='http://www.blogger.com/atom/ns#' term='multiuser'/><category scheme='http://www.blogger.com/atom/ns#' term='website'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='pear'/><category scheme='http://www.blogger.com/atom/ns#' term='insert'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrent'/><title type='text'>Multiuser atomic SQL; day one</title><content type='html'>Recently we've taken over support for a new, externally developed application that sends text messages to mobiles in response to shortcode requests for more information about cars, houses etc for sale.&lt;br /&gt;&lt;br /&gt;Under development and testing everything was fine. However, when it went live the registration process occasionally failed. After a brief examination I noticed this method for inserting records in the database class:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red128\green0\blue128;\red128\green128\blue0;}??\fs20 \cf1 {\b $newId}\cf0  \cf4 {\b =}\cf0  \cf1 {\b $this}\cf4 {\b -&gt;}\cf0 conn\cf4 {\b -&gt;}\cf0 nextID(\cf1 {\b $tableName}\cf0  \cf4 {\b .}\cf0  \cf5 "_id"\cf0 );} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;$newId&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;=&lt;/span&gt; &lt;span style="font-weight: bold;color:blue;" &gt;$this&lt;/span&gt;&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;conn&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;nextID(&lt;span style="font-weight: bold;color:blue;" &gt;$tableName&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;.&lt;/span&gt; &lt;span style="color:olive;"&gt;"_id"&lt;/span&gt;);&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;I suspected that this did something a little unusual.&lt;br /&gt;&lt;br /&gt;It had been written in Php5 backed by MySQL and was using the Pear DB package. It rapidly became clear the book "Professional PHP5" had been used a little too religiously. The book suggests this facade method for generating and getting the next ID for a new record that hides the operational differences between MySQL, PostreSQL, Oracle and other RDBMS.&lt;br /&gt;&lt;br /&gt;Under the hood, Pear DB creates an id tracking table of the same name suffixed with "_id_seq" for each table storing data with unique ids. It gets the value from this tracking table, adds one to the value, stores it back, and returns this value as the next id to be used in the insert statement for the new record.&lt;br /&gt;&lt;br /&gt;So I heard websites and the internet was a concurrent multiuser enviroment? Can anyone guess what might be the problem generating unique ids this way?&lt;br /&gt;&lt;br /&gt;MySQL gives the us the &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html"&gt;auto_increment&lt;/a&gt; feature. It also gives us the &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/mysql-insert-id.html"&gt;mysql_insert_id&lt;/a&gt; method. This allows us to get the last auto generated id if we need it:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red128\green0\blue128;}??\fs20 \cf1 {\b $newId}\cf0  \cf4 {\b =}\cf0  mysql_insert_id(\cf1 {\b $this}\cf4 {\b -&gt;}\cf0 conn\cf4 {\b -&gt;}\cf0 connection);} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;$newId&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;=&lt;/span&gt; mysql_insert_id(&lt;span style="font-weight: bold;color:blue;" &gt;$this&lt;/span&gt;&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;conn&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;connection);&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;"But surely, when inserting new records in a concurrent multiuser environment, we need actions like this to be as atomic as possible?" I hear you ask. The force (read SQL) is strong with this one. Correct.&lt;br /&gt;&lt;br /&gt;MySQL allows us to provide a value for an auto_increment field, or we can supply 'null' and allow MySQL to do it for us.&lt;br /&gt;&lt;br /&gt;So to fix this intermittent registration failure, we replace the line:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red128\green0\blue128;\red128\green128\blue0;}??\fs20 \cf1 {\b $newId}\cf0  \cf4 {\b =}\cf0  \cf1 {\b $this}\cf4 {\b -&gt;}\cf0 conn\cf4 {\b -&gt;}\cf0 nextID(\cf1 {\b $tableName}\cf0  \cf4 {\b .}\cf0  \cf5 "_id"\cf0 );} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;$newId&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;=&lt;/span&gt; &lt;span style="font-weight: bold;color:blue;" &gt;$this&lt;/span&gt;&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;conn&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;nextID(&lt;span style="font-weight: bold;color:blue;" &gt;$tableName&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;.&lt;/span&gt; &lt;span style="color:olive;"&gt;"_id"&lt;/span&gt;);&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;with:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red128\green0\blue128;\red128\green128\blue0;}??\fs20 \cf1 {\b $newId}\cf0  \cf4 {\b =}\cf0  \cf5 'null'\cf0 ;} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;$newId&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;=&lt;/span&gt; &lt;span style="color:olive;"&gt;'null'&lt;/span&gt;;&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;And LO, the bug is gone.&lt;br /&gt;Needless to say Pear DB has been replaced by something else. And interestingly if you read on a little in the book you'll see "we strongly recommend... ideally, allow your RDBMS to [generate the id]"&lt;br /&gt;&lt;br /&gt;So what? Read books carefully. Know the technology you're using. Concurrency requires atomic superness.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-9196743555093743014?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/9196743555093743014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=9196743555093743014' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/9196743555093743014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/9196743555093743014'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/03/multiuser-atomic-sql-day-one.html' title='Multiuser atomic SQL; day one'/><author><name>John Green</name><uri>http://www.blogger.com/profile/00454091456869602396</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='05522198464570262162'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-6696207888828846218</id><published>2009-03-17T10:28:00.016Z</published><updated>2009-03-25T15:28:34.413Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='login'/><category scheme='http://www.blogger.com/atom/ns#' term='password'/><category scheme='http://www.blogger.com/atom/ns#' term='website'/><category scheme='http://www.blogger.com/atom/ns#' term='user account'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='dictionary attack'/><category scheme='http://www.blogger.com/atom/ns#' term='hack'/><title type='text'>Securing web logins against dictionary attacks</title><content type='html'>It's good to learn from your mistakes; it's even better to learn from other people's. So, when &lt;a href="http://www.theregister.co.uk/2009/01/07/twitter_hack_explained/"&gt;Twitter got hacked by a simple dictionary attack&lt;/a&gt;, we, the development team at &lt;a href="http://www.compsoft.co.uk"&gt;Compsoft&lt;/a&gt;, thought it a good time to review our password security model.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Because pretty much everyone wants password protection for at least some part of their web site, password security is something we've implemented quite a few times already. And as nobody enjoys re-inventing the wheel, this already lives in our well-established reusable code libraries - meaning that if we ever identify a weakness we can fix it in one place. At the very least, all our future customers get this improvement out of the box; where appropriate, the upgrades get rolled out to our existing customers too.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Our password handling was already pretty tight - we use some pretty aggressive &lt;a href="http://en.wikipedia.org/wiki/Salt_(cryptography)"&gt;salting&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Cryptographic_hash_function"&gt;hashing&lt;/a&gt; to ensure that passwords are held so securely that even we can't crack them. Even though I have full access to the database, I don't know your password; I can't tell anything about your password; I can't even tell if two people have the same password. If I copy the password details from my user record to yours, I still won't be able to log in as you. It's got to the point that it's quite difficult for us to set up the first user record in a new database - even copying password details from one database to another won't work.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, storing the password securely is all well and good, but doesn't help if your users use passwords that are easily guessable, as Twitter found to their embarrassment. The key feature they'd failed to implement (and that we realised we'd immediately have to add to our arsenal) was preventing unlimited password attempts.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Though &lt;a href="http://en.wikipedia.org/wiki/Dictionary_attack"&gt;dictionary attacks&lt;/a&gt; are always going to be slow when executed across the internet, they're still entirely possible - especially given that the only limit on a typical hacker's time is how quickly he gets bored.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The easiest solution is to say "if you get your password wrong five times, your account gets blocked". This is quick and easy to implement, but what does it mean for our users? Sure, they'd be protected against having their account hacked, but could they not legitimately take five attempts before they remember which password they used for this site? At times I've taken a lot more than that, going through more and more possible passwords that I think I might have used, before finding that the one I tried first was right - I'd just typed it wrong.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Increasing the number of attempts allowed doesn't really solve the problem - if they breach it, they're locked out completely. That means we'd have to add some mechanism whereby they can contact an administrator and convince them that they are who they say they are, so that the admin will re-enable their account. Not only would this alienate users, but this isn't really practical for a solution we can reuse across many intra- and internet sites.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What's worse, it's easy for one malicious user to lock other users out of their accounts, simply by repeatedly trying to log in as them.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We need something that is entirely invisible to as many genuine users as possible, but that is insurmountable to a dictionary attack in any reasonable amount of time. Also, should we start suspecting a legitimate user might be a hacker, they mustn't feel like we've just slammed the door in their face.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The solution we finally opted for goes like this:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;You get ten attempts to try to remember your password.&lt;/li&gt;&lt;li&gt;On the eleventh attempt, your account is locked for one minute.&lt;/li&gt;&lt;li&gt;Each subsequent attempt locks your account for twice as long: two minutes, four minutes, eight minutes...&lt;/li&gt;&lt;li&gt;If you make no log in attempts for twenty-four hours, we reset the counter to zero again.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Almost all users will never see that this security exists. Those who break the ten-guess limit see a polite message informing them of why we think something's wrong ("a large number of login attempts using the wrong password") and how long they new have left to wait before they can try again.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The first few times they see this limit they'll not have to wait long, and in the meantime we're gently teaching them to think a little more carefully about what password they might have used.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On the other hand, a hacker using a dictionary attack would have to attack the same user id persistently for a full 24 hours to get through just the first 21 words in his attack dictionary.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The experience of the attacked user isn't too bad either - they'll only know there's even been a problem if they try to log in shortly after the hacker (or malicious user) has been trying to access their account. The worst that could happen would be that they wouldn't be able to log in until tomorrow.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For us, this is a nice solution. We've implemented it as part of our reusable code framework, and included it in the template used by our code generation tool. This means that even though we haven't started work making your next website for you yet, your next website is already more secure than Twitter was.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-6696207888828846218?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/6696207888828846218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=6696207888828846218' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6696207888828846218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6696207888828846218'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/03/securing-web-logins-against-dictionary.html' title='Securing web logins against dictionary attacks'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='15336493667160399642'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-8791029274549863493</id><published>2009-03-09T14:04:00.007Z</published><updated>2009-03-09T15:00:50.696Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='.net implementation'/><category scheme='http://www.blogger.com/atom/ns#' term='bug fix'/><title type='text'>Implementing visual inheritance in windows mobile</title><content type='html'>&lt;span style="font-family:verdana;"&gt;We've been working on a Windows Mobile 6 PDA application and one requirement is to have a status bar that shows internet connectivity and updates.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;In Windows programming, a common way to do this is to create a base form which has a status bar and a mechanism to update it, this form is then used as a template for other forms. This means that you have a single point of failure, update and maintenance. This is a good thing as if you added that status bar to all your forms, you'd increase your maintenance headache with each new form.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;On Windows Mobile, there is support for the same visual templating mechanism, but there are a few pitfalls.&lt;/span&gt; &lt;span style="font-family:verdana;"&gt;If for example on your base form you wanted to add a popup keyboard, you'd need to add a reference to Microsoft.WindowsCE.Forms.&lt;/span&gt; &lt;span style="font-family:verdana;"&gt;This unfortunately breaks the vis&lt;/span&gt;&lt;span style="font-family:verdana;"&gt;ual inheritance in Visual Studio's form designer saying "Visual inheritance is currently disabled", this also occurs when using Platform Invoke (a method of calling methods in the base operating system) in the base form.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Luckily there are a few workarounds for this:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Add a class diagram, select your base form, add a custom attribute of DesktopCompa&lt;/span&gt;&lt;span style="font-family:verdana;"&gt;tible(true), this adds an XML Metadata Attribute file (.xmta).The xmta file can cause a genasm.exe error, ensure the build action is set to None and the copy to output directory is set to Do not copy, this should now build fine.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gPRWTjkTHUU/SbUsPJN6hFI/AAAAAAAAABg/NIaPxtrJjPk/s1600-h/properties.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 204px;" src="http://2.bp.blogspot.com/_gPRWTjkTHUU/SbUsPJN6hFI/AAAAAAAAABg/NIaPxtrJjPk/s320/properties.gif" alt="" id="BLOGGER_PHOTO_ID_5311199974237307986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt; &lt;span style="font-family:verdana;"&gt;Job done, we have visual inheritance visible in the designer.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-8791029274549863493?l=compsoftplc.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/8791029274549863493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=28989665&amp;postID=8791029274549863493' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8791029274549863493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8791029274549863493'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/03/implementing-visual-inheritance-in.html' title='Implementing visual inheritance in windows mobile'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04912185286940984148'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_gPRWTjkTHUU/SbUsPJN6hFI/AAAAAAAAABg/NIaPxtrJjPk/s72-c/properties.gif' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>