Andrew Connell [MVP SharePoint]
1741 Posts |  46 Articles |  5310 Comments
.NET  |  MCMS  |  SharePoint  |  Office System
Andrew Connell's RSS Feed    
AC's Blog Quick Links
SharePoint Quick Links
Article Categories
Archives
May, 2012 (3)
April, 2012 (4)
March, 2012 (4)
February, 2012 (4)
January, 2012 (12)
December, 2011 (6)
November, 2011 (3)
October, 2011 (17)
September, 2011 (8)
August, 2011 (6)
July, 2011 (7)
June, 2011 (13)
May, 2011 (9)
April, 2011 (15)
March, 2011 (1)
February, 2011 (6)
January, 2011 (5)
December, 2010 (11)
November, 2010 (6)
October, 2010 (12)
September, 2010 (5)
August, 2010 (4)
July, 2010 (5)
June, 2010 (6)
May, 2010 (11)
April, 2010 (11)
March, 2010 (9)
February, 2010 (9)
January, 2010 (3)
December, 2009 (10)
November, 2009 (15)
October, 2009 (15)
September, 2009 (7)
August, 2009 (4)
July, 2009 (10)
June, 2009 (8)
May, 2009 (2)
April, 2009 (9)
March, 2009 (6)
February, 2009 (16)
January, 2009 (6)
December, 2008 (12)
November, 2008 (12)
October, 2008 (27)
September, 2008 (13)
August, 2008 (14)
July, 2008 (14)
June, 2008 (12)
May, 2008 (23)
April, 2008 (12)
March, 2008 (15)
February, 2008 (13)
January, 2008 (12)
December, 2007 (10)
November, 2007 (8)
October, 2007 (15)
September, 2007 (20)
August, 2007 (21)
July, 2007 (16)
June, 2007 (8)
May, 2007 (25)
April, 2007 (16)
March, 2007 (18)
February, 2007 (18)
January, 2007 (12)
December, 2006 (16)
November, 2006 (13)
October, 2006 (18)
September, 2006 (22)
August, 2006 (27)
July, 2006 (23)
June, 2006 (23)
May, 2006 (23)
April, 2006 (9)
March, 2006 (17)
February, 2006 (15)
January, 2006 (23)
December, 2005 (31)
November, 2005 (32)
October, 2005 (38)
September, 2005 (53)
August, 2005 (30)
July, 2005 (63)
June, 2005 (30)
May, 2005 (59)
April, 2005 (29)
March, 2005 (74)
February, 2005 (27)
January, 2005 (22)
December, 2004 (32)
November, 2004 (42)
October, 2004 (39)
September, 2004 (20)
August, 2004 (14)
July, 2004 (27)
June, 2004 (40)
May, 2004 (5)
April, 2004 (6)
March, 2004 (16)
February, 2004 (26)
January, 2004 (23)
December, 2003 (7)
November, 2003 (14)
October, 2003 (20)
September, 2003 (4)
Post Categories



Managed Windows Shared Hosting
Sunday, May 20, 2012

Browsing through my feeds I see this gem from a few days ago. Karine Bosch, the brains behind the CAML Builder we SharePointer’s lived by for so many years, has teamed up with Andy Van Steenbergen to release  much improved and current CAML Designer. Looks and runs great! Bit congrats guys!!! This is a must have tool for every SharePoint developer:

» Karine Bosch – CAML Designer

Wednesday, May 16, 2012

Last weekend I was poking around my music collection on my server and noticed a bunch of artists and albums not showing up in my library (I use Zune to listen to my music and copy it to my phone). Diving in I noticed one folder was full of M4A files… arg! Damn iTunes format… I don’t want Apple or Microsoft format, I want standard plain old MP3! Using the following PowerShell command, I found there were a ton of these types of files on my server:

   1: Get-ChildItem "\\RIVERCITY-NAS1\Music" -recurse -include *.m4a

