Easily determining if the mouse is over a control (WinForms)


So, I’m working up a slick little WinForms application for a client and in the process, creating a custom UI to make things “pretty”.  I’m swapping out images in a picture box, based on if the mouse is entering or leaving, up or down, etc, etc.

Strange thing happened with one of my picture boxes however… when the user clicks on the picture box, it opens up a dialog.  The user interacts with the dialog, and the image isn’t correct based on the supposed position of the mouse in relation to the picture box.

I had attached my image manipulation routines to the following events:

  • Mouse Enter – Load Mouse Over image
  • Mouse Leave – Load Mouse Out image
  • Mouse Down – Load Mouse Down Image
  • Mouse Up – Load Mouse Over Image

That all worked out well.. then I attached a dialog to the Click event of the picture box.. here’s what happened:

  • Mouse Enter – Load Mouse Over Image
  • Mouse Down – Load Mouse Down Image
  • Mouse Click – Load the dialog
  • User interacts with the dialog
  • Mouse Up – Load Mouse Over Image

The problem here is.. the mouse is no longer over the picture box.  The showing of the dialog suspends the control events fired while that dialog is active.. once the dialog goes away, the control events continue to fire, thus loading the mouse over image, even though the mouse is no longer over the picture box (cause it was moved while the user interacted with the dialog)

I needed a simple way to test to see if the mouse pointer was over the picture box.  This would allow me to check and see if I need to change an image during an event or not (or default to the “normal mouse out” image).

MousePosition

The MousePosition property returns a Point that represents the mouse cursor position at the time the property was referenced. The coordinates indicate the position on the screen, not relative to the control, and are returned regardless of whether the cursor is positioned over the control. The coordinates of the upper-left corner of the screen are 0,0.

That’s all well and good.. but that controls top, left, width and height are relative to the container (or containing form)…

PointToScreen()

Simply put, PointToScreen takes a given Point, and translates that point into screen coordinates.

Putting it all together

So now we can take what we’ve learned.. and create a simple little helper method to check if the mouse is currently over any control we want:

private static bool IsMouseOver(Control ctl)
{
if (MousePosition.IsEmpty) return false;
var frmOrigin = new Point(0, 0);
var ctlRect = new Rectangle(ctl.PointToScreen(frmOrigin), ctl.Size);
return ctlRect.Contains(MousePosition);
}

Let’s take it a step further and create an extension method for control to test if the control’s rectangle contains a given point..

public static class ControlExtensions
{
/// <summary>
/// Determines whether the specified point exists within the given controls Rectangle
/// </summary>
/// <param name="ctl">The Control.</param>
/// <param name="point">The point.</param>
/// <returns>
/// <c>true</c> if the specified CTL contains point; otherwise, <c>false</c>.
/// </returns>
public static bool ContainsPoint(this Control ctl, Point point)
{
if (point.IsEmpty) return false;
var origin = new Point(0, 0);
var ctlRect = new Rectangle(ctl.PointToScreen(origin), ctl.Size);
return ctlRect.Contains(point);
}
}


Which makes our final event code, very tight :)

private void picBoxFolder_MouseUp(object sender, MouseEventArgs e)
{
if (picBoxFolder.ContainsPoint(MousePosition))
picBoxFolder.Image = GetFolderImage(FolderButtons.Up);
}


author: Jason Monroe | posted @ Wednesday, October 28, 2009 4:23 PM | Feedback (1)

Examining Skip() and Fetch() with Linq and Entity Framework


So I heard a rumor, that Linq did some pretty need things with pushed up against SQL Server with regards to doing smart and efficient server side pagination of your queries.  I wanted to play around with things and see what I could discover…

The Setup

I created a simple data table, called.. TestData.

  1. CREATE TABLE [dbo].[TestData](
  2.     [Id] [int] IDENTITY(1,1) NOT NULL,
  3.     [TestStringIndexed] [varchar](50) NOT NULL,
  4.     [TestDateIndexed] [datetime] NOT NULL,
  5.     [TestNumberIndexed] [int] NOT NULL,
  6.     [TestStringNonIndexed] [varchar](50) NOT NULL,
  7.     [TestDateNonIndexed] [datetime] NOT NULL,
  8.     [TestNumberNonINdexed] [int] NOT NULL,
  9. CONSTRAINT [PK_TestData] PRIMARY KEY CLUSTERED
  10. (
  11.     [Id] ASC
  12.   )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS= ON) ON [PRIMARY]
  13. ) ON [PRIMARY]
  14.  
  15. GO

Then, I used my handy dandy RedGate Data Generator (No affiliation, just a happy customer) to insert a million records into my test table.

After that, I created a simple Entity Data Model for my one single table :)

captured_Image.png

With my model set up, I created a simple repository (following one of the billion of samples of the repository pattern found on the interwebs).  Since I’m just testing the skip and take, I only needed a simple fetch…

using System.Collections.Generic;
using System.Linq;

public interface ITestDataRepository
{
TData Fetch(int id);
IEnumerable<TData> FetchAll();
}

public class TestDataRepository : ITestDataRepository
{
private BlogTestingEntities _entities = new BlogTestingEntities();

public TData Fetch(int id)
{
return (from o in _entities.TDataSet
where o.Id == id
select o).FirstOrDefault();
}

public IEnumerable<TData> FetchAll()
{
return _entities.TDataSet.ToList();
}
}

Next was to set up a simple service that my application could call to get the test data (again, following any one of the billion examples)..

using System.Collections.Generic;
using System.Linq;

public interface ITestDataService
{
TData Fetch(int id);
IEnumerable<TData> FetchAll();
}

public class TestDataService : ITestDataService
{
private readonly ITestDataRepository _repository;

public TestDataService() : this(new TestDataRepository()){}

public TestDataService(ITestDataRepository repository)
{
_repository = repository;
}

public TData Fetch(int id)
{
return _repository.Fetch(id);
}

public IEnumerable<TData> FetchAll()
{
return _repository.FetchAll();
}
}

Finally, I made my application consume the service…

using System;
using System.Diagnostics;
using System.Linq;

class Program
{
static void Main(string[] args)
{
Write("Welcome to the Linq Skip/Take Test Application");
var svc = new TestDataService();
var watch = new Stopwatch();
Write("Fetching All Records [FetchAll()]");
watch.Start();
var allFetched = svc.FetchAll();
watch.Stop();
Write(" Total Records Returned : " + allFetched.Count());
Write(" Record Start Index : " + allFetched.First().Id);
Write(" Record End Index : " + allFetched.Last().Id);
Write(" Total Time : " + watch.ElapsedMilliseconds);
Write();

Write("Press any key to exit...");
Console.ReadKey(true);
}

private static void Write()
{
Console.WriteLine();
}

private static void Write(string msg, params string[] args)
{
Console.WriteLine(msg, args);
}
}

Quick Click of run and keeping an eye on SQL Profiler let’s us know everything is happening right and just as we expected (I’m fetching every record from the table)

captured_Image.png[1]

SELECT 
[Extent1].[Id] AS [Id],
[Extent1].[TestStringIndexed] AS [TestStringIndexed],
[Extent1].[TestDateIndexed] AS [TestDateIndexed],
[Extent1].[TestNumberIndexed] AS [TestNumberIndexed],
[Extent1].[TestStringNonIndexed] AS [TestStringNonIndexed],
[Extent1].[TestDateNonIndexed] AS [TestDateNonIndexed],
[Extent1].[TestNumberNonINdexed] AS [TestNumberNonINdexed]
FROM [dbo].[TestData] AS [Extent1]

Testing the Pagination

So, now it’s time to move forward with our testing of our handy skip and fetch methods to see what kind of damage we can do progress we can make!

First off, extend our program to make use of the overloaded FetchAll method to specify a page index and size:

watch.Reset();
Write("Fetching All Records [FetchAll(4, 100)]");
watch.Start();
var allFetchPaged = svc.FetchAll(4, 100);
watch.Stop();
Write(" Total Records Returned : " + allFetchPaged.Count());
Write(" Record Start Index : " + allFetchPaged.First().Id);
Write(" Record End Index : " + allFetchPaged.Last().Id);
Write(" Total Time : " + watch.ElapsedMilliseconds);
Write();

Click Run and watch our results..
captured_Image.png[3]
So we see that we’ve only got 100 rows returned as expected, with the starting index at 401 and ending at 500… And it took considerably less time to retrieve the results!  But wait!  Profiler reports that the query passed to SQL server is EXACTLLY the same as before.  So now I’m starting to speculate, that the Entity Framework is counting the records returned and stopping the query once it’s retrieved enough to satisfy the results.  Let’s test by changing our page index to 9,999…
captured_Image.png[5]
Ok.. so that still leaves us puzzled… it’s even faster this time getting the tail end of the results as it was before.  But still showing the exact same query as the original FetchAll() method.  Let’s swap them around so the page query is first, still on the last index page of the pagination..
captured_Image.png[11]
AH HA!  So the Entity Framework must be doing some wicked clever caching of our results some how to help protect us from ourselves!  But why doesn’t the paging happen on the server like I was lead to believe?

