Skip Ribbon Commands
Skip to main content

Budnack.NET

:

 

 Links

 
collapse  Fun
 Dilbert
 Recipes
 Brewing Ingredient Inventory
collapse  Local
 Buffalo.com
 NCCC
 UB
collapse  Tech Links
 Slashdot
Home
"Using mainstream technologies to makes the impossible possible through uncommon solutions."  Est. 2007
April 15
$80 For A Bike Repair Stand?  No Thanks.

​So I was thinking today how I need to adjust my deraileurs for this year's biking season.  I could either a) Pay a bike shop 60 bucks per bike for a yearly "tune-up" or b) Shell out almost 80 bucks ($60 plus tax, S&H) and get a stand to elevate my bikes as I repair them according to the awesome instructions in the Haynes Bicycle Book (http://www.amazon.com/The-Haynes-Bicycle-Book-Maintaining/dp/1563921375).  This I could make up in one season for less than it would cost to get my bikes tuned up professionally.

I chose option c)  Combine Grandpa's pipe clamps with $10 worth of PVC from Valu.

Done.  Check out the attached pictures.


January 17
Riding The Rails

​Once again, it's time for a course change.  For years, the lure of working in the world of Open Source has intrigued me.  Therefore, I have shed my day-job copy of Visual Studio and .NET for the exciting world of Ruby on Rails!  As a professional who has worked primarily in corporate enterprise environments, I shall be asking such questions as: How do we provide enterprise-grade solutions without having to decipher the license agreements of Microsoft, Oracle, and their ilk?  How can we use Open Source software to enable the business expert who normally reaches for the likes of Excel or Access - while maintaining scalability and redundancy required for an enterprise application?

Even though it seems that platform-wise I've developed "career ADD" over the years, I believe that one cannot afford to silo themself into an application stack.  One must be a "Technical MacGyver" - able to take any available materials and build something really clever that nobody ever thought of.

Leave out the duct tape and paper clips though.

September 20
Enforcing Compression On A SQL Server Database

Compression of your database allows you to use disk space very economically, while improving the network performance of your database.  As a DBA, you may want to take advantage of compression, but you may have a unique scenario where it may be unrealistic to maintain.  A couple of examples:

1.  Where you have developers that maintain their own databases and consistently forget to add the DATA_COMPRESSION option to their CREATE TABLE and CREATE INDEX statements.

2.  You have a vendor process that re-creates the database ​on a regular basis, and you don't have control over their database structure or scripts.

Well, look no further - Using SQL triggers, you can ensure that all tables and indexes on a given database are compressed.  Basically, we use triggers on CREATE TABLE and CREATE INDEX to intercept these statements, inject the compression option, drop the original object and re-create it using the rewritten statement.

NOTE:  No warranties are given or implied if you use this code example, so TEST!  If you have any builds to this, I'd be interested to see them.  Also, if you want to use Row compression instead of Page, simply change the scripts below to reflect that.

 

CREATE TRIGGER DDL_COMPRESS_ALLTABLES_PAGE
ON DATABASE
FOR CREATE_TABLE
AS
 DECLARE @TriggerCMD NVARCHAR(MAX)
 DECLARE @NewTriggerCMD NVARCHAR(MAX)
 DECLARE @ObjectName NVARCHAR(MAX)
 DECLARE @ObjectXML XML
 
 --Extract the original create statement for the table
 SET @TriggerCMD = EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
 SET @ObjectName = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(max)')
 SET @ObjectXML = EVENTDATA()
 
 IF PATINDEX('%WITH (%', @TriggerCMD) <> 0
  BEGIN
   IF PATINDEX('%DATA_COMPRESSION%', @TriggerCMD) = 0
    BEGIN
     --If there is a WITH statement, inject the compression option at the front
     SET @NewTriggerCMD = REPLACE(@TriggerCMD, 'WITH (', 'WITH (DATA_COMPRESSION = PAGE,')
    END
   ELSE
    BEGIN
     SET @NewTriggerCMD = @TriggerCMD
    END
  END
 ELSE
  BEGIN
   --If there is no WITH statement, put one at the end of the whole CREATE statement
   SET @NewTriggerCMD = @TriggerCMD + ' WITH (DATA_COMPRESSION = PAGE)'
  END
 --Drop the table that was created
 EXEC ('DROP TABLE ' + @ObjectName)
 
 --Re-create the table using the altered CREATE statement
 EXEC (@NewTriggerCMD)
GO

 

