Thursday, November 13, 2014

Setup Remote Debugging in Visual Studio 2013

Sometimes you need to debug an application running on a different server than the one you have Visual Studio installed on.  You can install something called Remote Tools for Visual Studio on the server where the application is running and debug from the other machine.
  1. Download Remote Tools for Visual Studio 20XX Update X.  Make sure you download the version and update number that matches your version of Visual Studio.
  2. Install it on the remote server.
  3. On the remote server, start up the application called Remote Debugger as administrator.
  4. In Visual Studio, choose Attach to Process in the Debug menu.
  5. Type the name of the server, and click "Refresh".
  6. Highlight any instances of w3wp.exe (assuming you are debugging a web app), and click attach.
You must remember that in order for this to work, you have to build your application in debug configuration, so that the .pdb files are deployed to the remote server.

Wednesday, September 10, 2014

Create a secure ASP.NET Web Api web service from scratch.

In a previous post, I described how to create a secure WCF web service.  Here, I will describe how to set up the same type of service using ASP.NET Web Api technology.

Initial Setup

First, create a new project using the ASP.NET Web Application template.  Choose the Web Api project template with No Authentication.

In the Web tab of the Project Properties, change it to Local IIS, and create a virtual directory.  Then change the application pool of this virtual directory to a pool that uses your own more powerful account.  While, you're in there, require SSL.

At this point, make sure you're everything is working by browsing to the api using this uri:  NameOfSite/api/values/5.  If you get json in return, you're good so far.

Authentication

Authentication and authorization can be configured automatically for you if you choose Local Accounts when you add the project.  However, if you want to implement your own custom authentication and authorization code, you need to jump through some hoops.

Authentication of a Web Api is done through what is called an Http Module.  This is a bit of code that you write that actually runs on IIS before the request hits your web service.  It's pretty heavy stuff, but is the only way I know how to do this at the time of this writing.  Add an Infrastructure folder to your project and add a class that implements the IHttpModule interface.  Like this:
Imports System.Net.Http.Headers
Imports System.Security.Principal

Public Class BasicAuthHttpModule
    Implements IHttpModule

    Public Sub Dispose() Implements IHttpModule.Dispose

    End Sub

    Public Sub Init(context As HttpApplication) Implements IHttpModule.Init
        AddHandler context.AuthenticateRequest, AddressOf OnAuthenticateRequest
        AddHandler context.EndRequest, AddressOf OnEndRequest
    End Sub

    Private Sub SetPrincipal(principal As IPrincipal)

        Threading.Thread.CurrentPrincipal = principal

        If HttpContext.Current IsNot Nothing Then
            HttpContext.Current.User = principal
        End If

    End Sub

    Private Function CheckUserNameAndPassword(userName As String, password As String) As Boolean

        If userName = "Steve" And password = "topsecret" Then
            Return True
        Else
            Return False
        End If

    End Function

    Private Function AuthenticateUser(userNamePasswordCombo As String) As Boolean

        Dim Validated As Boolean = False

        Try
            Dim MyEncoding = Encoding.GetEncoding("iso-8859-1")

            userNamePasswordCombo = MyEncoding.GetString(Convert.FromBase64String(userNamePasswordCombo))

            Dim Separator As Integer = userNamePasswordCombo.IndexOf(":")
            Dim UserName As String = userNamePasswordCombo.Substring(0, Separator)
            Dim Password As String = userNamePasswordCombo.Substring(Separator + 1)

            Validated = CheckUserNameAndPassword(UserName, Password)

            If Validated Then

                Dim MyIdentity = New GenericIdentity(UserName)
                SetPrincipal(New GenericPrincipal(MyIdentity, Nothing))

            End If

        Catch ex As Exception
            Validated = False
        End Try

        Return Validated

    End Function

    Private Sub OnAuthenticateRequest(sender As Object, e As EventArgs)

        Dim MyRequest As HttpRequest = HttpContext.Current.Request
        Dim AuthHeader As String = MyRequest.Headers("Authorization")

        If AuthHeader IsNot Nothing Then

            Dim AuthHeaderValue = AuthenticationHeaderValue.Parse(AuthHeader)

            If AuthHeaderValue.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) And AuthHeaderValue.Parameter IsNot Nothing Then
                AuthenticateUser(AuthHeaderValue.Parameter)
            End If

        End If

    End Sub

    Private Sub OnEndRequest(sender As Object, e As EventArgs)

        Dim MyResponse As HttpResponse = HttpContext.Current.Response

        If MyResponse.StatusCode = 401 Then
            MyResponse.Headers.Add("WWW-Authenticate", "Basic realm=""My Realm""")
        End If

    End Sub

End Class



To enable IIS to use this HTTP Module, add the following to your web.config:
<system.webServer>
    <modules>
      <add name="BasicAuthHttpModule"
        type="NameOfWebApplication.BasicAuthHttpModule, NameOfWebApplication"/>
    </modules>
</system.webServer>

In IIS, you also need to disable all authentication including anonymous on the site where the web api is hosted.

Do a quick test in the browser.  You should find that a login window comes up (in IE anyway) with which to provide your credentials.

Next, you'll want to create a little client application to test the web service.  A console application works great for this.  However, you will need to install a NuGet package called Microsoft ASP.NET Web API Client Libraries.  The id is Microsoft.AspNet.WebApi.Client.  Here is the code to call the Get method from your console:
    Async Function WebApiGetAsync() As Task

        Using Client As New HttpClient()

            Client.BaseAddress = New Uri("https://NameOfServer.Domain.com/NameOfSite/")
            Client.DefaultRequestHeaders.Accept.Clear()
            Client.DefaultRequestHeaders.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json"))

            Dim ByteArray = Encoding.ASCII.GetBytes("Steve:topsecret")
            Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Basic", Convert.ToBase64String(ByteArray))

            Dim Response As HttpResponseMessage = Await Client.GetAsync("api/values/5")

            If Response.IsSuccessStatusCode Then

                Dim Results As String = Await Response.Content.ReadAsStringAsync()

                Console.WriteLine(Results)

            Else

                Console.WriteLine(Response.StatusCode.ToString)
                Dim Results As String = Await Response.Content.ReadAsStringAsync()
                Console.WriteLine(Results)

            End If

        End Using

    End Function

Authorization

To create your own custom authorization, you just need to create your own Authorization Filter.  Just add a class called CustomAuthorizeAttribute to your Infrastructure folder like this:
Public Class CustomAuthorizeAttribute
    Inherits System.Web.Http.AuthorizeAttribute

    Protected Overrides Function IsAuthorized(actionContext As Http.Controllers.HttpActionContext) As Boolean
        Dim Authorized As Boolean = False

        For Each ThisRole As String In Roles.Split(",").ToList

            If SomeCustomLibrary.IsInRole(Threading.Thread.CurrentPrincipal.Identity.Name, ThisRole) Then
                Authorized = True
                Exit For
            End If

        Next

        Return Authorized
    End Function

End Class

There are a few things to note here.

  1. You must inherit System.Web.Http.AuthorizeAttribute and not System.Web.Mvc.AuthorizeAttribute.  
  2. This is invoked by using <CustomAuthorize(Roles:="RoleName1, RoleName2")>
How to call a POST from a client

To call a POST method from your client, do the following:
    Async Function WebApiPostAsync() As Task

        Using Client As New HttpClient()

            Client.BaseAddress = New Uri("https://NameOfServer.YourDomain.com/NameOfSite/")

            Dim MyModel As New ParameterModel With {.Parameter1 = "From the Web Service.", .Parameter2 = 484507, .Parameter3 = Now.Date}

            Dim ByteArray = Encoding.ASCII.GetBytes("Steve:topsecret")
            Client.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Basic", Convert.ToBase64String(ByteArray))

            Dim Response As HttpResponseMessage = Await Client.PostAsJsonAsync("api/NameOfController", MyModel)

            If Response.IsSuccessStatusCode Then

                Dim Results As String = Await Response.Content.ReadAsStringAsync()

                Console.WriteLine(Results)

            Else

                Console.WriteLine(Response.StatusCode.ToString)
                Dim Results As String = Await Response.Content.ReadAsStringAsync()
                Console.WriteLine(Results)

            End If

        End Using

    End Function

