Scott Hanselman

RFC: OpenTweets - Why is Microblogging centralized?

May 3, '08 Comments [21] Posted in Musings
Sponsored By

I'm thoroughly enjoying Twitter (follow me!) Apparently others are enjoying it also as there's a funny estimate that it's costing $14 billion in lost productivity (via a back of envelope calculation). There is about a million people on Twitter and maybe 60k adding each a month. Certainly it'll be blocked by most corporate firewalls soon for just this reason.

Twitter is also down ALL the time and it's been having weekly (daily?) scale problems for a YEAR, culminating in rumors that the development team is leaving Ruby on Rails that have been denied by Evan Williams (via a "Tweet," of course). However, that doesn't change the fact that Twitter is down so often there is a site dedicated to "Twitter Down Art" showcasing all the pictures that Twitter puts up when their sites are down. Google changes their art monthly and during holidays, but never goes down. Twitter goes down so often that they use that as an opportunity to change their art! So far, in this era of transparency, no one has explained in technical (or any) terms what the problem with Twitter is and folks are getting impatient. I think that it would be a great PR and Karmic move to just start a Twitter Technical Blog and share the crazy IT problem of the day. Surely someone is sleeping on a cot next to the TweetBoxes and has a story to tell.

There's another rumor that Twitter is worth about $150M. Seems to me that the second bubble hasn't popped. I'm certainly no business man, but we can build this better ourselves.

