Streaming Audio From WHS#

I have been looking into some of the options for streaming music from my WHS to devices in my house.

So far I don't seem to be finding many good options.  There are some that you point to a UNC share and then have to deal with a crappy UI to select the songs you want.

2 of the nicer options I have see are:

http://www.sonos.com/howitworks/

 

 

and

 

http://www.roku.com/products_soundbridge.php

 

 

 

http://www.roku.com/products_soundbridgeradio.php

 

 

I'm going to have to keep my eyes open for other options, but these seem like viable candidates.

 

Categories:  |  |  | 
Monday, January 05, 2009 10:29:56 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Learning Spanish In Cancun Mexico#

I recently had an opportunity to travel to Mexico for some spanish lessons.  I wanted to put up a little write up here so if someone else was searching google for some options they might come across my article.

I arranged for lessons with Francisco Romero of the Cancun Spanish Language Institute.

http://www.studyspanish-mexico.com/

We had a great experience with Francisco.  We opted for an immersion type experience, with Francisco speaking almost no english during our lessons, but unlike some of the other instructors we have had, he was clearly 100% fluent in english, and could help explain some of the nuances in english. 

I would really recommend him to anyone else considering taking language lessons while in Cancun.

Categories:
Sunday, January 04, 2009 4:36:27 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

HP MediaSmart Certificate Issues#

I am in the process of testing out a Windows Home Server (WHS) for possible use in backing up multiple machines.

Today I ran into a problem.  I noticed that when logging in remotely (using mydomain.homeserver.com) it was sending me to an http page and not an https page.

Asking me for my username/password that will allow anyone to access my machine over https is not acceptable.  I tried manually changing the url to https, but I got a certificate error.

I took a look at the certificate error and it appeared the certificate was for the URL https://MYDOMAIN  which is the name of the server, but not the full domain name.

I am not fully sure which change I made fixed the problem, but I went into Settings-> Remote Access and changed the "Web Site Home Page" from the HP page to the "Windows Home Server Home Page" because my friend had it setup this way and he had a button that took him to an HTTPS page to login, but I don't think that solved the problem.  I then clicked on "Change" on the "Domain Name" section and just re-confirmed all the same settings.  At this point I think it grabs a new certificate from homeserver.com and it made it start working.

Now if I could only figure out why my one laptop is not backing up....

 

Categories:  | 
Monday, December 15, 2008 10:46:59 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Extending Microsoft Data Access Blocks (early version)#

Microsoft has released several versions of their Data Access Blocks, but they started mixing all their blocks together at some point, so if you wanted to use the DAB, you had to also use the Configuration blocks, and you had to use the Encryption blocks, and those needed the logging blocks etc.

So in many of my projects I have kept with one of the earlier versions.

But, there was a problem.  Basically in order to pass parameters, the easiest way to do it was in an ordinal position way, such as:

Public Shared Sub Whatever(SomeParamsHere)
    Dim storedParams() As SqlParameter
    storedParams = SqlHelperParameterCache.GetSpParameterSet(ConnectionString, "Whatever")

    storedParams(0).Value = 1
    storedParams(1).Value = 2
    storedParams(2).Value = 3
    storedParams(3).Value = "abc"

   SqlHelper.ExecuteNonQuery(ConnectionString, _
        CommandType.StoredProcedure, _
        "ItProjectInfo_General_Update", _
        storedParams)

End Sub

Obviously, this code is hard to read because we don't know which parameters are getting which values w/o opening up the stored procedure and looking ourselves.

So I wrote some extra code to allow of working with SqlParameters in the form of Dictionary(Of String, SqlParameter).  Calling the same function would look like this:

Public Shared Sub Whatever(ByVal SomeParamsHere)
    Dim storedParams() As New Dictionary(Of String, SqlParameter)
    storedParams = SqlHelperParameterCache.GetSpParameterCollection(ConnectionString, "Whatever")

    storedParams.Item("@id").Value = 1
    storedParams.Item("@num").Value = 2
    storedParams.Item("@cat").Value = 3
    storedParams.Item("@name").Value = "abc"

    SqlHelper.ExecuteNonQuery(ConnectionString, _
         CommandType.StoredProcedure, _
         "ItProjectInfo_General_Update", _
         storedParams)

End Sub

This works for output parameters as well.

In order to make this work you need to edit the SqlHelper.vb code.

Inside the SqlHelperParameterCache class you need to add:

Public Overloads Shared Function GetSpParameterCollection(ByVal connectionString As String, ByVal spName As String) As System.Collections.Generic.Dictionary(Of String, SqlParameter)
    Dim parameters() As SqlParameter = GetSpParameterSet(connectionString, spName, False)
    Dim paramsCol As System.Collections.Generic.Dictionary(Of String, SqlParameter)
    paramsCol = SqlHelper.ParamArrayToDict(parameters)
    Return paramsCol