There are some key differences here between WCF and Web API.  With WCF, you can just call a function and specify parameters just like you would if the method was local.  With Web API, in cases of GETs the parameters are either provided via the URL with query parameters or the route.  With POSTs you pass a JSON object as data.  This JSON object has a "property" for each parameter that you need.





Thursday, September 4, 2014

Use SoapUI to test your web services

Recently, I created a web service that external organizations would use as an API to access our data.  I decided to use WCF and the SOAP architecture to achieve this.  I also created a little .NET console app to test the web service.  Everything worked great.  However, I was a little concerned that I might have unintentionally wrote some code that was only supported by the Microsoft stack.  How could I be sure that my web service could be used by someone using a different platform?

My first idea was to try to access the web service using jQuery.  I felt that if I could successfully invoke the web service using jQuery or JavaScript, this would demonstrate that Microsoft technology wasn't necessary to use my service.  However, I found that calling a SOAP based web service from client side scripting is not an easy task.  In fact, I never got this to work, and there is not a lot of information out there about how to do this.  One problem is that browsers have security measures to stop cross site scripting.  So the web service has to be part of the same site.  If you can get past that, you also have to manually build the SOAP envelope in your javascript which is tedious.  On top of that you have to figure out how to specify your logon credentials within the request.  I concluded that it is just not practical to call a SOAP service from the client.  I think this is where the advantages of using a REST style web service really pay off.

I discovered a widely used application called SoapUI.  It is a free download, and you can use it to invoke the methods of your web service for testing purposes.  This is a way to independently test your web service operations without being bound to Microsoft.

Installation is straight forward and instructions can be found on the site.  Note that you do not need to install Hermes if you're not testing a Java service.

Here is how to test a web service operation.

  1. Open SoapUI and right click on Projects, New SOAP Project.
  2. Name the project and specify the address of the WSDL of your service.
  3. Check the box that says Create Sample Requests.
  4. In the navigator, you'll see each operation of the service.  If you click the plus sign next to each operation you will see the sample request that was created for you.
  5. Click on the request and find the request properties.
  6. If the web service security is set up for TransportWithMessageCredential, then set the username and password properties to something that works.  Also set the WSS-Password Type to PasswordText.
  7. Double-click the request.
  8. In the request window, you'll see the SOAP envelope.  You can see where the parameters go, and can set these here.
  9. Then, click the green arrow which sends the request to the web service.
  10. The results will be shown in the right-hand pane.

Thursday, August 21, 2014

Quick way to see system information

This gives you a bit more detail than System Properties.
  1. Open a command prompt.
  2. Type msinfo32.

Monday, August 4, 2014

Using layer diagrams to validate your architecture

A problem with solutions that have a more sophisticated architecture is ensuring that developers adhere to the design.  It's pretty easy for a developer to inadvertently (or on purpose) ignore the system design and code it "just so it works".  One of the tools you can use to combat this is using a layer diagram in Visual Studio 2013 to validate your architecture.  This works best when adopting this from the very beginning of a project.

  1. Add a project using the Modeling Project template.  
  2. From the Architecture menu, choose New Diagram.
  3. Choose Layer Diagram.
  4. You can drag "stuff" from both the Architecture Explorer as well as Solution Explorer.
  5. Each time you drag something to the diagram, you create a "layer" for that "artifact".
  6. I tend to group likewise classes into namespaces, so dragging namespaces from the Architecture Explorer works well for me.
  7. To create higher-level (project level) layers, instead of dragging the project into the diagram, it works better to create your own generic layer that is not tied to any code, and then dragging the namespace layers into your generic layers.
  8. You can also drag individual classes from Solution Explorer onto the diagram.
  9. Once you have all your layers defined, then select all of the layers, right click, and choose Generate Dependencies.
  10. At this point, if you right click in some white space and choose Validate Architecture, you should validate fine.
  11. If anyone goes rogue and violates your architecture, then Validate Architecture will fail and direct you to the offending code.

Extension Methods and Namespaces

When working with Extension Methods, they will not be available unless you import the namespace in which they are found.  Extension methods appear that they are part of the object you are using but they are actually in a totally different module.  So, they won't show up in intellisense or complile or that matter if you don't import the namespace.

Friday, August 1, 2014

Setting up a secure WCF web service from "scratch" with ASP.NET Identity

For this example, I'm using Visual Studio 2013 with Update 2 installed.  Update 2 will ensure that the templates use the latest and greatest versions of all technologies involved.

Add a project using the WCF Service Application template.  You could also use the Asp.Net Web Application template, but I think you'll just end up with a bunch of extra references you don't need.  Now take a look at the web.config file.  You'll notice that using this template automatically adds the protocolMapping element which allows the service to be accessed using https.  If you did not use this template, you would have had to add this for https support.  You'll also notice that there are no endpoints or bindings configured.  That's because WCF has default bindings and IIS can determine the endpoint by examining the .svc file.

I delete the sample service created for you.

Next, I find it convenient to host the web services I'm developing on my local IIS.  Click on My Project, Web tab, and type http://{name of your computer}.{domain}.{com}/{something meaningful}.  It is important to use the fully qualified name of your computer because the certificate you will soon use is named the same and WCF won't like it if they are not the same.  Click Create Virtual Directory.  Open up IIS Manager, and change the app pool of the site to one with an associated identity of your (hopefully powerful) account.  This becomes important when you connect to a database for authentication.

Add your web service by using the WCF Service template.  Build the solution, and right click the service.  Choose View in Browser to make sure all is well so far.

Now it's time to enable SSL (https).  Read here to do this.  At this point, you'll want to change the Project URL to include https on the Web tab when you go to My Project.  I think it's a good idea to go ahead and setup a binding configuration and an endpoint.  As I said earlier, WCF can figure all this out because of default values.  However, Visual Studio's Add Service Reference automatic proxy generator can get confused when you are setting up a client.  You can either use the Microsoft Service Configuration Editor (Right click web.config and choose Edit WCF Configuration) tool or edit the web.config by hand.  If you use the tool, just click the Service folder, and choose Create a New Service.  This will walk you through a wizard to create the service node.  After that there is a link to create the binding configuration.  You end up with this inside the <system.serviceModel> element:

    <bindings>
      <basicHttpsBinding>
        <binding name="BasicHttpsBindingConfig" />
      </basicHttpsBinding>
    </bindings>
    <services>
      <service name="AssemblyName.YourService">
        <endpoint address="https://ComputerName.domain.whatever/IISSite/YourService.svc"
          binding="basicHttpsBinding" bindingConfiguration="BasicHttpsBindingConfig"
          contract="AssemblyName.IYourService" />
      </service>
    </services>

You also need to set the multipleSiteBindingEnabled to False when you are using https:

<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="false" />

At this point, I would create a little test app in a completely different solution and make sure you can call your new web service.  A Windows Console app will work great.  Just Add, Service Reference and specify the endpoint of the service.  By adding the reference, Visual Studio will add the following to your app.config file:

        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpsBinding_IYourService">
                    <security mode="Transport" />
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://ComputerName.domain.whatever/IISSite/YourService.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpsBinding_IYourService"
                contract="BenefitsServiceReference.IYourService" name="BasicHttpsBinding_IYourService" />
        </client>

There are a couple of things to note here.  Why does the client configuration set up for basicHttpBinding when the server configuration is set up for basicHttpsBinding?  Essentially basicHttpBinding and basicHttpsBinding are exactly the same.  The only difference is that basicHttpsBinding includes the <security mode="Transport" /> by default.

Now that the web service is up and running with SSL we want to configure it to require credentials in order to access it.  You can use the ASP.NET Membership, but this has been superceded by ASP.NET Identity and WCF doesn't directly interface with ASP.NET Identity yet.  So, we will create a custom user name and password validator which we will eventually use to authenticate with ASP.NET Identity.  First, we need to create the validator class itself.  Add references to the following:
  • System.IdentityModel
  • System.IdentityModel.Selectors
Add this class to your project:

Imports System.IdentityModel.Selectors
Imports System.ServiceModel

Public Class CustomUserNameValidator
    Inherits UserNamePasswordValidator

    Public Overrides Sub Validate(userName As String, password As String)

        If Not (userName = "Steve" AndAlso password = "topsecret") Then

            Throw New FaultException("Unknown Username or Incorrect Password")

        End If

    End Sub

End Class