Yikes… over 800 files! OK, that’s enough to look for a way to automate this conversion process. After a bit of research, I found the freely available VLC player had the ability to convert these types of files… for free. Sweet! So after a little work, I got this PowerShell script working:

   1: function ConvertToMp3(
   2:     [switch] $inputObject, 
   3:     [string] $vlc = 'C:\Program Files (x86)\VideoLAN\VLC\vlc.exe')
   4: {
   5:   PROCESS {
   6:     $codec = 'mp3';
   7:     $oldFile = $_;
   8:     $newFile = $oldFile.FullName.Replace($oldFile.Extension, 
   9: ".$codec").Replace("'","");
  10:     
  11:     &"$vlc" -I dummy "$oldFile" ":sout=#transcode{acodec=$codec,
  12: vcodec=dummy}:standard{access=file,mux=raw,dst=`'$newFile`'}" vlc://quit | out-null;
  13:     
  14:     # delete the original file
  15:     Remove-Item $oldFile;
  16:   }
  17: }
  18:  
  19: function ConvertAllToMp3([string] $sourcePath) {    
  20:   Get-ChildItem "$sourcePath\*" -recurse -include *.m4a | ConvertToMp3;
  21: }
  22:  
  23: ConvertAllToMp3 '\\RIVERCITY-NAS1\Music';

Sweet… until I noticed all the MP3 files didn’t have any ID3 tags. So I needed to add a step. I found an old copy of the TagLib# library. that would read the tags from one file and copy them to another. So I added the following function to the script:

   1: function DuplicateId3Tags
   2: {    
   3:     param (
   4:     [string]$sourceM4aTrack,
   5:     [string]$targetMp3Track
   6:   )
   7:  
   8:   # load sharp library for working with tags
   9:     [Reflection.Assembly]::LoadFrom("C:\Users\andrew.RIVERCITY\Documents\Music Workshop\taglib-sharp.dll")      
  10:   
  11:   #load files
  12:   $sourceM4a = [TagLib.File]::Create($sourceM4aTrack);
  13:   $targetMp3 = [TagLib.File]::Create($targetMp3Track);
  14:   
  15:   # copy tags
  16:   [TagLib.Tag]::Duplicate($sourceM4a.Tag, $targetMp3.Tag, $true);
  17:   
  18:   $targetMp3.Save();
  19: }

And added a call to the function right before I delete the original file and voila… 100% MP3 again!

   1: # update ID3 tags on target file
   2: DuplicateId3Tags "$oldFile" "$newFile";
Wednesday, May 02, 2012

Forward: this has nothing to do with SharePoint :)

I'm using Entity Framework 4.1+ and the cool Code First capability on a current project. For those unaware, Entity Framework (EF) is an code representation of your database. Code First (CF) is an approach where you define classes & relationships between them and let EF do the work of creating the DB and data model.

Spare me the debate about "I can write the schema & queries better than EF"… that's great… golf clap for you. Sure could and so could I, but I also wouldn't be nearly as productive in creating this app I'm working on. So why do I use it over doing it all by hand? Well it is (1) a level of abstraction which in my case makes me (2) more productive in creating the application and (3) is easy to maintain going forward not to mention (4) I love some of the capabilities baked into EF's CF model, specifically DB initializers, seeding the database & the testability.

One very cool aspect to EF CS is it is very friendly to writing tests. I'm not a huge fan of unit tests & much prefer integration tests… in other words: I'd much rather see my code working against a real database with real data than mocking everything up. CF helps you with this. First, when you create your model via code, you can pass in these database initializers (see this blog post, jump to "Database Initializers") . In a nutshell, you can take one of these classes and pass it to the EF CF engine and it will populate with YOUR seed data, great sample data!

So I was having a problem with these initializers & my tests. My challenge was that when my tests would run, they would seem to overlap with each other and some would fail. However when I ran the failing tests independently, they passed. Further inspection yielded that one test's work in the DB was affecting what other tests were doing. The obvious solution to this was to utilize transactions (specifically the TransactionScope), but I was having trouble getting it to work as well as implementing it in my test projects. After a lot of searching I came up empty for an obvious answer but one response to a question did get me going in the right direction. Another challenge I had was that I wanted to use one set of DB initializers when for some tests (those that expected the DB to be empty) and another set for the DB to be seeded with sample data. I figured it would help if I posted the solution for others who search for the same stuff.

