.NET Developments - A SearchWinDevelopment.com Blog

.NET Developments:

 

A SearchWinDevelopment.com Blog


A blog on all things .NET, with news and tips about Visual Studio, ASP.NET, Visual Basic programming, C# and .NET architecture.

Anonymous Methods - Elegance or Kludge

According to Wikipedia, a kludge (or, alternatively, kluge) is a clumsy or inelegant solution to a problem or difficulty. In engineering, a kludge is a workaround, typically using unrelated parts cobbled together. Especially in computer programs, a kludge is often used to fix an unanticipated problem in an earlier kludge; this is essentially a kind of cruft.

When I first stumbled upon the concept of anonymous methods in C# 2.0 the first thing I thought of was …jeez it’s just another name for GOTO!  I’ve since changed my mind.  Have any of you ever used the Gosub…  Return programming construct from way back in the GW-Basic days?  I’m dating myself but in a former life I had the responsibility of maintaining a servo controller program that ran a servo motor (a DC motor that is capable of moving in programmed increments forward and backward) for a plant that made flour tortillas.  (yes - for Taco Bell no less!)  But I digress.  This particular brand of “Servo Basic” as it was called did not have the ability to address function calls.  It was all done with line numbers.  The program started at 10 and ended at the highest line number.  The only way to program a function in this version of basic was to use the Gosub… Return construct.  For instance “Gosub 100″ would jump to line 100 in the program and start executing code until a “Return” statement was hit then control would return to the line after the calling “Gosub” statement.  It was all very archaic but very versatile when it was all you had. 

Now I tell you that story so I can tell you this one:  I was happily coding one fine day when I encountered a problem that I needed to solve and it occurred to me that a Gosub… Return would be perfect here!  It was a function with lots of values passed in that needed to perform the same processing multiple times but I didn’t want to pass all that data around on the stack.  This, my friends, is the perfect case for an anonymous method.  You can define an anonymous method anywhere inside a function and when you call the method, it has the same scope as the code that defined the method.  The example here uses a SqlDataReader to populate an object.  The reader may or may not have some columns in it.  Since the only way to determine the columns in the reader is to use the GetSchemaTable() function and look at the results, I wrote an anonymous method to perform the search and was able to use the search to check for the existence of the questionable columns. 

Notice the placement of the definition within the function.  It is defined after the definition of the ReaderSchema DataTable.  The executing code in the function has scope at the point of definition and so it “knows” about the DataTable.  The syntax is a little funny but makes sense once you work through it.  The name of the anonymous method is “HasColumn” and can now be called from anywhere in the function after its definition.  It returns a boolean and accepts a string as designated by the delegate it is based upon.

Now I could have simply put the HasColum() in its own function and passed the table in to it along with the column name I’m searching for but then I wouldn’t have this totally cool use of an anonymous method, now would I?  However, the question remains:  elegance or kludge?

VB6 Programmers - What happened to Printer.Print?

This post goes out to all you VB geeks that are wondering what happened to Printer.Print in VB.  This may be a dated topic but I have a feeling there are a few out there longing for those VB6 days when the printer was always sitting there loyal and waiting.  The VB6 programmer’s best friend.  Well, when you needed to print something anyway.   Once upon a time you could just write a few lines of code and *poof* you created a page of information for your users.  Now you have this PrintDocument thing and PrintDialogs and PrintPreviewDialogs and Graphics objects and the list just goes on and on.

Let me re-introduce you to printing in .NET.  Once you get through the slight grade of the learning curve, you’ll be convinced that .Net printing is better than anything you did with the printer object in VB6.

The task - print a smiley face on a piece of paper.  Lines of code in VB6 - about 6.  Lines of code the .net way - about 22 (but you could consolidate…).

That doesn’t sound like a good trade off.  It seems its easier in VB6.  However - what if you wanted to create a bitmap of the smiley face and then use that bitmap in various places as well as print it here and there?  How many line of code do you need now?

 In VB6 - I have no idea.  You would need to drop down to the API level and call graphics functions against a Device Independent Bitmap device context making sure you clean up after yourself in those places where cleanup is necessary.  Then you would need to save that bitmap to a file and/or have an image control somewhere that you could set using the memory bitmap (again using API calls).  Then perhaps you could print the smiley here and there using some similar printing code.

