Monday, December 14, 2015

Thursday, November 5, 2015

Prevent "Click Jacking"

One way to prevent "Click Jacking" is to prevent other sites from displaying your site in a frame.  To accomplish this, simply add this to your web.config:

<system.webServer>
 
...
 
    <httpProtocol>
        <customHeaders>
            <add name="X-Frame-Options" value="DENY" />
        </customHeaders>
    </httpProtocol>
 
...
 
</system.webServer>


Friday, October 30, 2015

.NET Exceptions

This post may seem obvious, but is something that I never knew for sure until today.  When an exception is raised, a stack trace is included as a property of the exception that describes where the exception occurred.  The stack trace will always reveal the method where the exception originated.  Even if Function A calls Function B, and Function B raises an exception that is caught in Function A, Function B will be in the stack trace.  This small bit of knowledge can save a bunch of time, because if Function A is in the stack trace, you can rest assured that it didn't happen in Function B.

Wednesday, October 21, 2015

Git Line Endings

When editing a text file in Windows, the operating system inserts two characters: carriage return and a line feed (AKA CRLF).  In any other operating system, only the LF character is added.  Because some projects are developed collaboratively on different operating systems. Obviously, this poses problems.  Git offers different configurations to deal with this.  With one configuration, Git will automatically replace CRLF with LF upon a commit.  I was stuck with this configuration one day because I believe I mistakenly told it to set it up that way during installation.  You don't want this if you do all your developing in Windows.  To turn this off, use this command:

git config --global core.autocrlf false

Creating and Using a Git Ignore File

Most of the time, there are certain files and folders that you do not want to track in your Git repository.  You have to explicitly tell Git which ones to ignore.  You provide this information in a special file you create in the root of your repository.  It is simply a text file named .gitignore.  Notice that there is no filename, just an extension.  Windows will not let you create a file with no name, so you have to create the file using a command in Git Bash.  Run the following from your root folder:

echo /bin > .gitignore

This command will create a file named .gitignore and put the "/bin" text in it.  This is the start of a very basic git ignore file.  It tells Git to ignore a folder named bin and all files contained in it.  You can add individual files and folders on separate lines.  Just double click the file in Windows and edit in Notepad.

Wednesday, October 14, 2015

Regular Expression Primer

I feel like I've finally cracked the code on regular expressions.  This is my attempt to document the essentials of regular expressions using JavaScript.  A regular expression essentially describes a pattern of text.

Generally, you use a regular expression (regex) in one of two ways:

  1. Test to see whether a specified string matches a regex exactly.  This is mainly used for validating input.
  2. Extract all instances of the pattern from a larger string of text.  The main use here is to replace the instances of the pattern with something else.
The easiest way to perform the first use is to define the regular express on the fly and then call the test method like so:

/^[0-9]+$/.test(inputToTest)

The test method returns true or false, based on whether the input string was a match.  The forward slashes simply delimit the regular expression.  The ^ indicates the beginning of the string, and the $ indicates the end of the string.  [0-9] says to match any number, and the plus means any number 1 or more times.  So, only numbers with one or more digits will match the regex.

The second use often involves replacing the matching text.  You can use a regex as a parameter when calling the string.replace method.  Let's say you want to replace all numbers in a string with the letter x.  Here is how you do it:

var results = inputString.replace(/[0-9]+/g, "x");

What's the "g" for?

That's the global flag.  That says to replace every matching text in the string with "x".

Now, let's talk about parenthesis.  A parenthesis in a regex means you can extract just the part in the parentheses.  Let's say you want to find everything with curly braces, and replace it all with just the text inside the curly braces.

var results = inputString.replace(/\{([A-Za-z]+)\}/g, "$1");

The &1 refers to the text matched by the first parenthesis.  So we would replace "{test}" with just "test".  Notice that the backslash is used to escape the curly brace character.

Sometimes a parenthesis is just a parenthesis and doesn't have to be referred to later.  You can just use it to group stuff.

These are really dumb examples to keep things simple, but these techniques are very powerful.  The best reference I've found for dealing with regex is here.


Monday, October 5, 2015

Use a Comparer to sort a generic List

I use lists a lot and most of the time I can sort the data before I load it into a list.  However, occasionally, I find myself in a situation where I really want to sort the data after it has been put into a list.  You can't use LINQ to sort a list.  You have to use the Sort method of the list object, and this method takes an IComparer object as a parameter.