For reference, I use MSTest as my test framework, MOQ for mocking & the awesome Unit Test Runner tool window in Visual Studio that ships with DevExpress' CodeRush.

The first thing I did was create a special class that would run once for all tests running under one test project. Creating a public static method decorated with the AssemblyInitialize attribute tells the MSTest framework to run this method once for each test run for the current assembly even if it includes multiple tests. I'm using this to force the creation of two databases: one that is seeded and one that is empty. After this runs I'll have two databases that have the assembly in their name. Now my tests can be configured to use either database.

   1: [TestClass]
   2: public class TestRunDatabaseCreator {
   3:  
   4:   public const string DATABASE_NAME_TEMPLATE = "CPT_CDS_{0}";
   5:  
   6:   [AssemblyInitialize]
   7:   public static void AssemblyInitialize(TestContext testContext) {
   8:     string projectName = GetCurrentProjectName();
   9:  
  10:     Console.Out.WriteLine("Test assembly init: creating unseeded DB...");
  11:     CreateUnSeededDb(projectName);
  12:  
  13:     Console.Out.WriteLine("Test assembly init: creating seeded DB...");
  14:     CreateSeededDb(projectName);
  15:   }
  16:  
  17:   private static void CreateUnSeededDb(string projectName) {
  18:     Database.SetInitializer(new SmokeTestCreateDbWithNoDataIfNotExists());
  19:     Database.SetInitializer(new SmokeTestDropCreateDbWithNoDataAlways());
  20:  
  21:     // create new DB connection to local SQL Server
  22:     string dbName = string.Format(DATABASE_NAME_TEMPLATE +"_UnSeeded", projectName);
  23:     string connectionString = string.Format(TestGlobals.CONNECTION_STRING_TEMPLATE, dbName);
  24:     var dbfactory = new DatabaseFactory(connectionString);
  25:  
  26:     // connect to DB to auto generate it
  27:     var customerContext = dbfactory.GetDataContext();
  28:     customerContext.Database.Initialize(true);
  29:   }
  30:  
  31:   private static void CreateSeededDb(string projectName) {
  32:     Database.SetInitializer(new SmokeTestCreateDbWithDataIfNotExists());
  33:     Database.SetInitializer(new SmokeTestDropCreateDbWithDataAlways());
  34:  
  35:     // create new DB connection to local SQL Server
  36:     string dbName = string.Format(DATABASE_NAME_TEMPLATE + "_Seeded", projectName);
  37:     string connectionString = string.Format(TestGlobals.CONNECTION_STRING_TEMPLATE, dbName);
  38:     var dbfactory = new DatabaseFactory(connectionString);
  39:  
  40:     // connect to DB to auto generate it
  41:     var customerContext = dbfactory.GetDataContext();
  42:     customerContext.Database.Initialize(true);
  43:   }
  44: }

Next, I wanted all tests to use these databases & ensure that any changes each test made were isolated to just that specific test. The easiest way to do this was to use a TransactionScope object which I stuck in the TestInitialize attribute. As long as I didn't complete/commit the transaction, the changes would never be committed to the DB. Since all the tests would use the same thing, I created a base test fixture which I could use in all tests as you see:

   1: public class BaseTestFixture {
   2:   private const string CONNECTION_STRING_TEMPLATE = "server=localhost;database={0};uid=sa;pwd=Password1!;";
   3:  
   4:   private TransactionScope _transactionScope;
   5:  
   6:   // DB factory from Entity Framework Code First
   7:   protected DatabaseFactory Dbfactory;
   8:   // Code First entity context
   9:   protected CustomerCacheContext CustomerContext;
  10:  
  11:   public virtual string DatabaseName {
  12:     get { return string.Empty; }
  13:   }
  14:  
  15:   [TestInitialize]
  16:   public void TestInitialize() {
  17:     // block init from firing
  18:     Database.SetInitializer<CustomerCacheContext>(null);
  19:  
  20:     // create new DB connection to local SQL Server
  21:     Dbfactory = new DatabaseFactory(GetConnectionString());
  22:  
  23:     // connect to DB to auto generate it
  24:     CustomerContext = Dbfactory.GetDataContext();
  25:  
  26:     // create transaction for everything in this testCreateStates
  27:     _transactionScope = new TransactionScope();
  28:   }
  29:  
  30:   [TestCleanup]
  31:   public void Cleanup() {
  32:     if (_transactionScope != null) {
  33:       _transactionScope.Dispose();
  34:       _transactionScope = null;
  35:     }
  36:  
  37:     CustomerContext.Dispose();
  38:     Dbfactory.Dispose();
  39:   }
  40: }