In .NET - its the same 22 lines of code and you can run those lines of code against any “Device Context” (using API terminology) by simply passing a Graphics object to the code that actually creates the smiley.  You could even create a bitmap object and simply use that bitmap throughout your program without ever getting close to the windows API.
Here are my CreateSmiley functions:

private void DrawSmiley(Graphics g, int Width)
{
  Pen p=new Pen(Color.Black);
  SolidBrush b = new SolidBrush(Color.Black);
  SolidBrush YellowBrush = new SolidBrush(Color.Yellow);
  Point Origin = new Point(0, 0);
  Size HeadSize=new Size(Width,Width);
  Rectangle Container=new Rectangle(Origin, HeadSize);
  Point LeftEye=Origin;
  Point RightEye=Origin;
  Point SmileTopLeft = Origin;
  LeftEye.Offset((int)(HeadSize.Width*.25), (int)(HeadSize.Width*.20));
  RightEye.Offset((int)(HeadSize.Width*.65), (int)(HeadSize.Width*.20));
  SmileTopLeft.Offset((int)(HeadSize.Width *.20), (int)(HeadSize.Width * .40));
  Size SmileSize = new Size((int)(HeadSize.Width*.60), (int)(HeadSize.Width*.40));
  Size EyeSize=new Size((int)(HeadSize.Width * .10),(int)(HeadSize.Width * .10));
  g.FillEllipse(YellowBrush, Container);
  g.DrawEllipse(p, Container);
  g.FillEllipse(b, new Rectangle(LeftEye, EyeSize));
  g.FillEllipse(b, new Rectangle(RightEye, EyeSize));
  g.DrawArc(p, new Rectangle(SmileTopLeft, SmileSize), 180, -180);
  b.Dispose();
  YellowBrush.Dispose();
  p.Dispose();
}

private Bitmap CreateSmiley(int Width)
{
  Bitmap Smiley = new Bitmap(Width, Width);
  Graphics g=Graphics.FromImage(Smiley);
  DrawSmiley(g, Smiley.Width);
  g.Dispose();
  return Smiley;
}

Pretty basic stuff and different than you did in VB6. You have access to all the API stuff without dropping down the the API level. Now as far as printing goes - there are a few objects that need your attention. The PrintDocument, PrintDialog, and PrintPreviewDialog objects. The PrintDocument object is the container for all your drawing methods. It handles paging and rendering of the stuff you are printing. The PrintDialog and PrintPreviewDialog objects manage the actual device you are printing to. The PrintDialog as you may have guessed will print to a printer while the PrintPreviewDialog prints to a preview window.

Here is some code that uses a PrintPreviewDialog and calls the printing methods above:

private void button1_Click(object sender, EventArgs e)
{
  PrintDocument pdoc = new PrintDocument();
  // hook up the event handler for the printpage event
  pdoc.PrintPage += new PrintPageEventHandler(pdoc_PrintPage);
  PrintPreviewDialog pdialog = new PrintPreviewDialog();
  pdialog.Document = pdoc;
  pdialog.ClientSize = new Size(640, 480);
  pdialog.Show();
}
void pdoc_PrintPage(object sender, PrintPageEventArgs e)
{
  Bitmap smiley=CreateSmiley(300);
  e.Graphics.DrawImage(smiley, new Point(150, 150));
  e.HasMorePages = false;
}

The VB.Net code is virtually the same. Just change the declaration variables around, change the curly braces to Sub/End Sub, remove the semi-colons and your 80% done.
This method of printing is easy to hook up and offers a great deal of flexibility but if you want real reporting power - there is no substitute for a good reporting engine such as SQL Server Reporting Services or Business Objects’ Crystal Reports. There are others.  I’m a convert.  I was a Crystal Reports bigot but if you’re using a SQL Server database - you get reporting services for free and I must admit after running SQL RS through its paces - I like it better than Crystal Reports.  That, of course, is my opinion.

