Wednesday, September 11, 2013

Developer Tip: Avoid random numerical constants

There always comes a time when we just need to use a single number or set of numbers in our code…. but please avoid typing something like:

if (permissionID == 3){
    // do something
}

Instantly I thinking

What is 3?

Is there a 1 and 2?

Is there documentation somewhere that can help?”

You can add a comment, that would be a bit helpful. But I believe a better solution is either an Enum or Class of constants. These solutions make your code more readable, and give more context around what “3” is.

Enum:

enum Permissions : int{
    None = 0,
    Read = 1,
    Write = 2,
    FullControl = 3
}
 
// .....
 
if (permissionID == (int)Permissions.FullControl){
    // do something
}
Class of Constants:
public static class Permissions {
    public static const int None = 0;
    public static const int Read = 1;
    public static const int Write = 2;
    public static const int FullControl = 3;
}
 
// .....
 
if (permissionID == Permissions.FullControl){
    // do something
}

Obviously these aren’t the only solutions… simply making a variable with a descriptive name might be enough…. but DO NOT just type a constant in the middle of your code.

Thursday, September 5, 2013

A must have SharePoint Management Tool

I know I’m late to the game on this, but I thought I would share for others that are unaware.

If you manage or develop against SharePoint you should look into

SharePoint Manager 2010

image

It’s a great tool for finding feature ID’s, managing lists, pretty much anything you need to know about your SharePoint server and everything in it.

Wednesday, May 1, 2013

C# code to force the debugger to launch

There are times where you just can’t manually attach the Visual Studio debugger to your code. Like when you’re trying to debug Sharepoint feature events (FeatureActivated, FeatureDeactivating, etc.) when Visual Studio is deploying your SharePoint project.

For those situations you can use this line of code to attach Visual Studio to your process.

System.Diagnostics.Debugger.Launch();

image

image

Just make sure to remove it before you ship your software.

Friday, March 1, 2013

HTTP Request Headers Testing

This is a trick I’ve been using for a while, but I wanted to share.

Sometimes third party software requests your Web Pages/Services and pass data via the HTTP Request Headers.

If you want to simulate these requests you can do so with Fiddler. Fiddler acts as a “man in the middle” for all the requests coming from your browser. Therefore, it has the ability to alter your HTTP requests before they are passed along to the appropriate destination.

Here is how you add a header to your browser requests.

Launch Fiddler and select Rules > Custom Rules…

Find the function called

static function OnBeforeRequest(oSession: Session)

Within this function you can add items to your request header by assigning key/value combination to the “oSession.oRequest” array.

Here’s an example:

static function OnBeforeRequest(oSession: Session)
{ 
    oSession.oRequest["Custom_Header_Key"] = "Custom Header Value";
}

Now any request from a browser will contain that value. Including localhost requests

2013-03-01_1427

For more information about Custom Rules, I encourage your to visit the Fiddler Script Cookbook

Wednesday, February 6, 2013

What is the “Mythical Man Month”

Well, there is a book out there explaining it.
The Mythical Man-Month: Essays on Software Engineering, Anniversary Edition (2nd Edition)
Though a great source, it’s one dry read.

I actually recommend the cliff notes.

The basic gist is this:

If a developer gives an estimate for a project that might take 320 hours or “2 Man Months.” Some might think 2 developers can complete the same task in half the time. 

This might work in a manufacturing world, but not so well in a software world because of two factors, partitioning and communication to maintain the partitions.

The reality of the matter is, software depends on other software. Some things can’t be independently partitioned. When they can’t, developers must constantly communicate to make sure their pieces will work together. This communication takes additional time.  The more developers you add, the more communication you need, and therefore the more time you’ll have to spend.

There is a “sweet spot,” but unfortunately, there isn’t a perfect way to calculate it. When writing software, every project is different.

-Justin Kohnen

For a better explanation I encourage you to read the book, or at least the cliff notes.

Monday, February 4, 2013

How to use Window 8 on a PC

So you’re thinking about installing Windows 8 (or you’ve already installed it) and you’re wondering “It’s changed so much, How the heck do I use it?”

I wanted to share an instructional video with you that will answer just that question.

Here is the 25 minute version

And here is the “3 minute” version

Friday, February 1, 2013

Preparing a SQL database for CLR assembly loading

A few times, I’ve had to install CLR assemblies into a Microsoft SQL database.

In order to do so, the deploying user must be granted certain permissions.

Here is the script I use.