Finally, I could create tests by inheriting the BaseTestFixture which not only created the EF CF context for me, but it also created the transaction scope for each test. There's a virtual property (DatabaseName) which the test tells the base class which database to connect to, either the seeded or unseeded one.

   1: [TestClass]
   2: public class CustomerSmokeTests : BaseTestFixture {
   3:   public override string DatabaseName {
   4:     get {
   5:       string projectName = TestRunDatabaseCreator.GetCurrentProjectName();
   6:       string dbPrefixName = TestRunDatabaseCreator.DATABASE_NAME_TEMPLATE + "_Seeded";
   7:  
   8:       return string.Format(dbPrefixName, projectName);
   9:     }
  10:   }
  11:  
  12:   [TestMethod]
  14:   public void TestGetCustomer() {
  15:     /// assign
  16:     CustomerContext.SaveChanges(); // trigger the initialization of DB
  17:     var customers = new CustomerRepository(CustomerContext);
  18:  
  19:     /// act
  20:     // get customer
  21:     var customer = customers.GetOne(c => c.PrimaryEmail == "ken.sanchez@adventure-works.com");
  22:  
  23:     /// assert
  24:     Assert.IsNotNull(customer, "Failed to retrieve expected customer from DB.");
  25:  
  26:     // verify data for customer
  27:     Assert.IsNotNull(customer.CrmData, "Failed to get CRM data for customer.");
  28:   }
  29: }

Hope this little trick helps someone else out there. You might ask why I didn't use ordered tests... I find those to be a pain to maintain and once I found that special AssemblyInitialize attribute, I felt like this was exactly what I needed.

Monday, April 30, 2012

This past week I participated as one of the presenters in the developer track at the International SharePoint Conference show in London. This show was different in that each track was solution based.

For the developer track we started the week by talking about the requirements gathering requirements and going through the process of what type of app to build, how to build based on the deployment (on-prem/cloud), what capabilities to leverage (farm/sandbox solutions, metadata, BCS, search, kitchen sink service app) and then we had detailed, deep-dive sessions on all the topics. At the end of the week we handed our WSP over to the IT Pro track who used it to get the site running in Office 365.

I had a blast working with my fellow dev track colleagues: Ben Robb, Eric Shupps, Matt McDermott, Mirjam van Olst, Paul Schaeflein, Todd Carter, Waldek Mastykarz and Wictor Wilen.

We’ve posted the entire solution we built to a special CodePlex site, SharePoint KnowledgeBase (ISC 2012), where you can get all the code. Further, I’ve posted the slides to my sessions on the Critical Path Training’s Member Site. Just head to our site, click on Members in the top nav, login (it’s a free account if you don’t already have one) and in the Presentations section look for AC’s ISC London Presentations.

Sunday, April 22, 2012

If you’re like me, you stay away from installing SharePoint on your client OS (Windows 7) and just put it on your server OS and run within a VM. However there are times you want to pop into Visual Studio without firing up a VM and exploring the code. Of course you can do that, but it gets tricky when you want to build or run unit tests.

One trick I use that works most of the time (not all the time) is to put the SharePoint assemblies on my machine and make my own SharePoint Root (aka “14 folder”) on my Windows 7 machine. It’s easy enough, but maybe you want to check the differences between different releases (RTM, SP1, CU’s, etc).

What I do is use PowerShell to extract all the DLL’s from the SharePoint Root folder and put them in a place I keep documentation, snippets, etc on my machine. For example, I’ll have a folder that looks like this:

c:\Dev\Ref\SharePoint\14 (4762.1000 – RTM)\

I only include the DLL’s because the SharePoint Root is huge. For SharePoint 2010 RTM, just the DLLs are about 60MB. Ideally I’d like to grab all XML, WEBPART, ASPX, and ASCX files when I’m researching how something works, but that takes just a bit more time. Then I’ll go to the place where the SharePoint Root is when it’s installed and add a symbolic link that points to it like this (from an administrator command prompt):