CREATE TRIGGER DDL_COMPRESS_ALLINDEXES_PAGE
ON DATABASE
FOR CREATE_INDEX
AS
 DECLARE @TriggerCMD NVARCHAR(MAX)
 DECLARE @TriggerCMD1 NVARCHAR(MAX)
 DECLARE @TriggerCMD2 NVARCHAR(MAX)
 DECLARE @NewTriggerCMD NVARCHAR(MAX)
 DECLARE @ObjectName NVARCHAR(MAX)
 DECLARE @TargetObjectName NVARCHAR(MAX)
 DECLARE @ObjectXML XML
 DECLARE @iOnIndex int
 
 --Extract the original create statement for the index
 SET @TriggerCMD = EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
 SET @ObjectName = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(max)')
 SET @TargetObjectName = EVENTDATA().value('(/EVENT_INSTANCE/TargetObjectName)[1]','nvarchar(max)')
 SET @ObjectXML = EVENTDATA()
 SET @iOnIndex = PATINDEX('%ON %',@TriggerCMD)
 SET @TriggerCMD2 = SUBSTRING(@TriggerCMD,@iOnIndex+3,LEN(@TriggerCMD))
 SET @TriggerCMD1 = REPLACE(@TriggerCMD,@TriggerCMD2,'')
 
 IF PATINDEX('%WITH (%', @TriggerCMD) <> 0
  BEGIN
   IF PATINDEX('%DATA_COMPRESSION%', @TriggerCMD) = 0
    BEGIN
     --If there is a WITH statement, inject the compression option at the front
     SET @NewTriggerCMD = REPLACE(@TriggerCMD, 'WITH (', 'WITH (DATA_COMPRESSION = PAGE,')
    END
   ELSE
    BEGIN
     SET @NewTriggerCMD = @TriggerCMD
    END
  END
 ELSE
  BEGIN
   
   --This checks for the ON statement at the end, NOT the one in front that specifies the object
   IF PATINDEX('% ON %', @TriggerCMD2) <> 0
    BEGIN
     --If there is no WITH statement, but an ON statement exists, inject the page compression
     --  option in front of it
     SET @NewTriggerCMD = @TriggerCMD1 + REPLACE(@TriggerCMD2, ' ON', ' WITH (DATA_COMPRESSION = PAGE) ON')
    END
   ELSE IF PATINDEX('%' + CHAR(13) + CHAR(10) + 'ON %', @TriggerCMD2) <> 0
    BEGIN
     SET @NewTriggerCMD = @TriggerCMD1 + REPLACE(@TriggerCMD2, + CHAR(13) + CHAR(10) + 'ON', + CHAR(13) + CHAR(10) + 'WITH (DATA_COMPRESSION = PAGE) ON')
    END
   ELSE
    BEGIN
     --If there is no WITH statement, put one at the end of the whole CREATE statement
     SET @NewTriggerCMD = @TriggerCMD + ' WITH (DATA_COMPRESSION = PAGE)'
    END
  END
 --Drop the index that was created
 EXEC ('DROP INDEX ' + @ObjectName + ' ON ' + @TargetObjectName)
  
 --Re-create the index using the altered CREATE statement
 EXEC (@NewTriggerCMD)
GO

 

August 09
Upgrade

I just recently upgraded my site to SharePoint 2010!  The look and feel is improved, plus it showcases a whole new ribbon bar and new integrations with Office.  I'm definitely liking it so far.

In general, this blog has gone through many changes.  It's been up for 3+ years, ever since I took an eMachine and started building a small playground for prototyping.  Virtualization has allowed me to easily upgrade from Server 2003 to 2008R2 (especially when separating out and upgrading the domain controller).

The free vSphere Hypervisor made this possible.  Once you build a box that meets the HCL, it gives you a nice little playground for experimenting with different platforms.

Go here for more information:  http://www.vmware.com/products/vsphere-hypervisor/overview.html

Later, I'll post my hardware specs.  It's not an "enterprise level" rig - it is economical enough for the price-conscious geek, yet enough power to help satisfy the "mad scientist" in you.

September 01
A New Direction
So, just when you thought the well was dry, here comes another post!
 
Alot has happened in the past year, which to me has been a year of change and renewal.  Though I still dabble in SharePoint a little, I have moved on to another company and a completely different set of responsibilities.  Expect to see more postings, but on the topics of SQL Server and Virtualization, with perhaps a smattering of SAN Administration and a "guest-starring" of SharePoint.  In addition, you may see postings on things outside the world of IT, such as cars, cycling, and fencing (yes, fencing).
 
On a more personal note, I have discovered a new church family at Restoration Church, which meets at the Park School in Snyder (a suburb of Buffalo).  I am part of a small Community Group, which meets every other week.  It has been wonderful to be able to discuss matters of life and faith in Jesus Christ with people my own age from different walks of life, after what seemed to be a period of isolation.
 
Hopefully it won't be another 8 months before I post something to this blog - and I hope that my readers can continue to glean some helpful nuggets of information from it.
 
Till we meet again,
Jer
December 07
Have a Misbehaving WebPart?

Sometimes, a WebPart just won't cooperate! Either you get Javascript errors on the page when you try to edit or remove it, or your page simply gives up and spits out an error. To remove that pesky WebPart, simply tack the following path onto the end of your site URL:

/_layouts/spcontnt.aspx?url=<Full URL Of The WebPart Page>

You will get a page that looks similar to this:

Here, you can close, reset, and delete problem WebParts on both Public and Personal views.

November 04
How To Access The Latest File Version in the ItemUpdating Event Receiver
For an event I was writing, I needed to know the contents of a file that was being uploaded by the user.  I could have easily used the following code in the ItemUpdated event to get this information:
 
SPFile spf = properties.ListItem.File;
 
HOWEVER:  The problem at hand required me to use ItemUpdating, because I wanted to cancel the upload and re-route the file contents if certain conditions were met.
 
The problem:  If you use the code above in ItemUpdating, you will actually get the pre-upload version of the file, NOT the contents that are currently being uploaded.  After some digging around in the forums, here's how I ended up doing it:
 
1.  You need to latch onto the HttpContext object in your constructor.  To do this, add the following code to your class definitiion (which I found at a SharePoint Kings blog post):
 
public class MyEventReceiver : SPItemEventReceiver
{
        HttpContext current;
        public MyEventReceiver()
        {
            current = HttpContext.Current;
        }
 
2.  In your ItemUpdating class, you need to look inside the Request object.  The file is stored in the Files collection (good place for it, eh?), under the key of what looks like the name of the control used to upload the file.  It should be the only one in there, so just use a foreach loop that runs once.  In the following example, I take the file contents and write them to a new file in the same document library, but with a different name:
 
foreach (string strPostedFileName in current.Request.Files)
{
   HttpPostedFile htpf = current.Request.Files[strPostedFileName];
   spw.Files.Add(strNewFileName + "." + strFileExt, htpf.InputStream);
   SPFile spfNewCopy = spw.GetFile(strNewFileName + "." + strFileExt);
   spfNewCopy.CheckIn("");
}
 
Note that strNewFileName is a server-relative URL, based on SPFile.ServerRelativeUrl.
 
Using this technique, you can intercept the file contents and do with them as you wish in your event receiver.
 
Cheers,
Jeremy
October 15
Why Your DataView WebPart May Be Acting Screwy
I had 2 XSLT DataView WebParts on a WebPart page in SharePoint.  Each was looking at a different document library.  Links for each document would work fine, but when I would hover over a document and click "View Properties" in one of the webparts, it tried to redirect me to a list item in the other list!  What gives?!?!
 
After hours of painstakingly comparing the two webparts and trying to find out the common thread, I stumbled on this nondescript call:
 
ctx.ctxId = <some number>
 
In both webparts, this value was the same.  When you look at the javascript and ID nomenclature of the HTML contained within, this value is used to differentiate Javascript objects from one webpart to another.
 
So for example:  One of the objects is an IFrame.  Its name is not "FilterIframe".  It is "FilterIframe<some number>".  When SharePoint's javascript calls are made, this number is used to find the IFrame of the webpart for which the call was intended.
 
So, when I found out 2 of these webparts had the same ctxId, I just took the XSLT of one, pasted it into Notepad, and replaced <some number> with a <new number>.  Pasted the webpart back in and all is well!
 
Cheers,
Jeremy
May 11
Selecting all text in a WPF TextBox using TextBox.Select()
I have read a few blog posts on this subject in my frustration to get this to work, but after playing around with this, I've figured out a way to select all text in a WPF textbox when you first click into it.
 
In my case, I have a TextBox and a ComboBox inside a WPF UserControl.  My first instinct was to use the following code:
 

private void ValueBox_GotFocus(object sender, RoutedEventArgs e)

{

ValueBox.SelectAll();

}

 
This works fine when you are purely using tabs, but what if the user actually clicks on the text box?  Answer:  it doesn't work.
 
After reading a few blog posts (especially this one by Eric Burke), and after trying different event handlers, I came to the following conclusions:
 
1.  You need to use the PreviewMouseLeftButtonDown event.  This is fired early enough, so that it will fire whether you select the text box with the I-beam or the Arrow.  Also, if you have any context menus (which pop up via right-click), this leaves them alone.
2.  The "handled" event argument needs to be set to "true", in order to keep from routing to the event that de-selects your text after you select it.
3.  You need to set the Keyboard focus inside your handler.  Otherwise, you won't be able to do anything inside your textbox (since execution will no longer automatically set the Keyboard focus).
 
So here's the code:
 

private void ValueBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

{

if (!this._hasfocus)

{

ValueBox.SelectAll();

Keyboard.Focus(ValueBox);

this._hasfocus = true;

e.Handled = true;

}

}

 
My control has a context menu associated with this text box, and it works just fine using this solution.
May 11
Back to Blogging
Greetings!  I know I don't have many (if any) readers, but that may change as I start posting technical content to my blog.  By technical, I mean code snippets, configuration settings, and any other tidbits of information that I feel should be shared with the rest of the developer community.  We'll see how this goes.
1 - 10Next