The Magic of OrderBy

When reading the example How to: Return or Skip Elements in a Sequence (LINQ to SQL) There’s a quick little blurb at the bottom, that’s almost non-noteworthy:

The following example uses Take to select the first five Employees hired. Note that the collection is first sorted by HireDate.

So.. let’s go ahead and modify our service to include this handy little bit of information

public IEnumerable<TData> FetchAll(int pageIndex, int pageSize)
{
var startIndex = (pageIndex * pageSize);
return _repository.FetchAll().OrderBy(o => o.Id).Skip(startIndex).Take(pageSize);
}

And run our results:

captured_Image.png[13]

And the query is the same as before as well…

Cut to the chase will ya?

The problem comes from how we’ve derived our repository…

The FetchAll() method in our repository is simply defined as:

public IEnumerable<TData> FetchAll()
{
return _entities.TDataSet.ToList();
}

So what we’re returning from the repository is an already run query on the _entities.TDataSet saying “Give me all of your records, and transform them to this handy dandy enumerable list”.  Then the service is responsible for taking that list and carving it up for the desired results (.OrderBy().Skip().Take())

At this point, you have two choices…

1. Move the pagination into the repository

using System.Collections.Generic;
using System.Linq;

public interface ITestDataRepository
{
TData Fetch(int id);
IEnumerable<TData> FetchAll();
IEnumerable<TData> FetchAllPaged(int pageIndex, int pageSize);
}

public class TestDataRepository : ITestDataRepository
{
private BlogTestingEntities _entities = new BlogTestingEntities();

public TData Fetch(int id)
{
return (from o in _entities.TDataSet
where o.Id == id
select o).FirstOrDefault();
}

public IEnumerable<TData> FetchAll()
{
return _entities.TDataSet.ToList();
}

public IEnumerable<TData> FetchAllPaged(int pageIndex, int pageSize)
{
var startIndex = pageIndex*pageSize;
return _entities.TDataSet.OrderBy(o => o.Id).Skip(startIndex).Take(pageSize);
}
}

using System.Collections.Generic;
using System.Linq;

public interface ITestDataService
{
TData Fetch(int id);
IEnumerable<TData> FetchAll();
IEnumerable<TData> FetchAllPaged(int pageIndex, int pageSize);
IEnumerable<TData> FetchAll(int pageIndex, int pageSize);
}

public class TestDataService : ITestDataService
{
private readonly ITestDataRepository _repository;

public TestDataService() : this(new TestDataRepository()){}

public TestDataService(ITestDataRepository repository)
{
_repository = repository;
}

public TData Fetch(int id)
{
return _repository.Fetch(id);
}

public IEnumerable<TData> FetchAll()
{
return _repository.FetchAll();
}

public IEnumerable<TData> FetchAllPaged(int pageIndex, int pageSize)
{
return _repository.FetchAllPaged(pageIndex, pageSize);
}

public IEnumerable<TData> FetchAll(int pageIndex, int pageSize)
{
var startIndex = (pageIndex * pageSize);
return _repository.FetchAll().OrderBy(o => o.Id).Skip(startIndex).Take(pageSize);
}
}


captured_Image.png[17] 

Finally!  We’ve got improvements in our results and an optimized query from Profiler!

SELECT TOP (100) 
[Extent1].[Id] AS [Id],
[Extent1].[TestStringIndexed] AS [TestStringIndexed],
[Extent1].[TestDateIndexed] AS [TestDateIndexed],
[Extent1].[TestNumberIndexed] AS [TestNumberIndexed],
[Extent1].[TestStringNonIndexed] AS [TestStringNonIndexed],
[Extent1].[TestDateNonIndexed] AS [TestDateNonIndexed],
[Extent1].[TestNumberNonINdexed] AS [TestNumberNonINdexed]
FROM ( SELECT [Extent1].[Id] AS [Id], [Extent1].[TestStringIndexed] AS [TestStringIndexed], [Extent1].[TestDateIndexed] AS [TestDateIndexed], [Extent1].[TestNumberIndexed] AS [TestNumberIndexed], [Extent1].[TestStringNonIndexed] AS [TestStringNonIndexed], [Extent1].[TestDateNonIndexed] AS [TestDateNonIndexed], [Extent1].[TestNumberNonINdexed] AS [TestNumberNonINdexed], row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number]
FROM [dbo].[TestData] AS [Extent1]
) AS [Extent1]
WHERE [Extent1].[row_number] > 999900
ORDER BY [Extent1].[Id] ASC

 
The thing I *DON’T* like about this solution.. is now the repository has been infected with what I consider to be business logic.  IMHO, the repository shouldn’t care what I want to order my results by, or how to determine what my start and stop is for my page index.  I believe that should go into the business layer (service).  So having said that…

2. Change the return type from FetchAll in the repository

Instead of returning IEnumerable<T> from the respository method, let’s go ahead and return IQueryable<T> so that we can let the business layer apply it’s logic straight to the query builder..

public IQueryable<TData> FetchAllQ()
{
return _entities.TDataSet;
}

Then, in the service layer, consume it..
public IEnumerable<TData> FetchAllQ(int pageIndex, int pageSize)
{
var startIndex = (pageIndex * pageSize);
return _repository.FetchAllQ().OrderBy(o => o.Id).Skip(startIndex).Take(pageSize);
}


The end result is the same…  We’ve got an optimized query being build and passed to the server so we’re effectively using server side paging to get our data. Since we’ve exposed the IQueryable interface from the repository, we’re allowing our business layer to (oddly enough) make business decisions on how that data is requested from the repository.  We’re still maintaining our separation of responsibilities, because the repository is the one that is actually acting as the DAL (ok, the Entity Framework is, but let’s not split hairs).

author: Jason Monroe | posted @ Tuesday, October 06, 2009 8:55 PM | Feedback (0)

Scott Hanselman's 2009 Ultimate Developer and Power Users Tool List for Windows


If your a developer.. if your a power user.. if you own a computer.  If you’ve ever turned on a computer.  If you’ve ever walked by a computer display at your local do-everything-sell-everything retailer.. Then you owe it to yourself to check out:

Scott Hanselman's Computer Zen - Scott Hanselman's 2009 Ultimate Developer and Power Users Tool List for Windows

That’s right folks.. After taking a year off and missing the 2008 update, Scott is back with a vengeance with his tools and utilities list.  Make sure you check it out!

If you want to link to his tools list (and why wouldn’t you) make sure you use his perm link here: http://www.hanselman.com/tools

author: Jason Monroe | posted @ Wednesday, September 02, 2009 10:37 AM | Feedback (0)

Creating a custom MSBuild Task for TFS Build


Our project has been making use of Subversion for our source control and JetBrains Team City for our continuous integration / deployment solution for a few years now.  I have always been happy with the flexibility that this solution has offered for us and would highly recommend that combination to anyone who is in need of a quality SCM / CI package.  In short, it just works.

Having said that, the “powers that be” have determined that we’re going to make the switch to Team Foundation Server. Now I’ve got nothing against TFS.  It is a fine product that has some outstanding workflow capabilities with regards to issue tracking, change management, etc, etc, etc.  My only issue was with the price of the thing (why I did not implement it in the first place).  Well, with our project being absorbed back into “the main office”, I no longer have the luxury of being the “renegade” and doing things my way, so it’s time to integrate what we’ve been doing all long with SVN/TC into TFS.

One of the tasks that we’ve created and utilized in SVN/TC creates a .zip archive of the pre-compiled website and SQL scripts that need to be deployed to the target environment.  Now the original task had some hard coded paths and values established in it (since it was only used by my project anyway) so I decided to make it a little more generic and robust so that it could be reused by other teams and projects.

A little thought goes a long way…

MSBuild tasks are automation tools.  That is to say, they are designed to automate processes that you would do by hand and run them at the proper time during the act of building your software.  As with any automation or integration processes that you develop, a bit of forethought into the tasks that you’re actually trying to accomplish will go a LONG way in the development of your own task.  During the development of this task, the first thing I did was to determine what exactly I wanted out of this automated process, and how I could make it generic enough to be reused for any project at any time.

1. The end result of the task should be a .zip file.

Simple enough right.  When you’re working with .Zip the de-facto standard in re-usable open source libraries is SharpZipLib. I’ve used it before in the past, I’ll use it on this project, and I’ll use it on future projects.  In short, it’s awesome.

2. I need the capability to name my final zip file whatever I want

It wouldn’t be very flexible if the end result of the build task was always “outputFile.zip”.  What if I wanted to name my zip file with the build number, changeset number, date stamp or the name of my favorite goldfish?  No.. Obviously, I need to include a property with my build task that lets me specify the file name my archive will be at the end of the day.

3. I need to specify where the output file will land

Just like with the file name, I’m going to need the ability to specify where the output archive will end up.  By allowing this information, we make the build task more generic and able to write our end archives to a deployment path, long term storage, web server or any other shared location as desired.