End Function

And inside SqlHelper class you need to add the following methods:

#Region " Dictionary Support Helpers "
Friend Shared Function ParamArrayToDict(ByVal params() As SqlParameter) As Dictionary(Of String, SqlParameter)
    Dim dict As New System.Collections.Generic.Dictionary(Of String, SqlParameter)(StringComparer.CurrentCultureIgnoreCase)
    For i As Integer = 0 To params.Length - 1
        dict.Add(params(i).ParameterName, params(i))
    Next
    Return dict
End Function

Friend Shared Function ParamDictToArray(ByVal dict As Dictionary(Of String, SqlParameter)) As SqlParameter()
    Dim params(dict.Count - 1) As SqlParameter
    Dim i As Integer
    For Each p As SqlParameter In dict.Values
        params(i) = p
        i += 1
    Next
    Return params
End Function
#End Region

Public Overloads Shared Function ExecuteDataset(ByVal connectionString As String, _
                                           ByVal commandType As CommandType, _
                                           ByVal commandText As String, _
                                           ByVal commandParameters As Dictionary(Of String, SqlParameter)) As DataSet ' Execute Dataset with generic dictionary support

    Dim parametersArray() As SqlParameter
    parametersArray = ParamDictToArray(commandParameters)
    Return ExecuteDataset(connectionString, commandType, commandText, parametersArray)
End Function


Public Overloads Shared Function ExecuteNonQuery(ByVal connectionString As String, _
                                              ByVal commandType As CommandType, _
                                              ByVal commandText As String, _
                                              ByVal commandParameters As Dictionary(Of String, SqlParameter)) As Integer
    Dim parametersArray() As SqlParameter
    parametersArray = ParamDictToArray(commandParameters)
    Return ExecuteNonQuery(connectionString, commandType, commandText, parametersArray)
End Function  ' ExecuteNonQuery with generic dictionary support


Public Overloads Shared Function ExecuteScalar(ByVal connectionString As String, _
                                              ByVal commandType As CommandType, _
                                              ByVal commandText As String, _
                                              ByVal commandParameters As Dictionary(Of String, SqlParameter)) As Object

    Dim parametersArray() As SqlParameter
    parametersArray = ParamDictToArray(commandParameters)
    Return ExecuteScalar(connectionString, commandType, commandText, parametersArray)

End Function ' ExecuteScalar with generic dictionary support

 

 

Categories:  |  | 
Thursday, December 04, 2008 1:36:06 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Using nant to build projects from the command line#

NAnt is a tool that can help you build your .net applications. 

You can get really detailed with it, but what if you just want to set it up to quickly build projects/solutions or run automated builds.  This is especially useful if you are rebuilding 1 project that you are in the process of testing so you don't have to wait for VS to figure out if any of the referenced projects need to be rebuilt.

Well, with a few quick steps you can have this.

After downloading NAnt you need to create a little batch file somewhere in your PATH (for example, c:\windows).  Name the file nant.bat and put this in it:

@echo off
"C:\apps\nant\nant-0.86-beta1\bin\NAnt.exe" %*

You will obviously want to replace my path with your own path to your nant exe that you downloaded.

Then add an entry to your PATH system variable to the directory that contains devenv.com.  For me this path is:
C:\Program Files\Microsoft Visual Studio 8\Common7\ide\

Then you just need to add a .build file to your project.  I name it the same as my project name but you can do whatever you want.

This build file should contain the following XML:

<?xml version="1.0"?>
<project name="ProjName" default="build" basedir=".">
  <target name="build">
    <exec failonerror="true" program="devenv.com" commandline="ProjName.vbproj /build Debug" />
  </target>
</project>

Rename ProjName as needed in this file as well.

Then all you need to do is navigate to the folder that contains the .build file from a command line and run:

nant

It will scan for the build file, and use devenv.com to build it.

You can also use this to build solutions, just change the .vbproj file to a .sln file.

Categories:  |  |  | 
Monday, December 01, 2008 4:35:19 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Webservices: The request failed with HTTP status 400: Bad Request#

We have a webservice that is called from an application under heavy use.

From time to time we are getting errors coming back from the webservice:

The request failed with HTTP status 400: Bad Request

The stack trace is not very helpful:

at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)

So basically the webservice is just throwing back a 400 error to the webservice request.

I haven't seen anyone online who has this type of issue.  I have seen several where they ALWAYS get this error, but none where it works most of the time and fails sometimes.

I am considering that it could be something in the network, like a proxy server or AV sniffer, but not sure.

 

Categories:  |  |  |  | 
Tuesday, November 18, 2008 5:21:48 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Compressing Web Service Calls#

