Spend time with my daughter – I’ve spent a lot of time with my daughter. PASSED
Be flexible – Hard to measure, my wife (the project leader) has given me a lot of crap for setting a goal that’s not measurable. With two kids, both me and my wife working full time and me doing sports at a pretty high level, I have no other choice but do be flexible
. So I’ll mark this one down as PASSED.
Lose weight – this was perhaps the most important and most challenging goal for me on a personal level and I’m extremely happy to say I PASSED! Almost 12 kg (~26.5 lbs) in less of a year. The spike you see in the beginning of October is SharePoint conference in sunny California, lots of beer and food
.

Clean up on the attic – this one I have FAILED miserably.
Learn Ruby – I’ve been hacking along on my ruby on rails site. Like the language a lot. I’m not all the way there yet but I see myself on track and gonna give myself a PASSED.
Git – not a pro yet but getting better at it. PASSED.
Windows Phone 7 App – MS Billing stole my money when the registration process on the developer site crashed (two times!) and that made me pissed off and lose interest in the whole thing. Need to carry on this goal to 2012. FAILED.
SharePoint Certification – Had to devote my time to look for a new job so FAILED this one.
National team in underwater rugby – Made it! Played my first (and probably last) world championship. We missed the final and ended up in third place, but other than that it was an awesome experience. PASSED.

Read up on running my own business – did read quite a lot but decided not to go for it now due to other circumstances. PASSED.
Cleanout Binders – Scanned seven binders in total, so I’m going to set give myself PASSED on this one to. Went through six binders and throwed away a lot of old crap and scanned the rest.
So the overall a pretty good year I think.
Summary

Six out of nine isn't half bad. Now I need to draw up some goals for 2012!
Been working for 2 weeks now after my parental leave and it has not been pleasant to a variety of reasons. If we exclude factors out of my direct control and focus on what I actyllay do (or should) control. The pomodoro technique was a real struggle. I’m all behind the theory, I was pshyced and motivated. But I just could not get those 25 minutes to work for me. There where a lot of interruptions, both externa and internal. So what do you do in this day and age when you got a problem? You tweet about it! So I did. @emilcardell gave me a tip working for him: do 20 pomodoros with a 10 min “break” between each.

I gave it a try, thinking “big difference between 20 and 25 minutes”… But man, that made the difference for me! I managed too keep most of the 20 min pomodoros intact. Not that I didn’t have interruptions but they where mostly manageable.
20 min on and 10 off, holy cow that’s ineffective you say. 3 weeks ago I would have agreed with you but today I don’t. The focus of the pomodoro makes (at least) me more effective than otherwise so over the course of a day I really think it’s a win for me.
Still aiming for the 25-5 rhythm. But as they say “baby steps”.
I’ve stopped with the monthly updates due to some non-encouraging feedback. However, half-time is big so here’s the half-time update.
Spend time with daughter – on track, not much to say.
Loose Weight – Also on track. I’ve been down at 90 kg and now I’m leveling out at 91-92 kg which seems to be a good weight for me. I can run without my knees hurting.