4. I want to be able to build my archive however I want!

This particular requirement is a biggie and the reason for the re-write to begin with.  The old version of the task took the pre-compiled website and dropped them in a ~\wwwroot folder of the archive and the SQL Scripts into a ~\scripts folder of the archive.  While this worked great for our build and deployment project, it didn’t allow for any outside usages.  For example, if another project wanted to make use of our build task, but they also wanted to include some files into a ~\documents path of the archive, they would be out of luck.  So I need to come up with a way to have the structure of the end archive configurable.

5. I need to specify a “working” folder where my archive is to be assembled

Having used SharpZipLib in the past, I’ve learned the easiest way to work with it (though, not the only way of course) is to point it at a single folder and say “go to town”.  That being the case, I decided that as part of the whole archive creation process, the files and folders that were to be added to the archive would first be copied into a “working” folder.  This would allow for the simple use of SharpZipLib.

6. I don’t want working process files left hanging around… or do I?

My original thought was to kill the working folder where the archive was assembled once the .zip file was created.  But then I thought about it and decided that in doing so, I was dictating how other teams might have to work with the task.  So I made the “CleanAfterBuild” property that can be set in configuration to allow for the task to clean up after itself.. or not.

But what about point number 4?

Looking at the MSDN documentation for MSBuild Properties I ran across this little paragraph:

Properties can contain arbitrary XML, which can aid in passing values to tasks or displaying logging information. The following example shows the ConfigTemplate property with a value containing XML and other property references. MSBuild replaces the property references with their respective property values. Property values are interpreted from top to bottom, so in this example, $(MySupportedVersion), $(MyRequiredVersion), and $(MySafeMode) should have already been defined.

<PropertyGroup>
<ConfigTemplate>
<Configuration>
<Startup>
<SupportedRuntime
ImageVersion="$(MySupportedVersion)"
Version="$(MySupportedVersion)"/>
<RequiredRuntime
ImageVersion="$(MyRequiredVersion)
Version="
$(MyRequiredVersion)"
SafeMode="
$(MySafeMode)"/>
</Startup>
</Configuration>
</ConfigTemplate>
</PropertyGroup>

This lead me to the understanding that based on this knowledge, I could specify the structure of my final archive in XML.  So, the end result would look something like this:

<PropertyGroup>
<CreateArchiveTemplate>
<ArchiveDefinition>
<ArchivePackage>
<PackageSource>$(BinariesRoot)\Release\_PublishedWebsites\WebSite</PackageSource>
<PackageTarget>~\wwwroot</PackageTarget>
</ArchivePackage>
<ArchivePackage>
<PackageSource>$(SolutionRoot)\SQLScripts\Implementation</PackageSource>
<PackageTarget>~\Scripts</PackageTarget>
</ArchivePackage>
<ArchivePackage>
<PackageSource>$(SolutionRoot)\Documents</PackageSource>
<PackageTarget>~\docs</PackageTarget>
</ArchivePackage>
</ArchiveDefinition>
</CreateArchiveTemplate>
</PropertyGroup>

Making the task

I like to keep all of my custom MSBuild tasks in their own assembly.  That being said, I also like them all to be under the same namespace.  So the first thing I do is setup my project properties to look like this:

captured_Image.png

Then I set up my references:

captured_Image.png[6]

Since all of the development that we do is targeting the 3.5 framework, I’ve referenced the 3.5 versions of MSBuild as well.

The CreateArchive Class

Starting out with the shell of the class, first thing we do is inherit from Task and define our properties that get exposed to the MSBuild configuration script:

public class CreateArchive : Task
{

[Required]
public string ArchiveName { get; set; }

[Required]
public string OutputPath { get; set; }

[Required]
public string WorkingPath { get; set; }

[Required]
public string Contents { get; set; }

public string CleanAfterBuild { get; set; }

private bool CleanWorking
{
get
{
switch (CleanAfterBuild.ToUpper())
{
case "YES":
case "OK":
case "TRUE":
return true;
default:
return false;
}
}
}

public override bool Execute()
{
throw new NotImplementedException();
}
}

We can make a little helper method to get our working directory based on the property passed in..

private DirectoryInfo GetCleanWorkingDirectory()
{
if (Log.HasLoggedErrors)
return null;

// clean/create our working directory
var diWorking = new DirectoryInfo(WorkingPath);
if (diWorking.Exists)
diWorking.Delete(true);
diWorking.Create();
return diWorking;
}

And another that will parse our XML passed into Contents and build our archive definition:

private void BuildArchiveStructure(FileSystemInfo diArchive)
{
Log.LogMessage(MessageImportance.High, "Building the archive package structure...");
try
{
var xDoc = new XmlDocument();
xDoc.LoadXml(Contents);
var nsmgr = new XmlNamespaceManager(xDoc.NameTable);
var xRoot = xDoc.DocumentElement;
if (xRoot == null)
{
Log.LogError("Null Xml Document Element");
return;
}
if (xRoot.Attributes["xmlns"] != null)
{
var nspace = xRoot.Attributes["xmlns"].Value;
nsmgr.AddNamespace("pkg", nspace);
}

var packages = xRoot.SelectNodes(MetaKeys.ArchivePackage, nsmgr);
if (packages == null)
{
Log.LogError("Could not find any package definitions in the configuration");
return;
}
Log.LogMessage("{0} package definitions to process..", packages.Count);
foreach (XmlNode package in packages)
{
var srcNode = package.SelectSingleNode(MetaKeys.PackageSource, nsmgr);
var tgtNode = package.SelectSingleNode(MetaKeys.PackageTarget, nsmgr);
if (srcNode == null || tgtNode == null)
{
Log.LogError("Could not locate the PackageTarget or PackageSource nodes for the archive definition");
break;
}
var target = tgtNode.InnerText;
if (target.StartsWith(@"~\"))
target = target.Substring(2);
target = Path.Combine(diArchive.FullName, target);
var diSource = new DirectoryInfo(srcNode.InnerText);
var diTarget = new DirectoryInfo(target);
if (!diTarget.Exists) diTarget.Create();
Log.LogMessage("
{2} Processing ArchivePackage [{0}] -> [{1}]", diSource.FullName, diTarget.FullName, DateTime.Now.ToShortTimeString());
diSource.CopyAll(diTarget, true);
}
}
catch(Exception ex)
{
Log.LogErrorFromException(ex);
}
}

It should be noted that the “CopyAll” method of the DirectoryInfo object is not part of the core framework.  It is rather an extension method that I’ve included in the source archive of this task that you can download below.

The helper method to create is the one that will generate the archive:

private void BuildArchiveFile(FileSystemInfo diArchive)
{
// create our zip archive in the root of the working path
var archiveFile = Path.Combine(OutputPath, ArchiveName);
if (Log.HasLoggedErrors) return;
// make sour our putput path exists
var diOutput = new DirectoryInfo(OutputPath);
if (!diOutput.Exists)
diOutput.Create();
// make the zip file
var fZip = new FastZip { CreateEmptyDirectories = true };
fZip.CreateZip(archiveFile, diArchive.FullName, true, "");
}

Finally we can build out our Execute() method:

public override bool Execute()
{
Log.LogMessage(MessageImportance.High, "Starting CreateArchive Custom Task [{0}]", DateTime.Now.ToShortTimeString());
Log.LogMessage("Using Configuration:");
Log.LogMessage("{0}", Contents);
try
{
var diWorking = GetCleanWorkingDirectory();
if (diWorking == null)
return false;

// build our working archive structure
BuildArchiveStructure(diWorking);

// build our archive file and move it to where it belongs
BuildArchiveFile(diWorking);

// clean our working directory if needed
if (CleanWorking) diWorking.Delete(true);
}
catch (Exception ex)
{
Log.LogErrorFromException(ex);
}

Log.LogMessage("{0} Finished CreateArchive Custom Task...", DateTime.Now.ToShortTimeString());
return !Log.HasLoggedErrors;
}

Download the Binaries, Source and Help Documentation

author: Jason Monroe | posted @ Monday, August 24, 2009 4:24 PM | Feedback (0)

Use the force Luke?


Rob Conery recently made a post (Be a Good Jedi: Build Your Own Blog « Rob Conery) about his continued dissatisfaction with his current blog engine of choice.  This is not the first time that he’s posted about not liking things.. from Community Server, to ORM tools, etc.  Yes, Rob can be opinionated and has no qualms about voicing his opinions out in the open.

Agree or disagree, you’ve got to respect him for at least that much.

However, on this topic, I’m not so sure.  I use SubText as my engine of choice.. I have for years.  Of course, there’s Jeff Atwood who’s totally in love with Movable Type. Don’t forget about Mads Kristensen and his wildly popular DotNetBlogEngine.

And then there’s hosted blog engine platforms like TypePad, Blogger and LiveJournal.

What I really don’t understand.. what feature is it that Rob is after that he can’t possibly find from the plethora of results found from a quick minute search on Google for “Blog Engine Software”?

He goes on to give some reasons why he thinks it’s a good idea:

  1. It’s the perfect app for a geek who wants a blog to build – they’re the perfect domain experts
  2. It’s easy (for the most part) but gets harder and harder the farther in your dive
  3. It’s ubiquitous. What a perfect interview topic: “I’d love to see how you handled asynchronous pings to Technorati and – oh – do you have a POP feature? Also – did you use MetaWeblog or Wordpress?”
  4. It’s your calling card. If your blog rocks – likely you do too. If it sucks and it’s slow – well…
  5. It’s a great way to learn a language. Want to try out ASP.NET MVC? Compare the LOC and features to your Webforms blog – then try Rails…
  6. Luke did it – and that’s good enough for me

However, he doesn’t say why he thinks the other engine software is not up to his standards or what features he’s missing.  That being the case, I just took it as a half baked vent and the start of another project that won’t make it past beta release.

But then he “gone and done did it”!

I’ll keep it on GitHub if you want to see it but I challenge you to do the same. Why not? It’s a great bit of sidework and who knows what could come of it…

The gauntlet has been thrown down!  He might as well said “I double dog dare ya!”

That also got me thinking about a reoccurring theme that Jeff Atwood has been blogging about and building your own personal brand.

I realize that 95% of the code that I write (and I write ALOT of code) is never seen by anyone other than the handful of developers that I hand picked to be on my team.  I don’t have a true branding strategy, public persona, accepted presence or source of reference that potential employers can seek out.  In this day and economy, there seems to be a need to some how, some way set yourself “above the pack”.  I’ve not done a good job there.

Yea, I’ve got my blog.  I don’t update it nearly enough.

Yea, I’ve got an article on CodeProject. I really should create more.

Yea, I’ve got some reputation points on StackOverflow. I need to be more active.

All in all, when it comes to building my “personal brand”.  I fail.  Perhaps, creating Yet Another Blog Engine would be a vehicle to act as the catalyst in jump starting my ambition to brand.  Maybe I’ll even get so far as to develop something past beta release.

So Mr. Conery, I accept your challenge!  I shall build the better mousetrap blog engine that you so desire!  I shall be chocked full of awesomeness, the stars shall align, angels will sing and global peace shall spring forth!

If only I could come up with a name….

author: Jason Monroe | posted @ Friday, August 14, 2009 10:11 AM | Feedback (1)

Using 32bit COM objects in 64bit IIS


So we’ve upgraded our web farm to Windows Server 2003 x64, and in the process established IIS to run in native x64 mode.  That part went like butter.

The problem is that portions of our web application rely on some various 3rd party 32bit objects.  Of course, while x64 windows itself can host a 32bit process, a 64bit process can not instantiate a 32bit process.  That is to say, while IIS is running in x64 mode, it can’t load and make calls to a 32bit object.

After contacting the various vendors of our 3rd party objects, we were told that it would be months, years or never for the release of native x64 versions of these objects.  Of course, that just won’t do.  Here is how we were able to resolve the issue and still maintain all of the functionality we had with the 32bit version of our software in 64bit mode:

.Net Remoting to the Rescue

Knowing that windows itself could spawn a 32bit process, and that process would have access to the 32bit objects, the decision was made to create a windows service to host the 32bit objects.  With the windows service responsible for the creation of the objects and calling the methods of those objects, then it was simply a matter of marshalling the calls to the windows servers across the x64 <-> x86 boundary.

x32-x64_Remoting_Overview

What we end up with is actually three separate projects.  We’ve got our original web solution project, we’ve got a new Windows Service project (which is the remoting host) and we’ve got a shared assembly between the two that holds the interface contract (and the result object that’s marshaled back, but we’ll get into that later).

Working from the Server to the Client

All of the samples and examples that I was able to find using Google and MSDN dealt with making calls from the client and executing work on the server, but no real emphasis was given to returning usable and tangible results to the client from the server. One of the things I discovered along the way was exceptions are not accurately marshaled across the machine boundary.  More importantly, if you raise an exception from the remote service, then that service no longer seems to respond to subsequent requests. 

Creating the shared interface & assembly

In looking back at the diagram above, It’s apparent that the client has to know how to talk to the service, and the service needs to know how to talk to the client.  That is to say that when the server calls something an apple, then the client has to know what an apple looks like.  If the client didn’t know what an apple looked like on the server, then it wouldn’t know if it should put it in the orange or lemon basket.

The best way to describe an object between two separate systems is with the usage of a shared interface.   So what we did was to create a separate lightweight assembly to house the common interfaces that both the client and server can consume and use. 

Dealing with our results first

During the process of developing the solution, we found that if we raised an exception from our service, that exception was not marshaled to the client.  Instead a remoting exception was raised.  Another caveat of throwing an exception from the service was that after the exception was called, the service would fail to respond to subsequent requests.  Due to this discovery, it was decided that we would return a common “Result” object from all of our remote method calls. 

   1: /// <summary>
   2: /// provides a common generic interface for all remoting return calls
   3: /// </summary>
   4: /// <typeparam name="T"></typeparam>
   5: public interface IRemoteResult<T>
   6: {
   7:     /// <summary>
   8:     /// Gets a value indicating whether this <see cref="IRemoteResult&lt;T&gt;"/> result is successful or failed.
   9:     /// </summary>
  10:     /// <value><c>true</c> if success; otherwise, <c>false</c>.</value>
  11:     bool Result { get; }
  12:     /// <summary>
  13:     /// Gets the value of the result.
  14:     /// </summary>
  15:     /// <value>The value.</value>
  16:     T Value { get; }
  17:     /// <summary>
  18:     /// Gets the error message.
  19:     /// </summary>
  20:     /// <value>The error message.</value>
  21:     string ErrorMessage { get; }
  22:     /// <summary>
  23:     /// Gets the result exception.
  24:     /// </summary>
  25:     /// <value>The result exception.</value>
  26:     Exception ResultException { get; }
  27: }
  28:  
  29: /// <summary>
  30: /// Remoting return call where return Value is a byte array
  31: /// </summary>
  32: public interface IRemoteResultByteArray : IRemoteResult<byte[]> {}
  33:  
  34: /// <summary>
  35: /// Remoting return call where return Value is a string
  36: /// </summary>
  37: public interface IRemoteResultString : IRemoteResult<string> {}

The IRemoteResult is the base interface for the result object.  It takes a generic type param which is the return type of the data that is consumed by the client from the server.  Notice that I created the IRemoteResultByteArray and IRemoteResultString interfaces based on the IRemoteResult.  This allows me to incorporate a strongly typed result value without having to maintain definitions of each.

Also notice that the “RemotingResult” interface contains a true or false representing the result of the remote call, as well as providing the ability to marshal the exception raised by the remote method internally to the client.  Of course, if the result is true, then the Value will contain the data returned from the remote call.

Now that we have the interface contract for the various Result objects, we can create the concrete implementation of those objects.

   1: [Serializable]
   2: public class RemoteResultByteArray : IRemoteResultByteArray
   3: {
   4:     public bool Result { get; set; }
   5:     public byte[] Value { get; set; }
   6:     public string ErrorMessage { get; set; }
   7:     public Exception ResultException { get; set; }
   8: }
   9:  
  10: [Serializable]
  11: public class RemoteResultString : IRemoteResultString
  12: {
  13:     public bool Result { get; set; }
  14:     public string Value { get; set; }
  15:     public string ErrorMessage { get; set; }
  16:     public Exception ResultException { get; set; }
  17: }

Notice that each of the concrete implementations are marked with the Serializable attribute.  This allows .Net to marshal the result object across the machine boundary.

Now that we know what to expect from the remoting service, let’s talk about the “what to do”

Creating the Shared Service Contract

One of the 32bit components that we’re working with is the ActivePDF Toolkit  It is basically a product that allows us to manipulate PDF documents.  One of the features that we utilize with the toolkit is the ability to take several PDF documents and merge them into one document “on the fly”.

I’m going to show you the code for our actual implementation of the merge process as an example.. but the long and short of it is, the shared service contract is what defines the method calls to your client that your remoting server will process.

   1: public interface IPdfToolkit
   2: {
   3:     /// <summary>
   4:     /// Merges the source PDF Documents and returns the final merge as a byte array
   5:     /// </summary>
   6:     /// <param name="info">The PDFInfo object that describes the final document.</param>
   7:     /// <param name="pdfFiles">The PDF files.</param>
   8:     /// <returns></returns>
   9:     IRemoteResultByteArray MergePDFToArray(PDFInfo info, List<PDFMergeInfo> pdfFiles);
  10:  
  11:     /// <summary>
  12:     /// Merges the source documents into a single PDF and returns the file name / path to the created output document
  13:     /// </summary>
  14:     /// <param name="info">The PDFInfo object that describes the final document.</param>
  15:     /// <param name="pdfFiles">The PDF files.</param>
  16:     /// <returns></returns>
  17:     IRemoteResultString MergePDFToFile(PDFInfo info, List<PDFMergeInfo> pdfFiles);
  18: }

 

So we’ve got a service contract with two methods, one merges a list of pdf’s to a single PDF and returns the result as a byte array, and the other returns a string, which is the path to the resulting file.  PDFInfo and PDFMergeInfo are supporting structures which are also defined in the shared assembly:

   1: [Serializable]
   2: public struct PDFInfo
   3: {
   4:     public string Title;
   5:     public string Subject;
   6:     public string Author;
   7:     public string Keywords;
   8:     public string OutputPath;
   9:     public bool DeleteAfterMerge;
  10:     public bool IncludeSeperatorPage;
  11:     public bool CreateSectionBookmarks;
  12:  
  13:     public PDFInfo(string title, string subject, string author, string keywords, string outputPath, bool deleteAfterMerge, bool includeSeperatorPage, bool createSectionBookmarks)
  14:     {
  15:         Title = title;
  16:         Subject = subject;
  17:         Author = author;
  18:         Keywords = keywords;
  19:         OutputPath = outputPath;
  20:         DeleteAfterMerge = deleteAfterMerge;
  21:         IncludeSeperatorPage = includeSeperatorPage;
  22:         CreateSectionBookmarks = createSectionBookmarks;
  23:     }
  24: }
  25:  
  26: [Serializable]
  27: public struct PDFMergeInfo
  28: {
  29:     public string FileName;
  30:     public string FriendlyName;
  31:     public bool Exists;
  32:     public bool Delete;
  33: }

With this new shared service contract, the client and server can both agree on what work will be performed, and what the results of that work will be.  So let’s move on to the Remoting Service itself…

Creating The Remoting Object (what actually does the work)

In the “Service” project we need to create an object that actually does the work we want it to do.  This is the object that makes the calls into the 32bit components, does the tasks it needs to do, and returns the results that we agreed upon in the shared assembly.  Since we’re working with the PDF Toolkit, I’ll go ahead and show you that…

   1: public class PdfToolkit : MarshalByRefObject, IPdfToolkit
   2: {
   3:     /// <summary>
   4:     /// Merges the source documents into a single PDF and returns the file name / path to the created output document
   5:     /// </summary>
   6:     /// <param name="info">The PDFInfo object that describes the final document.</param>
   7:     /// <param name="pdfFiles">The PDF files.</param>
   8:     /// <returns></returns>
   9:     public IRemoteResultString MergePDFToFile(PDFInfo info, List<PDFMergeInfo> pdfFiles)
  10:     {
  11:         var result = new RemoteResultString {Result = true};
  12:         if (string.IsNullOrEmpty(info.OutputPath))
  13:         {
  14:             result.Result = false;
  15:             result.ErrorMessage = "The OutputPath property can not be empty or null";
  16:             result.ResultException = new ArgumentException(result.ErrorMessage);
  17:             return result;
  18:         }
  19:     
  20:         try
  21:         {
  22:             // [... snip: Code that loops through the supplied list of files and merges them ...]
  23:         }
  24:         catch (Exception ex)
  25:         {
  26:             result.ErrorMessage = ex.Message;
  27:             result.ResultException = ex;
  28:             result.Result = false;
  29:         }
  30:         // finally return our result.. success or fail..
  31:         return result;
  32:     }
  33:     
  34:     /// <summary>
  35:     /// Merges the source PDF Documents and returns the final merge as a memory stream object
  36:     /// </summary>
  37:     /// <param name="info">The PDFInfo object that describes the final document.</param>
  38:     /// <param name="pdfFiles">The PDF files.</param>
  39:     /// <returns></returns>
  40:     public IRemoteResultByteArray MergePDFToArray(PDFInfo info, List<PDFMergeInfo> pdfFiles)
  41:     {
  42:         var result = new RemoteResultByteArray {Result = true};
  43:         var mergeResult = MergePDFToFile(info, pdfFiles);
  44:         if (!mergeResult.Result)
  45:         {
  46:             result.Result = false;
  47:             result.ErrorMessage = mergeResult.ErrorMessage;
  48:             result.ResultException = mergeResult.ResultException;
  49:             return result;
  50:         }
  51:         try
  52:         {
  53:             // read our output document into a stream object
  54:             using (var fs = File.OpenRead(mergeResult.Value))
  55:             {
  56:                 result.Value = new byte[fs.Length];
  57:                 fs.Read(result.Value, 0, (int) fs.Length);
  58:             }
  59:             // Delete our source file object since we're returning a stream
  60:             File.Delete(mergeResult.Value);
  61:         }
  62:         catch (Exception ex)
  63:         {
  64:             result.Result = false;
  65:             result.ErrorMessage = ex.Message;
  66:             result.ResultException = ex;
  67:         }
  68:         // Finally return our stream result object
  69:         return result;
  70:     }
  71: }

Some things to be aware of here.. The PdfToolkit concrete object inherits from MarshalByRefObject and implements the shared contract IPdfToolkit which was defined in the shared assembly.  The inheritance of MarshalByRefObject is what allows our PdfToolkit object to be accessed across application domain boundaries. 

Notice that the return types of each method (as declared by the IPdfToolkit) is an interface and the concrete result of the method is the concrete object defined in the shared assembly.  Since both our client (IIS) and server are aware and make use of the shared assembly, they are able to both call an apple an apple :)

Creating the Remoting Service

A point of definition here… Remoting Service != Windows Service.  It is important to make that distinction.  To define it simply (and probably wrongly) a remoting service is a collection of methods, objects, events, etc.. that are able to be accessed remotely. 

Now a point of order here, a Remoting Service must be hosted within another process.  The host of the remoting service can be any application that is running, or can be instantiated from a remote request.  All of the example code that I’ve found used a simple console application as the host for the remoting service.

Enough background…

The Remoting Service is what’s responsible for creating the channel, and registering the remoting object with the service.  For our needs, I set up a single RemoteSerivce object with a pair of public methods to setup and teardown the service and channels.

   1: public class RemoteService
   2: {
   3:     private const string CHANNELNAME = "x32bitHostServerChannel";
   4:     private const int TCPCHANNELPORT = 9083;
   5:  
   6:     private readonly PdfToolkit _pdfToolkit = new PdfToolkit();
   7:     private readonly TcpServerChannel _channel = new TcpServerChannel(CHANNELNAME, TCPCHANNELPORT);
   8:  
   9:     public void SetupService()
  10:     {
  11:         // Setup a channel for communication
  12:         ChannelServices.RegisterChannel(_channel, false);
  13:  
  14:         // Register our remoting services
  15:         RemotingConfiguration.RegisterWellKnownServiceType(typeof(PdfToolkit), "PdfToolkit", WellKnownObjectMode.Singleton);
  16:         
  17:         // bind our remoting objects with remoting service
  18:         RemotingServices.Marshal(_pdfToolkit, "PdfToolkit");
  19:     }
  20:  
  21:     public void TeardownService()
  22:     {
  23:         if (ChannelServices.GetChannel(CHANNELNAME) != null)
  24:             ChannelServices.UnregisterChannel(_channel);
  25:     }
  26:  
  27: }

While my example only shows one service being registered, in our actual implementation we’ve got several services registered.  The process for each is the same.  Create a private instance of the remoting object, register the service type with a unique name, then set the marshal of the unique name to the private instance.

I could have easily used Ipc as my channel instead of Tcp, but in our instance, we’ve got several web head front ends that all communicate back to our central remoting server.  This allows us to keep all of the remoting stuff on one box instead of having it installed on every one of our web hosts.

Creating the Service Host (Windows Service)

Alright, there are many samples and examples of creating a windows service.. making the installer, etc, etc.. so I won’t go into the nitty gritty of those details.. but I will show you the code for the actual service itself:

   1: public partial class Remoting32bitHost : ServiceBase
   2: {
   3:     private RemoteService _remoteService;
   4:  
   5:     public Remoting32bitHost()
   6:     {
   7:         InitializeComponent();
   8:     }
   9:  
  10:     protected override void OnStart(string[] args)
  11:     {
  12:         EventLog.WriteEntry(ServiceName + " Started", EventLogEntryType.Information);
  13:         _remoteService = new RemoteService();
  14:         _remoteService.SetupService();
  15:         EventLog.WriteEntry(ServiceName + " Channels Opened and Listening");
  16:     }
  17:  
  18:     protected override void OnStop()
  19:     {
  20:         EventLog.WriteEntry(ServiceName + " Tearing down channels");
  21:         _remoteService.TeardownService();
  22:         EventLog.WriteEntry(ServiceName + " Stopped");
  23:     }
  24: }

So, as you can see the actual service is very simple.  Just create a private instance of the RemoteSerivce object and instantiate it during the OnStart() event of the service.  Once it’s instantiated, then we can call the SetupService method.  When the service is stopped.. we call the TeardownService method.

You’re probably thinking that I could have just created the channel, registered the service types, and did the marshal binding right from the OnStart() event of the windows service.  And you’d be absolutely correct.  However, by having it as a separate object, I was able to utilize the RemoteService object from a test bed (windows console) application while I was developing and debugging… this meant I didn’t have to have the windows service actually installed and running on my machine (which of course, is a headache when you want to stop, start, recompile, etc).

Making the client talk to the service

The client is actually the easiest part of the whole process to build.  Though, from trudging through all of the sample code and examples “out in the wild” you’d probably be just as inclined to talk a long walk off a short pier.  That being the case, I’ll cut to the chase; We made a “remote wrapper” in the client application that is responsible for making the calls to the remote object.

   1: /// <summary>
   2: /// The PDFToolkit object is used to create a single merged PDF document from a list of several source pdf documents.
   3: /// It has the ability to create "page seperators" for the stitched together pdfs, as well as internal bookmark links.
   4: /// </summary>
   5: public class PDFToolkit : IPdfToolkit
   6: {
   7:     public IRemoteResultByteArray MergePDFToArray(PDFInfo info, List<PDFMergeInfo> pdfFiles)
   8:     {
   9:         IRemoteResultByteArray result = new RemoteResultByteArray { Result = false, ErrorMessage = "Unable to RPC to RemoteHost" };
  10:         // get the uri of the remote object we want to call
  11:         var uri = Common.GetRemotingUri("PdfToolkit");
  12:         // activate and get our remote object
  13:         var proxy = (IPdfToolkit)Activator.GetObject(typeof(IPdfToolkit), uri);
  14:         // build our result object
  15:         if (proxy != null)
  16:             result = proxy.MergePDFToArray(info, pdfFiles);
  17:         return result;
  18:     }
  19:  
  20:     public IRemoteResultString MergePDFToFile(PDFInfo info, List<PDFMergeInfo> pdfFiles)
  21:     {
  22:         IRemoteResultString result = new RemoteResultString{Result = false, ErrorMessage = "Unable to RPC to RemoteHost"};
  23:         // get the uri of the remote object we want to call
  24:         var uri = Common.GetRemotingUri("PdfToolkit");
  25:         // activate and get our remote object
  26:         var proxy = (IPdfToolkit)Activator.GetObject(typeof(IPdfToolkit), uri);
  27:         // build our result object
  28:         if (proxy != null)
  29:             result = proxy.MergePDFToFile(info, pdfFiles);
  30:         return result;
  31:     }
  32: }

It truly is as simple as that.  Use Activator.GetObject to create an instance of the type of remote object that you want using the proper Uri (I’ve got a helper method in our common library to give me the proper uri based on a remote type) then call the method you want.

The Big Gottcha!

In all of the samples and examples that I’ve found… for the client portion of the remoting solution, they all tell you that you have to create a channel on the client.  That just simply isn’t the case.  When you make a call to Activator.GetObject, it will create and register a channel for you if one is not already available.  We ran into situation where we tried to do our own channel management on the client side where the code would work well for a period of time (from 20 minutes to hours), then all of the sudden start failing.  As soon as we took the channel management code out of the client portion, we’ve not had a problem since.

Where’s the code?

I generally try to provide a code download with each of my articles.  Unfortunately with this type of article, your usage is going to probably be very different than mine.  Since so much of the code is dependant on 3rd party interfaces, there’s just no way that I could (given the time allotted for my day) put together a meaningful sample. 

Hopefully the snippets that I’ve provided are enough to help you through the hurdles of interfacing your legacy 32bit objects within an x64 architecture.  If you’ve got any questions, let me know.  I’ll do what I can to answer them.

author: Jason Monroe | posted @ Tuesday, June 16, 2009 5:06 PM | Feedback (0)

ASP.Net SQL Session State Gottcha – Serialization


Had a situation come up today when we were taking one of our sites SessionState management out of InProc to SqlServer.

The constructor to deserialize an object of type <type> was not found

Any custom object that you have created that you want to stuff into session, when using an out of process session management scheme (such as state server, sql server or your own custom implementation) needs to be decorated with the [Serializable] attribute.

After looking over our various data objects, I made sure that each one was properly decorated.  Since the majority of our data objects are rather simple in nature and contain intrinsic data types, the serializable attribute was all that was needed.

However, we have some core data objects that derive their implementation from DataSet.  Those were the ones with the problem…

   1: [Serializable]
   2: public class MyDataSet : DataSet 
   3: {
   4:     public int ParentRecordId { get; set; }
   5:     public string ConnectionString { get; set; }
   6:     
   7:     public MyDataSet(string connectionString, int parentRecordId) 
   8:     {
   9:         ConnectionString = connectionString;
  10:         ParentRecordId = parentRecordId;
  11:     }
  12: }

 

It was assumed that since DataSet implements ISerializable, then MyDataSet would be alright “out of the box”.  We were equally sure that MyDataSet wouldn’t have to do anything special since it was decorated with the serializable attribute and the custom properties were basic intrinsic types.

… And that’s where we were wrong

It seems that even though DataSet implements ISerializable, we need to have the seralizable constructor in MyDataSet as well.

   1: [Serializable]
   2: public class MyDataSet : DataSet 
   3: {
   4:     public int ParentRecordId { get; set; }
   5:     public string ConnectionString { get; set; }
   6:     
   7:     public MyDataSet(string connectionString, int parentRecordId) 
   8:     {
   9:         ConnectionString = connectionString;
  10:         ParentRecordId = parentRecordId;
  11:     }
  12:     
  13:     protected MyDataSet(SerializationInfo info, StreamingContext context) : base(info, context) { }
  14: }

We made the constructor protected because we don’t want it being called from anywhere but the .Net framework. 

So now the underlying DataSet object of MyDataSet is being serialized and deserialized as expected…  What we discovered was that now, ConnectionString and ParentRecordId was not being properly deserialized any longer.

That being the case, we had to roll up our own serialization utilizing the SerializationInfo object and overriding the GetObjectData() method in the base DataSet object.  Finally, we end up with our class looking like so:

   1: [Serializable]
   2: public class MyDataSet : DataSet 
   3: {
   4:     struct SerializationTags 
   5:     {
   6:         public const string ConnectionString = "MyDataSet_ConnectionString";
   7:         public const string ParentRecordId = "MyDataSet_ParentRecordId";
   8:     }
   9:  
  10:     public int ParentRecordId { get; set; }
  11:     public string ConnectionString { get; set; }
  12:     
  13:     public MyDataSet(string connectionString, int parentRecordId) 
  14:     {
  15:         ConnectionString = connectionString;
  16:         ParentRecordId = parentRecordId;
  17:     }
  18:     
  19:     protected MyDataSet(SerializationInfo info, StreamingContext context) : base(info, context) 
  20:     { 
  21:         ConnectionString = info.GetString(SerializationTags.ConnectionString);
  22:         ParentRecordId = info.GetInt32(SerializationTags.ParentRecordId);
  23:     }
  24:  
  25:     [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]    
  26:     public override void GetObjectData(SerializationInfo info, StreamingContext context)
  27:     {
  28:         base.GetObjectData(info, context);
  29:         info.AddValue(SerializationTags.ConnectionString, ConnectionString);
  30:         info.AddValue(SerializationTags.ParentRecordId, ParentRecordId);
  31:     }
  32:  
  33: }

Hope this helps someone save a headache or two :)

author: Jason Monroe | posted @ Thursday, May 21, 2009 2:51 PM | Feedback (0)

Disillusionment is never a fun time


I’ve always been a huge fan of Line6 and their acoustic modeling technology.  In my not so humble opinion, they have some of the most outstanding offerings in not only amplifier and cabinet modeling technologies, but in instrument modeling technologies as well.

I’ve played through and auditioned a number of their amplifiers from the simple Spider to the full on Vetta and loved the sounds they were able to produce.

I even use the Line6 GuitarPort as my direct PC interface for recording software.

GuitarPort

I truly *LOVE* the ease and simplicity of that little red box for getting rock solid and truly stellar tones down on a track without having to deal with hundreds of pounds and thousands of dollars worth of equipment, miles and miles of cables and enough patches and interfaces to make the pope swear.

The gear box software has a lot of cool features for a learning guitarist that I don’t use.. but the online community and ability to download tone patches from the online section truly rocks.

Having said all of that.. I don’t gig with my guitar port.  It’s tied to my computer where I can sit down and “fiddle” with it to get the tones I need.. spend time to iron everything out just … right.  The Gearbox software for the GuitarPort is like the ocean.. very accessible and easy to swim in.. but terrifyingly deep and equally easy to get lost in.  It’s not designed to be taken on the road.

But they have road gear!

Yes, Line6 offers not only studio gear.. but road gear as well.  Probably most notably is their POD line of equipment.

A buddy of mine happens to have a PODxt Live and is getting ready for a gig this weekend.  So he brought over his pod and we loaded it up to my studio and worked on getting some new patches into some of the unused user banks that he had free.

PODxtLive

So we plug it up and start tweaking some tones and patches in GearBox and saving them down to the POD.  We test the tones against his telecaster, my strat and my duel humbucker warlock.  We feed the output of the POD to the little Fender Bandit amp and test it through the mixing board to the PA.. each individual tone themselves sound golden.

Then frustration sets in

Hours of fun in setting up individual tone patches led to hours of frustration in getting those tone patches to work together. 

The PODxt, in all of it’s smarts and brains and technology, does not have a “master level” control for all of it’s patches to the output.  Basically speaking, there’s no way to easily equalize the output of the various patches so that switching from one tone to the other doesn’t require you to touch the board with your hands.

For example, we built a clean tone with a hint of chorus and delay adjusting the levels of the amp, mic, effects and cabinets to get just the tone that we wanted.  Then we built a gritty tone that had some drive and classic distortion with some reverb.  To get the tone that we wanted from that patch we made the patch a bit “hotter”…

So when we play the clean tone at amp level everything sounds awesome!  Then tap the bank switch to flip to the gritty tone, and the ears start to bleed.  We have to reach down and turn down the channel volume on the POD to make the amp level the same as what we had with the clean tone.

It seems to me, that since these tones are being produced through digital signal processing, that there should be some sort of overall output signal adjustment to level all of the patches to be the same.  If you want more volume from a patch.. well hell, that’s what the volume peddle is for right?

This seems to be a common complaint

In our efforts to resolve this problem, we did some research and digging around.  The common consensus is to “take the quietest patch and beef it up, then adjust the levels on your louder patches to bring them down”.  But in doing that, you’re changing the tone!

Some people are even going so far as to buy SPL meters and adjusting patch levels by what’s coming out of the amp!  That’s great… as long as you never move your amp or change venue’s or plug into a different amp or PA <eyeroll>.

Closing Thoughts…

In all fairness, I’ve not yet auditioned the POD x3 or the POD x3 Live so this problem may have been addressed with those products.  However, the x3 version uses the same GearBox and Monkey software that the GuitarPort and PODxt uses, so I’m doubtful that is truly the case.

I say unto you Line6, you guys make awesome studio gear and give us great tones.. But please don’t forget that there are gigging musicians out there who are having troubles with your gear and want to bring those same high quality patches with them out of the studio onto the road!

If anyone of you out there knows how to properly set the patch levels across multiple tones, please don’t hesitate to let us know.  ‘Cause obviously, we’re to stupid to figure it out :(

Technorati Tags: ,,

author: Jason Monroe | posted @ Wednesday, May 20, 2009 12:53 PM | Feedback (1)

Coding Tips: Struct Abuse - (or, Why didn’t I think of that?)


One of my personal pet peeves in development is the use of “Magic Numbers”in code.  I’m even so retentive to include string literals in my disdain of unmanageable code.  This especially becomes prevalent in data access code.

My nightmare

Handing me a piece of code that looks like this:

public class Foo
{
public string Bar { get; set; }
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string CreatedOn { get; set; }
public string CreatedBy { get; set; }
}

public class FooManager
{
public Foo GetFooById(string Id)
{
var retFoo = new Foo();
var param = new SqlParameter("Foo_Id", SqlDbType.VarChar, 25);
param.Value = Id;

using (var conn = new SqlConnection("Data Source=FooServer;Initial Catalog=FooDb;User Id=FooUser;Password=FooPassword"))
{
using (var cmd = new SqlCommand("FOO_FETCH_BY_ID", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(param);
var rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if (rdr != null)
{
rdr.Read();
retFoo.Bar = rdr["Foo_Bar"].ToString();
retFoo.Id = rdr["Foo_Id"].ToString();
retFoo.Description = rdr["Foo_Description"].ToString();
retFoo.Title = rdr["Foo_Title"].ToString();
retFoo.CreatedOn = rdr["Foo_CreatedOn"].ToString();
retFoo.CreatedBy = rdr["Foo_CreatedBy"].ToString();
}
}
} return retFoo;
}
}

is one of the quickest ways to fail a code review.

The code is littered with string literals.. and a blasted magic number!  (I know that the connection string is going overboard in this example.. but it’s there because I’ve seen it before)

Let’s do something a bit different:

public class Foo
{
public struct DBFields
{
public const string Bar = "Foo_Bar";
public const string Id = "Foo_Id";
public const string Title = "Foo_Title";
public const string Description = "Foo_Description";
public const string CreatedOn = "Foo_CreatedOn";
public const string CreatedBy = "Foo_CreatedBy";
}

public struct DBLengths
{
public const int Bar = 35;
public const int Id = 25;
public const int Title = 65;
public const int Description = 500;
public const int CreatedOn = 12;
public const int CreatedBy = 20;
}

public string Bar { get; set; }
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string CreatedOn { get; set; }
public string CreatedBy { get; set; }
}

public class FooManager
{
private const string DBSTRING = "Data Source=FooServer;Initial Catalog=FooDb;User Id=FooUser;Password=FooPassword";

private struct Procs
{
public const string FooById = "FOO_FETCH_BY_ID";
public const string FooByBar = "FOO_FETCH_BY_BAR";
public const string AllFooByCreator = "FOO_FETCH_ALL_BY_CREATOR";
}

public Foo GetFooById(string Id)
{
var retFoo = new Foo();
var param = new SqlParameter(Foo.DBFields.Id, SqlDbType.VarChar, Foo.DBLengths.Id);
param.Value = Id;

using (var conn = new SqlConnection(DBSTRING))
{
using (var cmd = new SqlCommand(Procs.FooById, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(param);
var rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if (rdr != null)
{
rdr.Read();

retFoo.Bar = rdr[Foo.DBLengths.Bar].ToString();
retFoo.Id = rdr[Foo.DBFields.Id].ToString();
retFoo.Description = rdr[Foo.DBFields.Description].ToString();
retFoo.Title = rdr[Foo.DBFields.Title].ToString();
retFoo.CreatedOn = rdr[Foo.DBFields.CreatedOn].ToString();
retFoo.CreatedBy = rdr[Foo.DBFields.CreatedBy].ToString();
}
}
}
return retFoo;
}
}

Wait.. What?!?

Alright, here’s what we did.. First we created a struct in the Foo object called DBFields.  This represents of the Foo Fields as they are so named in the DB.  Notice that it’s a struct of string constants.

The next thing we did was to create a struct of DBLengths in the Foo object.  This represents the length definition of all the fields in the Foo object as they correlate to the DB Definition.  Notice that it’s a struct of int constants.

In the FooManager, we created another struct called Procs.  This represents the name of each stored procedure that the FooManager users as it interacts with the DB in reference to the Foo object.

Most importantly, in the GetFooById() method.. there are no “Magic Numbers”  All that information is handled in one spot. 

You want to expand the Foo.Description field to 1000 instead of 500?  Modify the Foo.DBLengths.Description and the change will occure in every piece of code that uses the description length.  The Foo.Id property isn’t long enough?  Expand it and modify it in one place.

The stored procedure Foo_FETCH_By_ID is being re-written and the new name is FOO_FETCH_BY_ID2 and now you want to reference it by the new name..  Instead of search and replace, just modify the FooManager.Procs.GetFooById field and you’re good to go.

So what are you saying?

Magic Numbers are Bad.  Don’t use them.

author: Jason Monroe | posted @ Tuesday, May 12, 2009 8:26 AM | Feedback (2)

SQL Trickery: Rank and file your data with CTE, Rank, Case and Partition


Often as the case may be where you get a request from one of “those” people in the glass offices who like to wear suits and ties, take power lunches and talk with their hands for a particular set of data that just seems.. odd.

But being as the situation often is, “those” people control your pay checks, so you feel obligated to oblige their whims…

Let’s say you have a table in your data base that holds commission rates for sales people, and the dates those commissions are effective on.  It might look something like this:

   1: CREATE TABLE [dbo].[Commission_Rates](
   2:     [Rate] [numeric](18, 2) NOT NULL,
   3:     [Effective_date] [date] NOT NULL
   4: )

It might even have some data in it that looks something like this:

captured_Image.png

Now the suit comes up to you and says “Hey programmer Dude!  I’ve got a meeting with our investors in 30 minutes.. you have GOT to give me the most current commission rate as of ‘5/5/2009’ or we’re going to lose a ton of cash next quarter!”

Being the demi-god like person you are.. you say sure and whip up a quick query to get that data for him:

   1: SELECT TOP 1 RATE, EFFECTIVE_DATE 
   2: FROM COMMISSION_RATES 
   3: WHERE EFFECTIVE_DATE < '5/5/2009' 
   4: ORDER BY EFFECTIVE_DATE DESC
   5:  
   6: RATE                                    EFFECTIVE_DATE
   7: --------------------------------------- --------------
   8: 5.80                                    2009-05-01
   9:  
  10: (1 row(s) affected)
  11:  

Now the suit is all happy, but comes back in 5 minutes time and says “Hey programmer Dude!  You’re totally awesome.. but can you give me all of the upcoming rates after ‘5/5/2009’?”

Still not breaking a sweat, you come up with:

   1: SELECT RATE, EFFECTIVE_DATE
   2: FROM COMMISSION_RATES
   3: WHERE EFFECTIVE_DATE > '5/5/2009'
   4: ORDER BY EFFECTIVE_DATE ASC
   5:  
   6: RATE                                    EFFECTIVE_DATE
   7: --------------------------------------- --------------
   8: 5.40                                    2009-06-01
   9: 5.80                                    2009-12-01
  10:  
  11: (2 row(s) affected)

Yet again the suit is singing your IT praises for saving his bacon.  All of the sudden, it happens…  15 minutes into the meeting with the investors, you get a panic stricken phone call from the suit saying that all of these little bits of data are to confusing!  They need a single list of the most current rate, and all of the up coming rates at the same time!

Wonderful.  Pressure.  Resisting the urge to tell the suit something about improper planning on their part doesn’t constitute an emergency on your part, you set forth to give them what they want…  You might try something like this to start:

   1: SELECT TOP 1 RATE, EFFECTIVE_DATE 
   2: FROM COMMISSION_RATES 
   3: WHERE EFFECTIVE_DATE < '5/5/2009' 
   4: ORDER BY EFFECTIVE_DATE DESC
   5:  
   6: UNION ALL
   7:  
   8: SELECT RATE, EFFECTIVE_DATE
   9: FROM COMMISSION_RATES
  10: WHERE EFFECTIVE_DATE > '5/5/2009'
  11: ORDER BY EFFECTIVE_DATE ASC

It seems logical enough.. take the first query and union it with the second query.  After all, the result definition from the two queries are the same.

The problem here in is the fact that you can’t have an ORDER BY clause within the construct of a UNION statement.

Rethink the problem

Looking back on the first two visits to our humble cubicle dwelling, the suit actually made a request for two different sets of data.  The first set of data was for all of the rates that were prior to ‘5/5/2009’ (let’s ignore the fact that we did a TOP 1 filter and order by for now) and the second set of data was for all the rates that were after ‘5/5/2009’.

We can use a CASE statement to “virtually separate” our data into two lists.

   1: SELECT RATE
   2:     , EFFECTIVE_DATE
   3:     , CASE WHEN EFFECTIVE_DATE < '5/5/2009' THEN 0
   4:         ELSE 1
   5:     END AS LIST
   6: FROM COMMISSION_RATES
   7:  
   8: RATE                                    EFFECTIVE_DATE LIST
   9: --------------------------------------- -------------- -----------
  10: 5.60                                    2009-02-02     0
  11: 5.80                                    2009-05-01     0
  12: 5.40                                    2009-06-01     1
  13: 5.80                                    2009-12-01     1
  14: 6.00                                    2009-03-15     0
  15:  
  16: (5 row(s) affected)

So, now we have our data that can be identified by the effective_date being before or after the search date of ‘5/5/2009’

The next thing we need to do is sort our two lists because we want the “most current” rate prior to the search date.  That means that we need to order the results from each list by the effective_date in descending fashion.

In order to achieve our desired results, we need to make use of the RANK() function and using PARTITION BY to partition our rankings the same way that we’ve sorted our list by the case statement above:

   1: SELECT RATE
   2:     , EFFECTIVE_DATE
   3:     , CASE WHEN EFFECTIVE_DATE < '5/5/2009' THEN 0
   4:         ELSE 1
   5:     END AS LIST
   6:     , RANK() OVER (PARTITION BY CASE WHEN EFFECTIVE_DATE < '5/5/2009' THEN 0
   7:                                     ELSE 1
   8:                                 END
   9:                     ORDER BY EFFECTIVE_DATE DESC) AS SORT
  10: FROM COMMISSION_RATES
  11:  
  12:  
  13: RATE                                    EFFECTIVE_DATE LIST        SORT
  14: --------------------------------------- -------------- ----------- --------------------
  15: 5.80                                    2009-05-01     0           1
  16: 6.00                                    2009-03-15     0           2
  17: 5.60                                    2009-02-02     0           3
  18: 5.80                                    2009-12-01     1           1
  19: 5.40                                    2009-06-01     1           2
  20:  
  21: (5 row(s) affected)
  22:  

As you can see, we’ve now successfully split our data into two lists, and we also have a nice sorting order to our data as well.

At this point, I would take our query and wrap it up into a Common Table Expression (CTE) so that I can use it in another query.  Think of a CTE as a temporary view created in your query (there are a few other rules to them but that’s the jist of it all).

   1: WITH CTE_RATES (RATE, EFFECTIVE_DATE, LIST, SORT)
   2: AS (
   3:     SELECT RATE
   4:         , EFFECTIVE_DATE
   5:         , CASE WHEN EFFECTIVE_DATE < '5/5/2009' THEN 0
   6:             ELSE 1
   7:         END AS LIST
   8:         , RANK() OVER (PARTITION BY CASE WHEN EFFECTIVE_DATE < '5/5/2009' THEN 0
   9:                                         ELSE 1
  10:                                     END
  11:                         ORDER BY EFFECTIVE_DATE DESC) AS SORT
  12:     FROM COMMISSION_RATES
  13: )

Now I can reference CTE_RATES just as I would any other table or view in my system.  Let’s start by getting the most current “previous” rate:

   1: SELECT RATE, EFFECTIVE_DATE
   2: FROM CTE_RATES
   3: WHERE LIST = 0
   4:     AND SORT = 1
   5:  
   6: RATE                                    EFFECTIVE_DATE
   7: --------------------------------------- --------------
   8: 5.80                                    2009-05-01
   9:  
  10: (1 row(s) affected)

Sure enough, that is the most current rate prior to our search date (and exactly the same results as we gave the suit the first time)

Now let’s get all of our “current” rates after the search date (which happen to be list = 1)

   1: SELECT RATE, EFFECTIVE_DATE
   2: FROM CTE_RATES
   3: WHERE LIST = 1
   4:  
   5: RATE                                    EFFECTIVE_DATE
   6: --------------------------------------- --------------
   7: 5.40                                    2009-06-01
   8: 5.80                                    2009-12-01
   9:  
  10: (2 row(s) affected)

Yet again we’ve been able to duplicate the same results that we did earlier. 

Let’s try our UNION once again with these two queries and our CTE:

   1: SELECT RATE, EFFECTIVE_DATE
   2: FROM CTE_RATES
   3: WHERE LIST = 0
   4:     AND SORT = 1
   5:  
   6: UNION ALL
   7:  
   8: SELECT RATE, EFFECTIVE_DATE
   9: FROM CTE_RATES
  10: WHERE LIST = 1
  11:  
  12: RATE                                    EFFECTIVE_DATE
  13: --------------------------------------- --------------
  14: 5.80                                    2009-05-01
  15: 5.40                                    2009-06-01
  16: 5.80                                    2009-12-01
  17:  
  18: (3 row(s) affected)

We are nearly there… They want the results in descending order based in effective_date.  That is simply a matter of wrapping up the UNION query as a sub query to another query to apply the ORDER BY clause to. 

Complete Script:

   1: WITH CTE_RATES (RATE, EFFECTIVE_DATE, LIST, SORT)
   2: AS (
   3:     SELECT RATE
   4:         , EFFECTIVE_DATE
   5:         , CASE WHEN EFFECTIVE_DATE < '5/5/2009' THEN 0
   6:             ELSE 1
   7:         END AS LIST
   8:         , RANK() OVER (PARTITION BY CASE WHEN EFFECTIVE_DATE < '5/5/2009' THEN 0
   9:                                         ELSE 1
  10:                                     END
  11:                         ORDER BY EFFECTIVE_DATE DESC) AS SORT
  12:     FROM COMMISSION_RATES
  13: )
  14:  
  15: SELECT RATE, EFFECTIVE_DATE
  16: FROM (
  17:         SELECT RATE, EFFECTIVE_DATE
  18:         FROM CTE_RATES
  19:         WHERE LIST = 0
  20:             AND SORT = 1
  21:  
  22:         UNION ALL
  23:  
  24:         SELECT RATE, EFFECTIVE_DATE
  25:         FROM CTE_RATES
  26:         WHERE LIST = 1
  27:     ) AS QRY
  28: ORDER BY EFFECTIVE_DATE DESC

Yielding us the results of:

   1: RATE                                    EFFECTIVE_DATE
   2: --------------------------------------- --------------
   3: 5.80                                    2009-12-01
   4: 5.40                                    2009-06-01
   5: 5.80                                    2009-05-01
   6:  
   7: (3 row(s) affected)

After the meeting is over with the investors, the suit comes down to thank you for being so quick and responsive with getting them the information that they need.  The suit even goes so far as to tell you that he owes you a free lunch (which oddly enough, you never seem to be able to collect on).  You kick back and relax for the rest of the day safe and secure in the knowledge that your MAD HAXOR SQL SKILLZ has once again saved the day.

Technorati Tags: ,,,

author: Jason Monroe | posted @ Saturday, May 09, 2009 4:46 AM | Feedback (0)