mysmiley

WCF Certificates, by example

We bought into .NET Remoting early and have quite a few products in place that exploit the .NET Remoting lifestyle. Did I say lifestyle?  Yes. It seems that, once you go remoting, you don’t want to go back — that is, until WCF came along.  It is better (and worse) than remoting.  I won’t go into any comparison here but I do want to show an example of using certificate based security to validate a client process because it is pretty cool.  I’m using my standard Dog Pound example — which, someday, may run humane societies everywhere.

The architecture looks like this:

DogPoundSystem

Both applications are WinForms apps.  The DogServer is configured as the “Host” while DogClient is, you guessed it, the client.  My requirement is to fire up DogClient and talk to the server without logging in but I want to be secure in the fact that I’m being authenticated and authorized.  We can do this with WCF using either an http connection or a tcp connection and either using a self-hosted server or utilizing IIS as the host.  My example is self-hosted because, lets face it, we want that control!

Assuming you have some kind of application architecture set up (download the code and you will) you can make a few minor changes to the config files to enable secure communication between client and host.  Our example will not use https for the transport, but, even so, each message will be encrypted using a certificate.  The first thing we need to do is create some certificates. If you have a Windows domain with a domain controller that you control, it’s fairly easy to get the certificate server service up and running on Windows Server 2003.  For the purpose of this article, we’re using the makecert utility that comes with Visual Studio. Do this:

makecert -n "CN=DogBase" -sk DogBaseKey -pe -sr localmachine -sky exchange -ss TRUST -r DogBase.cer
makecert -n "CN=DogServer" -sk DogServerKey -pe -sr localmachine -ss MY -sky exchange -ic DogBase.cer -is TRUST DogServer.cer
makecert -n "CN=DogClient" -sk DogClientKey -pe -sr localmachine -ss MY -sky exchange -ic DogBase.cer -is TRUST DogClient.cer

After you execute the third makecert statement you should see DogClient and DogServer certificates in the personal store of [Local Computer]. Use the mmc certificate snap-in to view your certificates. You may need to copy the certificate from the Enterprise Trust store to the Trusted Root Certification Authorities store before things will work for you. I’m not a certificate guru by any means and getting this little sample running in a repeatable process was not the easiest thing i’ve ever done.

We’re finally ready to test some code.  If you downloaded the code then you have everything you need to perform a test.  If not then you need to modify your configuration files to use certificates and transport security as follows:

Click here to see the client config file

Click here to see the server config file

Click here to download the sample code

Some things to note about using makecert for your certificates:  It is easy to get things set up and it provides a good learning experience for certificates but the certificates created should not be used in a production environment. There are also a few caveats. I had to configure the client and server to use PeerTrust on each other’s certificates instead of the default ChainTrust (see the config files). I believe this is partly because I’m using makecert for my certificates and partly becaues my computer is part of a windows domain. I didn’t have this trouble when using certificates issued by the certificate authority from my domain controller. For similar reasons, I had to set the negotiateServiceCredential to false and supply the service certificate in the client configuration.

In a future post I will dive into Mixed-Mode security where we use https for the transport and encrypt the messages.

TFS to the rescue — almost

(Editor’s note: This is the first blog post by Christopher Yager, who will be writing on the .NET Developments blog from time to time. Yager is chief software architect at GLD Solutions Inc. and is currently using .NET 2.0 for his new development projects. Here he will blog about topics such as Windows Communication Foundation, Team Foundation Server and SQL Server. Welcome aboard, Chris!)

Before I get into this — welcome to my blog.  I’ll be posting mainly about my adventures in .NET programming — feedback is welcome.  I’m no guru but I did stay at a Holiday Inn Express last night.  (Actually as I write I’m still at said Holiday Inn… )