It's pretty obvious what is happening here.  If your User Name and Password is not right, an exception gets thrown back to the client.  Now we have to configure the web service to use this.  First of all we need to edit our binding configuration.  Remember that by default basicHttpsBinding uses Transport as the Security mode.  We need to change this to TransportWithMessageCredential.  We are protecting (SSL) the service at the transport (IIS) level and authenticating at the message (web service) level.  Here is the binding configuration after we do that:

    <bindings>
      <basicHttpsBinding>
        <binding name="BasicHttpsBindingConfig">
          <security mode="TransportWithMessageCredential" />
        </binding>
      </basicHttpsBinding>
    </bindings>

You also need to add a serviceCredentials behavior to your existing behavior element:

    <behaviors>
      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom"
              customUserNamePasswordValidatorType="AssemblyName.CustomUserNameValidator, AssemblyName" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>

As with most configuration changes, here you're definitely better off using the Service Configuration Editor tool.  This is where we specify our custom class for validating the user name and password.  Note the specific way that the class is specified along with the assembly that contains the class.

The only configuration change in your client console app is changing the security mode to "TransportWithMessageCredential".  When you run your console, you will notice that you'll get an exception if you fail to provide credentials.  To specify the client's credentials, do the following:

        YourServiceProxy.ClientCredentials.UserName.UserName = "Steve"
        YourServiceProxy.ClientCredentials.UserName.Password = "topsecret"

If the client provides accurate credentials, then the service will return results; otherwise, an exception will be thrown.

With this infrastructure in place, you can change the code in the CustomUserNameValidator class to connect to any database you want to authenticate.  I mentioned earlier my desire to access ASP.NET Identity to authenticate users for the web service.  In a separate solution, I have set up an ASP.NET MVC Web Application and configured it with ASP.NET Identity authentication.  I am going to use this web application to administer user accounts for my web service.  I simply add this class to my MVC project:

Imports Microsoft.AspNet.Identity
Imports Microsoft.AspNet.Identity.EntityFramework

Public Module SecurityManager

    Public Function IsAuthenticated(userName As String, password As String) As Boolean

        Dim MyUserStore As UserStore(Of IdentityUser) = New UserStore(Of IdentityUser)
        Dim MyUserManager As UserManager(Of IdentityUser) = New UserManager(Of IdentityUser)(MyUserStore)

        Dim MyUser As IdentityUser = MyUserManager.Find(userName, password)

        If MyUser Is Nothing Then
            Return False
        Else
            Return True
        End If

    End Function

End Module

Now, if I can call this function from my CustomUserNameValidator in my WCF project, I will be authenticating using ASP.NET Identity.  First add a reference to the dll produced by building the MVC project.  Then, simply add this code to your CustomUserNameValidator:

        If Not SecurityManager.IsAuthenticated(userName, password) Then
            Throw New FaultException("Unknown Username or Incorrect Password")
        End If

Of course, it's not quite that easy.  You need to do two more things:
  1. Use NuGet to install the same version of Entity Framework that your MVC project uses.  This will setup your web.config with some special Entity Framework stuff that you will need.
  2. Copy the connectionStrings section out of the MVC web.config file and put it into the WCF web.config file.  This connection string contains the database where the identity data is.
To get the name of the user who is accessing your service use this line:

System.ServiceModel.ServiceSecurityContext.Current.PrimaryIdentity.Name

So there we go.  We now have a secure web service.  Only accessible via https and secured by credentials stored in an ASP.NET Identity database.

Wednesday, July 30, 2014

Protect a WCF service using SSL - Part 2

In a prior post, I described how to protect a WCF service using SSL.  In the service .config file, you must do the following in order to expose the https endpoint:

<configuration>
  <system.serviceModel>
    <protocolMapping>
      <add scheme="https" binding="basicHttpsBinding" />
    </protocolMapping>
  </system.serviceModel>
</configuration>

The client configuration also needs some specific settings:

    <system.serviceModel>
        <bindings>
          <basicHttpsBinding>
            <binding name="BasicHttpsBinding_IDayOfTheWeekService"></binding>
          </basicHttpsBinding>
        </bindings>
        <client>
            <endpoint address="https://computername.yourdomain.net/WcfSecureServer/DayOfTheWeekService.svc"
                binding="basicHttpsBinding" bindingConfiguration="BasicHttpsBinding_IDayOfTheWeekService"
                contract="DayOfTheWeekReference.IDayOfTheWeekService" name="BasicHttpsBinding_IDayOfTheWeekService" />
        </client>
    </system.serviceModel>

Note that I am using basicHttpsBinding.  This just came out with .NET 4.5.  It's exactly the same as basicHttpBinding except the <security mode="Transport" /> is default so you don't have to specify this.  Also, if you generate your own certificate, you will get an error message that says something like:
Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost'
This is because WCF doesn't trust your self generated cert.  However, if you generate a certificate with the name of the computer that it is issued to, and specify the fully qualified name of the computer in the URL like I did above, WCF will allow it.

Tuesday, July 29, 2014

Specify ASP.NET timeout

ASP.NET will only allow a request to execute for 110 seconds by default.  This can be easily extended in the web.config with the following attribute:

<configuration>
  <system.web>
    <httpRuntime executionTimeout="300" />
  </system.web>
</configuration>

This example sets the timeout to 300 seconds.

Friday, July 18, 2014

WCF and ASP.NET Web API

When writing web services using .NET technology, you have a few options.

WCF:  Tried and true, this is the successor to the original ASMX style web services.  WCF has capabilities to create any type of service that can be accessed over a network, not just HTTP.  WCF tends to be a bit configuration heavy requiring the use of a special tool in Visual Studio to set the myriad of options up.  WCF generally uses the SOAP protocol.  While it is possible to create a REST style web service using WCF, it is recommended by Microsoft to use Web API technology for REST style web services.

ASP.NET Web API:  Web API allows you to create a REST style web service (no SOAP support) using an architecture that is very similar to MVC.  You create a set of controllers and configure a routing system to create your operations and accept parameters.  This tends to be simpler to setup and configure as it is very close to what you would do to configure an MVC web application.

There are also a couple of terms that need to be defined:

REST style web service:  When you apply a REST architecture to a web service, this changes the way in which the client calls the operations of the web service.  With a traditional web service, each call is represented by an HTTP GET verb with the URL that represents the name of the operation.  With a REST style web service, the URL represents a set of operations that are differentiated by the use of 4 different HTTP verbs (GET, POST, PUT, and DELETE).   I believe that the advantage of REST is that it is (allegedly) easier and makes more sense when called from client side code like JavaScript.  Therefore, it can be consumed by a wider variety of devices.  Also REST is necessary when implementing a data API using the OData protocol.

OData Protocol:  OData is set of specifications for creating a data API.  A data API is a service that exposes your database more directly over the web.  Instead of abstract operations that perform CRUD operations on the callers behalf, the data API allows the consumer to perform the CRUD operations nearly directly.  For example, each table could be represented as a URL and the user could query the table directly or even join together multiple tables.  This has the effect of moving the business logic to the client.

Conclusions

Using OData to access a database over the internet sounds like it could be useful.  And obviously you need to use REST in order to implement this.  However, setting up an OData endpoint using Web API is anything but straight forward right now.  In my opinion, this technology needs to mature a little longer for me to recommend using it.

If you're not going to use OData, then I just don't see the big advantage of using REST.  It seems to me that it would be awkward to organize your operations into sets of four HTTP verbs.  Another big disadvantage to using REST, is that there is no automatic proxy generation for consumers of REST style services.  Web API does seem like it works well, but it requires a REST style architecture.

This is my bottom line:  If you want to use a REST architecture, use Web API.  If you want to use a SOAP architecture, then use WCF.  At this time, I will continue to use SOAP and therefore WCF.

Wednesday, July 16, 2014

WCF Message Tracing

Message Tracing logs details on each communication in and out of the web service.  When making significant configuration changes, it is almost always best to use the Microsoft Service Configuration Editor to edit the web.config.  In many cases, it is just not practical to edit the web.config directly.  To access the editor, in the Visual Studio Solution Explorer, right click the web.config of the service and click Edit WCF Configuration.

