I'm an avid shutterbug and had the opportunity to explore some of Delhi, India's points of interest last weekend. I found myself with plenty of time while I was at one particular location - the 500 year old tomb of Isa Khan Niyazi (near to Humayun's Tomb) and I decided to have a go at creating a PhotoSynth. All this required was to take a huge number of photos of the site from pretty much every angle! I had a GPS with me too so I was able to geotag them when I got home (using Microsoft Pro Photo Tools.)
To create the Synth, I downloaded the tool, dragged-and-dropped all the photos I had taken of the location (612 of them!) on to it, and waited... My PC ran overnight and when it was done, this was the result:
http://photosynth.net/view.aspx?cid=ea9f844b-8ef8-43c1-ad74-06743e17f444
I'm rather pleased with how it came out! You can click around with the mouse, zoom in and out and generally explore the location very much like I actually did. All the 3D mapping etc. was done by the software, looking at the photos and working out what the place looked like! I didn't tell it a thing! Pretty amazing result, I thought.
There is also a 3D viewer version, which is also very cool:
http://photosynth.net/d3d/photosynth.aspx?cid=ea9f844b-8ef8-43c1-ad74-06743e17f444
I shall do more of these :-)
Those who know me will be familiar with my quest to avoid writing boring code using any tool that generates it for me (like CodeSmith + NetTiers or Software Factories). Thus it was with great excitement that I recently came across another one! It's called Microsoft Blueprints and is the next evolution of those Software Factories I love so much. (GAT/GAX, which are the heart of Software Factories, are going into Maintenance Mode. Blueprints is What's Next in this space from Microsoft.)
I found a particularly good blog post that describes how to get going with Blueprints so if all you do is read this you will have a pretty good idea of what I'm so excited about... :-)
When building WCF Services it's very useful to know how long the individual operations within it's various methods are taking that are outside of the Service itself e.g. calls to other services or to databases as the question is often asked, "Why is this Service [in Production] so slow right now?" By firing up perfmon against the Production box and Admin can check the counters you've created for that Service and tell you which one is taking longer than usual to give you an indication of what steps to take next.
Creating custom counters is quite straightforward:
PerformanceCounter _testCounter = null;
PerformanceCounter _testBaseCounter = null;
string _testCounterName = "Test Counter";
string _testBaseCounterName = "Test Base Counter";
string _performanceCounterCategory = "Test Counters";
if (!PerformanceCounterCategory.Exists(_performanceCounterCategory))
{
CounterCreationData cdTestCounter = new CounterCreationData();
cdTestCounter.CounterName = _testCounterName;
cdTestCounter.CounterType = PerformanceCounterType.AverageTimer32;
CounterCreationData cdTestBaseCounter = new CounterCreationData();
cdTestBaseCounter.CounterName = _testBaseCounterName;
cdTestBaseCounter.CounterType = PerformanceCounterType.AverageBase;
// Add counters to the collection. Make sure Base Counters come after Timer Counters.
CounterCreationDataCollection counterCreationDataCollection = new CounterCreationDataCollection(
new CounterCreationData[] {
cdTestCounter,
cdTestBaseCounter
});
// Create the category and pass the collection to it.
PerformanceCounterCategory.Create(_performanceCounterCategory, "Test Performance Counter.",
PerformanceCounterCategoryType.SingleInstance, counterCreationDataCollection);
}
else
Console.WriteLine(string.Format("Performance Counter Category '{0}' already created.", _performanceCounterCategory));
And you'd think this would be ok in order to use them:
int howLongToWait = new Random().Next(1000, 2000);
Console.WriteLine(string.Format("{0}: Waiting {1} ms", Thread.CurrentThread.ManagedThreadId, howLongToWait));
if (_testCounter != null) _testCounter.RawValue = Stopwatch.GetTimestamp();
Thread.Sleep(howLongToWait);
if (_testBaseCounter != null) _testBaseCounter.Increment();
What you'd expect to happen when you fire up perfmon on your nice new Performance Counter is that you would see the value the same as "howLongToWait" in the code above every time the last line of the code above executes (it reverts to zero shortly after). HOWEVER when you run this code in multiple threads, then the time taken to execute your method will be reported as much shorter than you know it to be; the more threads - the quicker it appears to run!
Luckily the solution is quite simple (and maybe you've thought of it already, but it took me a while...):
long ticksAtStart = Stopwatch.GetTimestamp(); // Record the start-time
Thread.Sleep(howLongToWait); // Wait
if (_testCounter != null) _testCounter.IncrementBy(Stopwatch.GetTimestamp() - ticksAtStart); // Thread Safe!
if (_testBaseCounter != null) _testBaseCounter.Increment(); // This tells the counter one iteration has happened
Here is a full example in case this helps. Run it as a console app and point perfmon at a a Category "Test Counters" and monitor the counter "Test Counter" and you should see values that are more like you'd expect (however depending on the frequency of the updates and the umber of theads you might not see every setting the application makes.)
using System;
using System.Threading;
using System.Diagnostics;
namespace Test
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Scheduling New Task...");
ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomething));
}
Console.ReadLine();
}
private static void DoSomething(object state)
{
TestClass testClass = new TestClass();
testClass.DoSomething();
}
class TestClass
{
PerformanceCounter _testCounter = null; // Main timer counter
PerformanceCounter _testBaseCounter = null; // We need two counters to measure a duration.
string _testCounterName = "Test Counter";
string _testBaseCounterName = "Test Base Counter";
string _performanceCounterCategory = "Test Counters";
public TestClass()
{
// Init Perf Counters in Constructor
if (!PerformanceCounterCategory.Exists(_performanceCounterCategory))
{
CounterCreationData cdTestCounter = new CounterCreationData();
cdTestCounter.CounterName = _testCounterName;
cdTestCounter.CounterType = PerformanceCounterType.AverageTimer32;
CounterCreationData cdTestBaseCounter = new CounterCreationData();
cdTestBaseCounter.CounterName = _testBaseCounterName;
cdTestBaseCounter.CounterType = PerformanceCounterType.AverageBase;
// Add counters to the collection. Make sure Base Counters come after Timer Counters.
CounterCreationDataCollection counterCreationDataCollection = new CounterCreationDataCollection(
new CounterCreationData[] {
cdTestCounter,
cdTestBaseCounter
});
// Create the category and pass the collection to it.
PerformanceCounterCategory.Create(_performanceCounterCategory, "Test Performance Counter.",
PerformanceCounterCategoryType.SingleInstance, counterCreationDataCollection);
}
else
Console.WriteLine(string.Format("Performance Counter Category '{0}' already created.", _performanceCounterCategory));
}
public void DoSomething()
{
if (!PerformanceCounterCategory.Exists(_performanceCounterCategory))
{
Console.WriteLine(string.Format("Not collecting Performance Statistics for this call; PerformanceCounterCategory {0} not found.", _performanceCounterCategory));
return;
}
if (PerformanceCounterCategory.CounterExists(_testCounterName, _performanceCounterCategory))
_testCounter = new PerformanceCounter(_performanceCounterCategory, _testCounterName, false);
if (PerformanceCounterCategory.CounterExists(_testBaseCounterName, _performanceCounterCategory))
_testBaseCounter = new PerformanceCounter(_performanceCounterCategory, _testBaseCounterName, false);
while (true)
{
int howLongToWait = new Random().Next(1000, 2000);
Console.WriteLine(string.Format("{0}: Waiting {1} ms", Thread.CurrentThread.ManagedThreadId, howLongToWait));
long ticksAtStart = Stopwatch.GetTimestamp(); // Record the start-time
Thread.Sleep(howLongToWait); // Wait
if (_testCounter != null) _testCounter.IncrementBy(Stopwatch.GetTimestamp() - ticksAtStart); // Set the Counter
if (_testBaseCounter != null) _testBaseCounter.Increment(); // This tells the counter one iteration has happened
}
}
}
}
If you need to make more than one call to one or more web services in your code in a single request, then you can do this using multiple threads for vastly better performance.
There are three ways of solving this problem, depending upon which layer your code resides (UI, Business Layer or Data Layer).
If your code is in the UI layer, then you can make use of the Async parameter in your ASPX:
|
<%@ Page Language="C#" Async="true" CompileWith="SlowWSAsync.aspx.cs" ClassName="Whatever.SlowWSAsync_aspx" %> |
like this (SlowWsAsync.aspx.cs):
|
…
using System.Threading;
namespace Chevron.UpstreamArchitecture.Services.Whatever
{
public partial class SlowWSAsync_aspx
{
// Get an instance of our Slow Web Service
Slow slowWebservice = new Slow();
void Page_Load(object sender, EventArgs e)
{
BeginEventHandler bh = new BeginEventHandler(this.BeginGetAsyncData);
EndEventHandler eh = new EndEventHandler(this.EndGetAsyncData);
AddOnPreRenderCompleteAsync(bh, eh);
}
IAsyncResult BeginGetAsyncData(Object src, EventArgs args, AsyncCallback cb, Object state)
{
// Note - this is serviced on the same thread as Page_Load
// but a different thread is used to service EndGetAsyncData
//
return slowWebservice.DoWhatever(cb, state);
}
void EndGetAsyncData(IAsyncResult ar)
{
string ret = slowWebservice.DoWhatever (ar);
}
}
} |
If you’re in the Business layer, then you can use something like this:
|
…
using System.Threading;
namespace Chevron.UpstreamArchitecture.Services.Whatever
{
class ConsoleApp
{
static void Main(string[] args)
{
DoStuffSimultaneously doit = new DoStuffSimultaneously();
// Call our method, passing in the data we want it to work on in parallel.
string stringsAppendedInMulitpleThreads = doit.DoStuff(new string[] { "one ", "two ", "three " });
// Spit out the results
Console.WriteLine(stringsAppendedInMulitpleThreads);
}
}
class DoStuffSimultaneously
{
string _response = string.Empty; // Common object the threads update with their work.
AutoResetEvent[] _waitAllEvents; // Array of objects to wait upon.
/// <summary>
/// This method takes in a set of work and calls multiple threads for each unit of work.
/// </summary>
/// <param name="whatToDo">An array of strings to be appended together, each by a different thread.</param>
/// <returns>The result of all the multiple threads' work.</returns>
public string DoStuff(string[] whatToDo)
{
// Create an array of objects to wait upon; we need one per thread
_waitAllEvents = new AutoResetEvent[whatToDo.Count];
// Populate array of waiting objects, one for each work item
for (int i = 0; i < whatToDo.Count; i++)
_waitAllEvents[i] = new AutoResetEvent(false);
// Create callback on the method we want to do the work
WaitCallback callBack = new WaitCallback(CallSlowWebServiceInNewThread);
// Iterate through all our work items, creating a thread for each and passing in the data
// we want the thread to work on and the event we are waiting on as a state object (a Pair in this example - could be any object)
for(int i=0; i < whatToDo.Count; i++)
ThreadPool.QueueUserWorkItem(callBack, new Pair(whatToDo[i], _waitAllEvents[i]));
// Wait until all our threads have signaled their wait object is done.
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
// WaitAll for multiple handles on an STA thread is not supported.
// ...so wait on each handle individually.
foreach (WaitHandle myWaitHandle in _waitAllEvents)
WaitHandle.WaitAny(new WaitHandle[] { myWaitHandle });
}
else
{
WaitHandle.WaitAll(_waitAllEvents);
}
// When we get here then all our threads have done their work, so we can return our result object.
return _response;
}
/// <summary>
/// This method calls our slow web service does some work in a separate thread.
/// </summary>
/// <param name="state">A Pair object containing a string as the work item, and a AutoResetEvent to set when we are done.</param>
static void CallSlowWebServiceInNewThread(object state)
{
// Get the work for this thread out of the pair
Pair pair = state as Pair;
// Get an instance of our Slow Web Service
Slow slowWebservice = new Slow();
// Call slow Web Service using our work item (be careful of race conditions here; so lock work item)
lock (_response)
{
// Get something from our Slow WebService
_response += slowWebservice.DoSomething(pair.First);
}
// Get our wait item out of the pair
AutoResetEvent autoResetEvent = pair.Second as AutoResetEvent;
// Set our wait item to indicate we are done here.
autoResetEvent.Set();
}
}
} |
Finally, if your code is in the Data Layer and you’re calling directly against SQL Server with a bunch of slow queries then you can use something like the code example below to have SQL Server work on them simultaneously and tell us when it’s done with them.
|
…
using System.Threading;
namespace Chevron.UpstreamArchitecture.Services.Whatever
{
class ExecSimultAsyncSqlStatementWaitAll
{
// Command-line app to demo launching loads of *simultaneous* SQL commands and
// waiting for them all to come back, where we can deal with all them in one loop.
static void Main(string[] args)
{
// Note "Asynchronous Processing=true" at the end of the connection string...
string sqlConnectString = "Data Source=whatever;Integrated Security=SSPI;" +
"Initial Catalog=whatever;Asynchronous Processing=true";
// This is just used to make SQL Server wait a random few seconds to simulate a long query
Random rnd = new Random((int)DateTime.Now.Ticks);
// Create an array of SQL commands with "n" members to simulate a batch of work to do
int n = 10;
SqlConnection[] connection = new SqlConnection[n];
SqlCommand[] command = new SqlCommand[n];
string[] sqlSelect = new string[n];
IAsyncResult[] asyncResult = new IAsyncResult[n];
WaitHandle[] _waitAllEvents = new WaitHandle[n]; // This object is what we use to wait on the batch
// Kick off 10 select statements that will run simultaneously; we DON'T wait for each one here
for (int i = 0; i < n; i++)
{
// In this example, each command actually just waits for between 1 and 10 random seconds
// In reality this could just be a slow query.
sqlSelect[i] = "WAITFOR DELAY '00:00:" + rnd.Next(1, 10) + "';";
connection[i] = new SqlConnection(sqlConnectString);
connection[i].Open();
command[i] = new SqlCommand(sqlSelect[i], connection[i]);
// Kick off a call to SQL Server; it will return *instantly* with an object we can wait upon
asyncResult[i] = command[i].BeginExecuteNonQuery();
Console.WriteLine("[{0}] Command {1} started: {2}", DateTime.Now, i, sqlSelect[i]);
// capture something to wait on for this command
wh[i] = asyncResult[i].AsyncWaitHandle;
}
// Wait for all processes to complete and output results
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
// WaitAll for multiple handles on an STA thread is not supported.
// ...so wait on each handle individually.
foreach (WaitHandle myWaitHandle in _waitAllEvents)
WaitHandle.WaitAny(new WaitHandle[] { myWaitHandle });
}
else
{
WaitHandle.WaitAll(_waitAllEvents);
}
for (int i = 0; i < wh.Length; i++)
{
int recAff = command[i].EndExecuteNonQuery(asyncResult[i]); // Get back the results of each query
Console.WriteLine("[{0}] Command {1} completed, records affected = {2}", DateTime.Now, i, recAff);
connection[i].Close();
}
Console.WriteLine("\nPress any key to continue.");
Console.ReadKey();
}
}
} |
"Terrarium" is a project Microsoft created with .NET 1.0 that allowed devs to write a bug or plant and have it live, fight and eat in a little digital world called Terrarium. This world connected to other instances running on other folks PC's and your bug could crawl between them and live on, even reproduce, in other people instances of Terrarium and thrive or become food for another dev's creature that was better at survival than yours. Survival of the best-programmed! You couldn't change anything about the world but you had quite a lot of creative freedom in creating your bug (or plant - not that the plants did a lot!) They could communicate and even pass on genetic traits to thier children. It was cool.
Well it went away, which is a shame; but recently was revived! Check it out!!
http://weblogs.asp.net/bsimser/archive/2008/07/16/reintroducing-terrarium-now-with-2-0-goodness.aspx
Now for the really hard part... What to call my first critter...
Saw this today and thought this intesting:
http://msdn.microsoft.com/en-us/library/cc645013.aspx
Bits and a sample are available:
http://msdn.microsoft.com/en-us/data/cc655792.aspx
Until now the only caching option from Microsoft has been the Caching block from the P&P group. This offering (code named "Velocity") really ups the ante...
I saw these Webcasts coming up this month and think they might be of interest to a lot of folks (all times are Eastern time):
· June 16th, 2008 – 12:00 p.m. to 1:00 p.m. – Introduction to the aspiring architect Web Cast series
http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380836
· June 17th, 2008 – 12:00 p.m. to 1:00 p.m. – Services Oriented Architecture and Enterprise Service Bus – Beyond the hype
http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380838
· June 18th, 2008 – 12:00 p.m. to 1:00 p.m. – TOGAF and Zachman, a real-world perspective
http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380840
· June 23rd , 2008 – 12:00 p.m. to 1:00 p.m. – Realizing dynamic systems
http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380846
· June 24th, 2008 – 12:00 p.m. to 1:00 p.m. – Web 2.0, beyond the hype
http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380848
· June 25th, 2008 – 12:00 p.m. to 1:00 p.m. – Architecting for the user experience
http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380850
· June 26th, 2008 – 12:00 p.m. to 1:00 p.m. – Conclusion and next steps
http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380852
Today there a bunch of new bits to play with that have up until now been a collection of individual CTP's - yes it's the first beta of Visual Studio 2008 and .NET Framework 3.5 Service Pack 1! This is more interesting than many betas as there a lot of new stuff in this Service Pack, not just bug fixes; including all of my most-anticipated new features:
- ASP.NET Data Scaffolding Support (ASP.NET Dynamic Data) - this is not dissimilar to Ruby On Rails in that it gets you to a web site in front of a database very quickly (and with minimal, possibly no, code) - really cool
- ADO.NET Entity Framework (and LINQ to Entities) - basically a very powerful, flexible ORM which, among other things, supports inheritance! Entities can be used in WCF, too. This is my favourite new feature :-)
- ADO.NET Data Services (was called "Astoria"): This is basically REST-based data services (including a LINQ Client that queries them); when used with the Entity Framework (optional, but cool) you can very quickly publish a really simple to use yet powerful API directly to your data schema - so cool (my second favourite new feature!)
These three alone will save a ton of code... I can't wait!! To learn more and see all the other stuff included in this Service Pack coming your way soon, be sure to read this.
If you're creating Web Services using WCF (or ASMX, for that matter) then you are, of course, using the Web Service Software Factory to create them (right?). Well one thing the WSSF does not include is the hooks to the various blocks within the Enterprise Library that many would find useful in tier freshly-generated Web Services; like Validation, Exception Handling and Logging, Performance Counters, Caching and Exception Shielding. These have to be manually added after you've generated your code.
Well recently a team from Avenade decided to fix this problem and have released to CodePlex an extension to the WSSF called the "EntLib Extensions To WSSF". Once installed (a matter of copying the dll's and updated configuration XML in the appropriate place) you get an additional option when choosing the implementation technology - "WCF with Entlib". Choosing this exposes a slew of new options within your Model that permits you to add all the logging, caching etc. hooks you like; you just need to use the EntLib Configuration tool on your finished Solution (just as you ordinarily would) in order to Make It Work, which is a lot simpler :-)
If you're developing Features for SharePoint then you will have discovered what a laborious process it is getting from the compiled dll, Feature.xml etc in Visual Studio to a deployed Feature in your SharePoint Dev environment. The least painful way I have of doing this so far is to make sure the directory structure of my solution matches that of the SharePoint Root Files directory, and then to use a batch file called after successful compilation that GAC's the dll, XCopy's the files in my feature to the SharePoint directory, and optionally builds the .wsp. This works but is still quite painful.
A colleague pointed me to a proof-of-concept by renowned SharePoint guru and Microsoft MVP Tedd Pattison called STSDEV on codeplex. (I've been to two of Ted's SharePoint classes - this one and this one - and I can't recommend them highly enough.) The tool he created simplifies this process even more by providing a tool you can install and call from the VS2005/8 "Tools" menu that prompts you to create one of a variety of Solution types - like Feature Solution, Web Part solution, etc. - in VS2005 or VS2008. The solution generated sets everything up for you and includes build targets (i.e. alternatives to the default "Debug" and "Release") that will build the solution, make the wsp, and install it on the SharePoint server! So the same end result is achieved but with a lot less batch files. If you do any SharePoint development, this tool is well worth a look.
If you like tools that make creating your data layers easier (like
NHibernate or code generation tools like
Codesmith &
NetTiers), you might be interested in the latest release from the ADO.NET team - the Entity Framework (EF). The
latest release,
announced today, now also supports Visual Studio 2008 RTM and together with a
modeling tool allows you to quickly construct a high-performance, disconnected data layer for your applications; a major time saver for this perennial chore.
I learned today that there was a book published a few months ago on two of my favourite technologies, the Composite UI Application Block (CAB) and the Smart Client Software Factory (SCSF):
Programming Microsoft Composite UI Application Block and Smart Client Software Factory
If you're not familiar with the CAB, and you write moderately+ complex WinForms applications, then you're going to want to take a look as it provides a basis for making your life much easier; especially if you are sharing the work with other developers. The SCSF automates much of the work of creating the CAB project in the first place using Visual Studio so once you've come to understand CAB then you're going to want to take a look at that, too.
Having a book available to help learn this stuff is going to be a great help to those new to this technology as the learning curve, though not very long, is pretty darn steep so I recommend new users pick up a copy of this book to ease them up it.
The future for the CAB looks bright, too; work has commenced on updating it for leveraging WPF and it will be called the WPF Composite Client. This builds upon the work done by a very cool project I've blogged about before called Acropolis which itself builds upon the CAB, taking all the best practices and baking them into Visual Studio. They recently announced they were calling a halt on Acroplis in favour of the WPF Composite Client so the latter is definitely an important one to keep an eye on if you're a WinForms developer.
This took me longer than it should have to get working as the things I tried first compiled but did nothing:
myList.Folders.Add("DoesNotWork", SPFileSystemObjectType.Folder);
The way I got it to work in the end was like this:
SPList myList = myWeb.Lists["My List"];
SPListItem newFolder = myList.Items.Add(myList.RootFolder.ServerRelativeUrl, SPFileSystemObjectType.Folder, null);
if (newFolder != null)
{
newFolder["Name"] = "Name of Folder";
newFolder.Update();
}
Hope this helps somebody :-)
If you're a MOSS guy like me then you'll know all about the MOSS Software Development Kit - and how it could really use.. erm... filling out :-)
Well an updated version of it has just been released (download it here or see it online here), along with one for SharePoint 3.0 too (download it here or see it online here).
As you might know, the Web Service Software Factory includes a Data Access Guidance Package that can generate sprocs, entities and data access components from a database schema - great if, like me, you hate typing all this boring code yourself when you need a nice Data Access Layer to talk to your Database.
Well this functionality was deemed important enough to warrant it's own project, and so now we have The Repository Factory. Worth keeping an eye on!