So TFS (Team Foundation Server), Microsoft’s answer to the software lifecycle management problem, really is a great product.  My team uses most features on a daily basis.  My headline is somewhat misleading but allow me some latitude while I state my case.  I run a software development company.  We produce software products and we have customers that use them.  (Go figure.)  We have a QA staff.  We test our products.  TFS has no way to capture the guts of a user defined test against a product that tests a particular requirement.  Specifically we needed to save metrics of test runs with success and failure rates, reasons for failure, environments tested, and lot of other neat stuff.  I didn’t expect TFS to have all this rich user testing goo so I expected we’d roll our own.  This article is about how we connected our hand-rolled testing metrics program with our Team Foundation Server.

The problem:  A scenario test fails; a bug is created against a product/task/whatever and needs to be linked to the test that caused the problem.

The Solution:  The TFS API!

Team Foundation Server has a plethora of components that you can leverage allowing seamless integration with the back end of your TFS implementation.  These components are found in the following path normally: 

[Program Files Root]\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies

**Client requirement: On any system you install your custom TFS linked software, Team Explorer must be installed.  An obvious server requirement is that you have a Team Foundation Server installed somewhere in your network or available via the Web.  If you’re interested in getting TFS running (and why wouldn’t you be?!) you can download a trial from Microsoft.

Our general requirement for this task was to view a list of active bugs for a team project and allow selection of one. 

OK — some meat for you code monkeys. 

Create a windows forms project in your favorite language.  Mine is C# but any .NET language will do.

Add references to the following assemblies.  You’ll need to browse for them since they are not in the GAC or otherwise registered for easy VS reference adding.  The image shows them all together but this is a doctored image to save space.

tfs references

Put a tab control on the form and set it to dock-fill (leave the 2 tab pages alone), size the form to 800X600 (this just saves us some time and coding).

We’re basically going to create two functions that perform the guts of the scenario.  The GetWorkItems function which utilizes the DomainProjectPicker dialog class to allow the user to select the team project they wish to examine and the PickWorkItemsControl user control which allows searching of the TFS work item store. 

                   

private void GetWorkItems()
{
    DomainProjectPicker dpp = new DomainProjectPicker();
    DialogResult dr = dpp.ShowDialog(this);
    if (dr == DialogResult.OK)
    {
        tfs = dpp.SelectedServer;
        tfsProject = dpp.SelectedProjects[0];
        this.Text = "My Team Foundation Link - " + tfsProject.Name;
        Store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
        TeamProject = Store.Projects[tfsProject.Name];
        pw = new PickWorkItemsControl(Store);
        pw.Dock = DockStyle.Fill;
        pw.PortfolioDisplayName = TeamProject.Name;
        this.tabPage1.Controls.Add(pw);
        pw.PickWorkItemsListViewDoubleClicked +=
            new PickWorkItemsListViewDoubleClickedEventHandler(
            pw_PickWorkItemsListViewDoubleClicked);
    }
}

The InitWorkItemControl function allows the user to view the details of a selected work item and utilizes the WorkItemFormControl control.


private void InitWorkItemControl()
{
    this.WorkItemControl = new WorkItemFormControl();
    this.WorkItemControl.Dock = System.Windows.Forms.DockStyle.Fill;
    this.WorkItemControl.FormDefinition = null;
    this.WorkItemControl.Item = null;
    this.WorkItemControl.LayoutTargetName = "WinForms";
    this.WorkItemControl.Name = "WorkItemControl";
    this.WorkItemControl.Size = new System.Drawing.Size(683, 428);
    this.WorkItemControl.TabIndex = 0;
    this.tabPage2.Controls.Add(this.WorkItemControl);
} 

We’ll tie this all together in the constructor for the form:


public Form1()
{
    InitializeComponent();
    InitWorkItemControl();
    GetWorkItems();
}

Here is what the finished product looks like: (This is an out-of-the-box dialog,  I didn’t write any of it.)
tfsConnect

The search control on this form does not have any of my code in it.  I only provided the tab control for it to live in.
tfssearch
The dialogs and controls exposed by the TFS API take care of the majority of the user interface, we just need to hook the stuff together with a little glue.  You can download the sample solution which has both C# and VB .NET versions of the program. 

Special thanks to Brian Randell who taught me this stuff through an article on MSDN Magazine.

 Download the source code here