Let's say you have a simple domain object with two properties:

Public Class DomainObject
    Public Property Name As String
    Public Property StartDate as Date
End Class

Then, let's say you have a List that's been loaded up with a bunch of DomainObject's.  Here's the definition:

Dim MyList As New List(Of DomainObject)

First, let's sort by just name.  You first have to create a Comparer class.  The Comparer class is a bit of code that tells the Sort method how to sort.  (NOTE:  If you're list consists of ONE simple type, like string, you don't have to provide the Sort method with a Comparer class.)  Here's a Comparer class that sorts only by the name:

Private Class DomainObjectComparer
    Implements IComparer(Of DomainObject)

    Public Function Compare(x As DomainObject, y As DomainObject) As Integer Implements IComparer(Of DomainObject).Compare

        '-1 means y is greater (i.e. y is AFTER x)
        '0 means x and y are equal.
        '1 means x is greater (i.e. x is AFTER y)

        If x.Name > y.Name Then
            Return 1
        Else
            Return -1
        End If

    End Function

End Class

This function compares two individual DomainObjects.  If x's Name is greater than y's Name, then we return 1.  When we return a 1, we are saying that x is greater than y.  In other words, x will come AFTER y.  The inverse is true when we return -1.  And if we return 0, they are absolutely equal.

Now, all we have to do is instantiate our DomainObjectComparer class and feed the resulting object into the Sort method like this:

Dim MyComparer As New DomainObjectComparer
MyList.Sort(MyComparer)

Now, our list is sorted by the name property.

If you want to sort first by Name and then by StartDate descending, try this:

Private Class DomainObjectComparer
    Implements IComparer(Of DomainObject)

    Public Function Compare(x As DomainObject, y As DomainObject) As Integer Implements IComparer(Of DomainObject).Compare

        '-1 means y is greater (i.e. y is AFTER x)
        '0 means x and y are equal.
        '1 means x is greater (i.e. x is AFTER y)

        If x.Name > y.Name Then
            Return 1
        ElseIf x.Name = y.Name Then
            If CDate(x.StartDate) > CDate(y.StartDate) Then
                Return -1 'Notice here that it's -1 because we want descending order.
            Else
                Return 1
            End If
        ElseIf x.Name < y.Name Then
            Return -1
        End If

    End Function

End Class

Friday, September 25, 2015

Simple CSS "Sticky Footer"

This method would probably need some tweaking to work in older browsers, but for my purposes, it works pretty good:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <style>
        html {
            height: 100%;
        }
        body {
            height: 100%;
            margin: 0px;
        }
        .container {
            background-color: lightgray;
            height: 100%;
        }
        .footer {
            height: 50px;
            background-color: gray;
            margin-top: -50px;
        }
    </style>
</head>
<body>
    <div class="container">
        
    </div>
    <div class="footer">

    </div>
</body>
</html>

Thursday, September 24, 2015

Git push and pull

As I've explained in earlier posts, the command

git push origin master

is used to push changes to a remote repository.  Similarly, the following command

git pull origin master

pulls changes from the remote repository and merges these changes in with your local branch.

Tuesday, September 15, 2015

Implementing Forgot Password and Email Confirmation in ASP.NET Identity

This is one of those tasks that is not very difficult to actually accomplish but exceedingly difficult to find good instructions on how to do it.  Forgot Password is simply a page where the user can enter his or her email address if he has forgotten his/her password.  He/she then receives an email containing a link where the password can be reset.  Email Confirmation means that when a user first registers, he/she cannot log in until the email is confirmed.  How is the email confirmed?  The person is sent an email containing a link to click that will mark the address as confirmed.  This all sounds complicated, but ASP.NET Identity builds all of this for you when you create an ASP.NET web application with Individual Accounts.  However, the code in the AccountController is commented out initially.  Because email is a central part of these operations, you must first configure your email.

To configure your email, just open up the IdentityConfig.vb file.  Find the EmailService class and add code to the SendAsync method.  The code below illustrates some code that sends an email using a traditional SMTP server:

Public Class EmailService
    Implements IIdentityMessageService

    Public Function SendAsync(message As IdentityMessage) As Task Implements IIdentityMessageService.SendAsync
        ' Plug in your email service here to send an email.

        Dim SmtpServer As String

        If System.Configuration.ConfigurationManager.AppSettings("SmtpServer") Is Nothing Then
            Throw New Exception("The SmtpServer key is not present in the web.config file.")
        Else
            SmtpServer = System.Configuration.ConfigurationManager.AppSettings("SmtpServer")
        End If

        Dim FromAddress As String

        If System.Configuration.ConfigurationManager.AppSettings("ConfirmationEmailFrom") Is Nothing Then
            Throw New Exception("The ConfirmationEmailFrom key is not present in the web.config file.")
        Else
            FromAddress = System.Configuration.ConfigurationManager.AppSettings("ConfirmationEmailFrom")
        End If

        Dim MyClient As New System.Net.Mail.SmtpClient(SmtpServer)

        Dim MyMessage As New System.Net.Mail.MailMessage

        MyMessage.From = New Net.Mail.MailAddress(FromAddress)

        MyMessage.Subject = message.Subject

        MyMessage.Body = message.Body
        MyMessage.IsBodyHtml = True

        MyMessage.To.Add(message.Destination)

        MyClient.Send(MyMessage)

        Return Task.FromResult(0)

    End Function

End Class

Once this is configured, go back to your AccountController and uncomment out the appropriate lines.

reCAPTCHA 2.0

The folks at Google have released a new version of their CAPTCHA product named reCAPTCHA.  They refer to the new version as the No CAPTCHA reCAPTCHA.  It's fairly easy to implement even in an ASP.NET MVC web application as I'll show below.

First, go here and sign up.  You input the domains at which your site will be hosted.  LocalHost always "just works" so don't worry about development.  However, if you're testing at a different domain than production, be sure to put both in there.  You'll be given two keys.  The "site" key and the "secret" key.

Implementing the CAPTCHA is a two part process.

First Part - Display the CAPTCHA control for the user to "solve"

Add this to the top of your view:

<script src="https://www.google.com/recaptcha/api.js" async defer></script>

Then add this where you want the CAPTCHA box to appear:

<div class="g-recaptcha" data-sitekey="SITE-KEY-GOES-HERE" ></div>

That's all.

Second Part - Verify that the CAPTCHA was solved correctly

This is the more tricky of the two parts.

Once the user submits the form, reCAPTCHA is going to insert an additional form field named g-recaptcha-response into the form.  This will look like gobbly-gook.  This response along with the secret key needs to be sent to a Google web service.  The web service will return a JSON object that contains a success attribute.  If the success attribute is true, the user solved the CAPTCHA and you can safely assume that he or she is not a bot.

First, in your controller, add a data contract that you can deserialize the JSON response into:

<System.Runtime.Serialization.DataContract>
Private Class GoogleResults
    <System.Runtime.Serialization.DataMember(Name:="success")>
    Public Success As Boolean
End Class

Next, in your post action method within the controller use the following code:

Dim RecaptchaResponse As String = Request("g-recaptcha-response")

Dim MyClient As System.Net.WebClient = New System.Net.WebClient