To configure message tracing, follow these steps in the Configuration Editor:

  1. In the Diagnostics folder, click Message Logging and set LogEntireMessage to True.  Also set LogMessagesAtServiceLevel and/or LogMessagesAtTransportLevel to True, depending on your needs.  Most of the time these messages will be identical.  If you are encrypting at the message level, then the message logged at the transport level will be encrypted.  If you are encrypting at the transport level, then both will be unencrypted and practically identical.  The Transport Level is the host level.  So this is logged when the host (IIS in most cases) redirects the message to the service.  The Message Level is the actual service level.
  2. In the Diagnostics folder, right-click Sources and choose New Source.
    • From the drop down, choose System.ServiceModel.MessageLogging
    • Choose Verbose as the Trace Level.
  3. In the Diagnostics folder, right-click Listeners and choose New Listener.
    • Type "MessageLog" as the Name.
    • In the InitData field, use the browse button to set a path and filename of the logfile.
    • TraceOutputOptions:  Click the drop down and select which options you want.  I just like to include the DateTime
    • TypeName:  Click the ellipses and choose System.Diagnostics.XmlWriterTraceListener
To view the log file, you want to use a tool called Microsoft Service Trace Viewer.  I believe this is included with Visual Studio.  To find it just do a search using the start button for Service Trace Viewer.  Or try just right-clicking the log file and choosing Open.

An alternative way to accomplish this is:

  1. Click the Diagnostics folder and then click the Enable Message Logging link.
  2. Set the Log Level by clicking the link next to the "Log Level:" label and only check the Service messages box.
  3. Click on the link of the listener, and choose a location and options as described above.
  4. You may also want to click the Message Logging node and choose Log Entire Message.
  5. You may also want to click the Source that was created and select Verbose.



UPDATE 7/22/2015:  Curiously, I couldn't find it on a PC that I know has .NET installed.  I found it here:  C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools

UPDATE 7/24/2015:  Added the alternative method of setting up tracing.  I had some issues getting the standard method to work.

Tuesday, July 15, 2014

Protect a WCF service using SSL - Part 1

We have a scenario where we are exposing a WCF service over the internet that is hosted in IIS.  We want the communication with the service to be protected using SSL.  The encryption/decryption is handled completely by IIS, so there is minimal need to edit the configuration of the service itself (See Part 2).  First you need a certificate.  To create your own for testing:

  1. Open IIS (as administrator).
  2. Choose the top level node in the Connections pane.
  3. Click Server Certificates in the IIS section of the middle pane.
  4. Click Create Self Signed Certificate.  The friendly name should match the name of the computer.
Now configure SSL:
  1. Right click Default Web Site and choose Edit Bindings.
  2. Click Add, choose HTTPS, and select the certificate you just created.
Finally, set up your service to require SSL:
  1. Click on the web application that hosts your service.
  2. In the middle pane, IIS section, double click on SSL Settings and check the "Require SSL" box.

Friday, June 27, 2014

Changing the SharePoint 2007 farm account password

When you first configure SharePoint 2007 and it's associated Shared Services Provider on a server, you specify a username and password in several places.  You will see this informally called the "farm account".  If this password ever gets changed, there are a few hoops you need to jump through in order for SharePoint to continue to function.  This page demonstrates the different steps to accomplish this.  I'll summarize here:

stsadm -o updatefarmcredentials -userlogin DOMAIN\USERNAME -password THEPASSWORD

iisreset /noforce

stsadm -o updateaccountpassword -userlogin DOMAIN\USERNAME -password THEPASSWORD –noadmin

stsadm -o spsearch -farmserviceaccount DOMAIN\USERNAME -farmservicepassword THEPASSWORD

stsadm -o spsearch -farmcontentaccessaccount DOMAIN\USERNAME -farmcontentaccesspassword THEPASSWORD

stsadm -o osearch -farmserviceaccount DOMAIN\USERNAME -farmservicepassword THEPASSWORD

stsadm -o editssp -title SharedServicesProviderName -ssplogin DOMAIN\USERNAME -ssppassword THEPASSWORD

iisreset /noforce

Go to the Shared Services Provider page, Search Settings, and click on the Default content access account.  Change the password here.

Wednesday, June 25, 2014

Removing a stubborn assembly from the GAC

Sometimes when removing a assembly from the GAC, you will get an access denied message.  In this case, you'll need to use the gacutil utility to remove the file.  This is installed as part of Visual Studio and can be accessed by opening a Visual Studio Command Prompt.  If the computer you are working with does not have Visual Studio installed, you can copy the tool from a computer that does.  Just stick it in the framework folder:  C:\Windows\Microsoft.NET\Framework\v....

Here is the command to remove the file:

gacutil -u NameOfFileGoesHereWithoutTheExtension

Thursday, June 12, 2014

Recaptcha

If your project requires CAPTCHA functionality, I highly recommend Recaptcha.  Recaptcha is a free service offered by Google that serves up CAPTCHA functionality.  First, you need to sign up here.  Assuming you've got a google id and are signed in, all you need to provide is the domain where you will be using recaptcha.  Google will provide you a public and private key that will be used by the recaptcha control.

For ASP.NET, you just need to download the recaptcha dll and reference it in your project.  Then put this at the top of the page where the CAPTCHA functionality is needed:

<%@ Register TagPrefix="recaptcha" Namespace="Recaptcha" Assembly="Recaptcha" %>

This snippet will render the CAPTCHA control itself:

                    <recaptcha:RecaptchaControl
                        ID="recaptcha"
                        runat="server"
                        Theme="white"
                        PublicKey="Provided By Google"
                        PrivateKey="Provided By Google"
                    />


And finally, this code will check to make sure the correct code was entered. This assumes you have a ValidationSummary control on your page.

        If Page.IsValid = False Then
            Return
        End If

jQuery Plugins

Sometimes you will come across some bit of functionality that jQuery doesn't handle natively and jQuery UI doesn't offer up a solution.  For example, let's say you need to implement a mask on a text box for a phone number.  You could use the Ajax Control Toolkit, but I've had issues getting this to work so I don't recommend it.  I love jQuery and jQuery UI, but you can't do this "out of the box".

A jQuery plugin is an extension of jQuery that "some guy" has written to accomplish something that jQuery doesn't do by itself.  In fact, jQuery UI is basically a "plugin".  The only difference is that jQuery UI is official and a plugin is not.  And this is what makes me a little hesitant to use plugins.  But, in the case of our phone number mask example, I think it's probably the best fit.

First go to the jQuery Plugins page and find something you think will work.  The inputmask seemed to work well for me.  Download all the files, and stick them all in a folder in your project folder.  There should be some documentation either on the plugin page or downloaded into your folder.  It will tell you how to use the plugin in your code.  As an example, here is how I used the inputmask.

First add this script to your page.

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="InputMask/dist/jquery.inputmask.bundle.js" type="text/javascript"></script>

Note that I'm using a content provider (google) to host the "out of the box" jQuery code.  This is simply for brevity.

Then your jQuery would look like this:

        $(document).ready(function () {
            $("#txtPhoneNum").inputmask("999-999-9999");
        });

Friday, May 16, 2014

ApexSQL Search

ApexSQL Search is a free tool that can be used to search SQL Server databases for objects as well as creating charts that illustrates dependencies within the database.  The tool can be found here.

The tool is an add-in for Visual Studio and Sql Server Management Studio.  After installation, ApexSQL will show up in the menu for both applications.  Mostly, I run it when in Visual Studio.  Just open the Server Explorer window and create a database connection.  Select the connection and choose one of the options from the APEXSQL menu.  Select View Dependencies to open up a Dependency Viewer window that will show you a chart with every dependency in the database.  This will be overwhelming, so you can toggle off different dependency types in the toolbar.

UPDATE 2/15/2019:  The View Dependencies feature is no longer part of the free ApexSql tool.  It looks like this is now part of their ApexSql Analyzer tool which is most definitely NOT free.

Thursday, May 15, 2014

Windows Communication Foundation

I like to think of Windows Communication Foundation (WCF) as the portion of the .NET Framework that concerns the hosting and consumption of services.  A "service" can be thought of as a server program that exposes a set of operations that is accessible to client programs over a network.  A service that provides its operations over the internet can be thought of as a "web service".

A WCF service consists of:
  1. An interface that defines both the service and its operations.
  2. A class that provides the implementation of the operations.
To create a WCF service in Visual Studio:
  1. Add an ASP.NET Web Application project (Use the "Empty" template) or a WCF Service Application project.
  2. Then add a WCF Service item.
