I’ve been enjoying the stability and extra performance of a 64 bit OS for about 2 years now so I am surprise and somewhat disappointed that the latest round of goodness from Microsoft – i.e. SharePoint 2010, Office 2010 and Visual Studio 2010 have some annoying incompatibilities in this mode.
Datasheet View of a SharePoint list with a 64 bit version of Office does not work, you just get this annoying dialog: Apparently this is because the ActiveX control is not available for 64 bit OS’s. I have only tested on 2008 R2 server – Windows 7 64 bit may be ok. Also, Intellitrace in Visual Studio – aka Historical Debugging - does not support SharePoint (or any 64 bit app?). I’m sure Microsoft are aware of these limitations and will offer solutions in due course – but really, 64 bit has been coming for a while and I think we can expect not to see this sort of incompatibility, especially for Office. For me this has tarnished my experience only a tad, but overall, 64 bit everywhere is better than 32 bit in the same way that cake is better than two week old bagels.
Old news I guess but it takes a while for things to filter down sometimes. From the latest iPhone SDK license: Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs. Applications must be originally written in Objective-C, C, C++, or JavaScript as executed by the iPhone OS WebKit engine, and only code written in C, C++, and Objective-C may compile and directly link against the Documented APIs (e.g., Applications that link to Documented APIs through an intermediary translation or compatibility layer or tool are prohibited). This appears to kill MonoTouch and many other platforms such as Adobe’s attempt to get flash on the iPhone. As a user of the iPhone this probably wont make much difference to me as I don’t use a lot of the crappy little apps. As a human being – and more importantly – as a software developer – this makes me madder than hell. I believe that Apple have taken the place of the most evil software company on the planet. Don’t let anyone tell you otherwise. They have always been evil and until Steve Jobs has gone for good, they have no chance of being honest or decent. As soon as I can get my hands on a Windows Phone 7 Series, the iPhone goes into the blender! (or to my daughter more likely – she more interested in cool than political correctness). Rant over.
I’m in the deep end at the moment. SharePoint 2010 provides an improved mechanism for service applications that replaces Shared Service Providers. I’m not ready to say I understand how these beasts (and they are a beast) work yet, but I can tell you that at this early stage of the 2010 release cycle (i.e. very nearly RTM) there is bugger-all documentation available. The following list may prove useful if you want to get started learning this. Andrew Connell has a video and some sample code from Channel9. The video is very hard to watch but there are a few tid-bits that may prove useful. The sample code is also useful but not as complete as I’d like (for the client end there is only a powershell script to test). Tony Bierman has a 4 part series that steps through the process and explains the various files in some detail, but again, this is not totally complete (there are no sample PS scripts) and the example is unusal (a web service for autocomplete). Plus he has added a few extra features to the code which are useful I’m sure – but confusing when you are learning. MSDN of course has a bunch of sample and documentation – but this seems to be the most incomplete version I have found – I’m sure it will improve when SharePoint is actually released. Sridhar Raghunathan has posted a fixed version of this sample but it is also somewhat incomplete (no admin pages or deployment scripts). There is another one here that I haven’t looked at. I also got my hands on a presentation and some training kit material (not public yet sorry) which helped a bit. My current solution is a blend of all of these samples – which are generally similar. How I just need to make it work. More later…
Loving SharePoint 2010 :) We are doing a LOT of work with this baby and so far it’s been a fairly painless experience. I’m currently diving deep into creating a custom Service Application… more on these later. It’s the little things that make the difference for day to day SharePoint dev. Replaceable parameters are a fantastic worry-removing new features. In the past (SP 07) you had to include full assembly reference in .ASPX and similar files thus: SomeNamespace.SomeClass, SomeAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6017a297d36052bf
The problems occur when you update the version of change an assembly name etc – things that can happen quite often during the early stages of a product life cycle. Getting the key is also a complete PITA. With replaceable parameters you can let Visual Studio worry about these. SomeNamespace.SomeClass, $SharePoint.Project.AssemblyFullName$ The parameter will be replace during packaging. There is a bunch of different parameters you can use in various types of files like XML and ASPX. HOWEVER, not all files are processed. In my case I have a .SVC file (for WCF). Luckily, it’s very easy to add processing for this. - In Visual Studio, right click the SharePoint project and select Unload.
- Right click the project again and select Edit
- At the end of the first property group in the proj file, add this:
You can list as many extensions as you want, seperated by ;. Full documentation is on MSDN. Enjoy
Here’s an example of great UX. Error reporting and possible solutions are presented in SharePoint 2010 Central Admin thus: Selecting an item in the list displays: Key Points. 1) The categorisation of the lists. 2) The message in the list is human readable – not just some stupid error number and cryptic message. 3) The explanation of the problem is clear and concise. 4) The remedy is similarly understandable and, best of all 5) The remedy contains a link to the solution Wouldn’t it be fantastic if all products were so well designed? How much more productive would programming be if Visual Studio worked like this. eg: Warning: You have a compiler error in a LINQ query with a join. Click here for a solution. Clicking would show the native compiler error, a few links to MSDN documentation, the top 10 web search hits for the issue and a link to see more in Bing/Google. You could maybe also add in automatic refactoring, tied to code analysis rules or whatever. Hey, how about this one: Warning: The application you are creating has already been created by 12,875,435 other developers. Would you like to download one of these instead? :)
I'll freely admit that I'm often first to defend Microsoft in just about everything they do. For development tools you can't beat Visual Studio and .Net. Office 2010 rocks. Yes, I even love SharePoint (again :).
HOWEVER, Internet Explorer 8 is the biggest waste of time I have ever seen.
According the Tom's Hardware Review (http://www.tomshardware.com/reviews/firefox-chrome-opera,2558.html) Chrome is the #1 browser and I'm inclined to agree. The things that really nailed it for me are the lack of standards support and the javascript speed in IE. These are the 2 most important features for successful modern web sites and having 60-ish percent of users with a slow buggy browser is bad news. The most damning eveidence is clear - only a 20% pass rate on Acid3 (http://en.wikipedia.org/wiki/Acid3).
I switched to Chrome for most work a while ago and version 4 of this slipped quietly onto my machines without me noticing. It's a pleasure to use. It's fast, stable, simple and nearly all web sites work flawlessly - the few that don't tend to be IE specific sites.
My message to Microsoft is this. Give up!! You've lost. You've had 10 years? to give the world a better browser. Google has done it in 1 year. The only reason IE has 60% dominance is because it's on every copy of Windows that gets installed and most corporate users don't want the hassle of a non-integrated browser. If you really want to have a browser worthy of forcing onto everyones desktop then please just use WebKit and add whatever tweaks you need to that.
Pro's
- It would match my iPhone.
- It's shiny
- I would be cool for 5 minutes (probably in my mind only)
Con's
- No Flash
- No (real) .Net / Silverlight
- Safari on the iPhone is complete shite so I'm not hopeful a bigger version would be any better
- Shiny screen makes it useless for reading books for any duration, unless the lighting conditions are perfect
- No camera
- No USB or SD
- Small capacity - 64Gb is ok but barely
- Support for Exchange mail and calendaring is critical for work use - not likely to see Outlook for i* anytime soon
- Expensive when compared to a comparably featured notebook
- I'm beginning to hate Apple (see below)
Ok, so some of these points are very personal to me, but the point I'm trying to make is this is definately a v1 device. The OS may be slick but some critical features are missing. I have a small notebook that already does more than the iPad. It's cheaper, faster, more capable and almost as portable. But the battery only lasts 6 hours and it doesn't have fruit on the lid.
The thing that worries me the most is that the iPad is produced by Apple. They are such a closed company. They are very reticent to talk about anything that might upset their carefully crafted image and brand. They are overly secretive. They are expensive.
As Apple grows and gains even more dominance over their market slice they will inherit the title that Microsoft used to hold - that of the most hated IT company on the planet. Sure there are still those that believe Microsoft are evil. These are people that don't work with Microsoft products and people every day. Their opinion is based on ignorance and arrogance. Much like me and Apple really.
I have no desire to become an Apple techie. I see these things as consumer devices. Great for doing what they are intended to do but controlled by a maniacle tyrant who won't listen to criticism and will kill anyone who speaks out against them. Much like the Chinese government or Islam.
So now I have painted myself into a corner, I will pobably still get one. Becuase I am weak and easily attracted to shiny stuff and becuase everything Apple does is just soooo cool and fantastic that I can't possibly not have one.
I hate myself.
Day 2 began with more sizzle – lots of announcements and goodies. SilverLight 4 Scott Guthrie - as always – gets to make the best announcements. SilverLight 4 is out in Beta now and release will be 1st half of next year (probably around MIX time I’d guess). Here’s the highlights: - Support for external devices including cameras and microphones. Scott did a fun little demo using a web cam and some special effects. You can also interact with the stream – in another demo that took a snapshot of a barcode and did a lookup for the book.
- Printing. Let me say that again PRINTING!!! Awesome!! Custom print preview also.
- Multicasting support. Don’t know what this is but it got a couple of ooo’s and ahhhh’s.
- RichText, Clipboard (system or app), MouseWheel, Right Click and Drag and Drop. They demoed some of these using an awesome (so I say awesome too much?) Facebook client (the code for which is available).
- Command Manager and MVVM framework. Our SL gurus spend a lot of time getting this basic code working on every significant SL project. This will save many hours!
- HTML Control. Totally awesome! You can use this to display any old HTML including plugins such as Flash. In this demo they played a Rick roll video off YouTube in a HTML control that was embedded in a SL app. Then they chopped up the ‘page’ into a jigsaw and shsuffled the pieces. All this while the video was still playing! Incredible stuff!
- Shared Assemblies. No more sharing of code and recompiling. Assemblies compiled in .Net 4 will be able to be used from SilverLight and non SilverLight apps. Another big timesaver there.
- WCF & REST enhancements including support for TCP Channels!! OMG!
- Intellisence for data binding.
- COM automation via the DLR. They demoed this by creating items in Outlook. Very easy and natural.
- Implicit Styles.
- Keyboard in fullscreen mode.
- Profiling support.
- CHROME support. Ha! Take that Google.
- And best of all – fully trusted applications outside the browser!! WICKEDLY AWESOME!
- Oh and it’s still only ~5MB and it’s twice as fast.
The relevance of WPF is in question now I think. SilverLight 3 now has a 45% install base (that’s 45% of all PC’s on the planet I think). SharePoint and Office 2010 Apart from watching an awesome SharePoint and SilverLight demo involving a racing car that looked strangely familiar there wasn’t a lot of stuff shown. Highlights were using the new tools in Visual Studio 2010 to create SharePoint Solutions. This has improved the experience by several orders of magnitude. Main features I caught: - Sandbox deployments
- F5 compile and debug – no more compile, deploy, activate, run, attach blah blah.
- Can develop without SharePoint installed locally.
Beta is out now. Goodies They demoed a bunch of the latest hardware and some of the cool new things you can do with this gear. Stuff like HD, MultiTouch and many cores. Then they announced that every attendee at PDC would get a free notebook! AWESOME!! I didn’t think this would include me – given the nature of my attendence – but I asked and I recevied! Woo hoo. I love Microsoft.
I’m sitting in a session at PDC 09 on SQL Azure futures. Here’s some notes for me and anyone else who cares. Backups and Clones - Backups are coming. Can now(?) create a clone of a database. Something like CREATE DATABASE fred AS CLONE OF bob.
Operations - API for provisioning – useful for SaaS providers. Great for Multi-tenant too.
- Better deployment and upgrades.
- Data Sync.
- Upgrade and downgrade options between db sizes (1 & 10 GB).
Scale-Out - Woa! TicketDirect mentioned again!
- Dynamic database splits. And merge back of course.
- Additional db size options. Maybe up to 50 GB.
- Multiple db connections.
- Fan out query for multiple db’s.
Other - Support for profiler
- Full Text Search
- CLR
- BI
Sensitive Data - Codename Vidalia – woosh – this went over my head.
We are already into the 2nd day of Microsoft’s Professional Developers Conference (PDC 09). This year the theme is very clearly Cloud Computing and Azure but there are a sprinkling of sessions on Visual Studio 2010, Team System, Languages and even a little SharePoint and CRM/XRM. Day 0 was workshop day and I attended and slightly assisted ‘The Yellow Croc Man’ (aka Chris Auld) with his sessions on developing for the Azure Platform. Chris did a fantastic job – pointing out a lot of things that us developers don't normally care/think about as much as we should – i.e., pricing and data sovereignty. These are very important issues with Azure and cloud computing in general. Bad programming can cost a lot of dosh. Our TicketDirect project was used extensively during Chris’ preso and at the end of the day, Mat Davey (TicketDirect CEO), Chris and I took the stage to answer questions (which was slightly scary). Today was Key Note day with Ray Ozzie (Microsoft Chief Architect) and a host of walk-on ‘softies and 3rd parties. Key points here were the announcement of : PinPoint – a market place for all things Microsoft. It’s up now - http://pinpoint.microsoft.com Project Dallas – data as a service. In CTP now - http://www.theregister.co.uk/2009/11/17/microsoft_dallas_data_service/ SQL Data Sync – Synchronise data from SQL Local to/from SQL Azure. I think this is part of SQL 08 R2 – CTP available now. Project Sydney – this allows you to connect direct to on-premise SQL Server from cloud roles. AppFabric – Will include caching (velocity), workflow, monitoring, service bus, service hosting and access control. Most usefully this will enable multi-tenant apps. CTP will be out early next year. This is a host for applications and replaces the .Net Services SDK. More on this after later sessions. Visual Studio 2010 will also include a bunch of new stuff to make deployment much much simpler for cloud and non-cloud applications. System Centre and IIS – admin tools to support AppFabric. BizTalk 2009 R2 – updates for new SQL and Windows server R2 releases. PowerShell access. Mapping enhancements and updated B2B accelerators. Interestingly, WordPress is now hostable on Azure – this is still a PHP Apache app – no .Net there. Microsoft are providing a production ready service for this ahead of the office switch-flick on January 1. Following the keynote we attended the Lap Around Azure session by the Direct of the Platform, Manuvir Das. Once again, TicketDirect was shown and received a very favourable response. Day 1 is only half over! I’ll update with more news later.
SQL Azure will throttle your connections to protect resources in the data centre. When SQL Azure does this is non-deterministic – or at least, Microsoft cannot specifically tell you when it will do this because there are many complicated factors. It could be the number of concurrent requests, the CPU or IO usages, the weather – who knows! In the end it doesn’t really matter – you, THE DEVELOPER, must but be aware of this and deal with it. SQL Throttling is manifested by a dropped connection. This may appear as a Native Error 10054 when you try to open a connection or some other error if the connection is dropped after being opened. To cope with this throttle a retry will normally be all that is required. At the connection and command level this is easy but it can be complicated by unstructured code. So, having a nice clean data layer will make the solution much easier to implement, but this applies equally to ‘messy’ code :) We reused the Retry Policy mechanism that is provided with the Storage Client. In the old sample storage client the syntax was a lot simpler but in the interest of less confusion I wont talk about that. The new November SDK works just as well, but you need to do a tad more work. The following sample is a connection manager that is used by the data layer. using System; using System.Data; using System.Data.SqlClient; using Microsoft.WindowsAzure.StorageClient; namespace MyApp.DataLayer { public class ConnectionManager { /// <summary> /// Maximum number of retries /// </summary> private const int MAX_RETRIES = 3; /// <summary> /// The retry policy for operations that can be retried (sql etc) /// </summary> private RetryPolicy RetryPolicy { get; set; } /// <summary> /// Wait 5 seconds between retries /// </summary> private const int WAIT_BETWEEN_RETRIES = 5000; public ConnectionManager() { this.RetryPolicy = RetryPolicies.Retry(MAX_RETRIES, TimeSpan.FromSeconds(5)); } private SqlConnection OpenConnection(string connectionString) { SqlConnection con = null; try { DieHard.RequestWithRetry(RetryPolicy, () => { SqlConnection connection = new SqlConnection(connectionString); connection.Open(); con = connection; }); return con; } catch (Exception ex) { throw new Exception("Error connecting to " + connectionString, ex); } } } } The interesting part is the DieHard helper class. using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.WindowsAzure.StorageClient; using System.Threading; namespace MyApp.DataLayer { public static class DieHard { public static T RequestWithRetry<T>(RetryPolicy retryPolicy, Func<T> action) { ShouldRetry shouldRetry = retryPolicy(); int retryCount = 0; while (true) { TimeSpan delay = TimeSpan.FromSeconds(0); try { return action(); } catch (Exception ex) { if (!shouldRetry(retryCount, ex, out delay)) throw; } retryCount++; Thread.Sleep(delay); } } public static void RequestWithRetry(RetryPolicy retryPolicy, Action action) { ShouldRetry shouldRetry = retryPolicy(); int retryCount = 0; while (true) { TimeSpan delay = TimeSpan.FromSeconds(0); try { action(); return; } catch (Exception ex) { if (!shouldRetry(retryCount, ex, out delay)) throw; } retryCount++; Thread.Sleep(delay); } } } } DieHard has 2 variants of the same Retry invoker – 1 for void actions and the other for a generic return value. There is a couple of points to mention. The timeout and the number of retries to attempt may vary depending on your situation and other factors – don’t use my 5 second 5 retries settings as the best possible option for you. You need to be aware of transactions. Retries should encapsulate the transaction as dropping a connection will rollback the transaction. So, except for this example of retrying the open connection you should use the retry mechanism at the higher domain level. Enjoy!
This is something I have wanted for a while now. Today I finally got around to doing something about it. I created a simple console application that can execute a SQL script file that you would normally use in Management Studio or SQLCMD. You might well ask why I would do such a thing. - SSMS and SQLCMD is not always available or in the right place
- I don't have the code for SSMS and SQLCMD so I cant change the way they work
In you read my previous post on deploying to SQL Azure then the first point will make sense. The next step is to make this script processing code work in Azure so I don't have to create databases from my client. Hopefully this will speed things up a little or a LOT. Anyways, since I've always wanted someone to write this code and never found any, here it is in case you are in the same boat. class Program { static int Main(string[] args) { string connectionstring = args[0]; string sql; try { using (FileStream fs = new FileStream(args[1], FileMode.Open, FileAccess.Read)) { byte[] bytes = new byte[fs.Length]; fs.Read(bytes, 0, (int)fs.Length); sql = Encoding.UTF8.GetString(bytes); } } catch (Exception ex) { Console.WriteLine("Unable to read sql script: " + ex.Message); return 1; } string batchTerminator = @"##GO##"; //Regex regex = new Regex(@"(^|\s+)" + batchTerminator + @"\s", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled); string[] strings = sql.Split(new string[] {batchTerminator}, StringSplitOptions.None); using (SqlConnection con = new SqlConnection(connectionstring)) { con.Open(); SqlCommand cmd = new SqlCommand(); cmd.CommandType = System.Data.CommandType.Text; cmd.Connection = con; for (int i = 0; i < strings.Length; i++) { Console.Title = "Processing " + i.ToString() + " of " + strings.Length.ToString(); //if ((!regex.IsMatch(strings[i])) && (!string.IsNullOrEmpty(strings[i].Trim()))) if (!string.IsNullOrEmpty(strings[i].Trim())) { Console.WriteLine(strings[i]); try { cmd.CommandText = strings[i]; cmd.ExecuteNonQuery(); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("O.K."); Console.ForegroundColor = ConsoleColor.Gray; } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Error: " + ex.Message); Console.ForegroundColor = ConsoleColor.Gray; return 2; } Console.WriteLine(); Console.WriteLine(); } } return 0; //Console.WriteLine("Press ENTER when complete"); //Console.ReadLine(); } } } Ok, so it’s not the prettiest or most bullet proof code on the planet, but it works. The RegEx is the key to the process. It’s not perfect – it expects GO commands to separate the batches and you need to have GO on a line by itself. It’s easy to extend this should you wish. [Update] Regex don't work! It’s just too hard to find all the GO’s accurately. Instead, I manually search and replace Go with ##GO##. This is a lot easier/safer to split with. I also removed all PRINT statements from my scripts but you could easily parse these out when processing and have then display as progress messages (no need to send them to the server). Enjoy!
Moving data from one SQL Server to another is a fairly trivial task these days. You have many options – backup/restore the database, SSIS, detach/copy/attach, ADO.Net, BCP, blah blah blah. Moving data to SQL Azure is more challenging. Here is my experience and some details of the solution. The Scenario The application we are creating has a master application database and database per ‘client’. The per client database will be partitioned into many smaller databases – each being a replica of the source database with a filter on one or two tables. The creation of the partitions will require the client application to be shut down for a period of time – not ideal but acceptable. SQL Azure does not (yet) include any support for partitioning or sharding so we knew we would have to create the solution ourselves. Options We wanted to have a flexible partitioning solution so from the outset I thought that SSIS would provide a mechanism that would allow the client to create their own partition rules as required. When I started creating the solution BCP was not available. Trials and Tribulations Before partitioning of the database could be performed it was necessary to move the source database to SQL Azure. Before moving the database it’s necessary to have a script that will create the empty database schema. When I first did this there where no tools so I used the database tools in VSTS to import from the local database and then manually tweaked the script to make it compatible with SQL Azure. These days there is the Migration Wizard on CodePlex which does pretty good (but not perfect) job of migrating your schema and optionally data. Problem 0 Executing the schema script is very very slow. Locally it takes seconds. In SQL Azure it can take up to fifteen minutes. We have tested this from several connections (inside and outside our network and with different service providers) and it’s never been less than eight minutes. Our contacts at Microsoft can run the same script in three minutes. I have some ideas why this is slow and a possible solution… more on this later if I solve it… but for now this is a big problem – 15 x 42 (the number of partitions) = way too long! It’s been a long time since I’ve had to do anything with SQL Server beyond creating databases for SharePoint or EPiServer and SSIS was completely new to me. However, I managed to piece together a package that copied the tables from one database to another. This package called other packages – 1 for each table – that would truncate the destination table and copy the records. Problem 1 Because there we 30 or so packages I used xml package configuration files to specify the database connections so that I could change the source and destination in one place. When running the packages in Visual Studio this would constantly remind me that the connection had changed (when it hadn’t) so I had to turn this off. Not a big problem but annoying. Problem 2 Running each separate table copy worked fine most of the time but running all of the packages in sequence (see problem 3) would fail in different places for various reasons. Sometimes I would get duplicate key errors – which was theoretically impossible. Problem 3 All but two of the tables have identity columns. To move the data I had to SET IDENTITY_INSERT ON for the destination table. OLE DB Destination tasks in the dataflow let you specify identity inserts but these don't work in SQL Azure – you must currently use ADO.Net source and destinations tasks. You can only have a single SET IDENTITY_INSERT ON per database so this means I had to run all these identity table packages sequentially which makes the whole process very slow. Problem 4 Reliability. SSIS in Visual Studio seems to me to be very unreliable and flaky. I was plagued with performance issues and crashes. In the end, frustration got the better of me and I gave up on SSIS. Thankfully, BCP for SQL Azure became available last week so that provided an option with more control and visibility. ADO.Net includes a SQLBulkCopy class. This will let you move data from many different sources to a database table. It provides a few options to control the behaviour of the operation and this seemed like the best option – the last time I used command line BCP was back in ‘95 with SQL Server 6.5 I think – or it might have been Sybase (which in those days was pretty much the same thing). I whipped up a simple unit test and some classes to test SQLBulkCopy and it didn’t take long to realise that this wasn’t going to work either. Problem 5 I kept getting errors about not having SET XACT_ABORT set ON. Binging for this led me down the DTC path. This is the same path that leads to hell! I couldn’t understand why DTC was getting involved because I had not invoked any transactions. I thought that BCP or my source data reader query was doing something funky so I just added the following SQLCommand query before I started the bulk copy: SqlCommand xact = new SqlCommand("set xact_abort on", dst); xact.ExecuteNonQuery(); This seemed to work, for a while. (It turned out that the base class for my unit test was declaring a TransactionScope that wrapped everything in my unit test. I didn’t spot this until I have up with SQLBulkCopy so it may well be that this is not necessary now). Problems 6, 7 & 8 I’m not exactly sure when I decided to give up on SQLBulkCopy but it was somewhere around the problems with timeouts, lockups and random results. My options were now reduced to a short list of one – command line BCP. After a few false starts (I don’t read instructions as well as I could) I managed to get something working quite well. Success! Moistly… I created a batch file to test the various options with BCP. It’s really pretty simple to use but I wanted the simplest possible solution that would be easy to support and maintain. Using the native option (-n) provided this but it does mean that should and destination tables need to be almost identical. When creating the schema script I had re-ordered the columns on one table. This was enough to cause a problem for native mode which generated some cryptic errors. Thankfully the error file (-e option) provided enough clues to figure out what was wrong. Throttling SQL Azure will drop connections when/if there is a heavy load on a database. This it to enable high availability – which sounds silly – how can it be highly available if the connections keep dropping? – but in reality this just means you need to be prepared for a connection to drop and transactions to fail if the load on the database / server is exceeded. Determining what the threshold is for throttling of the connections is difficult. So difficult in fact that one might say impossible. Throttling is triggered by activity by all users of a server. The server is also virtual (not as in a virtual machine but as in a virtual connection to one or more virtual machines). My BCP commands on one table (the largest) would consistently cause the throttling to kick in. This table has about 230,000 rows – not huge by and stretch of the imagination. Thankfully, BCP allows to to specify the batch size and the first and last rows to use. For this table I found that 10,000 rows per batch worked most of the time and executing BCP on chucks of 50,000 records seems to have stopped the throttling. Using the first and last row options also provided the opportunity to retry a chuck of records should throttling kill the connection. The final (so far) code for running command line BCP in a mode that SQL Azure can handle looks like this. This code is far from complete but should be sufficient to explain the process. Please feel free to adopt and enhance as you see fit. private void copyTableWithCmdLineBCP(string sourceServer, string sourceDatabase, string sourceTable, string sourceRule, string sourceUserName, string sourcePassword, string destinationServer, string destinationDatabase, string destinationTable, string destinationUserName, string destinationPassword, int rowsToCopy) { string ofile = Path.GetTempFileName(); string sourceQ = getSourceQuery(sourceDatabase + ".dbo." + sourceTable, sourceRule); string countQ = getCountQuery(sourceDatabase + ".dbo." + sourceTable, sourceRule); string args; // export to a temp file if (sourceUserName == null) { // no user name so use trusted security args = string.Format("\"{0}\" queryout \"{1}\" -S {2} -T -n -E", sourceQ, ofile, sourceServer); } else { args = string.Format("\"{0}\" queryout \"{1}\" -S {2} -U {3} -P {4} -n -E", sourceQ, ofile, sourceServer, sourceUserName, sourcePassword); } execProcessAndCheck(Properties.Settings.Default.BCPCMDPath, args, "Bulk copy export failed for table " + sourceTable); // import the file one chuck at a time for (int startRow = 1; startRow <= rowsToCopy; startRow += MAX_ROWS_PER_BATCH) { int tries = 0; if (destinationUserName == null) { // no user name so use trusted security args = string.Format("{0}.dbo.{1} in {2} -S {3} -T -n -b 10000 -E -F {4}", destinationDatabase, destinationTable, ofile, destinationServer, startRow); } else { args = string.Format("{0}.dbo.{1} in {2} -S {3} -U {4} -P {5} -n -b 10000 -E -F {6}", destinationDatabase, destinationTable, ofile, destinationServer, destinationUserName, destinationPassword, startRow); } int endRow = startRow + MAX_ROWS_PER_BATCH - 1; if (endRow < rowsToCopy) { args += " -L " + endRow.ToString(); } // execute with retries while (!execProcessAndCheck(Properties.Settings.Default.BCPCMDPath, args, "Bulk copy import failed for table " + destinationTable) && ++tries <= MAX_RETRIES) { Logger.WriteLog(LogCategory.Error, "Operation failed due to connection failure. Will retry."); Thread.Sleep(WAIT_BETWEEN_RETRIES); } } } This uses a couple of helper methods. getSourceQuery and getCountQuery simply return queries for a specified table name and ‘rule’ The rule is a string which defines how to partition the table. A switch statement is used to determine the WHERE clause for a table based on the table name and rule value. execProcessAndCheck executes a command line with arguments and captures the output. private bool execProcessAndCheck(string cmdLine, string args, string errorMessage) { _processOutput = new StringBuilder(); ProcessStartInfo psi = new ProcessStartInfo(cmdLine, args); psi.RedirectStandardError = true; psi.RedirectStandardOutput = true; psi.UseShellExecute = false; psi.CreateNoWindow = true; Process prs = new Process(); prs.OutputDataReceived += new DataReceivedEventHandler(prs_OutputDataReceived); prs.StartInfo = psi; prs.Start(); prs.BeginOutputReadLine(); if (prs != null) { prs.WaitForExit(MAX_PROCESS_TIME); if (!prs.HasExited) { prs.Kill(); throw new Exception(errorMessage + " - command has exceeded the maximum allowable time and was exterminated."); } } return checkProcessResults(prs, errorMessage); } The output is captured by a simple event handler: void prs_OutputDataReceived(object sender, DataReceivedEventArgs e) { if (!string.IsNullOrEmpty(e.Data)) _processOutput.AppendLine(e.Data); } _processOutput is a class scoped StringBuilder. The results from the process are checked by checkProcessResults: private bool checkProcessResults(Process prs, string message) { if (prs.ExitCode != 0) { // look for error 10054 - this means that SQL Azure has throttled and we should retry string output = _processOutput.ToString(); if (output.Contains("NativeError = 10054")) { return false; } message += ": Error Code = " + prs.ExitCode.ToString() + " : Message = " + output; throw new Exception(message); } return true; } This is all very specify to the way BCP.exe and SQLCMD.exe work – if you want to use this for other command line tools then some tweaking will no doubt be required. Summary SQL Azure is an extremely powerful platform - despite the issues described above. It will definitely get better as the product gets closer to release. Most of my problems are caused by my recent inexperience with SQL tools and the general nature of an unfinished product. Learning how to do this stuff now will provide a better understanding of the realities of cloud based computing as opposed to hosting a SQL Server on some internet connected remote server. Performance of the database creation, upload and partitioning could be enhanced in several ways. Threading could help enormously when creating the partition databases but throttling may reduce any benefit when it comes to uploading the data. Using multiple SQL Azure servers would also help a little. Moving the functionality into the cloud could be possible if SQLBulkCopy would work betterer and if I had a mechanism for creating the database schema other than SQLCmd.exe. All of these options are possible given more time – but PDC09 is our hard deadline - so what I have so far will hopefully be good enough for a wicked kick-arse sexed-up demo of what is possible with this awesome platform! I’ll talk more about this application when I can… :)
It’s been a while since I’ve blogged anything about EPiServer – 2 reasons - 1) I haven’t done an awful lot with it lately and 2) it’s just so easy it seems silly to blog about. However, over the last couple of weeks I’ve been helping out on a web site replacement project and one of my tasks was to install and configure the various servers – development, staging, UAT & production. So, me thinks it’s time to talk about it. SuperDeploy Normally EPiServer installation is performed manually using the EPiServer setup and Deployment Centre tools. However, for this project we attempted to script the entire process using PowerShell scripts. We have created a deployment tool with PowerShell – aptly named SuperDeploy – that we use for SharePoint installation and database creation. This is very useful for creating fully automated installations that we can use during development and when we need to install on the clients environment. So, it seemed natural that we should extend this to work with EPiServer. SuperDeploy uses a simple XML file to define what to install and where - the how is hard coded into PowerShell functions in the script. Anyways, SuperDeploy works very well and provided a nice repeatable installation for all servers – up to a point. With a bit more work it could do everything but time is.. you know what, so some manual steps were needed to finish off the production server. The final production installation had 2 web servers identically configured. The EPiServer site files were installed to a folder on F:\ and this folder was mirrored between the 2 servers using Windows DFS – so changes to files on one server were automatically and instantly copied to the other server – essentially meaning we had a single set of files for both servers. We could have had the files on a external drive array of some sort but this would mean a single point of failure. Replicating the files between servers provides an extra level of redundancy. The EPiServer virtual file system (VPP) was also replicated using the same DFS mechanism. The SQL 2005 database was on a third server and this was mirrored using log shipping to a forth server. Load Balancing I’ve come to notice over recent years than when something looks hard and not very well documented – it turns out to be obvious and simple. Such is the case with the configuration of EPiServer load balancing. Documentation of the setup of EPiServer load balancing is hard to find. In fact the only documentation I could find was a single blog post. This worried me somewhat as there isn’t a lot of detail in this post and it wasn’t an official EPiServer document. But I needn’t have worried – 5 of the 6 steps were correct but step 4 is applicable to IIS 6, not IIS 7 which we were using. For IIS 7, httpModules must be specified in the <system.webserver> section of the web.config – not in <system.web>. You can also configure these in IIS Manager. The setup of Microsoft NLB was already done for us and the tool linked to in the above post proved that the network was indeed setup correctly. The hardest part was testing that the servers were actually load balanced. Fortunately – a mistake by me editing the IIS config meant that one of the sites would not run. Browsing from a test client machine gave me an HTTP 500 error from IIS. It was impossible to know which server was failing so we disabled one of the servers from the load balancing by turning off the NLB agent. When the client browser was able to see the site correctly we new a) which server was broken and b) NLB was working. Crude? Yes, but good enough. Some better testing is still required of course, but that's another story. Even the smoothest installation can have surprises. When we ran the site, we were prompted to login to view the home page – which is strange as it’s a public web site with anonymous access enabled. We compared the production server configuration of IIS and web.config to the other servers and these were identical – we thought. In the end, we configured the IIS anonymous access user to be the application pool account rather than IUSR and the setup was done. Morals of the story EPiServer installation is easy – even for multiple load balanced servers. If you do have multiple server then ensure they are identically configured – Virtual Machines are a life saver! Mirroring or sharing the site installation folder will help with this (but it also means a mistake on 1 server will potentially be a mistake on all servers – instantly!). Script your installation as much as possible. It make repeating your installation simple. Install often and early – preferably as part of your development cycle. Don’t wait till the end of the development to test your deployment – YOU WILL REGRET IT – trust me! If you can, have your automated build cycle run your deployment script every night. Be pragmatic. Perfect is great if you can afford it but customers and bosses are rarely willing to pay for this. Good enough is usually good enough!
After posting about using TCP with the .Net Service Bus and making it look sooooo simple, I’ve lost most of today trying to get the fracking thing working! I doesn’t matter what I do in the config, the service host keeps prompting me for a Card (from CardSpace) even though I had everything setup for UserNamePassword creds. After much stuffing around I noticed that my solution had the wrong version of the service bus DLL (0.15.0.0 – March CTP I think). This was my bad – I had copied the DLL to a solution folder. So I grabbed the '”new” version (0.16.7.0) from the July CTP Assemblies folder and tried that. Same result! Arg! Looking in the GAC I could see it had version 0.16.0.0. What the ?!! Time for a reinstall me think. Download from MS. Install. Chug chug…. Ok, now I have version 0.16.71.1. Right. Fine. But the GAC still has 0.16.0.0 and my app still is broked. Lord - give me strength! I re-added the project assembly reference to my local non gac copy and set copy local and now it all works again. I can’t delete the old version from the GAC without uninstalling the SDK completely so it will have to stay there. Weird! The Joy of CTP.
We recently implemented the .Net Service bus to expose some in-house WCF services to the world wide world. It may be useful for me and others if I describe how to do this :) This setup allows you to switch between tcp and http relay binding with configuration. The Host For the in-house systems you need to create a host – you cant use IIS as the service bus requires a connection to be initiated by both ends of the communication. We created a Windows Service application that also runs as a console app. This is much simpler when developing and debugging. To create this service: 1) create a new windows service using the standard VS template and add a reference to Microsoft.ServiceBus (in addition to your service and data contracts which I hope are in separate assemblies!) 2) change the Application Output Type to Console Applications. 3) add some code to Program.cs to flick to console mode: if (args.Length > 0 && args[0].ToLower() == "/console") { myService.RunConsole(args); } else { ServiceBase.Run(ServicesToRun); } 4) in your service code add the following method: internal void RunConsole(string[] args) { OnStart(args); Console.WriteLine("My ServiceHost is running... Press Enter to stop the service"); Console.ReadLine(); OnStop(); } Now for the service bus stuff. 5) in the service class, add a member for the service host: ServiceHost _host = null; 6) in the OnStart method of your service add the following : // create a behavior for the service bus – it need creds of some type TransportClientEndpointBehavior behavior = new TransportClientEndpointBehavior(); behavior.CredentialType = TransportClientCredentialType.UserNamePassword; behavior.Credentials.UserName.UserName = Properties.Settings.Default.ServiceBusSolutionName; behavior.Credentials.UserName.Password = Properties.Settings.Default.ServiceBusPassword; // create an address for the service bus. config allows a switch between tcp and http Uri address;
if(Properties.Settings.Default.ServiceBusBinding == "nettcp") { address = ServiceBusEnvironment.CreateServiceUri("sb", Properties.Settings.Default.ServiceBusSolutionName, Properties.Settings.Default.ServiceBusServiceName); } else if(Properties.Settings.Default.ServiceBusBinding == "basichttp") { address = ServiceBusEnvironment.CreateServiceUri("http", Properties.Settings.Default.ServiceBusSolutionName, Properties.Settings.Default.ServiceBusServiceName); } else throw new ArgumentException("Invalid binding for Service Bus"); // create the host _host = new ServiceHost(typeof(MyService), address);
// update all the end points with the new behavior – you may need more than one – or not – up to you foreach (ServiceEndpoint endpoint in _host.Description.Endpoints) { endpoint.Behaviors.Add(behavior); }
// open the portal to another dimension – a dimension of sight and sound _host.Open(); Now for some config. For me this was the hardest part. Hard coding WCF config is much simpler! 7) create some service model bindings for netTcpRelayBinding & basicHttpRelayBinding <bindings> <netTcpRelayBinding> <binding name="default" /> </netTcpRelayBinding> <basicHttpRelayBinding> <binding name="default"> <security mode="None" /> </binding> </basicHttpRelayBinding> </bindings> 8) add an endpoint for your service: <endpoint name="MyServiceEndpoint" address="" binding="netTcpRelayBinding" contract="MyApp.ServiceContracts.IMyService" bindingConfiguration="default" /> 9) if you want to use basic http then add this instead: <endpoint name="MyServiceEndpoint" address=http://mysolution.servicebus.windows.net/MyService binding="basicHttpRelayBinding" contract="MyApp.ServiceContracts.IMyService" bindingConfiguration="default" />
And that’s about it for the service host. If you need to have metadata support (WSDL) then that’s a whole other story that I will try to blog about seperately. The Client Azure worker roles do not have a web or app .config you can use for WCF configuration settings. Web roles do have a web.config but this can only be changed by a redeploy of package so it’s not the best idea to put anything but service configuration in there. In my case, I needed to access the in-house services from both the web and worker roles so I created a class lib project with a single helper class. 1) create a Windows Class Library and add references for Microsoft.ServiceBus plus your service and data contracts. 2) Create a static class with a single static method – call it what you like but something like GetClientChannel() will do. Add the following code: IMyChannel channel; // this is a simple combo interface of IChannel and IMyService
Uri address; // create the behavior for SB creds TransportClientEndpointBehavior behavior = new TransportClientEndpointBehavior(); behavior.CredentialType = TransportClientCredentialType.UserNamePassword;
// get the creds from the cloud config behavior.Credentials.UserName.UserName = RoleManager.GetConfigurationSetting("ServiceBusSolutionName"); behavior.Credentials.UserName.Password = RoleManager.GetConfigurationSetting("ServiceBusPassword");
// create a channel factory ChannelFactory<IMyChannel> channelFactory = new ChannelFactory<IMyChannel>();
// create the binding – config allows us to select http or tcp if (RoleManager.GetConfigurationSetting("ServiceBusBinding").ToLower() == "basichttp") { channelFactory.Endpoint.Binding = new BasicHttpRelayBinding(EndToEndBasicHttpSecurityMode.None, RelayClientAuthenticationType.None); address = ServiceBusEnvironment.CreateServiceUri("http", RoleManager.GetConfigurationSetting("ServiceBusSolutionName"), RoleManager.GetConfigurationSetting("ServiceBusServiceName")); } else if (RoleManager.GetConfigurationSetting("ServiceBusBinding").ToLower() == "nettcp") { channelFactory.Endpoint.Binding = new NetTcpRelayBinding(EndToEndSecurityMode.Transport, RelayClientAuthenticationType.None); address = ServiceBusEnvironment.CreateServiceUri("sb", RoleManager.GetConfigurationSetting("ServiceBusSolutionName"), RoleManager.GetConfigurationSetting("ServiceBusServiceName")); } else { throw new ArgumentException("Invalid service bus binding configuration option: " + RoleManager.GetConfigurationSetting("ServiceBusBinding")); }
// update the factory for A B & C channelFactory.Endpoint.Address = new EndpointAddress(address); channelFactory.Endpoint.Behaviors.Add(behavior); channelFactory.Endpoint.Contract.ContractType = typeof(ICRMChannel); channel = channelFactory.CreateChannel(new EndpointAddress(address)); channel.Open(); return channel; Tada! All done. Provided I haven’t introduced any bugs then this should give you a connection to you in-house services, by passing any firewall crap that those pesky IT people seem to insist on. Enjoy :)
So far, so good. Twitter has not taken over my life. I’ve tweeted and chirped a little this week and have found a few colleagues to follow and vice versa. It’s also been a little useful and has helped me solve a couple of problems quicker than the usual methods (forums and web searches). It’s interesting to see Twitter going main stream. When one of our sales guys asked which twitter client to use I thought ‘oh well, twitter is surely dead now!’ but then I read that CRM 5 will have a Twitter interface and I’m guessing (truly – no insider info anymore) we will see similar functionality in Office 2010. Google Wave has this too. I’m not tempted to create the next killer twitter client yet. Tweetdeck works well enough for me at this stage but I can see that I will soon run out of screen real estate. Best thing about twitter? It’s go me blogging again :)
PowerShell takes a while to learn – especially if you have an aversion to manuals as I do – I prefer to learn on the fly. So, when I wanted to convert a variable containing a comma delimited string into an array I was lost. After a bit of playing and ‘binging’ I found that it was actually very very easy: # start with a string $roles = "db_owner"
# now it’s an array of 1 element $roles = ,$roles Sweet!
I searched for a while to find an easy way to run a command from a PowerShell script and wait for it to finish. Most of the example I found use Invoke-Expression but this wont wait. In the end I resorted to the tried and true .Net Fx: # run a command line and wait for it to be done function RunAndWait([string] $command, [string] $arguments) { $proc = New-Object System.Diagnostics.Process $proc.StartInfo.FileName = $command $proc.StartInfo.Arguments = $arguments $proc.Start() $proc.WaitForExit() } You need to seperate the command (aka FileName) from any arguments, but otherwise this seems to work nicely. However, PowerGui doesn’t always wait when you are debugging so be careful if you are stepping through your script and expect it to stop in logical places.
The July CTP of the .Net Services SDK only support 2008, Vista or Windows 7. This is true of the previous CTP’s but it was not enforced until the latest release. Luckily for me there is a simple workaround. On a machine that does have the July CTP installed, take a look in C:\Program Files\Microsoft .NET Services SDK (July 2009 CTP)\Assemblies. There is a tool in here called RelayConfigurationInstaller.exe. Copy this and the Microsoft.ServiceBus.dll to your target machine and run the exe with /i. Then copy the DLL to the GAC and your done. It appears as though RelayConfigurationInstaller simply adds the required machine.config settings on the target machine. You could also do this manually if required. Of course, this is not officially supported but MSFT are listening. If you really need legacy OS support for this then post a message to the forums and ask for it before it’s too late. Full Credit to Clemens Vasters for this tip.
Having a blog is like having a nagging wife – not blogging makes me feel guilty. The thing is, I just don’t have the time to to write the type of blog posts I like to write – long and accurate. Not that I’m ever very accurate, but well … Anyways, I’ve been ranting about how stupid twitter is and what a complete time waster it is without actually trying it. Then it occurred to me that twitter might actually be a useful alternative to long exhaustive blog posts. So, I’ve signed up again and am tweeting a little about very development focused things. You wont catch me tweeting about the weather or Michael Jackson etc. Currently I’m into Azure dev so I’m finding lots of little things to chirp about. I haven’t found a lot of tweets to follow yet apart from the obvious candidates – scottgu etc – but I did get my first reply today when I sent a message to a Microsoft tweet. Very sweet! Follow me if you love me :) jonesienz
|