I’ve been eating using Glycemic Index, which has worked remarkably well. Two downsides: My stomach crashed after a while so I can’t eat strict GI now and it’s damn expensive.
Clean up attic – way behind. It’s such a mess I don’t even know where to start…
Learn Ruby – Coming along nicely. In hindsight I should have concentrated more on Ruby and less on Rails when starting, but I’m getting there. I’m working on a new Rails-site for my underwater rugby team as a learning project (https://github.com/nippe/Pdk-Team-Site).

Git – I feel pretty confortable using git. I still get myself in jams every now and then, but I see that as a part of the learning process. So I feel done with this as a goal and the plan is just to keep using it.
Windows Phone 7 App – Haven’t gotten around to this. Try to register for a developer subscription but Microsoft billing stiffed me for 300 kr (~ $50) without me getting a subscription.
SharePoint Cert – Started studying a little, then summer came…
National Team in Underwater Rugby – I MADE IT! Playing in the world championships in Helsinki august 15th to 20th.
Reading up on starting my own business – this stagnated due to other factors at home, but I’m still playing around with the idea.
Clean out binders – half way there scanned in 4 out of 8.
Summary
So, to summarize. I’m pretty much on track. A few thins lag behind. I hope I’ll be able to do a push after the summer when I start working again.

This post is a little coding for fun exercise showing one way to send push notifications to your iPhone/iPad from .NET. It’s also a shameless plug for the open source .Net library I written for this, called Prowlin (https://github.com/nippe/Prowlin) in conjunction with Prowl on the iPhone.
So, to demo this in a simple and efficient way I’m going to write a simple URL monitor that tries to get an url and if the response code is something else than 200 it sends a notification to the iPhone/iPad. I’m going to write it as a simple console application. If one would like to run it as a service TopShelj (https://github.com/Topshelf/Topshelf) helps with that or a simple scheduled task might suffice.
Scene set, lets get started. The app is simple (can be improved immensely).
First, get the latest Prowlin binary from https://github.com/nippe/Prowlin/downloads or get the source from https://github.com/nippe/Prowlin and compile yourself.
Create a console application project and add a reference to Prowlin and System.Net. And off you go:
1: using System;
2: using System.Net;
3:
4: namespace Prowlin.UrlMonitor
5: {
6: internal class Program
7: {
8: private static void Main(string[] args) {
9: if (args.Length <= 0) {
10: Console.WriteLine("Enter URL as parameter");
11: return;
12: }
13: string urlToTest = args[0];
14: var request = WebRequest.Create(urlToTest) as HttpWebRequest;
15: WebResponse response = default(WebResponse);
16:
17: try {
18: response = request.GetResponse();
19: }
20: catch (WebException webException) {
21: string message = string.Empty;
22:
23: switch (webException.Status) {
24: case WebExceptionStatus.Timeout:
25: message = "Request timed out";
26: break;
27: case WebExceptionStatus.ProtocolError:
28: var httpWebResponse = webException.Response as HttpWebResponse;
29: message = httpWebResponse.StatusCode + " " + httpWebResponse.StatusDescription;
30: break;
31: default:
32: message = "Other problem";
33: break;
34: }
35:
36: SendProwlNotification(message, urlToTest);
37: }
38: }
39:
40: private static void SendProwlNotification(string message, string url) {
41: var notification = new Notification
42: {
43: Application = "URL Monitor",
44: Description = message,
45: Event = url + " not available",
46: Priority = NotificationPriority.High,
47: Url = url
48: };
49: notification.AddApiKey("589a2d241e6ea26a11c994af835012eb3230f39f");
50:
51: var prowlClient = new ProwlClient();
52: prowlClient.SendNotification(notification);
53: }
54: }
55: }
The program takes one parameter in, an URL. I don’t check if it actually is an URL in this sample.
The body of the program (the main function) does the try-to-get-url logic and if that call (line 18 above) fail the catch block calls SendProwlNotification on line 36. The SendProwlNotification is very straight forward or at least I hope so.
Instantiate a notification object, set properties and add one or more API Keys (used by Prowl so that notifications end up on the right phone).
New up a ProwlClient and call SendNotification with the created notification. And voila!



I’ll try to get the package up on NuGet within the coming weeks.
Time for the third follow up on how this years goals are going. Damn time moves fast.
Spend time with my daughter – going along nicely. Due to some sickness I’ve almost spent to much time with her
.
Loose weight – Going good except around the 14th I was alone with the kids for a week and the 3 ½ yrs old became sick so no sleeping for dad. You can see the weight curve going up during that week. No sleep –> low blood sugar –> unstoppable candy cravings
.

So far this year has been going pretty good:

Clean up the attic – Status Q
.
Learn Ruby – Coming along, though slowly. But I started on my little hobby project: a site for my team with some attendance rsvp’s, a wall to post on and stuff. Will put it up on github as soon as it’s something that works.
I’ve gotten a little de-railed (pun intended
) by starting reading the RSpec Book, which is an awsome read but doesn’t really get me closer to creating a site for the team. But a really good dive in to BDD, Cucumber and such.

Git – Going good, now going through Rob Conery’s awsome git series on tekpub.

Windows Phone 7 App – All I’ve done is to locate a series of web casts on channel9 that I will use as staring point.
SharePoint Certification – Haven’t started yet…
Read up on running my own business – not done much more this month.
Clean out binders – Progress! Two more binders are now in PDF format! So 4 out of 8 done.

Before going on parental leave I was involved in a fairly large SharePoint project with a distributed team. A question that arose for us was how we should handle script registrations in the solution. With many developers going at it we felt we where in risk of redundant registrations or a registration left out because of miscommunication or faulty assumptions within the team.
Even though we did this in SharePoint I see no reason why it shouldn’t work in a ASP.NET scenario.
Problem statement
How does any given webpart or user control know and ensure that the script it needs is registered on the page.
One possible solution
The solutions is of course many, this is the one I proposed as a solution.
First step is to have a central “repository” of script keys.
public class Keys
{
public class jQuery
{
public static string Version_1_4_4_min = "jquery-1.4.4.min.js";
public static string Easing_Version_1_3 = "jquery.easing.1.3.js";
public static string BxSlider_min = "jquery.bxSlider.min.js";
public static string UI_min = "jquery-ui.min.js";
public static string Corner = "jquery.corner.js";
}
}
public class Paths
{
public class jQuery
{
public static string Version_1_4_4_min = "/_layouts/BrandX/js/jquery-1.4.4.min.js";
public static string Easing_Version_1_3 = "/_layouts/BrandX/js/jquery.easing.1.3.js";
public static string BxSlider_min = "/_layouts/BrandX/js/jquery.bxSlider.min.js";
public static string UI_min = "/_layouts/BrandX/js/jquery-ui.min.js";
public static string Corner = "/_layouts/BrandX/JS/jquery.corner.js";
}
}
Then some sort of centralized registration logic/service.
public class ClientScriptService
{
private static string _scriptTagTemplate
= "<script type=\"text/javascript\" src=\"{0}\"> </script>";
public static void EnsureClientScript(Page page, string scriptKey, string scriptPath, Type callerType)
{
ClientScriptManager scriptManager = page.ClientScript;
if (scriptManager.IsClientScriptBlockRegistered(scriptKey) == false) {
scriptManager.RegisterClientScriptBlock(callerType,
scriptKey,
string.Format(_scriptTagTemplate, scriptPath));
}
}
}
The effect being that each web part ensures its own script dependencies.
protected void Page_Load(object sender, EventArgs e) {
ClientScriptService.EnsureClientScript(this.Page,
Scripts.Keys.jQuery.Version_1_4_4,
Scripts.Paths.jQuery.Version_1_4_4,
this.GetType());
}
My thought with this was to use it consistently throughout the portal so for example the master page contains a server control registering scripts that is used throughout the portal. For example:
public class MasterPageScriptRegistrations : WebControl
{
protected override void CreateChildControls() {
base.CreateChildControls();
ClientScriptService.EnsureClientScript(this.Page,
Scripts.Keys.jQuery.Version_1_4_4_min,
Scripts.Paths.jQuery.Version_1_4_4_min,
this.GetType());
ClientScriptService.EnsureClientScript(this.Page,
Scripts.Keys.jQuery.Easing_Version_1_3,
Scripts.Paths.jQuery.Easing_Version_1_3,
this.GetType());
/* ... */
}
}
So what do you think? Good/bad? Am I making a hen of a feather? I really appreciate feedback (either here in the comments or by email to niklas.nihlen[at]gmail.com).
Time for the second follow up on how this years goals are going.
Spend time with my daughter – Spot on! She is actually “helping” me write this post. She also decided not to sleep a night for time being so the time we spend together is a little to much for my taste
.
Loose weight – Is going ok. Actually thought I would start loosing more faster when turning up the knob on work out. Maybe I need to start eat well to..

Clean up the attic – Status Q
.
Learn Ruby – Moving along nicely. Almost read “Rails for .NET Developers” and started playing around a little.

Git – Progress! I’ve managed to get myself in to a half day workshop with Matthew McCullough. Awesome stuff, I learned a lot. I also put up my first repository at github.

Windows Phone 7 App – Haven’t gotten around to it yet.
Read up on running my own business – On track. Attended seminars in writing a business plan and budgeting.
Clean out binders – Still sorting PDF’s from the the binders I scanned in January. So still only 25% done.
I know your reaction to this. Oh no you didn’t! Yes I did. I went ahead and created a scorecard! Guess my years at Microsoft indoctrinated me some
.

I use Polar ProTrainer 5 to track all my physical training (running, underwater rugby, crossfit and so on). I also have multiple computers and want to be able to access and sync my watch from anyone of them. When I travel in my work that becomes extra important.
So here is how I solved it.
IR Stick
First of all I had to get a IR USB stick after upgrading my last computer to 64-bit. The only one I found that supports 64-bit was Polar’s own. Very expensive, but it works. Polars info about the IrDA adapter can be found here.
Dropbox
You need a dropbox account.
I located my personal folder C:\Program Files (x86)\Polar\Polar ProTrainer\Niklas Nihén it might be under compability files (Vista and later) C:\Users\username\AppData\Local\VirtualStore\Program Files (x86)\Polar\Polar ProTrainer. Then I copied that to my Dropbox folder.
ProTrainer
Then I installed Polar ProTrainer 5 on my new computer. When installed you’re promted to create a new User. Ther I chosed to create a New Person.

Then I selected Add Existing Person…

Then I browsed to my pdd-file from the “old” copied profile.

I was up and running. Then I installed Polar ProTrainer on my other computer and added the profile in exactly the same manner.
Viola! I can sync my watch with any of the computers and it shows up on all of them. Probably not at all supported by Polar but it works for me
. Hopefully this helps someone else that faces the same challenge.
Happy running!
I’ve been playing around a little with the Pomodoro technique to see if I can increase my productivity (and effectively).
For you that haven’t heard about the Pomodoro technique is a way of using an egg timer to focus you’re self in 25 minutes intervals. Read more about it at www.pomodorotechnique.com
I’m by no means an expert on the Pomodoro technique, I’m just getting started. But it really appeals to me because I usually have problems focusing at one thing at the time.
What’s the first thing I do when starting to get into a new technique? Yep, you guessed it. Check out the tools! So this post won't focus on doing the Pomodoro technique, there’s others that does that so much better than me, but on the tools available. I will focus on windows with some mentioning of web and iPhone tools.
I was trying to find a desktop tool to run on Windows 7. I stumbled upon Concentrate of Mac OS and got really jealous. So I started on a little endeavor to se what's available in the Windows world. This is not in any way a complete guide. Just stuff I managed to sniff out.
Windows
Pomodoro – MillSquareSoftware
This pomodoro tool is avaliable at http://www.millsquaresoftware.com/pomodoro.html. It’s pretty good. It has a task list that you can work from. I don’t think it saves stats on interruptions and such. Visually it’s not that appealing. Looks like a small little winforms app which isn't that sexy. But with my limitied testing it does the job.

Pomodario
Pomodario is an Adobe Air app that is available for download from http://code.google.com/p/pomodairo/. Somehow very many pomodoro apps seems to be Adobe Air apps. I’m not thrilled about Adobe Air and would rather have something more Windowsiy. That said pomodario is actually my Pomodoro app of choice so far.

It has a nice interface keeping track of interruptions and such. Remember the first time I tried it I nearly shat myself when the alarm bell went of. Luckily the volume is adjustable. Pomodario also has a nice statistics function.

Focus Booster
Focus Boster can be downloaded from http://www.focusboosterapp.com. It two is an Adobe Air app.

They way I understand FocusBooster is that its just the timer, no tasklist, logging of interruptions and such.
Tomatoday
I don’t have Tomatoday naild down yet. Seem promesing but unmature. It’s a SilverLight app available at http://www.tomatoday.dk/ that can be runned in or out of browser.

It has a task list but that does not seem to be connected to the timer what I can see (but again this can be to my lack of understanding).

So not I favorite of mine, but I think it might be if development continues.
Dinner Timer
This is not a Pomodoro app per se. But what is a pomodoro but a kitchen timer. So if you do all the other stuff on paper this will probably work fine, haven’t tried it myself. Available from http://www.dinnertimer.com/

Web
For web the one I found was Tomatoist which is great. But it doesn’t work for me. I loose it in a tab somewhere so it becomes more of a distraction than a productivity helper.

iPhone
There is a lot of options here, the one I’ve tried and liked the most is myPomodoro Lite. It’s pretty good in my opinion, the thing that disturbs me is the single taskness of the iPhone. If you want to change playlist in iPod/Spotify –> the timer pauses.


Summary
My favorite so far is Pomodario. It’s simple to use and tracks simple statistics. Do you have any other favorites?
As my friend Johan points out, the first month of 2011 has reached its end. So how am I doing against the original goals?
Spend time with my daughter - Hell yeah! We’re still in a finding-the-routine phase, but it’s awesome.

Lose weight – getting there. My problem is that when I turn up the knob on exercise I become so incredible hungry all the time..

Clean up on the attic – baby steps. I’ve gone through all cables (can you believe I hade 4 boxes of the stuff).
Learn Ruby – managed to install ruby and rails both Windows and on a Ubuntu box and create a basic scaffold app.
Git – Nope, not yet.
Windows Phone 7 App – Nope, not yet.
SharePoint Certification – Nope, not yet.
Read up on running my own business – Get started, attended a introduction seminar at Nyföretagscentrum.
Cleanout Binders – Yep, doin’ it! I had 16 binders to start with. My goal is to get rid of at least 8. So far I have eliminated 2. So 25% done. But that’s not true, I haven't sorted the 40-50 pdf-files the 2 binders resulted in.
So, this is the thing to do I have understood. To write up a “goal post” in the beginning of the year. I don’t mean a goal post as in the picture but a post about my goals. I know you got that straight up, but I still had to be the smart ass
. Here it goes:
Spend time with my daughter – I’m starting this year with an extensive parental leave with my 1+ year daughter, the goal here is to give her a lot of time and make sure I am the favorite parent
. Which leads to my next goal:
Be flexible – after the summer both me and my wife will be working with two kids in day care. Have no idea how that’s gonna pan out so I might have to reduce working time a little.
Lose weight – not that I feel particularly overweight but my knees hurt when I intensify my running and that’s no fun at all. I thing my best performing weight is 85-90 kg (187-198 pounds) and I’m now at 100 kg (220 pounds).
Clean up on the attic – I have a lot of old deprecated stuff that can be thrown away.
Learn Ruby – in the PragProg fashion of learning a new language a year (which I have not done so far) I’m going to get into Ruby and Ruby on Rails. My learning project is to create a site for my underwater ruby team where players can accept training invitations and such (think I’ll put it on github)
Git – Get my head around distributed version control systems starting with Git. Tekpub here I come.
Windows Phone 7 App – Nothing fancy, just want to build basic app to get my head around how tis done.
SharePoint Certification – Not that I think certifications really say that much about a persons skill, but we got it in our goals at work and for me it’s a bit of an ego boast to pass one.
National team in underwater rugby – this is a tough one. I’ll decide in March if I’m going to try to get into the team. Has to do with what the family says about it too. It takes time from home to get in the team.
Read up on running my own business – a thought I’ve been playing with for a while that I need to get more facts about before making a decision about it. Maybe hit some seminars on the topic as well.
Cleanout Binders – I’ve got a lot of old irrelevant papers in binders. That has to be processed and thrown away or scanned. My goal is to get rid of half the binders at least.
Well that’s it I think.
This is something that’s been on the back burner for a while for me. I haven’t gotten around to trying it out until now. I just want to apologize up front for the code as images in this post, not proud of that but some circumstances led to that, sorry.
Short Intro
Moles is a isolation framework from MS Research (the almighty Peli de Helux, once Mr. MBUnit). It enables you to “mock” otherwise un-mockable objects like SPContext, SPWeb and so on.
Read more about it here: http://research.microsoft.com/en-us/projects/pex/
And this white paper: Unit Testing SharePoint Foundation with Microsoft Pex and Moles
Install Moles Visual Studio Plug-in
Moles is distributed as a plug-in to Visual Studio, the 64-bit version (SharePoint 2010 is 64-bit only) can be download from this location: http://visualstudiogallery.msdn.microsoft.com/en-us/22c07bda-ffc9-479a-9766-bfd6ccacabd4
Install it in god old Next * n –> Finish manner.
Generate Moles
Next step is to generate Moles from the Assemblies containing the classes you want to isolate/mock. Crack open your SharePoint project after you installed the plug-in. Expand your references and locate the reference that you want to generate Moles from, I chose Microsoft.SharePoint.Publishing in the image below, but as you can see I’ve already done it for Microsoft.SharePoint. Right-click it and select Add Moles Assembly.

Now Build your project and let’s have a look at what changes the Moles framework done to your project.
- Added a .moles file
- Added a .moles.dll assembly to the MolesAssemblies directory
- Added a reference to the .moles.dll assebmly

This next step is only valid if you’re using Team Foundation Server. In order for this to work on the TFS build server (anyway, the way we got it working), you need change the build action of the <Assembly name>.moles file from Moles to None.

And you’re set to go do some testing.
Writing Tests
First off, let's have a look at a method we want to get tested.

As we can see it takes a SPWeb object as a parameter and calls web.Site.RootWeb on it. (It passes this to the CountryRepository, but we don't have to care about that here - it's also mocked :)).
So we need to get our test started. Some initial points:

- Use the HostType attribute to indicate that it's a Mole-test
- Trap default behaviours
- Create your Moles. Note that the objects starts with M + the original object name. SPWeb -> MSPweb, SPSite -> MSPSite and so on.
Next step is to set up behavior for the moles. Remember from above web.Site.RootWeb. so the first spweb returns an spsite that returns a spweb (RootWeb). Hooking up behaviors for properties is done by the original property name plus Get/Set. Hooking up the Site property on a SPWeb object hence becoms spweb.SiteGet. The image below illustrates this and how to build the command chain.

That done we can now call InitializeView with our Moled spweb and get a predictable controlled execution:

Now let's look at the test as a whole. Worth noticing is that there is a few Moq mocks in this test also to isolate the thing I want tested.

Hope this post can lower the hurdle for some to get into unit testing your SharePoint code.
When working in a development environment you’re bound to get it dirty or
someone else on the team make major refactoring's. You need do clean up and make
a clean deploy. Here’s a simple way to retract and un-install all SharePoint
Farm Solutions using PowerShell (haven’t tried this with sandboxed solutions).
Retract All
Get-SPSolution |
foreach { Uninstall-SPSolution -Identity $_.Name -Confirm:$false -AllWebApplications }
Remove All
Get-SPSolution |
foreach { Remove-SPSolution -Identity $_.Name -Confirm:$false -Force }
That's it
So this post has really no big point. I started out by the fact that I’m a heavy user of Tasks in Outlook, as I have eluded to earlier: http://www.nnihlen.com/blog/archive/2009/05/22/adding-outlook-tasks-fast-using-launchy-with-a-little-programming.aspx
Much of my personality comes form being an athlete (and a geek) and as the mentality from that is to always improve you’re self. But that’s kinda hard if you don’t have any measurements. So on that note bundled up with a growing curiosity for for OData I sat down and came up with the following scheme.

So the idea is to import the task data from Outlook into a a database and then expose it as an OData service to for example Excel PowerPivot to play with the data and maybe try out the ASP.NET charting components.
Import
I created a simple database schema:

The import is at this stage a very brute force thing. I figured you run it seldom, the amount of data isn’t that big and so on. So I went for the very ugly generate-SQL-statements-and-run-them-using-ADO.NET approach. I delete the data every time and recreate it. Not very elegant but works for the moment. I guess the next step here would be to use the C and U in the OData CRUD promise. But that will have to go into vNext.
So here it is in all its ugliness:
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using Microsoft.Office.Interop.Outlook;
using Exception = System.Exception;
namespace OutlookTaskStatistics.Importer
{
internal class Program
{
private static void Main(string[] args)
{
var categoriesHt = new Hashtable();
Application olApp;
NameSpace ns = null;
SqlConnection conn = null;
try
{
olApp = new Application();
ns = olApp.GetNamespace("mapi");
ns.Logon("Outlook", Missing.Value, false, true);
MAPIFolder taskFolder =
olApp.Session.GetDefaultFolder(OlDefaultFolders.olFolderTasks);
conn = new SqlConnection(ConfigurationManager.ConnectionStrings["OutlookStatsDB"].ConnectionString);
conn.Open();
using (SqlCommand truncateCmd = new SqlCommand("TRUNCATE TABLE TasksCategories; DELETE FROM Tasks; DELETE FROM TasksCategories", conn))
{
truncateCmd.ExecuteNonQuery();
//truncateCmd.CommandText = "DELETE FROM Tasks";
//truncateCmd.ExecuteNonQuery();
}
var cmdGetCategories = new SqlCommand("SELECT * FROM Categories", conn);
categoriesHt = GetCategoriesHashTable(cmdGetCategories);
int i = 0;
foreach (object taskItem in taskFolder.Items)
{
var ti = taskItem as TaskItem;
if (ti.Categories != null)
{
string[] taskCategories;
taskCategories = GetTaskCategories(ti);
foreach (string taskCategory in taskCategories)
{
if (!categoriesHt.ContainsKey(taskCategory.Trim()))
{
var updateCategoriesCmd =
new SqlCommand("INSERT INTO Categories (CategoryName) VALUES (@catName)", conn);
var catNameParameter = new SqlParameter("@catName", SqlDbType.VarChar, 50);
catNameParameter.Value = taskCategory.Trim();
updateCategoriesCmd.Parameters.Add(catNameParameter);
updateCategoriesCmd.ExecuteNonQuery();
categoriesHt = GetCategoriesHashTable(cmdGetCategories);
}
}
}
string insertTasksStatement =
"INSERT INTO Tasks (TaskId, Subject, CreateTime, StartDate, DueDate, CompletedDate, Complete, Importance) " +
"VALUES (@entryId, @subject, @createDate, @startDate, @dueDate, @completedDate, @completed, @importance)";
var cmd = new SqlCommand(insertTasksStatement, conn);
var paramTaskId = new SqlParameter("@entryId", SqlDbType.VarChar, 140);
paramTaskId.Value = ti.EntryID;
var subjrectParam = new SqlParameter("@subject", SqlDbType.VarChar);
subjrectParam.Value = ti.Subject;
var createaionParam = new SqlParameter("@createDate", SqlDbType.SmallDateTime);
cmd.Parameters.Add(createaionParam);
if (DateSeemsSane(ti.CreationTime))
{
createaionParam.Value = ti.CreationTime;
}
else
{
createaionParam.Value = DBNull.Value;
}
var startDateParam = new SqlParameter("@startDate", SqlDbType.SmallDateTime);
cmd.Parameters.Add(startDateParam);
if (DateSeemsSane(ti.StartDate))
{
startDateParam.Value = ti.StartDate;
}
else
{
startDateParam.Value = DBNull.Value;
}
var dueDateParam = new SqlParameter("@dueDate", SqlDbType.SmallDateTime);
cmd.Parameters.Add(dueDateParam);
if (DateSeemsSane(ti.DueDate))
{
dueDateParam.Value = ti.DueDate;
}
else
{
dueDateParam.Value = DBNull.Value;
}
var completeDateParam = new SqlParameter("@completedDate", SqlDbType.SmallDateTime);
cmd.Parameters.Add(completeDateParam);
if (DateSeemsSane(ti.DateCompleted))
{
completeDateParam.Value = ti.DateCompleted;
}
else
{
completeDateParam.Value = DBNull.Value;
}
var completedParam = new SqlParameter("@completed", SqlDbType.Bit);
completedParam.Value = ti.Complete;
var importanceParam = new SqlParameter("@importance", SqlDbType.VarChar);
switch (ti.Importance)
{
case OlImportance.olImportanceLow:
importanceParam.Value = "Low";
break;
case OlImportance.olImportanceHigh:
importanceParam.Value = "High";
break;
default:
importanceParam.Value = "Normal";
break;
}
cmd.Parameters.Add(paramTaskId);
cmd.Parameters.Add(subjrectParam);
cmd.Parameters.Add(completedParam);
cmd.Parameters.Add(importanceParam);
cmd.ExecuteNonQuery();
if (ti.Categories != null)
{
string[] taskCategories = GetTaskCategories(ti);
foreach (string taskCategory in taskCategories)
{
string stmt =
"INSERT INTO TasksCategories (TaskId, CategoryId) VALUES (@taskId, @catId)";
var categoryTaskCmd = new SqlCommand(stmt, conn);
categoryTaskCmd.Parameters.Add(new SqlParameter("@taskId", ti.EntryID));
categoryTaskCmd.Parameters.Add(new SqlParameter("@catId",
(int) categoriesHt[taskCategory.Trim()]));
categoryTaskCmd.ExecuteNonQuery();
}
}
i++;
if(i % 100 == 0)
{
Console.Write(i.ToString());
}
else
{
Console.Write(".");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
finally
{
if (conn != null)
{
if (conn.State != ConnectionState.Closed)
{
conn.Close();
}
}
ns.Logoff();
}
}
private static string[] GetTaskCategories(TaskItem ti)
{
string[] taskCategories;
if (ti.Categories.IndexOf(';') > 0)
{
taskCategories = ti.Categories.Split(';');
}
else
{
taskCategories = ti.Categories.Split(',');
}
return taskCategories;
}
private static bool DateSeemsSane(DateTime dateToCheck)
{
if (dateToCheck.Year >= 1900 && dateToCheck.Year < 4501)
{
return true;
}
else
{
return false;
}
}
private static Hashtable GetCategoriesHashTable(SqlCommand cmdGetCategories)
{
var categoriesHt = new Hashtable();
SqlDataReader categoryReader = cmdGetCategories.ExecuteReader();
while (categoryReader.Read())
{
categoriesHt.Add(categoryReader[categoryReader.GetOrdinal("CategoryName")],
categoryReader[categoryReader.GetOrdinal("CategoryId")]);
}
categoryReader.Close();
return categoriesHt;
}
}
}
Exposing OData
Next step is to expose the data as a OData service.
Entity Framework Model
First of all we got to put a layer on top of the database that WCF Data Services (previously known as Astoria) understands, namely Linq to SQL or Entity Frame. I decided to go with EF here, so I right clicked in the solution tree and selected Add –> New Item… And then selected ADO.NET Entity Data Model.

Select Generate From Database

Next step is to chose what DB to generate from and give the enties a name space:

Then select what tables (or sprocs/views for that matter) should be included in the model.

Hit Finish and my result looked like this:

OData Service
Next thing to do is to expose the model as OData. First up we create an OData Service or as Visual Studio (and Microsoft Marketing) likes to put it – WCF Data Service. (I you bingle that you probably wanna put “Astoria” in the search to).
When it’s created the xxx.svc.cs file will pop up in Visual Studio, here you’ll need to make two changes (or more if you want to lock down the data a little more then “ReadAll”). As I tried to show in the image below I tell the DataService to be of OutlookTaskStatsEntities and I set the Entity Access Rule to apply to “*”, that is all entites.

Ok, now we’re done, lets try it! F5 and hit the TaskStats.svc with a browser:

Looks good, now we can drilldown using the URL if we want to. For example http://localhost:36277/TaskStats.svc/Categories(2) shows me the category “Personal”.

Excel PowerPivot
Ok, now we have the data out of Outlook and exposed as OData. Next step in my plan is to get it into Excel and I’m going to use PowerPivot for excel for that. If you don’t have the plug-in installed go get it from www.powerpoivot.com.
Fire up Excel and start PowerPivot.

Let’s fetch the (o)data by hitting the “From Data Feeds” button.

And the wizard kicks off. First step enter the service URL:

After that we decide what data to import.

The import succeeds (hopefully).

And we have the data in Excel.

Here is where my current skillset fails me and I really have to get better at massaging this data in Excel, maybe I should ask some of my BI centric customers for help :). Anyway here’s a little example of a first view of the data. I chose to create a Pivot diagram.

After adding some axis and slicers here’s what I got:

Summary
I think the points I want to drive with this post is:
- Show a way to access data in Outlook
- I hope I’ve shown in this post that it is relatively simple to expose you model as OData. This is of course a greatly simplified example where I don’t really care about security.
- Have a look at PowerPivot
Next up I’m going to consume the OData from Linq and see if I can do some fun statistics and graphics, but that’s another post.
This post is very basic and probably not needed for most. But I got the question so I figure I’ll put it out there and hopefully it might help someone.
It’s mostly just a bunch of pictures showing you how to go about this task.
Before
First lets look at the present state. Available WebParts:

As seen above, no Business Data web parts. Available Shared Applications:

Do it
Here we go. To perform the task, go to Central Administration and follow the steps below. Make sure you got your product key from MSDN or wherever kind of license you’re running.








Result
Now there is a few more web parts available

And also a bunch of Shared Applications:

This introduction does not talk about how to deploy SharePoint itself but rather
solutions on top of SharePoint that leverages the platform. For SharePoint deployment
check out the technet docs on it.
In most cases there is four ways to deploy functionality and configuration to a
SharePoint platform
|
Browser
|
Apply settings and perfom administrative taskt through the web ui of
Central Admin and site settings.
|
|
stsadm
|
Stsadm is a command line tool that lives in C:\Program Files\Common Files\Microsoft
Shared\Web Server Extensions\14\bin
Stsadm perfomes administrative operations of a wide spectrum.
|
|
PowerShell
|
Starting with the 2010 release of SharePoint PowerShell is supported
as an out of the box administrative and automation tasks.
|
|
Code
|
Almost everything that can be done by the options listed above can be
done through code and wise versa.
|
Scenario
Let’s start out with a scenario. The developer has created some SharePoint
artifacts in Visual Studio 2010 using the SharePoint tooling. All deployment has
been local through Visual Studio’s menu options or just by using F5.

To get a feeling of what has to be done every deployment we can have a look at Visual
Studios default configuration.

Now it’s time to deploy to another box, like the Consolidated Development
Environment.
Packaging
Every time you deploy with Visual Studio a Windows SharePoint Package (called WSP’s)
is created and deployed.

The same package is used for deployment to other boxes to. You find the package
in the projects bin directory in the folder corresponding to your build configuration.

The WSP package contains the stuff from the Visual Studio. Examples are:
- Dlls – for GAC or \bin deployment
- Safe controls entries for web.config – will keep track of these types of changes
- SharePoint specific folders – deploys stuff to the 14-hive to folders like
Layouts, Images, …
To gain a greater understanding of what is deployed through the wsp packages you
can have a look at the manifest file for the package. Look in pkg
folder in the file system and navigate down to manifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="321c78d2-61cc-4a3c-9551-2a0cf3f83a3f" SharePointProductVersion="14.0">
<Assemblies>
<Assembly Location="Nihlen.SharePoint.Web.dll" DeploymentTarget="GlobalAssemblyCache" />
</Assemblies>
<TemplateFiles>
<TemplateFile Location="Images\Nihlen\additional_arrow.png" />
<TemplateFile Location="Images\Nihlen\arrow_down.png" />
<TemplateFile Location="Images\Nihlen\arrow_down_active.png" />
<TemplateFile Location="Images\Nihlen\button_buy.png" />
<TemplateFile Location="Images\Nihlen\button_search.gif" />
<TemplateFile Location="Layouts\Nihlen\CSS\base.css" />
<TemplateFile Location="Layouts\Nihlen\CSS\Coromant.css" />
<TemplateFile Location="Layouts\Nihlen\CSS\demo.css" />
<TemplateFile Location="Layouts\Nihlen\CSS\reset.css" />
<TemplateFile Location="Layouts\Nihlen\CSS\style.css" />
<TemplateFile Location="Layouts\Nihlen\ErrorPage.aspx" />
</TemplateFiles>
<FeatureManifests>
<FeatureManifest Location="Nihlen.SharePoint.Web_PageArtifacts\Feature.xml" />
<FeatureManifest Location="Nihlen.SharePoint.Web_RootWebTemplate\Feature.xml" />
<FeatureManifest Location="Nihlen.SharePoint.Web_Web\Feature.xml" />
</FeatureManifests>
</Solution>
So first thing you need to is to gather the WSP’s and copy them up to a server
in the SharePoint farm. The don’t need to be distributed to all machines in
the farm, this is handled by the wsp deployment framework within SharePoint. I usually
use the box running Central Admin for this task, no real reason really – just
habit.
You can gather up the WSP’s manually or do as I do an use a simple PowerShell
script for this task. It’s dead simple:
$trgPath = Read-Host "
Enter target path"
get-childitem C:\Projects\Nihlen\Main\Source -Recurse -Include *.wsp | foreach-object -process{copy-item $_.FullName -destination $trgPath}
When you got the WSP-files up on the server, use remote desktop to connect to the
server.
Add Solution (wsp)
First time out, you need to add the solution to SharePoint and make it aware that
the package exists. To see what solution packages are added to your farm, crack
open Central Administration and navigate to System Settings and
then Manage Farm Solutions under Farm Management.

If your dealing with a clean environment there is a text there explaining that there
are no solutions deployed, but if there are some solutions deployed, they will show
up there in a list with some info about them.
Web UI
There is no way to add a solution using the web user interface.
stsadm
Stsadm is the “old” way of doing this, but it’s still fully supported.
Here’s how you do it.
stsadm -o addsolution -filename <solution file name>
[-lcid] <language>
So for example:
stsadm –o addsolution –filename Nihlen.SharePoint.Web.wsp
PowerShell
Using PowerShell for deployment is pretty straight forward. First of all you need
to load up the commandlets for SharePoint. This can be done in two ways. The first
option is to simply run the SharePoint Management Console form the start menu and
they are loaded for you right off the bat.

If you’re running an ordinary PowerShell prompt or script you have to add
it yourself.
Add-PSSnapin Microsoft.SharePoint.Powershell
When you’ve taken one of the approaches described above you can get cracking
on adding the solution to the farm. This is done with the Add-SPSolution commandlet.
Example:
Add-SPSolution E:\Deploy\2010-10-01_01\Nihlen.SharePoint.Web.wsp
There is of course a few other parameter to play with if you like: http://technet.microsoft.com/en-us/library/ff607552.aspx
Code
Using code this can be done by using the
SPSolutionCollection on the
SPFarm object.
SPFarm.Local.Solutions.Add(“E:\Deploy\2010-10-01_01\Nihlen.SharePoint.Web.wsp”);
That said, this approach is very seldom used.
Installing Solution (wsp)
Now when you solution(s) are added to the farms solution store you can install them.
This also can be done in a couple of different ways.
Web UI
When the solutions is added to the solution store it can be accessed via Central
Administration (System Settings –> Manage Farm Solutions.
You can click on the package name and get deployment options.

Stsadm
stsadm –o deploysolution has a few parameters to play with.

Many of these parameters depends on how the features within the solution is scoped.
In the example below there are only farm scoped features, hence no use of the –url
or –allcontenturls parameters. So a simple example could be:
stsadm -o deploysolution -name Nihlen.sharepoint.wsp
-immediate –allowgacdeployment

PowerShell
The equivalent in PowerShell is the
Install-SPCommandlet. So to do the same thing as
Install-SPSolution "Nihlen.SharePoint.wsp"
–GACDeployment
Activating Features
Next step in the deployment process is to activate features. There is a lot of logic
that ends up encapsulated in SharePoint Features. One example is custom web.config
changes.
Visual Studio 2010 defaults to auto activating of features.

This is all god for development purposes but for deployment to other environments
(UAC, Prod, …) I prefer a much more granular control over what what gets
executed when. So my recommendation is to turn this off.
Let’s have a look at how we can activate features.
Web UI
Where in the UI you activate features depends on how they are scoped.

|
Farm
|
Activation is performed under Central Admin (System Settings
–> Mange Farm Features)
|
|
Web Application
|
This is scoped for a Web Application and is activated/deactivated in
Central Administration under Application Management –>
Manage Web Applications, select a web application and chose
Manage Features in the ribbon.
|
|
Site
|
Is Site Collection scoped. Point browser to your site. Enter
Site Actions –> Site Settings and make sure you’re
on the top level (otherwise click Go to top level site settings) and click on
Site collection features
|
|
Web
|
Scoped to a single SharePoint web. Enter Site settings on that web and
chose Manage site features (in the Site Actions section)
|
So, this is what it could look like this:
Stsadm
Activating a feature using stsadm is also dependent on the scope, but that just
makes some of the parameter vary.

Example:
stsadm -o activatefeature -name Nihlen.SharePoint.Examples_Feature1
-url http://sp2010:3001
PowerShell
PowerShell’s corresponding commandlet is
Enable-SPFeature.
Enable-SPFeature -identity Nihlen.SharePoint.Examples_Feature1 -URL
http://sp2010:3001
Retraction
When deploying to test and UAC environments and deploying before the first go live
version I usually recommend full retraction and re-deploying every time. Handling
upgrades is a whole different ballgame by itself.
Summary
So to try to tie this post up. User PowerShell when possible. The steps are:

Here’s an sample PowerShell script doing it:
Add-PSSnapin Microsoft.SharePoint.Powershell -erroraction SilentlyContinue
<# -- Processing script arguments -- #>
function End {
Write-Host "-- Finished step: " $args[0] -ForegroundColor blue
}
function Begin {
Write-Host "-- Beginning step: " $args[0] -ForegroundColor blue
}
function WriteStatus {
Write-Host "" $args[0] -ForegroundColor green
}
cls
$deployUrl = Read-Host "
Enter the web application url"
#$dropPath = Read-Host "
Path to folder containing WSP files"
$p = Get-Item .\
$dropPath = $p.FullName
$task = "
Uninstalling Solution Nihlen.SharePoint.Web.wsp"
Begin $task
Uninstall-SPSolution -Identity "
Nihlen.SharePoint.Web.wsp" -Confirm:$false
End $task
$task = "
Uninstalling Solution Nihlen.SharePoint.wsp"
Begin $task
Uninstall-SPSolution -Identity "
Nihlen.SharePoint.wsp" -Confirm:$false
End $task
Read-Host "
Verify in Central Admin that packages are uninstalled/retracted and then hit enter"
$task = "
Remove Solution Nihlen.SharePoint.Web.wsp"
Begin $task
Remove-SPSolution -Identity "
Nihlen.SharePoint.Web.wsp" -Force -Confirm:$false
End $task
$task = "
Remove Solution Nihlen.SharePoint.wsp"
Begin $task
Remove-SPSolution -Identity "
Nihlen.SharePoint.wsp" -Force -Confirm:$false
End $task
Read-Host "
Verify remove ok, and hit enter to restart IIS"
$task = "
Restarting IIS"
Begin $task
Write-Host "
Not running at the moment"
#Restart-Service W3SVC,WAS -force
#Start-Service W3SVC,WAS
End $task
$task = "
Adding wsp Nihlen SharePoint Core"
$fileName = $dropPath + "
\Nihlen.SharePoint.wsp"
Begin $task
Add-SPSolution $fileName
End $taks
$fileName = $dropPath + "
\Nihlen.SharePoint.Web.wsp"
$task = "
Adding wsp Coromant Web: " + $fileName
Begin $task
Add-SPSolution $fileName
End $taks
$task = "
Installing wsp Nihlen SharePoint Core"
Begin $task
Install-SPSolution "
Nihlen.SharePoint.wsp" -GACDeployment #-AllWebApplications #-WebApplication $deployUrl -GACDeployment
End $taks
$task = "
Installing wsp Coromant Web"
Begin $task
Install-SPSolution "
Nihlen.SharePoint.Web.wsp" -GACDeployment #-WebApplication $deployUrl
End $taks
Read-Host "
Veriry that packages are installed/deployed in Central Admin and hit enter for feature
activation"
Enable-SPFeature -url $url -identity WebTeplatesFeature
This script is a first draft so don’t see it as something final.
//Niklas
In Sweden, I don’t know why, we’re very week number centric. Questions like the ones listed below are not uncommon:
- “What weeks will you have vacation”
- “Can you be done by week 42?”
What I have to do then is to switch into Outlook, Ctrl+2 my way to the calendar and switch to monthly view where I have week numbers enabled.
As you can imagine this really upsets a productivity-geek-wannabe as me. So, Visual Studio to the rescue (as always ;)). I wrote a little application which sole purpose in life is to show me what week it is in the system tray.
As always I googled it with bing first and found some good inspiration and how-to info. I found a good article on CodeProject wich showed me pretty much how to do what I wanted.
Here the specifics.
I created a Console Application project in Visual Studio and got rid of the default stuff.
I then created the TrayWeekApplicationContext class which inherits from ApplicationContext. From there I do everything. In the Constructor I hook up timer, update event, context menu and NotifyIcon. The timer ticks once an hour, after all how often am I going to stare at the thing Sunday evening at midnight?
private NotifyIcon _notifyIcon;
private IContainer _components;
private Timer _timer;
private ContextMenuStrip _contextMenu;
public TrayWeekApplicationContext()
{
_components = new Container();
_notifyIcon = new NotifyIcon(_components);
_notifyIcon.Visible = true;
UpdateUi();
//Set timer to redraw
_timer = new Timer();
_timer.Elapsed += TimerElapsed;
_timer.Interval = 60*60*1000; //Hourly update
_timer.Enabled = true;
_timer.Start();
//Initialize context menu
InitContextMenu();
}
The interesting stuff (if you call it that, it’s not rocket science directly) happens in the UpdateUi() method:
private void UpdateUi()
{
Graphics graphics;
Font font;
Image image = TrayWeekResources.date;
using (graphics = Graphics.FromImage(image))
{
int weekNo = DateHelper.GetCurrentWeekNumber(DateTime.Now);
font = new Font("Lucida Console", 18, FontStyle.Regular);
SizeF size = graphics.MeasureString(weekNo.ToString(), font);
Point startingPoint = CalculateStartingPoint(size);
graphics.DrawString(weekNo.ToString(), font, Brushes.GhostWhite, startingPoint);
SetBaloonTip(weekNo);
_notifyIcon.Icon = ImageToIcon(image);
}
}
Here you can se how I get an icon and draw the text upon it. And that’s about that.
You can download the Visual Studio 2010 project here. And be aware, there is a lot of hard coded stuff, such as Swedish localization, that should be promoted to a settings dialog or retrieved from Regional Options.
This is more of a note to self, how could I forget again, I’m an idiot post than anything else. So here it goes, if you’re writing a app that is supposed to do anything with SharePoint and get FileNotFoundException when trying to new up a SPSite object.
SPSite site = new SPSite(“http://myDevSite”);
Chanses are you’re Platform Target is set to "x86”. Change that to “Any CPU” or “x64” and you should be good to go.
This is only a SharePoint 2010 issue, not 2007.
When you’re accessing built in SharePoint fields (such as Title) from code, do you go:
listItem["Title"] = xVar;
listItem[0] = xVar;
Don’t! Have a look at SPBuiltInFieldId that keeps tracks of the Id’s for the built in fields for you:
string title = myListItem[SPBuiltInFieldIds.Title];