Twitter is centralized, which is insane (unless you're Google or Amazon or Live.com, etc, which are actually distributed in their own special way).

Twitter is IRC, it's IM, it's chatrooms, but ultimately it's just microblogging with a multi-format API. Here's the XML for my Twitter Account but it looks nicer as Atom.

But I already have a blog! Why use a service when I already host a blog? I hooked up Microsummaries to DasBlog two years ago. There's clearly precedent.

Two folks I know already have Twitter Backup Feeds. Both LazyCoder (backup twitstream) and Dave Winer (twitstream) have Backup Twitter Feeds. Dave takes it even farther and makes his twistream discoverable via a link in his blog:

<link rel="twitstream" href="http://twitter.scripting.com/daveRss.xml" />

With backups like these, who needs Twitter? There is already a very responsive group of Twitter client applications some of which, like twhirl cross-post to Pownce and Jaiku, two Twitter competitors. Russell Beattie has an idea for an Open Twitter Server called Peep using Jabber.

I propose that we distribute Twitter into generalized spec for microblogging and just use RSS or Jabber for the transport. I think the very-fast-rev'ing Twitter clients would support it. 

Thoughts? Should Twitter be a service or should Microblogging be an Open Thing?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

The Weekly Source Code 25 - OpenID Edition

April 30, '08 Comments [161] Posted in ASP.NET | ASP.NET MVC | DasBlog | Identity | Source Code
Sponsored By

OpenID Logo We spent a lot of time at Corillian (my last job) thinking about Identity, and a few months before I left I started getting into Cardspace and OpenID. This was a little over a year ago. We did a podcast on OpenID as well.

At that time, I tried to take the only .NET implementation at the time of OpenID which was written in in Boo written originally by Grant Monroe and port it to C# causing me to go through the Programmer Phases of Grief. Andrew Arnott and Jason Alexander took the reins and we spend a number of late nights trying to get a good OpenID library working. I gave up, but they soldiered on and created dotnetopenid (downloads), including a client and server as well as Andrew's excellent ASP.NET controls .

Fast-forward to now. My new friend Aaron Hockley decided to a stands and promote OpenID. He said:

Effective immediately, I will no longer comment on tech blogs that don’t support OpenID for comment authentication.

He's just one guy, but his heart is in the right place. He points out that:

Google offers it as a Blogger option. It’s available as a super-easy-to-install WordPress plugin. Movable Type has it as a built-in feature.

OpenID is a good thing and it's Growing. You may already have an OpenID if, for example, you have a Yahoo! account. More on this soon.

How to turn your blog into an OpenID

Simon Willison wrote How to turn your blog into an OpenID and it's very easy.

STEP 1: Get an OpenID. There a lots of servers and services out there you can use. I use http://www.myopenid.com for two reasons. One, I know the CEO (they're in Portland), and two, they support optionally using CardSpace to authenticate yourself (as well as the standard way with password).

STEP 2: Add these two lines to your blog's main template in-between the <HEAD></HEAD> tags at the top of your template. Most all blog engines support editing your template so this should be an easy and very possible thing to do.

Example:

<link rel="openid.server" href="http://www.myopenid.com/server" />
<link rel="openid.delegate" href=
http://YOURUSERNAME.myopenid.com/ />

This will let you use your domain/blog  as your OpenID. Now, I can log in with "http://www.hanselman.com" when I see an OpenID Login option - and so can you! Go do it now!

Making OpenID Logins Easier

If you have a blog or site with OpenID support, you should go get this little snippet of JavaScript and install an OpenID ID Selector on your blog from http://www.idselector.com/.

virgin-3

One of the things that is slowing OpenID adoption is that many people don't realize that they may already have one. That's what this little Javascript is trying to do by showing folks sites that they recognize. This way my Dad could login using Yahoo and it would make sense to him. It's a little busy, but it's a start. I've added an http://www.idselector.com/ to my blog for comments.

Adding OpenID Support to DasBlog

A year ago, I originally tried to port the Boo code to C# in an attempt to enable OpenID in DasBlog but eventually gave up. However, last night, I re-familiarized myself with the OpenID spec (it's on 2.0 now) and started reading the source for http://code.google.com/p/dotnetopenid/.

In a word, it's a joy. I was able to get OpenID running OK in two hours and working well and up on my blog in two more. I have to give credit to the fantastic work that Andrew Arnott and Jason Alexander and team are doing. It's come far and you should know about it, Dear Reader.

I had two scenarios in DasBlog (again, in case you didn't know, it's the C# and XML-based blog that runs this site and others) to handle.

First, I wanted to support OpenID for Comments which wouldn't actually "log a user in" in the stateful FormsAuthentication sense. I think this isn't a very common scenario, and I'd describe it as One-Time Occasional Authentication. In this case, I used the dotnetopenid classes directly in a moderately complex scenario.

Second, I wanted to support OpenID to login as the Administrator for my site. This would, in fact, log me in via FormsAuthentication. This would be a common scenario that you'd probably care about as it's very typical. In this case, I used the dotnetopenid ASP.NET Controls, which were about as easy as falling off a log. (That's pretty easy.)

Here's the first, harder, scenario.

If you've entered your OpenID and hit Submit Comment then we'll store the current entry and the comment you're submitting. We'll be redirecting away to get authenticated and we'll need them when we get back. If you're running in a WebFarm, you'll want to store these temporary variables in a database or somewhere that doesn't have node-affinity.

Session["pendingComment"] = comment.Text;
Session["pendingEntryId"] = ViewState["entryId"] as string;
OpenIdRelyingParty openid = new OpenIdRelyingParty();
IAuthenticationRequest req = openid.CreateRequest(openid_identifier.Text);
ClaimsRequest fetch = new ClaimsRequest();
fetch.Email = DemandLevel.Require;
fetch.Nickname = DemandLevel.Require;
req.AddExtension(fetch);
SaveCookies();
req.RedirectToProvider();
return;

What I think of as an "OpenID Client" is called a "Relying Party" or "RP" in the parlance of the OpenID folks. In this code we create an AuthenticationRequest and add some additional claims. There's a nice interface-based extension model in this lower-level library that lets you Request or Require information from the user's profile. For comments on the blog, I just need your email for your Gravatar and your Nickname for Display.

I then call RedirectToProvider, and that's if for the request side. Remember I said this was the hard scenario! Not so hard. ;)

Next, we're redirected to an OpenIDProvider, we authenticate (or not) and are redirected BACK with additional information encoded on the GET. On the way back in, in our Page_Load (or an HttpHandler if you like) we check the Response status.  If we're Authenticated, we grab the info we requested and add the comment. Bam. Sprinkle in a little error handling and we're all set.

OpenIdRelyingParty openid = new OpenIdRelyingParty();
if (openid.Response != null)
{
// Stage 3: OpenID Provider sending assertion response
switch (openid.Response.Status)
{
case AuthenticationStatus.Authenticated:
ClaimsResponse fetch = openid.Response.GetExtension(typeof(ClaimsResponse)) as ClaimsResponse;
string nick = fetch.Nickname;
string homepage = openid.Response.ClaimedIdentifier;
string email = fetch.Email;
string comment = Session["pendingComment"] as string;
string entryId = Session["pendingEntryId"] as string;
if (String.IsNullOrEmpty(comment) == false && String.IsNullOrEmpty(entryId) == false)
{
AddNewComment(nick, email, homepage, comment, entryId, true);
}
break;
}
}

Here's the second scenario where we'll log in as the Administrator of the blog. I just register the DotNetOpenId assembly in my ASPX page and put an <openidlogin> control on the page. Notice that even the claims I created in the manual scenario above are just properties on this control. There's also events like OnLoggedIn to handle the results.

<%@ Register Assembly="DotNetOpenId" Namespace="DotNetOpenId.RelyingParty" TagPrefix="cc1" %>
<cc1:openidlogin id="OpenIdLogin1"
RequestEmail="Require" RequestNickname="Request" RegisterVisible="false"
RememberMeVisible="True" PolicyUrl="~/PrivacyPolicy.aspx" TabIndex="1"
OnLoggedIn="OpenIdLogin1_LoggedIn"/></cc1:openidlogin>

This controls renders nicely as seen in the screenshot below.

image

In the OnLoggedIn event, I call my existing security APIs (Thanks to Tony Bunce and Anthony Bouch) and set the AuthCookie from FormsAuthentication.

protected void OpenIdLogin1_LoggedIn(object sender, OpenIdEventArgs e)
{
UserToken token = SiteSecurity.Login(e.Response);
if (token != null)
{
FormsAuthentication.SetAuthCookie(userName, rememberCheckbox.Checked);
Response.Redirect(SiteUtilities.GetAdminPageUrl(), true);
}
}

Poof. I love using well designed libraries and just work. At this point all that was left was adding some CSS and tidying up.

OpenID and ASP.NET WebForms and MVC

The dotnetopenid source includes source for sample sites. It actually includes three samples, two WebForms and one ASP.NET MVC.

The MVC implementation is very clean, even though (or because?) it doesn't use controls. Here's the Authenticate Controller Action:

public void Authenticate() {
var openid = new OpenIdRelyingParty();
if (openid.Response == null) {
// Stage 2: user submitting Identifier
openid.CreateRequest(Request.Form["openid_identifier"]).RedirectToProvider();
} else {
// Stage 3: OpenID Provider sending assertion response
switch (openid.Response.Status) {
case AuthenticationStatus.Authenticated:
FormsAuthentication.RedirectFromLoginPage(openid.Response.ClaimedIdentifier, false);
break;
case AuthenticationStatus.Canceled:
ViewData["Message"] = "Canceled at provider";
RenderView("Login");
break;
case AuthenticationStatus.Failed:
ViewData["Message"] = openid.Response.Exception.Message;
RenderView("Login");
break;
}
}
}

What about CardSpace?

Infocard LogoOpenID is a spec for a protocol that "eliminates the need for multiple usernames across different websites, simplifying your online experience."  What's cool is that it's open, so you (the consumer) gets to pick your Provider. It's not owned by anyone, so it's ours to screw up (or succeed with).

CardSpace is built into Vista and installed on XP when you put .NET 3.0 on your system. There are also Identity Selectors for Safari and Firefox in the works. It's different than OpenID in that it's concerned with strong authentication. Therefore, they are very complimentary.

Here's my CardSpace login as I'm getting ready to log into this blog...

image

...because my chosen OpenID provider at http://www.myopenid.com (it's free) also supports both InfoCards and SSL Certificates for authentication as well as strong passwords.

Notice the "Sign into Information Card" icon below next to the IconCard purple icon.

image

An OpenID provider can choose to use anything available with which to authenticate you. Here's a video of a Belgian using an eID to authenticate against an OpenID provider at http://openid.trustbearer.com/ that supports biometric devices, USB keys, and smart cards.

So What?

Get involved and give it a try! Here's some things you can do.

  1. Sign up for a Free OpenID at MyOpenID or one of the many public OpenID providers out there.
  2. Go use your new OpenID at one of the many sites that supports OpenID.
    • Come back to this post and leave your first comment using OpenID!
  3. Watch Simon Willison talk about the case for OpenID (video)

And, if you're a developer, get an OpenID library like dotnetopenid and consider enabling your app. Consider using the Javascript ID Selector to make for a nicer User Experience.

Technorati Tags: ,,

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

A Smarter (or Pure Evil) ToString with Extension Methods

April 27, '08 Comments [24] Posted in Programming
Sponsored By

Three years ago I postulated about a ToString implementation for C# that seemed useful to me and a few days later I threw it out on the blog. We used in at my old company for a number of things.

Just now I realized that it'd be even more useful (or more evil) with Extension Methods, so I opened up the old project, threw in some MbUnit tests and changed my implementation to use extension methods.

So, like bad take-out food, here it is again, updated as ToString() overloads:

[Test]
public void MakeSimplePersonFormattedStringWithDoubleFormatted()
{
Person p = new Person();
string foo = p.ToString("{Money:C} {LastName}, {ScottName} {BirthDate}");
Assert.AreEqual("$3.43 Hanselman, {ScottName} 1/22/1974 12:00:00 AM", foo);
}

[Test]
public void MakeSimplePersonFormattedStringWithDoubleFormattedInHongKong()
{
Person p = new Person();
string foo = p.ToString("{Money:C} {LastName}, {ScottName} {BirthDate}",new System.Globalization.CultureInfo("zh-hk"));
Assert.AreEqual("HK$3.43 Hanselman, {ScottName} 1/22/1974 12:00:00 AM", foo);
}

It's moderately well covered for all of the hour it took to write it, and I find it useful.

image

Here's all it is.

public static class FormattableObject 
{
public static string ToString(this object anObject, string aFormat)
{
return FormattableObject.ToString(anObject, aFormat, null);
}

public static string ToString(this object anObject, string aFormat, IFormatProvider formatProvider)
{
StringBuilder sb = new StringBuilder();
Type type = anObject.GetType();
Regex reg = new Regex(@"({)([^}]+)(})",RegexOptions.IgnoreCase);
MatchCollection mc = reg.Matches(aFormat);
int startIndex = 0;
foreach(Match m in mc)
{
Group g = m.Groups[2]; //it's second in the match between { and }
int length = g.Index - startIndex -1;
sb.Append(aFormat.Substring(startIndex,length));

string toGet = String.Empty;
string toFormat = String.Empty;
int formatIndex = g.Value.IndexOf(":"); //formatting would be to the right of a :
if (formatIndex == -1) //no formatting, no worries
{
toGet = g.Value;
}
else //pickup the formatting
{
toGet = g.Value.Substring(0,formatIndex);
toFormat = g.Value.Substring(formatIndex+1);
}

//first try properties
PropertyInfo retrievedProperty = type.GetProperty(toGet);
Type retrievedType = null;
object retrievedObject = null;
if(retrievedProperty != null)
{
retrievedType = retrievedProperty.PropertyType;
retrievedObject = retrievedProperty.GetValue(anObject,null);
}
else //try fields
{
FieldInfo retrievedField = type.GetField(toGet);
if (retrievedField != null)
{
retrievedType = retrievedField.FieldType;
retrievedObject = retrievedField.GetValue(anObject);
}
}

if (retrievedType != null ) //Cool, we found something
{
string result = String.Empty;
if(toFormat == String.Empty) //no format info
{
result = retrievedType.InvokeMember("ToString",
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.IgnoreCase
,null,retrievedObject,null) as string;
}
else //format info
{
result = retrievedType.InvokeMember("ToString",
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.IgnoreCase
,null,retrievedObject,new object[]{toFormat,formatProvider}) as string;
}
sb.Append(result);
}
else //didn't find a property with that name, so be gracious and put it back
{
sb.Append("{");
sb.Append(g.Value);
sb.Append("}");
}
startIndex = g.Index + g.Length +1 ;
}
if (startIndex < aFormat.Length) //include the rest (end) of the string
{
sb.Append(aFormat.Substring(startIndex));
}
return sb.ToString();
}
}

Enjoy.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Greatest Hits

April 27, '08 Comments [12] Posted in Musings
Sponsored By

Greatest Hits I've officially been blogging for six years this week. Yikes! It didn't all suck, but it was pretty rough there early on and I've finally found my blog's heartbeat.

Here's a little about me if you're interested, but more importantly, here's some posts that are the most often-read according to the last several year's web server logs. If you enjoy them, consider subscribing via RSS or email. I also do a weekly podcast that you might like. It's available on iTunes and Zune and you can get the complete MP3 here. I publish an Ultimate Tools List each year at http://www.hanselman.com/tools that you might like.

Blogging

Twitter

Programming

.NET

Gadgets

Africa, Travel and Language

Books and Music

Diabetes

Babies and Children

Family

General Coolness

Staying Organized and Home Office

Reviews

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Hack: Parallel MSBuilds from within the Visual Studio IDE

April 26, '08 Comments [21] Posted in ASP.NET | MSBuild | Programming | Tools
Sponsored By

There were a number of interesting comments from my post on Faster Builds with MSBuild using Parallel Builds and Multicore CPUs.

Here's a few good ones, and some answers. First,

Is the developer that sits inside of VS all day debugging able to take advantage of the same build performance improvements?

Yes, I think. This post is about my own hack to make it work.

@Scott, there are still people using VS2005 and .Net 2.0 (our employers are either too cheap to upgrade or we work in non-profit[my case]) So it would be nice for posts like this to clearly denote that these are things only available in the 3.0/3.5+ world. Or should I just assume that .Net 2.0 is dead?

Certainly 2.0 is not dead, considering that 3.5 is still built on the the 2.0 CLR. Additionally, if you're a 2.0 shop, there's really no reason not to upgrade to VS2008 and get all the IDE improvements while still building for .NET 2.0SP1 as MSBUild supports multitargeting.

However, the underlying question here is, "why are you teasing me?" as this gentleman clearly wants faster builds on .NET 2.0. Well, this trick under VS2008 still works when building 2.0 stuff.

If you're using a Solution File (SLN) it's automatic, and if you're using custom MSBuild files, you can build .NET 2.0 stuff with the 3.5 MSBuild by putting

<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>

under a <PropertyGroup> in your C# project. Then you can use /m and get multiproc builds. Not much changes though, because either way your build output is running on CLR2.0. (.NET 3.0 and .NET 3.5 use CLR2.0 underneath.) You will get some warnings if you try to use v3.0/v3.5 types.

It's true that parallel managed code compilation lags behind unmanaged.

Welcome, msbuild, to the 21st century. ;-) GNU make has the -j switch (the equivalent to /m here) _at least_ since the early-to-mid 1990's. We use its mingw port to drive Visual Studio 2003's commandline interface to build vcproj files and to handle dependencies, and since we got multi-core build machines, our build times have improved tremendously (we're talking about roughly 2,5 million SLOCs).

There's a number of reasons for that. For example, Visual Basic is compiling in the background all the time while you're typing in VS using a non-reentrant in-proc compiler. The in-proc C# compiler is the same way.

The Multicore MSBuild with VS Hack

This trick is unsupported because it hasn’t been tested. Off the top of our collective head, I can’t think of why it wouldn’t work OK, at least if your solution is all VB/C#. Having VC projects in your solution, especially if there are project references with the VB/C# projects, would probably not work so well. That’s because VC projects are not native MSBuild format in VS2008.

To start with, this is a totally obvious hack. We'll add an External Tool to Visual Studio to call MSBuild, then add some Toolbar buttons.

First, Tools | External Tools. We'll add MSBuild, pointing it to the v3.5 .NET Framework folder. Then, we'll add /m to the arguments for multi-proc and /v:m (where the v is verbosity and the m is minimal) to tone down MSBuild's chattiness. Finally, we'll check the Use Output Window box and set the initial directory to the current Solution's Directory.

Adding MSBuild to External Tools

Next, we'll right click on the Toolbar, and hit Customize.

External Tools in Visual Studio

Then, from the Commands tab, drag the number of the newly added External Tool (mine is #3) to the Toolbar. I also added a little Lode Runner icon to the button. Additionally, I added a Clean Solution option, just because I like it handy.

Parallel MSBuild Button in Visual Studio

You can also re-map Ctrl-Shift-B if it makes you happy, but I used Ctrl-Shift-M, mapping it to the Tools.ExternalCommand, again, in my case it is #3.

image

At this point, I can now run MSBuild out-of-proc from inside Visual Studio.

What DOESN'T Work

The only thing that doesn't work for me so far is that the errors reported by MSBuild don't appear neatly parsed in the Error List. For some, this may be a deal breaker. However, the good news is that if you double click on the errors in the Output Window you WILL get taken automatically to the right file and line number which is all I personally care about. Still, sucks.

image 

Gotchas for this Hack

If you're building against a SLN file you can use Project References or manually specified project dependencies otherwise MSBuild has no way to figure out the dependencies and you might get "file locked" or other weird concurrency errors.

Also, even if Project to Project references are set up, sometimes project authors are a bit sloppy (I've done this) and inadvertently access the same file in multiple projects, which can cause spurious file locking/access errors. If you see this behavior, turn off multiproc.

Note also that while you can do builds with MSBuild like this, if you get F5 and start a debug session the VS in-process compilers will do a quick build. It WILL figure out that it doesn't need to do anything, but it will check.

Hey, it's NOT faster for me?

If you have a small solution (<10 projects) and/or your solution is designed such that each project "lines up" in a dependency chain rather than a dependency tree, then there will be less parallelism possible.

If you're using a small number of projects, or you're using Visual Basic on small projects, which is compiling in the background anyway, you might not get big changes. Additionally, remember that we're shelling out n new instances of MSBuild, while VS compiles using the in-process versions of the languages compilers. With a small number of projects, in-proc single-core might be faster.

I've got 900 Projects and Visual Studio is Slow, what's the deal?

"Doctor, doctor, it's hurts what I do that!"

"Then don't do that"

Seriously, yes, there are limits. Personally, if you have more than 50 or so projects, it's time to break them out into sub-system SLN files, and keep the über-solution just for the build server.

The team is aware that if you have hundreds of projects in a solution VS totally breaks down. I, and many others, have made suggestions of things like a "tree of projects" where you could build from one point down, and there's ways you can simulate this with multiple-configurations, but it's kinda lame right now if you have a buttload of projects.

Here's a post I did three years ago called How do you organize your code? and I think it still mostly works today. I was using NAnt at the time, but the same concepts apply to MSBuild. Forgive me now, as I quote myself:

Every 'subsystem' has a folder, and usually (not always) a Subsystem is a bigger namespace. In this picture there's "Common" and it might have 5 projects under it. There's a peer Common.Test. Under CodeGeneration, for example, there's 14 projects. Seven are sub-projects within the CodeGeneration subsystem, and seven are the NUnit tests for each. The reason that you see Common and Common.Test at this stuff is that they are the 'highest." But the pattern follows as you traverse the depths. Each subsystem has it's own NAnt build file, and these are used by the primary default.build.

This is not only a nicer way to lay things out for the project, but also for the people on the project, most of whom are not making cross-subsystem changes.

Action Item for you, Dear Reader

If you have feedback then email the MSBuild team at msbuild@ (you know the company name) and they will listen. I warned them you might be emailing, so be nice. If you DEEPLY want multi-proc builds in the next version of Visual Studio, flood them with your (kind) requests. They are aware of ALL these issues and really want to make things better.

It's interesting as I've been at MSFT about 7 months now to realize that for something like multi-proc builds to work it involves (all) the Compiler Teams, the VS Tooling Teams, and the MSBuild folks. Each has to agree it's important and work towards the goal. Sometimes this is obvious and easy, and other times, less so.

Thanks for Dan Moseley, Cliff Hudson and Cullen Waters for their help!

Related Links

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.