Most webservers will compress data if the clients support it.

Unfortunately for .net developers the auto generated proxy classes that access webservices don't include this functionality.

I'll show you how to achieve this while avoiding changing any code in the auto generated proxy classes.

(These classes utilize ICSharpCode.SharpZipLib.dll so you'll have to download this)

This following class will deal with decompressing a response.

Imports System.Net
Imports ICSharpCode.SharpZipLib

Public Class UncompressedGzipResponse
    Inherits System.Net.WebResponse

    Private cCompressedGzipResponse As HttpWebResponse

    Public Sub New(ByVal compressedGzipResponse As HttpWebResponse)
        MyBase.New()
        cCompressedGzipResponse = compressedGzipResponse
    End Sub


    Public Overrides Function GetResponseStream() As System.IO.Stream

        Dim compressedStream As System.IO.Stream = New GZip.GZipInputStream(cCompressedGzipResponse.GetResponseStream)
        Dim decompressedStream As New System.IO.MemoryStream
        Dim size As Integer = 2048
        Dim writeData(2048) As Byte
        While True
            size = compressedStream.Read(writeData, 0, size)
            If size > 0 Then
                decompressedStream.Write(writeData, 0, size)
                Dim s As String = System.Text.Encoding.ASCII.GetString(writeData)
                s = s & ""
            Else
                Exit While
            End If
        End While
        decompressedStream.Seek(0, IO.SeekOrigin.Begin)

        Return CType(decompressedStream, IO.Stream)

    End Function

    Public Overrides Property ContentType() As String
        Get
            Return cCompressedGzipResponse.ContentType
        End Get
        Set(ByVal value As String)
            cCompressedGzipResponse.ContentType = value
        End Set
    End Property

    Public Overrides Property ContentLength() As Long
        Get
            Return cCompressedGzipResponse.ContentLength
        End Get
        Set(ByVal value As Long)
            cCompressedGzipResponse.ContentLength = value
        End Set
    End Property

    Public Overrides ReadOnly Property Headers() As System.Net.WebHeaderCollection
        Get
            Return cCompressedGzipResponse.Headers
        End Get
    End Property

End Class

This next class will handle most of the logic so that your proxy class can be as small as possible:

Public Class WebServiceCompressionHelper
    Public Shared Function GetWebRequest(ByVal uri As System.Uri, ByVal output As WebRequest, ByVal compress As Boolean) As WebRequest

        '*** add gzip
        If compress Then
            output.Headers.Item(Net.HttpRequestHeader.AcceptEncoding) = "gzip"
        End If

        Return output
    End Function

    Public Shared Function GetWebResponse(ByVal output As WebResponse, ByVal request As System.Net.WebRequest) As WebResponse

        Dim compressedResponse As HttpWebResponse = Nothing
        If TypeOf output Is HttpWebResponse Then
            compressedResponse = CType(output, HttpWebResponse)
        End If

        If compressedResponse IsNot Nothing AndAlso compressedResponse.ContentEncoding = "gzip" Then
            output = New UncompressedGzipResponse(compressedResponse)
        End If
        Return output
    End Function
End Class

In order to make use of this we need to tap into a few methods in the auto generated proxy.  The easiest way to do this is to extend the proxy class into your own subclass, like so:

Public Class MyService
    Inherits generated.proxy.class.here
    Protected Overrides Function GetWebRequest(ByVal uri As System.Uri) As System.Net.WebRequest
        Return Walshgroup.Webservices.Common.WebServiceCompressionHelper.GetWebRequest(uri, MyBase.GetWebRequest(uri), True)
    End Function
    Protected Overrides Function GetWebResponse(ByVal request As System.Net.WebRequest) As System.Net.WebResponse
        Dim output As System.Net.WebResponse = MyBase.GetWebResponse(request)
        Return Walshgroup.Webservices.Common.WebServiceCompressionHelper.GetWebResponse(output, request)
    End Function
End Class

Now, instead of instantiating your generated proxy class, you will simply instantiate your subclass.

That's it!

 

Categories:  |  | 
Monday, November 17, 2008 5:30:44 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Deleting Projects From TFS#

For some reason the TFS Team Explorer UI doesn't give you the ability to delete team projects.

To do this you need to make use of the TfsDeleteProject command line utility.

Basically just navigate to:

C:\Program Files\Microsoft Visual Studio 8\Common7\IDE

and run the command:

TfsDeleteProject /server:http://SERVERNAME:8080 PROJECTNAME

After you do this, you may need to run the "TfsVersionControl Administration Job" job on the machine running SQL for TFS.  It's under SQL Agent/Jobs.

Finally, the team projects will continue to show up in Source Control Explorer.  This is because you need to do a "GET" on the projects in order for them to clean up local files.  Once you do a get on the projects they will be gone from your workspace list.

Categories:  | 
Wednesday, November 05, 2008 1:18:22 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Killing a process#

99 times out of 100 you can kill any process from within task manager, but what about that 100th time when it just doesn't work?

That's when it's time to get out the command prompt.

In task manager, you need to first get the PID.  Click View -> Select Columns and put a check next to PID (Process Identifier).  This will show you the PID in the task manager Processes tab.

Now, open command prompt and run:

Kill -f PID

If the process you want to kill was started by a scheduled task you need to run:

AT HH:MM <path>\kill -f PID

or

Soon <path>\kill -f PID

 

Categories:
Monday, October 27, 2008 7:58:26 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Veracruz Spanish Immersion School#

I am in the process of looking for a spanish school for this winter when I will be traveling to the Yucatán Peninsula.

I had meant to write something on here about my last trip to Mexico when we went to Veracruz.

We stayed at the Veracruz Spanish Immersion School.  Well, actually because we were there during their most busy week and we requested an odd schedule they put us up in one of their other houses, which was a short bus ride (or walk) from the school. 

The school is run by an American couple, who I think have setup a great program in Veracruz.  They meet you at the airport to make sure you arrive without issue.  Our rooms were nice, and all the rooms had A/C, which was extremely important as it was the hight of the summer.  Wireless internet access turned out to be equally important as some things with one of my clients meant that I needed to have internet access from my laptop to assist them, and I was able to do this without problem.

We met a lot of interesting people who were staying at the school.  I think probably the idea of language immersion programs might bring out some slightly odd people, and there were some for sure :), but we met a lot of nice people and spent a good amount of time hanging out with them.

