Wednesday, April 13, 2011

Powershell Base64 Image Generator For Data URIs

Data URIs are gaining in popularity. There are websites that will generate the URI (like http://www.motobit.com/util/base64-decoder-encoder.asp), but requires the uploading of files to someone else server, corporate policies can make these unusable. I haven't seen one in Powershell, so I made one. The code is pretty basic.

You need to know what MIME type for the file, but they are pretty easy to discover. The most common ones I have used:
  • image/gif
  • image/x-icon
  • image/vnd.microsoft.icon
  • image/png
  • image/jpeg

#####
#
#	Base64.ps1
#		Converts a file to or from base 64
#
#	Useful for generating data protocol image addresses:
#	In CSS:
#		background: #ff url('data:image/gif;base64,<Base64String>')
#
#	In HTML:
#		<img src="data:image/gif;base64,<Base64String>" alt="X">
#
#	Usage (encode):
#		.\base64.ps1 favicon.ico favicon.b64 -encode
#
#	Usage (encode & copy to clipboard):
#		.\base64.ps1 favicon.ico -encode -SetClipboard
#
#	Usage (decode):
#		.\base64.ps1 favicon.b64 favicon.ico -decode
#
#
#####
param (
	[string] $source = $(Throw 'source: required parameter'),
	[string] $destination = "",
	[switch] $encode,
	[switch] $decode,
	[switch] $SetClipboard
)

function Main
{
	$file = Get-Item($source);
	if ($encode)
	{
		$bytes = get-content -encoding byte $file.Fullname
		$result = [System.Convert]::ToBase64String($bytes);
		if ($SetClipboard) {Set-Clipboard $result;}
		if ($destination.length -eq 0)
		{
			return $result;
		}
		else
		{
			set-content -encoding UTF8 -Path ".\$destination" -Value $result;
		}
	}
	elseif ($decode)
	{
		$bytes = get-content -encoding UTF8 $file.Fullname;
		[System.Convert]::FromBase64String($bytes) | set-content -encoding Byte -Path ".\$destination";
	}
	else
	{
		Write-Host("The encode or decode switch is required.");
	}
}

. Main

For more information on Data URIs, refer to RFC2397 or the Wiki page for the Data URI Scheme for examples on how to use them.

Saturday, October 30, 2010

Connection was Unexpectedly Closed

I encountered an issue were a web service was calling a mainframe web service and every other time I would get the following error.

Error: "The underlying connection was closed: A connection that was expected to be kept alive was closed by the server."

As it turned out the mainframe was not setup to keep connections alive. Due to limitations with the mainframe, changing this functionality was not an option. So a simple partial class handled this automatically.

namespace <webservicenamespace> 
{
  public partial class <webserviceproxy> 
  {
    protected override System.Net.WebRequest GetWebRequest(Uri uri) {
      System.Net.HttpWebRequest webRequest = base.GetWebRequest(uri);

      webRequest.KeepAlive = false;

      return webRequest;
    }
  }
}

Saturday, October 2, 2010

Handling Enumerations from a Web Service with Generic Functions

Looking back at some code I ran across a handy piece of code that I wrote to save a good deal of typing, increase maintainability and readability.

Dealing with enumerations from a web service can be confusing at first. The enumeration field names are the same on both sides (client and server) of the web service, however the values are likely not going to be the same. This is especially true if the enumeration is defined with specific values that don't start with 1. The client side will give the enumeration values starting with 1. This means that when saving the value back to a web service object with a property of the enumeration type, you must make sure that the correct enumeration value is returned.

We run into situations where the enumeration value needs to be resolved from enumeration field name and the enumeration field name needs to be resolved from a value. The to just handle this inline can be rather hard to read and requires duplicate typing. Generic functions to the rescue.

Public Shared Function ParseEnum(Of T)(ByVal value As String) As T
    Return CType(System.Enum.Parse(GetType(T), value, True), T)
End Function


Public Function ResolveEnumToValue(Of T)(ByVal value As Object) As String
    Dim genericType As Type = GetType(T)
    Return [Enum].GetName(genericType, value)
End Function

Thursday, June 17, 2010

Using SQL Transactions in Powershell

It occurred to me that I have not seen a write up on System.Transactions.TransactionScope usage in powershell. I have tried this on Powershell v2, not sure if this works in Powershell 1. So here it goes...

The example below just shows the usage, I leave it as an exercise to the reader to add in the database query code.

"Start. " + [DateTime]::Now().ToString();

try {
 $transScope = New-Object System.Transactions.TransactionScope;

 ## Insert Queries

 "Complete";
 $transScope.Complete();
}
catch [Exception] {
    #$_ | fl * -Force
 Write-Host $_.Exception.ToString();
}
finally {
 if ($transScope) {
  $transScope.Dispose();
 }
}

"Done. " + [DateTime]::Now().ToString();

A more complex example just waiting for SQL statements. It shows some nested transactions.
"Start. " + [DateTime]::Now().ToString();

try {
 $transScope = New-Object System.Transactions.TransactionScope;
 
 ## Insert Queries
 
 try {
  ## Performs queries that are not included in a transaction.
  $transScope2 = New-Object System.Transactions.TransactionScope([System.Transactions.TransactionScopeOption]::Suppress);
  
  ## Insert Queries
  
  $transScope2.Complete();
 }
 finally {
  if ($transScope2) {
   $transScope2.Dispose();
  }
 }
 
 ## Insert Queries

 try {
  ## Perform actions that should be included in a side transaction outside of the enclosing transaction
  $transScope3 = New-Object System.Transactions.TransactionScope([System.Transactions.TransactionScopeOption]::RequiresNew);
  
  ## Insert Queries
  
  $transScope3.Complete();
 }
 finally {
  if ($transScope3) {
   $transScope3.Dispose();
  }
 }
 
 ## Insert Queries
 
 "Complete";
 $transScope.Complete();
}
catch [Exception] {
    #$_ | fl * -Force
 Write-Host $_.Exception.ToString();
}
finally {
 if ($transScope) {
  $transScope.Dispose();
 }
}

"Done. " + [DateTime]::Now().ToString();

Wednesday, June 16, 2010

VB.NET Debug Visualizer for Guids for Visual Studio 2010

Every once in a while I must program in VB.NET. My largest frustration is how Visual Studio handles Guids while debugging VB.NET code.

Seeing "System.Guid" as the value for a variable that contains a Guid is really not helpful. Debugging in C# correctly displays the actual value in the same situation.

Visual Studio provides an avenue to rectify this issue. You can create a new class library project and replace the contents of the default class file with the below code snippet.

<Assembly: DebuggerDisplay("{ToString()}", Target:=GetType(Guid))>

Public Class EmptyGuidVisualizerClass
    ' Empty
End Class

After compiling, copy the DLL to "%USERPROFILE%\My Documents\Visual Studio 2010\Visualizers" and restart Visual Studio. The Guids should resolve to their actual values.

After installing this in Visual Studio 2010, I found that it also works in Visual Studio 2008. The DLL should, likewise, be placed in the Visualizers directory in the Visual Studio 2008 folder in My Documents.

I created a batch file that can be used to install the DLL for 2010 and 2008. The batch file and the DLL must be in the same directory.

@ECHO OFF
SET STARTDIR=%CD%

pushd .

cd "%USERPROFILE%\My Documents"

IF EXIST ".\Visual Studio 2008" (
pushd .
echo "2008 Exists!"
cd ".\Visual Studio 2008"

IF NOT EXIST ".\Visualizers" (
 echo "Creating Visualizers Directory."
 mkdir Visualizers
)

copy "%STARTDIR%\GuidVisualizer.dll" .\Visualizers

popd
)

IF EXIST ".\Visual Studio 2010" (
pushd .
echo "2010 Exists!"
cd ".\Visual Studio 2010"

IF NOT EXIST ".\Visualizers" (
 echo "Creating Visualizers Directory."
 mkdir Visualizers
)

copy "%STARTDIR%\GuidVisualizer.dll" .\Visualizers

popd
)

popd

After creating it, I googled and found someone who came up with almost the same code, http://www.michelrenaud.com/?p=7 . This blog post contains pictures if you care to see the end result. Microsoft Connect has a similar resolved issue: https://connect.microsoft.com/VisualStudio/feedback/details/89801/show-guid-value-in-debug.

Friday, May 21, 2010

Use XQuery to convert a timestamp value to a Base64 string

SQL is a very powerful language, even with its limitations. SQL doesn't have the ability to convert Timestamp values to their base64 representations. However, you can use XQuery to do the conversion for you.

In the example below "Version" is of type Timestamp. I didn't notice any performance degradation during my testing.

SELECT  t1.Version
      , cast(N'' as xml).value('sql:column("t1.Version")', 'varchar(20)') 
FROM Table1 t1

This example opens up a new way to solve problems in SQL. It is intriguing to me to think about the other uses for leveraging XQuery to pick up SQL's slack.