Dim Reply As String = _
            MyClient.DownloadString(String.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", "SECRET-KEY-GOES-HERE", RecaptchaResponse))

Dim MySerializer As New System.Runtime.Serialization.Json.DataContractJsonSerializer(GetType(GoogleResults))

Dim MyStream = New System.IO.MemoryStream(Encoding.Unicode.GetBytes(Reply))

Dim Results As GoogleResults = CType(MySerializer.ReadObject(MyStream), GoogleResults)

If Not Results.Success Then
    ModelState.AddModelError("", "You must verify that you are not a robot.")
End If

If Not ModelState.IsValid Then
    Return View(model)
End If


Friday, July 31, 2015

Close connections to your IndexedDB databases

Recently, I was attempting to run the deleteDatabase method of the IDBFactory interface of the IndexedDB API.  I noticed that occasionally the method would just hang there like it was stuck.  I slowly began to realize that it would hang if a connection was currently open.  This led me to researching how to close connections.

When you open a connection using the open method of IDBFactory, you get an object of type IDBDatabase.  In my experience, the only thing you do with the IDBDatabase object is to create the transaction object from it.  After you create the transaction, you should then immediately close the IDBDatabase object which closes the connection you opened.  At first, I wondered if you had to wait until you were done with the transaction before closing the connection, but apparently the close method knows to wait until all transactions created from it are completed.  This is from the specification:
Wait for all transactions created using connection to complete. Once they are complete, connection is closed.
Your code should look something like what is shown below. In this case, request is the IDBOpenDBRequest object.

request.onsuccess = function() {
    var db = event.target.result;

    var tx = db.transaction(['TableName'], 'readwrite');

    db.close();
}

Monday, July 27, 2015

Left Outer Join using LINQ

Left outer joins are another example of something that's seems intuitive in SQL but appears foreign in LINQ.  Here we have two tables, TableOne and TableTwo both with a common TableOneId column.  TableOne always has a record and TableTwo has 0 to many records for each TableOne record.  The first query will return every record from both tables even if the TableOne record has no TableTwo record.  The second query will only return records from TableOne only if they have no corresponding TableTwo record.  By the way, this is VB.


'Without a where clause

Dim Query = 
    From t1 In TableOnes
    Group Join t2 In TableTwos On t1.TableOneId Equals t2.TableOneId Into gj = Group
    From grouping In gj.DefaultIfEmpty
    Select t1, grouping


'With a where clause

Dim Query = 
    From t1 In TableOnes
    Group Join t2 In TableTwos On t1.RecordId Equals t2.RecordId Into gj = Group
    From grouping In gj.DefaultIfEmpty
    Where grouping Is Nothing
    Select t1, grouping
 

Thursday, July 23, 2015

Security Auditing in WCF

It is possible to log all security successes and/or failures to the event log by just modifying your configuration file.  This can be a quick and easy way to see if any funny business is going on with your web service.  However, a better solution is to log these types of events to a database that is easier to check and query on if you're doing this on a regular basis.

I'm a fan of the Service Configuration Editor tool (In Visual Studio, right click the web.config and select Edit WCF Configuration) rather than changing the XML directly, but it's helpful to see both.

First add a Service Behavior Configuration.  It doesn't necessarily have to be named.  Then add the serviceSecurityAudit behavior to the configuration:


Now, expand the behavior configuration, and select the newly added serviceSecurityAudit:


I recommend choosing the "Application" log as the location.  Here, I have chosen to log both successes and failures at the message level.  Once this is set up, simply go to the Event Viewer and you'll see information entries for each authentication or rejection.  To turn it off, just set it to None and leave it in the web.config in case you want to turn it on again.

Here is the settings as they exist in the XML:

<behaviors>
  <servicebehaviors>
    <behavior name="">

...

      <servicesecurityaudit auditloglocation="Application" 
          messageauthenticationauditlevel="SuccessOrFailure" 
          serviceauthorizationauditlevel="None">
      </servicesecurityaudit>
    </behavior>
  </servicebehaviors>
</behaviors>

Tuesday, July 21, 2015

Query XML files with LINQ

If you regularly work with XML, knowing a technique to directly query it can be a real asset.  I have found LINQ to XML together with LINQPad to be really helpful.  The best thing to do is to simply show an example.  Here we have a trivial XML file that we load in and display:


Then, let's say we want to list all plants from the file:


The tricky part is that if there are namespaces in your xml (and there usually is), then you need to include the namepace in braces.

Manually perform GET and POST HTTP actions

In an earlier post, I talked about HTTP and how to use the TELNET client to manually perform HTTP requests independent of a browser.  TELNET works great when playing around with requests on your local PC, but gets finicky when trying to connect to remote servers.  Plus, it's just plain tedious to work with.

I found that a better alternative is to write a little program to make these requests and then output the response to a text file.  It's actually pretty simple to do this in .NET by using the WebRequest class.  Here is a link to where you can find everything you need to know about WebRequest.

Thursday, July 16, 2015

Simple .NET Web.Config Transform Files

Let's say you have a web application, and you're ready to publish the changes either to test or production.  After you get the files published to the web server, you have to go into the web.config file and change the settings so that it points to the proper environment (database connection strings, web service URLs, etc.).  Most times you remember to do this, but sometimes you don't.  Or maybe you have somebody else do it, and they forget.  Or sometimes the web.config gets deleted from the web server, and you have to guess what all the settings were.  This is where a transformation file can really help.

Visual Studio automatically generates a transform file for both the release and debug configurations.  You can see these by clicking "Show All Files" and expanding the web.config.  The transform file is just a set of rules telling the publish profile how to change the web.config for that configuration.  A simple example is below:

  
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.serviceModel>
    <client>
      <endpoint name="TheWebServiceName" address="http://www.thisisfake.com/FictionalService.svc" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" ></endpoint>
    </client>
  </system.serviceModel>
</configuration>

Our web application calls a web service that is at a different URL in production than in our development environment.  Above is a simple example of a transform file that changes the address attribute of the endpoint element when the name matches "TheWebServiceName".

Monday, June 8, 2015

Visual Studio Git

Visual Studio provides Git tools and will automatically detect the presence of a local Git repository even if you have set it up using command line tools.  I suggest continuing to use the command line tools if you are comfortable with that.  It can be confusing when you start editing a file that you are tracking with Git.  All of a sudden there is a check mark next to the file in Solution Explorer.  What just happened?  The answer is nothing.  Visual Studio can compare the file with the most recent commit in the repository and it is just letting you know that the file has changed.  If you were to click the Commit button in Team Explorer (remember, I prefer the command line tools), Visual Studio would first stage the files (git add) and immediately commit (git commit) them.

Git Overview

Git is an open-source software version control system.

It is a decentralized system which means that the source code repository resides on your local machine.  You make your changes on your local PC, you commit those changes to a repository on your local PC.

You can create a remote repository on GitHub or Assembla and "push" your changes to those sites in order for your teammates to download and "clone" their own local repository.

You can download Git here:  http://www.git-scm.com  This download includes a couple of GUI tools and Git Bash.

Git is a Unix program.  Although many GUI's exist for using Git, it is recommended that you learn to interact with the original program using a command line.  If you are using Windows, Git Bash is the program that you will use to give these commands to Git.

First configure Git:

git config --global user.name "Steve Emrick"
git config --global user.email steve@steve.com

You need to create a local repository.  Navigate to the directory that contains the folder to store your repository files. Then run an init command.

cd c:\users\semrick
git init <nameofsubdirectory>

To do anything with a repository you have to change the current directory to the directory containing the repository files.

If you change a file in your repository, and you want to commit the change, you have to "stage" the file by adding the file to the "index":

git add <Name of File>

Or, if you have a bunch of files in your repository, and you change a handful, you don't have to add each file individually.  Using the following command will add and only add the files you have changed from what is in the last commit:

git add .

Add on the dry-run option if you just want to see which files will be added:

git add . --dry-run

Perhaps, you want to see which files you have changed, but not staged:

git status

To commit a file in the index:

git commit --message 'A comment'

At this point, you will probably want to create what is called a "remote repository" hosted on the internet. After signing up on Assembla.com and creating a repository there, follow the instructions that Assembla provides.  If you use the https method, you just use the command below. Otherwise if you choose (ssh), you'll probably have to generate a certificate and register it with Assembla and Git.

git remote add origin https://git.assembla.com/{repository name goes here}.git

This creates a remote repository named origin on Assembla.  To "push" a commit to the remote repository just:

git push origin master

To "pull" commits down from the remote repository, just:

git pull origin master

If you make a change to a file, and before you add it to the index and commit it, you decide to undo it, you would:

git checkout <FilenameWithRelativePath>

I believe this replaces the specified file with the version from the most recent commit.  Checkout has a different meaning in Git than in TFS.  An easy way to find the path and all files that have been changed is to do a git status.


Wednesday, April 1, 2015

SharePoint 2007 Session Timeout

You can set the timeout of the session in SharePoint 2007 by opening up Central Administration, clicking Application Management, and clicking Manage Session State.

Monday, March 30, 2015

The Distinct Statement in LINQ

The Distinct statement in LINQ is pretty straight-forward:

Dim SearchResults = (
    From a In EntityName
    Select a.Column1, a.Column2, a.Column3
).Distinct()

However, if EntityName is a view, you may notice the Distinct statement might not work.  You may find that your results contain duplicate rows.  How can this be?

The Distinct capability is only available on columns that aren't set as "unique".  And this makes sense, I suppose, because why would anyone want to do a Distinct on a column where duplicates are impossible?

But if your EntityName is a view, and one of the columns comes from a unique table column, then Entity Framework marks it as an "Entity Key" in the EDMX data model.  Of course, if your view is joining tables, like they often do, you could certainly expect some duplicates in these key fields.  This is exactly the case where a Distinct statement would not work for you.

The lesson here is to open up the EDMX data model, and set the Entity Key property of any non-unique columns in your view to False.  Then Distinct should work properly.

Tuesday, February 24, 2015

PowerShell

PowerShell is a command line administration tool that comes with Windows.  I haven't used it much as a developer, but I have discovered a few little things that make me think it could be useful for discovering what certain .NET objects are capable of without compiling new code.

Check this out:


I created a variable called MyString, and then tested out the SubString function.

Then I wanted to see how the GeneratePassword method of the Membership class worked, so I imported the assembly that contains the Membership class, and called GeneratePassword.

I can see this being useful because I can call .NET code on the fly without first creating a project in Visual Studio.

Thursday, February 19, 2015

ASP.NET Web Api 404 errors

I recently deployed a ASP.NET Web Api web service to a production server and kept getting 404 errors when I made requests.  After extensive research I finally traced the problem to the web.config file.  I don't totally understand why this fixed it, but it has something to do with how IIS resolves the URL.

In the web.config, you'll find this line:

<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

This needs be changed to:

<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

Notice the removal of the period from the "path" attribute.

Wednesday, February 4, 2015

Response.Redirect

When you redirect to another page using .NET, you normally use the Response.Redirect method.  However, if you only supply the URL as the parameter, you'll get a ThreadAbort exception thrown. This can fill the event log pretty darn quick.  To avoid this, set the second parameter to False.  This will immediately end the response, so no exception is thrown.

The only "exception" to this rule (haha), is when you want code to execute after the Response.Redirect.  In this case you can't immediately end the response.  In this case, you either have to put up with the exceptions in the log, or catch the ThreadAbort exception and just swallow it.

Thursday, January 22, 2015

SOAP and REST

I found a really great article that very simply describes the difference between SOAP and REST.  Most articles you read are written by folks that know a lot about one protocol but not the other.  And usually they are very biased toward REST.  For example, you'll see articles like "Why SOAP sucks" and the like.

In my experience SOAP is easier to create clients with if you have an IDE that can generate code using the WSDL file.

REST is easier to create clients with if you're calling the web service from JavaScript or you don't have code generation tools.

http://blog.smartbear.com/apis/understanding-soap-and-rest-basics/

Thursday, January 8, 2015

SharePoint 2007 - Determine Configuration Databases

It can be difficult to see which databases are used by which SharePoint farm especially when you have been experimenting with several different environments.

To see what databases are used simply open up Central Administration, and click Operations.  Then go to Perform a Backup.  On this page, you will see all of the configuration databases used by this farm.

Of course, if it's content databases you're interested in, simply go to the Content Databases page under Application Management.

Monday, January 5, 2015

.NET Framework and CLR Versions

In this article, I'm going to attempt to explain what a developer needs to know about the relationship between the .NET CLR version and the .NET Framework version.  I am not attempting to explain what the CLR is or is not.  I am also pretending that version 1.0 did not exist, because I never used it.

First, there was .NET Framework version 2.0 which included .NET CLR version 2.0.  You wrote an application that targets .NET 2.0.  You installed .NET Framework 2.0 on your server, and installed your application.

Then Microsoft released .NET Framework version 3.0 but still included .NET CLR version 2.0.  You installed .NET Framework 3.0 on your server, and since your application was built using a version of the framework that included .NET CLR version 2.0, your application will continue to run with version 3.0 of the Framework.

Then Microsoft released .NET Framework version 3.5 but still included .NET CLR version 2.0.  You installed .NET Framework 3.5 on your server, and again since you application was built using a version of the framework that included .NET CLR version 2.0, you application will continue to run with version 3.5 of the framework.

Then everything changed with .NET Framework version 4.0.  Version 4.0 shipped with CLR version 4.0.  Your app won't work with version 4.0 unless you recompile the app with it targeted to .NET 4.0.  However, on your server, .NET 3.5 will remain installed, so you're app will still work using .NET 3.5 as it did before.

Now, .NET Framework version 4.5 (and 4.5.1) is now out.  These ship with CLR version 4.0.  So if you install 4.5 on your server, your apps built using 4.0 will still work using the new framework.

Determine which version of the .NET Framework is installed


  1. Open the Registry Editor (regedit).
  2. First look here:  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP.  Expand NDP and you will see all of the versions installed.
  3. To see if 4.5 and over is installed, you need to expand the v4 folder and click "Full".  Look at the version entry to see what version of 4 is installed.