The instructors were mostly in their early 20s.  Based on talking with some of the other students who had been doing these immersion programs for a while, it seemed like that might be different from most other programs, where older more experienced instructors were used, but I thought it was great.  I enjoyed talking with all our teachers, and they were all immensely friendly and helpful. 

All the instructors and students ate breakfast and lunch together, which gave you a chance to meet some of the other students/instructors that you might not have in your classes.  They also have one of the instructors during non-lesson hours from 5am to 9pm in the common area/living room.  This is a great idea, because if nothing is going on you can go hang out and practice your spanish, or just listen to others if you don't feel like talking.

The other thing they do, which is a really great idea, is that for 2 hours a day you go out on the town with one of the instructors.  You can use this time to practice your spanish, to learn about the city, to learn the bus system, to see sites, or in our case, to go find out how we can buy tickets for the upcoming futbol game between Cruz Azul and Los Tiberones Rojos.

One day a week is a day long trip to one of a number of destinations.  This is when we went to see some ruins.  We walked into the local town for lunch, and walked across a suspension bridge.  It was fun.

Veracruz was a nice place.  Safety was not an issue during our trip.  We were our walking around the city past midnight, and it was no big deal.  The buses that run up and down the main road were really easy to use and we took them several times a day to get all over the place.

The only problems we had were that I got sick (sore throat/cold) and then near then end of our trip got "sick" (montezuma's revenge!).  I probably had some bad ice somewhere.  Next time I'll bring some medicine in case that happens.  But overall, it wasn't that big of a deal. 

We have a few other places we would like to visit, but I would definitely go back.  We had fun and I think we learned a lot even though we were only there for a week.

 

Categories:
Monday, October 20, 2008 12:52:05 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Sub Sub Notebooks#

This is really pretty cool. 

It's really really small: 95mm by 65mm by 15.5mm, but with a resolution of QVGA, I don't see it doing all that well among people who really would consider using this for their email/internet access.

 

But this does pose an interesting question, will we ever have a smartphone that is able to run a normal OS and standard resolutions when connected to a doc?  My phone has more processing power than my old laptop did.  Why can't it run a real OS and standard apps?

Categories:  | 
Monday, October 20, 2008 12:21:49 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Putting code in server controls attributes#

You can't do something like this:

<asp:Label id="lbl1" runat="server" Text=<%= CurrentUserName %> />

That is because it won't let you assign a server tag result to the attribute of a server control.

Thankfully, there is a solution:

http://weblogs.asp.net/infinitiesloop/archive/2006/08/09/The-CodeExpressionBuilder.aspx

 

Categories:  |  | 
Wednesday, October 08, 2008 2:25:31 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Master of Science#

This week I received a notification that I had been awarded a letter of commendation from the University of Chicago.

I realized that I never posted anything on here about my graduation.  I graduated this summer with the degree of Master of Science in Computer Science.

I'm obviously proud to have been able to graduate from such a well regarded school. 

I know that I learned a lot of valuable things while I was going to class, in areas that I probably would not have entered otherwise.

Best news is, I paid it all as I went.  So I have no debt!  :)