The WCF service must be hosted.  The obvious choice is to host it in IIS.  However, the service can be hosted in any .NET Windows application as well.

How does the host know to listen for requests?  Setting in the web.config file.  The following configuration indicates to the .NET framework that a WCF service is running:

  <system.serviceModel>
    <services>
      <service name="ProjectName.DayOfTheWeekService">
        <endpoint address="http://localhost:8000/DayOfTheWeekService.svc" binding="basicHttpBinding"
                  name="basicHttpBinding_IDayOfTheWeekService"
                  contract="ProjectName.IDayOfTheWeekService" />
      </service>
    </services>
  </system.serviceModel>

If you wanted to host this in IIS, just publish the files to a site.  If you wanted to host it in a Windows Form app, do something like this:

    Private MyServiceHost As System.ServiceModel.ServiceHost

    Private Sub ButtonStart_Click(sender As Object, e As EventArgs) Handles ButtonStart.Click
            MyServiceHost = New System.ServiceModel.ServiceHost(GetType(ProjectName.DayOfTheWeekService))
            MyServiceHost.Open()
    End Sub

Consuming a web service is pretty straightforward.  Just add a Service Reference in Visual Studio and a proxy class will be generated for you to call the service operations with:

        Dim DayOfWeekProxy As New DayOfTheWeekServiceReference.DayOfTheWeekServiceClient("BasicHttpBinding_IDayOfTheWeekService")

        Console.WriteLine(DayOfWeekProxy.GetDayOfTheWeek(InputDate))


The client configuration is very similar to the server configuration. Essentially to connect to a service, the client must use the same configuration.

    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IDayOfTheWeekService" />
            </basicHttpBinding>
        </bindings>
        <client>
          <endpoint address="http://SERVERCOMPUTER:8000/DayOfTheWeekService.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IDayOfTheWeekService"
                contract="DayOfTheWeekServiceReference.IDayOfTheWeekService"
                name="BasicHttpBinding_IDayOfTheWeekService" />
        </client>
    </system.serviceModel>

Tuesday, May 13, 2014

MVC Exception Handling

This is a followup post to my original post about simple .NET exception handling.

The ASP.NET MVC Framework contains an attribute named HandleErrorAttribute.  You can decorate a controller or an action simply by typing <HandleError> above the controller or action definition.  If an unhandled exception occurs anywhere in the scope decorated with HandleErrorAttribute, MVC will display a view named "Error" to the user automatically.  Typically, this view is generated for you when you create a new MVC application and is placed in the Shared folder.  The HandleErrorAttribute will only work if you have customErrors turned on in your web.config.  HandleErrorAttribute works great but it doesn't log.  In order to add this functionality to the attribute you need to create a new class that inherits from the HandleErrorAttribute like this:

    Public Class HandleErrorAndLogAttribute
        Inherits HandleErrorAttribute

        Public Overrides Sub OnException(filterContext As ExceptionContext)

            If Not filterContext.ExceptionHandled Then

                Dim MyException As Exception = filterContext.Exception
                
                ...

                'Logging code goes here

                ...
 
                MyBase.OnException(filterContext)

            End If

            'filterContext.Result = New ViewResult With {.ViewName = "Error"}

        End Sub

    End Class

Now, if you want to use your new attribute, you would just type <HandleErrorAndLog>.  You can globally apply this attribute to everything in your application by editing the FilterConfig.vb file like this:

Public Module FilterConfig
    Public Sub RegisterGlobalFilters(ByVal filters As GlobalFilterCollection)
        'filters.Add(New HandleErrorAttribute())
        filters.Add(New HandleErrorAndLogAttribute())
    End Sub
End Module

Apparently, there are certain exceptions that this attribute does not handle such as HTTP exceptions that occur outside of the MVC context.  To ensure these errors are handled, you should also log errors in the MvcApplication_Error event of the Global.asax.vb file.  Be sure to set the defaultRedirect attribute of the customErrors node in the web.config file to the Error View.  You will need to create an action method that will display the Error view when it is redirected in this way..

Thursday, May 8, 2014

Network Basics

TCP/IP

Most computer networks today including the Internet use TCP/IP.  An IP address uniquely identifies each computer on a TCP/IP network.  You may have noticed that your home computer has an IP address that is not exactly unique.  This is because all computers that are connected to your home router make up your own "private" network.  Since your network is private, no computers from outside your network will be communicating directly with your computer.  Therefore all private networks use IP addresses in the 192.168.x.x range.

What you think of as your home router or modem is actually a combination of things.

It is a modem.  A modem is responsible for converting the communications into a form that can be sent over telephone or cable wires.

It is a router.  The router routes packets of data to the computers they are bound for.

It is a gateway.  A gateway connects one network to another.  A residential gateway typically employees something called Network Address Translation or NAT.  In fact, you will often see your router referred to as a NAT device.  The gateway is the only piece of hardware on your home network that has a "real" IP address accessible from the internet.  NAT maps this IP address to the private IP address given to your PC.  It is generally true that if you have a NAT device between you and the internet, then your computer cannot accept requests from outside the NAT device (i.e. the internet).  However, you can configure your gateway to use something called "Port Forwarding" where you tell the gateway to forward requests to a particular port on the gateway to a port on your PC.

EndPoints, Sockets, Ports

These three terms mean essentially the same thing.  When a client program on one computer wants to communicate with a server program on another computer, the client program needs to know two things:

  1. IP address of the computer the server program resides on.
  2. The number of the port that the server program is "listening" on.
Together, these two things are called an endpoint, socket, or just port.

DNS

Since IP addresses are hard to remember, they came up with the Domain Name System.  This is simply a registry that relates a name with an IP address.  When you type www.google.com into your browser, the router actually looks up what the IP address is for that name using what is called a DNS server.  The DNS server is typically provided to you by the ISP.  However, you can change this to whatever you want.  Open DNS for example.


Firewalls

A firewall simply acts as a barrier between your computer and the network (either private or the internet).  Technically, your gateway is acting as a firewall, since by default it doesn't allow any incoming connections directly to your computer.  Windows ships with Windows Firewall and is turned on by default.  You can configure rules to allow or disallow programs from using specific ports on your computer.

Wednesday, May 7, 2014

Add an existing solution to TFS 2013

This post assumes you have a TFS server configured.

First you will need to create a TFS project to hold your files.

  1. In Visual Studio 2013, Team Explorer, click the navigation drop down bar and select Projects and My Teams and then choose Add New Project.  You may need to be a collection administrator to do this.  Browse here https://<TFS Server>/tfs/<Collection Name>/_admin to add a user to this group.
  2. A wizard will appear that will walk you through all of the options.
  3. The most important option here (and the most difficult to understand) is choosing the process template.  Essentially, you are choosing what application lifecycle management style you use while developing software.  I chose Scrum because it's something that I'm interested in and it's the default choice.
  4. You'll also need to choose a version control system, Git or TFVC.  With Git the repositories are stored locally and with TFVC, there is a single version of the truth on the server.  TFVC seems more appropriate if you're going to have a full blown TFS server.
Next, add your solution to the new project.
  1. If you don't know your branching needs yet, then don't create them at this point.  However, more than likely at some point, you will want to create branches.  To prepare for this possibility always put your initial files into a folder called Main.
  2. Map the new project to a local workspace.
  3. In Source Control Explorer, right click the project, and choose New Folder and call it Main.
  4. Check in this new folder.
  5. In File Explorer, copy your code into the Main folder in your workspace.
  6. In VS, open your solution from the Main folder in your workspace.
  7. Right-click the solution, and choose Add Solution to Source Control.
  8. Then Check In everything and you're done.

Thursday, May 1, 2014

TFS Cache

The other day I connected to a test TFS server that was identical to the production TFS server using Visual Studio 2013.  When I tried to connect back to the production TFS server, I got a 404 error.  To fix the problem, I closed Visual Studio and cleared this folder:

C:\Users\<You>\AppData\Local\Microsoft\Team Foundation\5.0\Cache

Tuesday, April 29, 2014

Enabling remote connections to a named instance of SQL Server