c:\[Path to Web Server Extensions]]>mklink /d 14 “c:\Dev\Ref\SharePoint\14 (4762.1000 – RTM)”

Now when I navigate to the 14 folder I go to the same place where you find it on an installed machine, but it really lives somewhere else. If you want to switch to something like SP1, then you copy those same assemblies and recreate the 14 link to point to the new folder.

One day I’ll write some utility or PowerShell script to handle the deletion/creation of the symbolic link to the version I’m interested in. One last thing: this is *not* a replacement for testing your projects in a real deployment… it’s just a quick & dirty trick.

Wednesday, April 11, 2012

Tomorrow night (Thursday, April 12, 2012) I’ll be presenting a developer topic to the local Jacksonville, FL SharePoint User’s Group. The talk will be at the Deercreek Country Club… anyone up for a round? :)

Developing with SharePoint Server 2010 Metadata

The Managed Metadata Service application in SharePoint 2010 allows users to create and utilize taxonomies in various ways. Microsoft has included a robust taxonomy API in SharePoint 2010 that can be leveraged in custom solutions. In this session we'll explore how you can interact with taxonomies within the Managed Metadata Service application as well as work with metadata columns in custom solutions from a development perspective.

» Jacksonville, FL SharePoint Users Group – April 12 Meeting Registration

Monday, April 02, 2012

Gotta love April 1st… this is my anniversary date for my MVP award. You never know if you’re going to have an April Fool’s joke pulled on you or not.

Regardless, I got the email this weekend that I was renewed for my 8th year in the MVP program. Guess the joke was that my junk filter caught it first (does it every year!) :P.

My first two years were for Content Management Server (CMS) and when CMS was retired in favor of moving the feature set over to the SharePoint platform, I was transitioned over. Here we go for another year!

Thursday, March 22, 2012

Maybe it’s just me, but the only thing I can think of since seeing the new UI for the beta of Visual Studio 11 and all the explanation the Visual Studio Blog puts out (specifically here & here) is how inconsistent the different divisions within the organization are and how they don’t seem to reuse each other’s research, specifically for end users. The first line in both of the posts I just linked to start with “We hear you.”… don’t get me wrong, that’s great they are listening to their customer feedback that’s rolling in after seeing the new UI. But what seems to have been missed is the “We listened to ourselves” …

Between Office 2003 & Office 2007 the Office team did a TON of research around the UI. They found people were taking 13 clicks to add tables to their documents when in reality it was only a total of 7 clicks (not exact numbers, I’m paraphrasing here). Their reasoning is that there were so many commands in a product like Word (1,300+ to be exact) that people couldn’t find what they wanted. So they came up with this results-driven interface which showed you things you could do based on what you were doing. For instance if you didn’t have a picture selected, you didn’t get picture editing tools. The result of this is the Office Ribbon which is now not only in all the Office clients (as of Office 2010), but it is also in the fastest growth product in the history of the company (SharePoint) and we’re seeing it now making it’s way into Windows 8 (as in Windows Explorer). Surprise? No.. the guy who ran Office when the Ribbon was invented (Steven Sinofsky) now runs the Windows division & brought along his top UI guy Jensen Harris. But they wouldn’t take something from one of the biggest revenue generating products for the company (Office), of which SharePoint is a sizeable piece of that, and put it into one of the other biggest revenue generating products (Windows) if it wasn’t successful with end users.

Then you get the developer division… they show all this research about how they cleaned up the UI for Visual Studio 11. Frankly, I thought the one app that would benefit the most from the Ribbon was Visual Studio with its infinite menus, commands, tool bars and buttons. More specifically, Visual Studio is crying for a results driven user interface. They took the drab look and feel from Blend, tweaked it, and pushed it into Visual Studio. But maybe I’m in the minority here… I just don’t get why when you see a ton of research into usability in one area, and watch it get implemented across so many products, why we don’t see those same investments get reused in something like Visual Studio.