/*===========================================================
  THIS SCRIPT WILL PREPARE A SERVER FOR LOADING AN ASSEMBLY 
  BY GRANTING RIGHTS FOR THE SPECIFIED USER TO LOAD
  ASSEMBLIES OF ALL PERMISSION SETS
  AND SETTING THE DATABASE TO TRUSTWORTHY TO 
  ALLOW THE ASSEMBLY TO BE LOADED INTO CLR
  NOTE: MAKE SURE YOU REPLACE THE <Username> PLACEHOLDER
    WITH THE USERNAME YOU WISH TO ELEVATE PERMISSIONS FOR
  NOTE 2: A USER CANNOT ELEVATE THEIR OWN PERMISSIONS. THIS SCRIPT
    SHOULD BE RUN BY A DIFFERENT USER THAN THE ONE BEING ELEVATED
  NOTE 3: RUN IN DATABASE YOU WANT TO LOAD THE ASSEMBLY
  ===========================================================*/
       DECLARE @user NVARCHAR(50)
       DECLARE @tsql NVARCHAR(MAX)
       DECLARE @error INT
 
       SELECT @user = '<Username>'
 
       PRINT 'STEP PREPARE SERVER AND DATABASE FOR ASSEMBLY LOADING'
       PRINT 'SERVER  :   [' + @@SERVERNAME + ']'
       PRINT 'DATEBASE:   [' + db_name() + ']'
       PRINT 'USER    :   ' + @user
       PRINT 'START TIME: ' + convert(varchar(max), getdate())
 
       PRINT ''
       PRINT 'GRANT PERMISSION TO LOAD EXTERNAL_ACCESS ASSEMBLIES'
       SET @tsql = 'USE MASTER ' + char(13) + char(10) + 
                            'GRANT EXTERNAL ACCESS ASSEMBLY TO ' + @user + ''
 
       EXEC sp_ExecuteSQL @tsql 
       SET @Error = @@Error
       IF @Error <> 0 
              BEGIN
                     PRINT 'ERROR OCCURRED: ' + CONVERT(varchar(50), @error)
                     PRINT 'GRANTING EXTERNAL_ACCESS LOADING PERMISSIONS'
                     PRINT 'TO ' + @user
              END
       ELSE
              BEGIN
              PRINT 'GRANT PERMISSION TO LOAD UNSAFE ASSEMBLIES'
              SET @tsql = 'USE MASTER ' + char(13) + char(10) + 
                                   'GRANT UNSAFE ASSEMBLY TO ' + @user + ''
              
              EXECUTE sp_ExecuteSQL @tsql 
              SET @Error = @@Error
              IF @Error <> 0 
                     BEGIN
                           PRINT 'ERROR OCCURRED: ' + CONVERT(varchar(50), @error)
                           PRINT 'GRANTING UNSAFE LOADING PERMISSIONS'
                           PRINT 'TO ' + @user
                     END
              ELSE
                     BEGIN
                     PRINT 'MARK DATABASE ' + db_name() + ' SO ASSEMBLIES CAN RUN'
                     SET @tsql = N'USE MASTER ' + char(13) + char(10) + 
                                          'ALTER DATABASE ' + db_name() +
                                         ' SET TRUSTWORTHY ON '
                     EXEC sp_Executesql @tsql 
                     SET @error = @@ERROR
                     IF @error <> 0 
                           BEGIN
                           PRINT 'ERROR OCCURRED: ' + CONVERT(varchar(50), @error)
                           PRINT 'MARKING DATABASE ' + db_name() + ' SAFE TO RUN ASSEMBLIES'
                           END
                     END
              END                        
       PRINT ''
       PRINT 'STEP COMPLETED'
       PRINT 'END TIME: ' + convert(varchar(max), getdate())

I post this in hopes that someone else will find value in it.

Cheers,

Justin

Thursday, December 20, 2012

Error 21 CA0055 : Could not unify the platforms

After a recent upgrade from Silverlight 4.0 to Silverlight 5.0, I started getting this error from Visual Studio 2010

Error 21 CA0055 : Could not unify the platforms (mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, mscorlib, Version=5.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e) for '[path to Silverlight project dll]'.

Took me a while to track it down, and I found the solution to my problem in this post.

Being that we don’t use Code Analysis, I just turned it off on my Silverlight project.

2012-12-18_1304

But if you do use it, you’re going to have to run the command line arguments as the post suggests.

Tuesday, December 18, 2012

Error 17 Unknown build error, 'An item with the same key has already been added.'

I recently got this error after doing a code merge. No source file, no line number, just the project name and nothing else to point me in the proper direction to rectify my issue.

After much searching I found the answer to my problem in this post.

The post states this can occur if there are duplicate lines within a <ItemGroup> node in a csproj file.

I did a compare on my project file and found this.

2012-12-18_1053

I removed the duplicate line and everything was right with the world again.

Thursday, November 15, 2012

redgate SQL Source Control Revision Numbers