Recently, I installed SQL Server 2012 on a machine that I also had SQL Server 2008 R2 installed.  Because the default instance was the 2008 instance, I had to create a new instance that I named STEVE2012.  Even though STEVE2012 was configured to allow remote connections (by default), I still got the tell-tale "make sure remote connections are allowed" error messages when I tried to connect a web app to this instance.  I had to do the following:

  1. Open up SQL Server Configuration Manager (You can find this in the Start Menu under Microsoft SQL Server).
  2. Expand SQL Server Network Configuration and then click on Protocols for STEVE2012.  Double-click TCP/IP and set the Enabled property to "Yes".
  3. Then, click SQL Server Services in the tree view, and restart the service for STEVE2012.
So Named Instances are listening on a dynamic port rather than the standard 1433.  If your database server has a firewall (mine doesn't...development), you'll need to configure the instance to listen on a static port using the configuration manager.  Then open up this port in your firewall.

Thursday, April 17, 2014

Publishing Web Applications using Visual Studio

"Publishing" a web application means preparing the application into a state from which it can be "deployed" to the web server.  For me, this has always been two distinct processes, but Visual Studio has some publishing options that allow you to deploy to a web server as part of the publishing process.

You have 4 "publish methods" to choose from when you right click a web application project and select Publish.  FTP, File System, Web Deploy, and Web Deploy Package.

File System

Here you are simply choosing a folder and when you click Publish, the files will be placed in this folder.  You can then copy these files into the physical directory of the site.

FTP

Same idea as above except you are selecting a folder on another computer.

Web Deploy

This is also known as One-Click Publishing.  You simply specify the server name and the site, and Visual Studio will deploy the site for you when you publish.  Specify the Destination URL field if you want the default browser to open up with this address when publishing and deployment is complete. Keep in mind that the server you are deploying to must support Web Deploy.  Here are the instructions to set up a web server to support Web Deploy:

  1. Download and install Web Deploy 3.5.  (This assumes you are publishing using Visual Studio 2013).  During installation, be sure to click Custom and choose to install all the features available.
  2. Open up IIS, and click the root server node in the tree view on the left.
  3. Select Management Service.
  4. The options will be grayed out if the Web Management Service is running.  Stop the service, and be sure to check the "Enable remote connections" checkbox.
  5. In addition you may need to add your development machine's IP address to the box at the bottom.
  6. You might also need to open a firewall port (8172 by default), on the server.




Web Deploy Package

Same idea as Web Deploy except a package is created instead of Visual Studio deploying the application for you.  A package is simply a zip file that contains the published application files that you would also see if you selected the File System option.  However, the package can be imported using IIS with a nifty wizard.


Web deploy packages allow you to set some runtime parameters for the web.config file.  If there is a value that the developer does not know at compile time (like a password), the administrator will be prompted for the value when he imports the web deploy package.  Simply add a file called parameters.xml to the project directory in Visual Studio and put something like this in there:

<parameters>
  <parameter name="Test Key 1 Entry" 
             description="Specifies what environment you are in."
             defaultValue="Development" tags="">
    <parameterEntry kind="XmlFile"
                    scope="\\Web.config$"
                    match="//appSettings/add[@key='TestKey1']/@value">
    </parameterEntry>
  </parameter>
</parameters>

The parameter node describes what it will look like in the IIS wizard when you import the package.  The parameterEntry node describes how to update the file.  The scope attribute defines the file to update, and the match attribute represents an XPath that selects the attribute and node to update.

A note on transforming web.config files

When you do know the web.config settings for various environments at compile time, you transform web.config files.  Essentially this means modifying the web.config that gets published based on the build configuration.  Instructions for doing this is beyond the scope of this post.

Monday, April 7, 2014

ASP.NET Membership Encryption and View State Encryption/Validation

When using .NET's Membership provider to implement Forms Authentication in your application, the user names and passwords are encrypted in the database (aspnet_Membership) table.  You must specify the encryption method and a key to perform the encryption and decryption in the web.config file.  This is where this is specified:

<system.web>
    <machineKey decryptionKey="YOUR KEY GOES HERE" decryption="AES" />
<system.web />

Despite the name, the decryption and decryptionKey attributes are not only used for decryption but are also used for encryption.  This tells Membership how to encrypt passwords and usernames in the database.  It will also tell ASP.NET how to encrypt the View State if you are configured to encrypt the View State.  This decryption attribute is set to AES.  This is the standard for encryption at the time of this writing.  In fact the decryption attribute's default is AES.  Triple DES (3DES) is also acceptable if you have older DES stuff.

How do you generate a decryptionKey?  Click on the application in IIS, and double click the Machine Key icon.  Here you can select the Generate Keys option on the right to generate a key for you.  If you click Apply, it will update the machineKey node in the web.config file with the information.

The validation and validationKey attributes are only used to validate the View State.  A hash value is created by using the validationKey and the hash function specified by the validation attribute.  This hash value is compared to what it initially was when it was sent by the browser to what is is when the server receives it.  If they are different, then the server knows that the View State was tampered with.  The validation attribute is set to "SHA1" by default.  You don't necessarily need to generate a validationKey.  ASP.NET can generate one each time a request is made.  However, if you have multiple load balanced web servers, then you must generate a validationKey so that the servers can share the Session Id.  You would follow the same procedure in IIS to generate a validationKey if you so desire.  Here is an example of the machineKey node with both validation and decryption attributes configured.

<system.web>
    <machineKey validationKey="YOUR KEY GOES HERE" 
        decryptionKey="YOUR KEY GOES HERE" decryption="AES" validation="SHA1" />
<system.web />

How to encrypt the View State

Saturday, April 5, 2014

How to enable SSL on a web site in IIS


  1. Open IIS.
  2. Click the root node in the tree view at the left.
  3. Double click Server Certificates.
  4. In the list on the right, choose either Create Self Signed Certificate or Import.
  5. Click the site you want to secure.
  6. Click Bindings on the right and click Add.
  7. Choose https and select the certificate in the drop down list.
That's it.  Now you're site is listening on port 443 (default for https requests).  If you're using a self-signed certificate, your browser will throw up all kinds of red flags, but you are encrypted now.

Lots of good info here.

ASP.NET IIS Registration Tool (aspnet_regiis.exe)

Let's say you install a new version of Visual Studio which also installs a new version of the .NET Framework.  If you are using IIS (not IIS Express) on your local PC to host a site you are developing, it won't work until you register the new version of the framework with IIS by using the registration tool.  The tool exists in each version of the frameworks folder.  Just browse to the folder of the framework you want to register and run the tool with the -i option.

Open a Command Prompt as an administrator.

cd C:\Windows\Microsoft.NET\Framework64\v4.0.30319 for example.

Then, aspnet_regiis.exe -i

MS info on tool

Friday, March 28, 2014

"Classic" ASP

"Classic" ASP is the version of ASP that existed prior to ASP.NET being introduced in 2002.  It was only given the name "Classic" after ASP.NET superseded what was then called just ASP.  A Classic ASP site consists of a bunch of .asp files with associated .html, .js, and .css files.  Nothing within a Classic ASP site is compiled.  It is all interpreted at run-time, which is why ASP.NET offered performance gains.  An .asp page is just HTML with a bunch of server scripts inside of <% ... %> tags.  The scripting language of choice is VBScript although technically you could use JScript (not to be confused with Javascript).

Of course, no one writes "Classic" ASP anymore.  But you may have an old application that you need to host while you ponder a rewrite.  Here are a few things you'll need to do if you don't have a time machine:

  1. Classic ASP is disabled by default in IIS.  Go to Control Panel, Programs, Turn Windows features on or off.  Expand Internet Information Services, World Wide Web Services, and Application Development Features.  Check the ASP box.
  2. Set up the site in IIS like you normally would.
  3. By default, you're not going to see error messages that you need to see.  Open up IIS as an administrator and double click the ASP icon under IIS.  Expand Debugging Properties, and set Send Errors to Browser to True.
  4. Then, if you're using IE, you need to go into Internet Options, on the Advanced tab, and uncheck the box for Show friendly HTTP error messages.

Tuesday, March 25, 2014

Add a Bootstrap jQuery widget to an MVC view.

Bootstrap is an awesome open source UI framework that uses both CSS and jQuery to provide a great user experience.  Besides straight up CSS, they offer some "widgets" that offer some functionality that jQuery UI does not provide.  The process for getting a widget on your view is almost exactly the same as using jQuery UI.

You have to render both the jQuery and Bootstrap bundles in your layout view.  If you don't have a Bootstrap bundle, you just need Bootstrap.js.  Also ensure Bootstrap.css is in your CSS bundle.

This markup will render a button that will produce the popover widget when clicked.

<button type="button" id="Example" class="btn btn-default" data-container="body" data-toggle="popover" data-placement="top" data-content="Phone:  555-5555">
   Popover on top
</button>

Then, add a jQuery file with the following:

$(document).ready(function () {
    $("#Example").popover();
});

Friday, March 21, 2014

ASP.NET Identity - Get a user id

After a user logs in, how do you get the user id, which is stored as a GUID?  You don't have to go through the UserManager class which would require a trip to the database.  You can use the following code but you have to include the Imports statement or it won't work.

Imports Microsoft.AspNet.Identity

...

User.Identity.GetUserId()

Thursday, March 20, 2014

ASP.NET Identity - Using Roles

Roles allow you to restrict parts of your application to specific roles.  These roles are stored in the AspNetRoles table that is created by ASP.NET Identity.  You can create roles programatically or just insert them directly into the table using SQL.  If you're using SQL, you can just use an INSERT statement with a GUID and a name.  Programmatically, you would do the following:

Dim MyRoleStore As New RoleStore(Of IdentityRole)
Dim MyRoleManager As New RoleManager(Of IdentityRole)(MyRoleStore)

MyRoleManager.Create(New IdentityRole("Support Staff"))

IdentityRole is the Entity Framework object that ultimately represents (mapped to) a row in the AspNetRoles table.

Once you have some roles defined, you can associate a role to a user like this:

Dim Result As IdentityResult = _
     Await UserManager.AddToRoleAsync(MyUser.Id, "Support Staff")

Finally in order to restrict parts of your application, you simple add an Authorize filter to the ActionMethod you want restricted like this:

<Authorize(Roles:="Support Staff")>
Function MyActionMethod() As ActionResult

    ...

    Return View()

End Function

Finally, if the user is not authorized, they will be redirected to a specific page, usually the login page.  ASP.NET Identity is not forms authentication so this redirect is not in the web.config.  In an MVC app, it is in the Startup.Auth class ConfigureAuth method:

app.UseCookieAuthentication(New CookieAuthenticationOptions() With {
.AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
.LoginPath = New PathString("/Account/Login")})

Tuesday, March 18, 2014

ASP.NET Identity Basics

ASP.NET Identity is a system for handling authentication and authorization.  It was released with .NET 4.5.1 that shipped with Visual Studio 2013.  It replaces ASP.NET Membership.

Like Membership, it is a (sort of) simple way to implement forms authentication in a .NET application.  Identity differs from Membership in that it can be unit tested, allows external providers (such as Facebook and Google), and it works for all .NET technologies.

It is surprisingly easy to configure a new MVC web application for forms authentication using Identity.  Simply add an ASP.NET Web Application project and choose MVC with Individual User Accounts.  Remember to set the Framework version of the new project to 4.5.1 or you will not have these options.

The resulting project will contain:
  1. An AccountController class that will handle all authentication and user profile functionality.
  2. A web.config with a connection string pointing at a yet-to-be-created LocalDB database.
  3. A set of Account views that handles logging in, registrations, and user profile management.
  4. An AccountViewModels file that contain view models the Account views use.
  5. An IdentityModel file that contain classes that derive from the built in Identity classes.
  6. A Startup.Auth file that contains code to configure authentication on start up.
All of this is nicely integrated with the default views and controllers that the ASP.NET template has included for a standard MVC application.  You can run it and start registering and logging in immediately with no additional configuration.

It is important to understand the users and passwords are stored in the LocalDB database referred to in the web.config file.  This database is created by ASP.NET when you register the first user.  When you want to go to production, you can just script this thing out and move it to a production SQL Server.

If you look at the AccountController code, you'll notice that a Microsoft.AspNet.Identity.UserManager class is called for much of the authentication functionality.  The UserManager class almost exclusively offers asynchronous methods.  Therefore, you have to follow the rules of calling asynchronous methods when using this class.

Monday, March 17, 2014

Calling an asynchronous method

.NET 4 included a programming model and a few extra operators (await and async) to support asynchronous programming.  Even if you're not interested in doing anything asynchronously, there are certain classes in .NET that only offer asynchronous methods.  An asynchronous method can be identified by 3 things:
  1. The Async operator in the method signature.
  2. The word Async in the method name.  (This is only a standard and is not enforced)
  3. A return type of Task or Task(Of TResult).
An asynchronous method can only be called from another asynchronous method.  The method or event handler you are calling it from must be designated with the Async operator.

As an example, we are going to call the GetStringAsync method of the HttpClient class.

    Private Async Sub ButtonKickOff_Click(sender As Object, e As EventArgs) Handles ButtonKickOff.Click

        Dim Client As New System.Net.Http.HttpClient

        TextBoxResults.Text = Await Client.GetStringAsync("http://www.google.com")

    End Sub

This event handler is from a Windows Forms application.  Note that I added the Async operator to the event signature.  In this case, I'm calling the asynchronous function in a synchronous way, so I simply use the Await operator to signal that I'm just going to wait until it completes.

    Private Async Sub ButtonKickOff_Click(sender As Object, e As EventArgs) Handles ButtonKickOff.Click

        Dim Client As New System.Net.Http.HttpClient

        Dim Results As System.Threading.Tasks.Task(Of String) = _
            Client.GetStringAsync("http://www.google.com")

        LabelStatus.Text = "Processing..."

        TextBoxResults.Text = Await Results

    End Sub

Here, I am calling GetStringAsync and while it is executing, I am moving on. I immediately display a message to the user and then wait for the result.

LocalDB

When developing applications that use SQL Server for persistence, you now have 3 options:

  1. Install a full version of SQL Server.
  2. Install SQL Server Express.
  3. Use LocalDB.
Option 1 is expensive, and has a big footprint.

Option 2 is free, is limited, and has a big footprint.

Option 3 is free, is limited, and has a small footprint.

LocalDB seems to be the preferred way for developers to connect to databases while in the development process.  It is installed with Visual Studio 2012 forward.  Any databases created require no administration or configuration.

To connect to you LocalDB instance, simply use (localdb)\v11.0.  Databases, tables, and stored procedues can all be created in Visual Studio, so there is no need to install SQL Server at all while developing or doing research.

Friday, March 14, 2014

modern.IE

Modern.IE (literally just type modern.ie in your address bar) is a great site that contains a lot of resources if you are writing code to take advantage of new HTML5 features or just looking to ensure your site behaves itself across multiple versions of IE.

The most useful thing it offers is free downloadable virtual machines that have the various versions of IE installed.  You need a separate virtual machine for each version since multiple versions of IE cannot be installed on the same PC.  When you download a VM, there are several files you must download.  Typically there is an exe with one or more rar files.  They're big, so if your connection is slow, consider a download manager program like Free Download Manager.  Once the four files are in place, just kick off the exe and it will extract everything and produce the VM files for you.  I used Virtual PC for Windows 7 and it worked great.  Virtual PC is part of Windows 7 so you don't have to install or configure it.  Just open the file and it boots up.  After a while, you'll be prompted to activate the Windows software on the vpc, but you should ignore this per the license agreement.

Thursday, February 27, 2014

Two ways to validate a string against a regular expression

The .NET framework provides at least two ways to accomplish regular expression validation.  Microsoft seems to prefer you use RegExStringValidator for simple validation, but as you can see below, it is anything but simple.  I see no reason not to use the RegEx class which is much cleaner.

Use the RegExStringValidator class


Dim MyRegEx As String = "(?=.{8,})(?=(.*\d){1,})(?=(.*[A-Z]){1,})(?=(.*[a-z]){1,})"

Dim MyRegExValidator As New System.Configuration.RegexStringValidator(MyRegEx)

Try

    Dim StringToValidate As String = "gDLDdE12"

    If MyRegExValidator.CanValidate(StringToValidate.GetType()) Then
        MyRegExValidator.Validate(StringToValidate)
    End If

    'If no exception occurs, then the validation succeeded.
    
Catch ex As Exception

    'If an exception occurs, then the validation failed.

End Try


Use the RegEx class


Dim RegExEngine As System.Text.RegularExpressions.Regex = _
    New System.Text.RegularExpressions.Regex("(?=.{8,})(?=(.*\d){1,})(?=(.*[A-Z]){1,})(?=(.*[a-z]){1,})")

If RegExEngine.IsMatch(NewPassword.Text) Then
    'Validation is successful.
Else
    'Validation is not successful.
End If

Wednesday, February 26, 2014

Regular Expressions for password validation

Regular Expressions can look like Greek and be a real pain to wrap your head around, but sometimes they are necessary.  It's fairly easy to find a regular expression for common uses like email and phone numbers.  However, I didn't have much luck finding a regular expression to validate the format of a password.  This is probably because there are so many variations on what is considered an acceptable password.

By reverse engineering some Microsoft examples, I've discovered an easy way to create a regular expression for your specific password validation needs.

Let's walk through this:

What is the minimum length of the password?  Let's say 8.  So start with:

(?=.{8,})

Do you require at least one number?  If yes, then append:

(?=(.*\d){1,})

Do you require at least one capital letter?  If yes, then append:

(?=(.*[A-Z]){1,})

Do you require at least one lower case letter?  If yes, then append:

(?=(.*[a-z]){1,})

Do you require at least one "special" character?  If yes, then append:

(?=(.*\W){1,})

When we string these requirements together, we get:

(?=.{8,})(?=(.*\d){1,})(?=(.*[A-Z]){1,})(?=(.*[a-z]){1,})(?=(.*\W){1,})

By omitting and including the various sections, you should be able to create a regular expression that matches your application's definition of an "acceptable" password.

Wednesday, February 5, 2014

Use PowerShell to add an event log source.

Open PowerShell and Run as an Administrator.

[System.Diagnostics.EventLog]::CreateEventSource(name of source goes here, "Application")

Monday, January 27, 2014

SQL Server Update table with value from a joined table.

This comes up rarely, but is a little esoteric so it is worth noting.  You want to update values in one table with a value from another table.  Use the following syntax:

UPDATE TableOne
SET ColumnOne = T2.ColumnFromT2
FROM TableOne T1
   Join TableTwo T2
      On T1.CommonId = T2.CommonId

Tuesday, January 21, 2014

Updating code to use modern web standards - HTML5 and XHTML5

I am working on several sites that were developed 5-10 years ago, and they are all having compatibility issues with the newer versions of IE.  Since IE 8, the answer has been the Compatibility Mode function.  However, this button and its associated function is being phased out.  It's now buried in the menu of IE 11, so I'm concerned about it's going away with IE 12.  I'm starting to research and fix the sites so that they display properly in modern browsers.

The majority of the problems is that the site "just looks bad" without compatibility mode.  The first step is to change the markup, so that it meets current standards.  Using Visual Studio, I'm validating all markup with XHTML5.  I'm not introducing any new HTML5 tags.  I'm simply changing the existing markup so that it isn't flagged by the validator.  I'm also fixing any display issues that crop up.

What is HTML5 and XHTML5?  HTML5 is the latest and greatest version of HTML.  Modern browsers support most of the standard.  Older browsers support only the stuff that has been around forever (tables and input tags and such).  XHTML5 is the XML version of HTML5.  It is basically the same thing except that XHTML5 is slightly stricter.  For example, HTML5 will let you write a tag and not close it.  XHMTL5 requires lowercase letters just like XML does.

I think XHTML5 is appropriate to validate your markup with since it is a bit more strict, and forces you to write tidier markup.

Tuesday, January 14, 2014

Browser definition files

Deep within the .NET framework installation is a folder full of what are called browser definition files.  For example this folder for version 4 forward is here:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\Browsers

It is full of xml configuration files with an extension of .browser.  These files tell ASP what Javascript and HTML to render for each browser and version.

When IE 10 was released there was an issue with certain things not working.  An example was a DropDownList control not posting back.  It turns out that there was a bug in the browser definition file for IE in the .NET framework.  This link describes this:

http://www.hanselman.com/blog/BugAndFixASPNETFailsToDetectIE10CausingDoPostBackIsUndefinedJavaScriptErrorOrMaintainFF5ScrollbarPosition.aspx

Microsoft created a hotfix that updates these files and fixes the bug when you run it on the server hosting the site.  I was really hesitant about deploying a hotfix to a production web server.  My preference is to wait for hotfixes to be put into at least a cumulative update if not a service pack (This doesn't appear to have happened at the time of this writing).  So, I added the updated IE browser definition file directly to the Visual Studio web project by adding a special ASP.NET folder named App_Browsers.  I then added the updated .browser file from the link above to this new folder.  After I published the site, the issues I had disappeared.

UPDATE:

I ran into similar problems with IE 11.  However, I could not find the browser files for IE 11 anywhere.  It looks like Microsoft prefers you to go the hotfix route.  So I installed the following hotfix on the web server, and everything then rendered correctly.

http://www.microsoft.com/en-us/download/details.aspx?id=39257

KB2836939

What is ASP.NET Impersonation?

When using Windows authentication, the User property of the HttpContext will be set to whoever is browsing your web application.  This allows a programmer to do certain things based on the user who is currently accessing the system.  However, the current user will not be used to determine access to file resources or connect to a database for example.  (I believe the application pool identity is used by default).  What if you want to use the current user for this other access?

You need to impersonate the current user when accessing these resources.  Simply put the following in your web.config file:
<system.web>
    <identity impersonate="true" />
</system.web>
You can also specify a username and password to use.  I'm not sure the value in this since you could always just use the app pool identity, but if you need to, do this....
<system.web>
    <identity impersonate="true" userName="Steve" password="Supersecret" />
</system.web>

Friday, January 10, 2014

AJAX Enabled WCF Service with Windows Authentication

Let's say you have a WCF Service that you are calling from jQuery code.  Everything works fine until you set up Windows Authentication.  Then it blows up.  The problem is that the binding has to be configured to work with Windows Authentication.  Let's first look at the endpoint in the web.config file. Take a look at the binding attribute. It should say "webHttpBinding". WebHttpBinding means that your web service responds to HTTP requests.  This is necessary because this is the only way jQuery can call your service.  In fact, I believe Visual Studio sets it in this way when you added the AJAX Enabled WCF Service rather than a plain old WCF Service.  However there is no configuration for the WebHttpBinding itself, which means it just uses its default configuration which I believe is configured to use anonymous authentication.  So we need to configure the WebHttpBinding to use Windows Authentication by putting the following nodes inside the system.servicemodel node:
    <bindings>
      <webHttpBinding>
        <binding>
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows"></transport>
          </security>
        </binding>
      </webHttpBinding>
    </bindings>


Tuesday, January 7, 2014

Testing Android apps using a Nook HD

I've been doing some android development on the side lately, and have been using my phone for testing since my experience with emulation has been terrible so far.  However my phone is an old Gingerbread phone and there were some features in the newer versions of Android that I wanted to take advantage of.  I have a Nook HD which is built upon the Ice Cream Sandwich version of Android, so I took on the task of using the Nook to test.

It wasn't the easiest experience to configure this, so I wanted to document this while it is fresh in my mind.  First you need to read this document:

https://nookdeveloper.zendesk.com/entries/21943338-nook-developer-start-up-guide

Start with the standard Android dev environment:  The ADT bundle you download at Google.

You have to install something called the Nook SDK which you can install by using the Android SDK Manager tool inside of Eclipse.  It's in the Window menu.  Then, follow directions in the document.  The SDK Manager tool looks like it is also used to update your dev environment and a bunch of stuff was already selected, so I just installed all of that along with the Nook SDK.  But I really think the Nook SDK was the only thing I needed checked.

You do need to set the PATH variable.

This is where things get stupid.  If you're just using the emulator, I don't think you need this, but of course I wanted to run apps directly on the device.  The Android Debug Bridge (adb) is some kind of command that Eclipse uses to side load apps onto your device for testing.  The document shows you how to test to see if your device is seen by adb.  Mine wasn't seen (of course).  It suggests you install some special drivers.  To get the drivers, you have to register as a Nook developer and get approved.  There are silly questions that you just make up answers to and wait 8 hours, and then you're in.  After that, download the drivers.  In Device Manager, I had to "Uninstall the device", and then click on the device that was labeled BNTV400 (not MyNOOK) and then I install (or maybe it was update) the driver and browse to the driver you downloaded.  Once this was done, adb could see the device.  I did have to adb kill-server, adb start-server, once before it would work with Eclipse.

I'm actually quite surprised I got this working.