I for one was *very* disappointed when I saw the new drab & gray Visual Studio experience. I find the icons a hell of a lot harder to read and consume than before.

Tuesday, March 13, 2012

Need a development environment for your SharePoint team? Don’t want to spend the time building out the environment? We at Critical Path Training recently built out what we call our “All Up” virtual machine which we use in all our developer & SharePoint Designer courses as a Cloudshare showcase solution. This means you can get a copy of it and use it yourself even if you aren’t taking one of our classes.

If you are taking one of our classes, such as a webcast offering where you need to have your own VM, of course you can build one using our setup guide available for free in the Members section of our website or you can use the Cloudshare VM.

You’ve got access to the VM for a 14-day free trial or you can sign up for a subscription with Cloudshare.

Sunday, March 11, 2012

It's now been a few months since I got one of the first Amazon Kindle Fire's (see previous review posts here & here) and I've come to a conclusion: it just isn't for me. I've switched back to my iPad (1st gen) for my tablet experience. Why? Two core reasons that I touched on in my last review:

  • Performance: To put it simply, there's a reason the entry-level iPad is $300 more than the Kindle Fire. I found myself wanting something that was more responsive and quick than the Kindle Fire.
  • Bias towards connectivity: Amazon's approach was to make a device that was lacking on the storage capacity (8GB) because you'll stream movies from their servers. For me that model doesn't work. I travel a good bit and while we have WiFi on planes, it isn't terribly fast nor is it reliable. Streaming a movie in a hotel room isn't cheap or fast (hotel connectivity is also slow & spotty). I have a Verizon LTE hotspot but that's metered and streaming a movie would suck up a good percentage of my bandwidth. I like how I can rip a bunch of movies and copy them over to my iPad and it's 32GB storage space.
  • Browser: I know I said three, but the whole Silk experience was slower than using my iPad. Conceptually it makes sense why it should be faster, and tests may prove it, but in my test (browsing to a few sites using my Windows 7 laptop, iPad (1st gen) and Kindle Fire the first time and on page refreshes all using the same wireless connection at my house… the Kindle Fire was the slowest one by a sizeable margin (IE9 on my laptop was a bit faster than Safari on the iPad).

All of these things were aspects I noticed in the first few days of having the device but I wanted to live with it for a while before making up my mind. I started to come to the conclusion about 2 months of using it and for the last month (all of January) I tried to look past some of the frustrations. For the last 3 weeks I switched back to my iPad and shut the Kindle Fire off & stopped taking it on trips. As someone who roots for Amazon, I'm a bit sad to say I didn't miss it.

With all this being said, I don't think the Kindle Fire is a bad device. I'd give it a 3.5 our of 5 stars, but for my usage and lifestyle, it just isn't for me. Like I've said before… there's a reason it's $300 less than the entry level iPad. I still think the iPad is overpriced but I don't blame Apple. When you're selling them like crazy, what's the incentive to lower the price? They obviously found a great price that maximizes profit (which made me happy when I was a stock holder). I actually wouldn't be the least bit surprised if they iPad3 was $25-50 more than the iPad2… like that would hurt sales!

I do want to reiterate one thing I said in one of my previous posts: one huge thing I've learned is how non-user friendly the Android platform is. Yes, Amazon customized it, but from what I've seen I'm not at all a fan (compared to some Droid phones I've seen). Apple (with their iOS) and Microsoft (with Windows Phone 7.*) can rest easy… in fact those Blackberry & Droid users would be great targets for Microsoft as possible customers!

So for now I'll enjoy my iPad & wait for the Windows 8 tablets to hit the market… I really want to have a single OS experience and not have to keep copying stuff between machines.

In related news, there's a new Kindle Fire in great condition entry listed on eBay that includes a zipper sleeve … make me an offer!


Copyright © 2003 - 2012 Andrew Connell
Creative Commons License 
This work is licensed under a Creative Commons License

 
SharePoint Training
Looking for SharePoint 2010 training for developers, administrators, power users, information workers, end users & web designers? Look no further! My company, Critical Path Training offers the best SharePoint training around! We offer public & private classes both as in-person instructor-loed hands-on classes and online classes. Check out our schedule and course catalog for all the ways we can get you going on your SharePoint path!