Anyone that’s developed with me in the last 7 years knows that I’m a HUGE fan of redgate. Honestly, now that I use their tools, I don’t know how I would work on MS SQL databases without them.

Recently, I’ve been taking a deep dive into SQL Source Control and SQL Compare. So far, I love it.

  • SQL Source Control: Is a Microsoft SQL Server Management Studio plug-in which allows me to commit my database schema, static data, and migration scripts into version control.
  • SQL Compare: Is a stand alone tool that allows me to compare and deploy schema changes. From a Database, Backup, Snapshot, Script Folder, or directly from source control to any combination there of.

In my case, I am using SQL Compare to deploy schema changes directly from source control, to my database.

One notable feature, is SQL Compare’s use of Extended Properties to track the version control revision number, in the database.

Here is an example of the script they use:

   1: DECLARE @RG_SC_VERSION BIGINT
   2: SET @RG_SC_VERSION = 13670
   3: IF EXISTS (SELECT 1 FROM fn_listextendedproperty(N'SQLSourceControl Database Revision', NULL, NULL, NULL, NULL, NULL, NULL))
   4:   EXEC sp_dropextendedproperty N'SQLSourceControl Database Revision', NULL, NULL, NULL, NULL, NULL, NULL
   5: EXEC sp_addextendedproperty N'SQLSourceControl Database Revision', @RG_SC_VERSION, NULL, NULL, NULL, NULL, NULL, NULL
   6: GO

This means you can figure out the revision number of your database by querying the Extended Property.

   1: SELECT Name, Value FROM fn_listextendedproperty(N'SQLSourceControl Database Revision', NULL, NULL, NULL, NULL, NULL, NULL)

Why does this matter?

Well, when the time comes to update a client’s database to the latest version, it’s as easy as.

  1. Figure out the version of their database (using the script above)
  2. Using SQL Compare: Set your “Source” to the Head of your source control, set the “Target” to the version of the database the client is at
  3. Using SQL Compare: Compare the two database schemas, and generate a deploy script

So awesome.

Monday, November 12, 2012

Using a delimited list for SQL ‘IN’ statement

Sometimes I want to pass a list of items from my C# code to my stored procedures so they can be used as part of an ‘IN’ clause.

In my greener years I would do something like:

Unsafe Way

<WARNING>Do NOT write code like this. This opens the door to SQL injection. </WARNING>

   1: -- @ProductIDs contains a list of id's delimited by a ',' (i.e. '1,34,56,7,8,98')
   2:  
   3: sp_executesql 'SELECT * FROM Products WHERE ProductID IN (' + @ProductIDs + ')'

Safer Way

My safer solution is adding a function to my database called “SPLIT.”

Function:
   1: CREATE FUNCTION [dbo].[SPLIT] (
   2:     @str_in VARCHAR(8000),
   3:     @separator VARCHAR(4) )
   4: RETURNS @strtable TABLE (strval VARCHAR(8000))
   5:  
   6: AS
   7:  
   8: BEGIN
   9:     DECLARE
  10:         @Occurrences INT,
  11:         @Counter INT,
  12:         @tmpStr VARCHAR(8000)
  13:     
  14:     SET @Counter = 0
  15:  
  16:     IF SUBSTRING(@str_in,LEN(@str_in),1) <> @separator 
  17:         SET @str_in = @str_in + @separator
  18:  
  19:     SET @Occurrences = (DATALENGTH(REPLACE(@str_in,@separator,@separator+'#')) - DATALENGTH(@str_in))/ DATALENGTH(@separator)
  20:     SET @tmpStr = @str_in
  21:  
  22:     WHILE @Counter <= @Occurrences 
  23:     BEGIN
  24:         SET @Counter = @Counter + 1
  25:         INSERT INTO @strtable
  26:             VALUES ( SUBSTRING(@tmpStr,1,CHARINDEX(@separator,@tmpStr)-1))
  27:  
  28:         SET @tmpStr = SUBSTRING(@tmpStr,CHARINDEX(@separator,@tmpStr)+1,8000)
  29:  
  30:         IF DATALENGTH(@tmpStr) = 0
  31:  
  32:         BREAK
  33:     END
  34:  
  35: RETURN 
  36: END

This function takes a “str_in” parameter representing the delimited String, and separator parameter representing the delimiter of the string.

Using these two values, the delimited string is broken apart into a table that can be queried.

Usage:
   1: SELECT *
   2: FROM Products
   3: WHERE
   4: ProductID IN ( SELECT * FROM SPLIT(@ProductIDs, ','))

I’m sure there is a more efficient way to perform the same task, but it works well enough for my needs. However, I am open to suggestions.

 

Happy Coding,

Justin