Implementing Basic Authentication in ASP.NET 2.0

by Administrator 27. August 2008 20:35

I have many times wanted to implement basic authentication in asp.net applications, but has been unwilling to use the built in basic authentication of IIS, since I think its a bother to use either the Windows machine's users since its a pain to administer and does not easily tie into an existing solution of user authentication you have, like a CMS or what have you. People would proably argue that I should use forms based authentication, but thats not always possible, like if you want to have your services accessible from lets say a program that runs on another machine, i.e. a service that polls for data. That program need Basic authentication or Digest authentication, since thats much more easy to implement when you dont have a browser as the client.

You could use the built in WindowsAuthentication http module of asp.net, but then you are stuck with using the windows users, and manage roles for them in windows as well and that kind of sucks, since you would proably want to use your application's user administration to manage access to your application.

So what you want to do is create your own HttpModule that provides Basic Authentication functionality.

It sounds harder than it actually is, and I have created a complete package of files you can copy/paste and implement a little code yourself, and then you have a ready to plugin Basic authentication module.

What I have created is a HttpModule that takes care of the Basic Authentication, then I have created a couple of interfaces that needs implementing. The implementations of the interfaces will provide answers to the Basic Authentication HttpModule about whether or not a given user is a valid user, and whether or not the user is allowed to see a given page or do a given request.

The code for the interfaces is pretty simple, which interfaces usually is since its the implementation that does all the work :)

Interfaces needed:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Security.Principal;

namespace Smithfamily.Blog.Samples
{
    /// <summary>
    /// An authentication and authorization provider for very simple applications
    /// Should probably be either implemented with a database backend, 
    /// or using a web.config custom section
    /// Implementors of this interface should provide a default no args constructor to be used
    /// by the AuthenticationModule
    /// </summary>
    public interface IAuthProvider : IDisposable
    {
        /// <summary>
        /// Validates the username and password and returns whether or not the combination is a valid user
        /// </summary>
        /// <param name="userName">The username to validate</param>
        /// <param name="password">The password to match</param>
        /// <param name="user">The user object created</param>
        /// <returns>true if the combination is a valid user;false otherwise</returns>
        bool IsValidUser(string userName, string password, out IBasicUser user);

        /// <summary>
        /// Determines whether or not the current request is allowed to continue for the given user
        /// </summary>
        /// <param name="request">The request to check</param>
        /// <param name="user">The user</param>
        /// <returns>true if request is authorized;false otherwise</returns>
        bool IsRequestAllowed(HttpRequest request, IBasicUser user);

    }

    /// <summary>
    /// interface for a very simple user object that contains the bare 
    /// minimum to do authentication against a real backend
    /// </summary>
    public interface IBasicUser : IIdentity
    {
        /// <summary>
        /// Gets or sets the username of the user.
        /// </summary>
        /// <value>The username of the user.</value>
        string UserName
        {
            get;
            set;
        }
        /// <summary>
        /// Gets or sets the password.
        /// </summary>
        /// <value>The password.</value>
        string Password
        {
            get;
            set;
        }
    }
}


The IAuthProvider is the interface for the class you need to implement that will do lookup in your backend for users, and will validate whether or not a user have access to a give resource. The IBasicUser is an interface for a very simple user object that can contain the bare minimum to authenticate a user. I have implemented IBasicUser and will pass an implementation of that to the configured IAuthProvider.

I have also made a silly implementation of the IAuthProvider that will accept any users for logon, but will only authorize a user with the username bjorn, i.e. anyone can log on, but only I am allowed to do anything. The implementation is just as an example, please don't implement your versions like this, but rather read the users from a database, and validate their password properly.

The HttpModule itself is pretty simple as well.

Basic Authentication Module:

using System;

using System.Collections.Generic;

using System.Text;

using System.Web;

using System.Security.Principal;

using System.Configuration;

using System.Reflection;

 

namespace Smithfamily.Blog.Samples

{

    /// <summary>

    /// HttpModule that provides Basic authentication for asp.net applications

    /// </summary>

    public class BasicAuthenticationModule : IHttpModule

    {

        private static IAuthProvider authProvider;

 

        #region IHttpModule Members

 

        /// <summary>

        /// Initializes the <see cref="BasicAuthenticationModule"/> class.

        /// Instantiates the IAuthProvider configured in the web.config

        /// </summary>

        static BasicAuthenticationModule()

        {

            string provider =

                ConfigurationManager.AppSettings["Smithfamily.Blog.Samples.BasicAuthenticationModule.AuthProvider"];

            Type providerType = Type.GetType(provider, true);

            authProvider = Activator.CreateInstance(providerType, false) as IAuthProvider;

        }

 

        /// <summary>

        /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.

        /// </summary>

        public void Dispose()

        {

            authProvider.Dispose();

            authProvider = null;

        }

 

        /// <summary>

        /// Initializes a module and prepares it to handle requests.

        /// </summary>

        /// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application</param>

        public void Init(HttpApplication context)

        {

            context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);

            context.AuthorizeRequest += new EventHandler(context_AuthorizeRequest);

            context.BeginRequest += new EventHandler(context_BeginRequest);

 

        }

 

        /// <summary>

        /// Handles the BeginRequest event of the context control.

        /// </summary>

        /// <param name="sender">The source of the event.</param>

        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>

        void context_BeginRequest(object sender, EventArgs e)

        {

 

            HttpApplication context = sender as HttpApplication;

            if (context.User == null)

            {

                if (!TryAuthenticate(context))

                {

                    SendAuthHeader(context);

                    return;

                }

 

            }

            BasicUser bu = context.User.Identity as BasicUser;

            context.Response.Write(string.Format("Welcome {0} with the password:{1}", bu.UserName, bu.Password));

        }

 

        /// <summary>

        /// Sends the Unauthorized header to the user, telling the user to provide a valid username and password

        /// </summary>

        /// <param name="context">The context.</param>

        private void SendAuthHeader(HttpApplication context)

        {

            context.Response.Clear();

            context.Response.StatusCode = 401;

            context.Response.StatusDescription = "Unauthorized";

            context.Response.AddHeader("WWW-Authenticate", "Basic realm=\"Secure Area\"");

            context.Response.Write("401 baby, please authenticate");

            context.Response.End();

        }

 

 

        /// <summary>

        /// Handles the AuthorizeRequest event of the context control.

        /// </summary>

        /// <param name="sender">The source of the event.</param>

        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>

        void context_AuthorizeRequest(object sender, EventArgs e)

        {

            HttpApplication context = sender as HttpApplication;

 

            BasicUser bu = context.User.Identity as BasicUser;

            if (!authProvider.IsRequestAllowed(context.Request, bu))

            {

                SendNotAuthorized(context);

            }

        }

        /// <summary>

        /// Sends the not authorized headers to the user

        /// </summary>

        /// <param name="context">The context.</param>

        private void SendNotAuthorized(HttpApplication context)

        {

            context.Response.Clear();

            context.Response.StatusCode = 403;

            context.Response.StatusDescription = "Forbidden";

            context.Response.Write("403 baby, You are not allowed to see this");

            context.Response.End();

        }

 

        /// <summary>

        /// Tries to authenticate the user

        /// </summary>

        /// <param name="context">The context.</param>

        /// <returns></returns>

        private bool TryAuthenticate(HttpApplication context)

        {

            string authHeader = context.Request.Headers["Authorization"];

            if (!string.IsNullOrEmpty(authHeader))

            {

                if (authHeader.StartsWith("basic ", StringComparison.InvariantCultureIgnoreCase))

                {

 

                    string userNameAndPassword = Encoding.Default.GetString(

                        Convert.FromBase64String(authHeader.Substring(6)));

                    string[] parts = userNameAndPassword.Split(':');

                    IBasicUser bu = null;

                    if (authProvider.IsValidUser(parts[0], parts[1], out bu))

                    {

                        context.Context.User = new GenericPrincipal(bu, new string[] { });

                        if (!authProvider.IsRequestAllowed(context.Request, bu))

                        {

                            SendNotAuthorized(context);

                            return false;

                        }

                        return true;

                    }

 

                }

 

            }

            return false;

        }

 

        /// <summary>

        /// Handles the AuthenticateRequest event of the context control.

        /// </summary>

        /// <param name="sender">The source of the event.</param>

        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>

        void context_AuthenticateRequest(object sender, EventArgs e)

        {

            HttpApplication context = sender as HttpApplication;

            TryAuthenticate(context);

 

        }

 

        #endregion

    }

 

    /// <summary>

    /// Sample IAuthProvider that will authenticate all users, and only allow access to user with a username of bjorn

    /// </summary>

    public class BasicAuthProvider : IAuthProvider

    {

 

        #region IAuthProvider Members

 

        /// <summary>

        /// Validates the username and password and returns whether or not the combination is a valid user

        /// </summary>

        /// <param name="userName">The username to validate</param>

        /// <param name="password">The password to match</param>

        /// <param name="user">The user object created</param>

        /// <returns>

        /// true if the combination is a valid user;false otherwise

        /// </returns>

        public bool IsValidUser(string userName, string password, out IBasicUser user)

        {

            user = new BasicUser();

            user.UserName = userName;

            user.Password = password;

 

            return true;

        }

 

        /// <summary>

        /// Determines whether or not the current request is allowed to continue for the given user

        /// </summary>

        /// <param name="request">The request to check</param>

        /// <param name="user">The user</param>

        /// <returns>

        /// true if request is authorized;false otherwise

        /// </returns>

        public bool IsRequestAllowed(HttpRequest request, IBasicUser user)

        {

            return user.UserName == "bjorn";

        }

 

 

        /// <summary>

        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

        /// </summary>

        public void Dispose()

        {

            //This is intentional, since we don't have any resources to free in this very simple sample IAuthProvider

        }

 

        #endregion

    }

 

    public class BasicUser : IBasicUser

    {

        /// <summary>

        /// Gets or sets the username of the user

        /// </summary>

        /// <value>The username of the user.</value>

        public string UserName

        {

            get;

            set;

        }

        /// <summary>

        /// Gets or sets the password.

        /// </summary>

        /// <value>The password.</value>

        public string Password

        {

            get;

            set;

        }

 

        #region IIdentity Members

 

        /// <summary>

        /// Gets the type of authentication used.

        /// </summary>

        /// <value></value>

        /// <returns>

        /// The type of authentication used to identify the user.

        /// </returns>

        public string AuthenticationType

        {

            get

            {

                return "Custom";

            }

        }

 

        /// <summary>

        /// Gets a value that indicates whether the user has been authenticated.

        /// </summary>

        /// <value></value>

        /// <returns>true if the user was authenticated; otherwise, false.

        /// </returns>

        public bool IsAuthenticated

        {

            get

            {

                return UserName != null;

            }

        }

 

        /// <summary>

        /// Gets the name of the current user.

        /// </summary>

        /// <value></value>

        /// <returns>

        /// The name of the user on whose behalf the code is running.

        /// </returns>

        public string Name

        {

            get

            {

                return UserName;

            }

        }

 

        #endregion

    }

}


Let me go throught the code in the BasicAuthenticationModule step by step so you understand what is happening.

Initialization:
/// <summary>
/// Initializes the <see cref="BasicAuthenticationModule"/> class.
/// Instantiates the IAuthProvider configured in the web.config
/// </summary>
static BasicAuthenticationModule()
{
    string provider = 
ConfigurationManager.AppSettings["Smithfamily.Blog.Samples.BasicAuthenticationModule.AuthProvider"]; Type providerType = Type.GetType(provider, true); authProvider = Activator.CreateInstance(providerType, false) as IAuthProvider; }


These lines of codes configures the authentication module, and is done only once per application restart.

What these lines do is that they look in the Web.config for a appSettings parameter called Smithfamily.Blog.Samples.BasicAuthenticationModule.AuthProvider, and tries to create an instance of the fully qualified type name and use it as its implementation of IAuthProvider. This web.config parameter is where you configure the basic authentication module to use your IAuthProvider implementation.
i.e.

Web.config configuration of BasicAuthenticationModule:
<appSettings>
    <add key="Smithfamily.Blog.Samples.BasicAuthenticationModule.AuthProvider" 
value="Smithfamily.Blog.Samples.BasicAuthProvider"/> </appSettings>



These lines of codes simply calls Dispose on the implementation of the IAuthProvider just in case there is some resources that need to be disposed.

Dispose:
/// <summary>
/// Disposes of the resources (other than memory) used by the module that 
/// implements <see cref="T:System.Web.IHttpModule"/>.
/// </summary> public void Dispose() { authProvider.Dispose(); authProvider = null; }


The following lines of codes is simply telling the application that the module wants to be part of the following events:

AuthenticateRequest, AuthorizeRequest and BeginRequest.

The reason why we need hooks on these events is that this is where we will do our magic, so without registering event handlers on these events there will be no basic authentication

Init:
/// <summary>
/// Initializes a module and prepares it to handle requests.
/// </summary>
/// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, 
/// properties, and events common to all application objects within an ASP.NET application</param>
public void Init(HttpApplication context) { context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest); context.AuthorizeRequest += new EventHandler(context_AuthorizeRequest); context.BeginRequest += new EventHandler(context_BeginRequest); }


The following event handler gets called each time a request begins on the server, and this is the perfect place to try to authenticate the user, which is what we do.

We call the method TryAuthenticate and if we get a false back from that method, we send the needed authentication headers to the user and returns.

If we the TryAuthenticate method returns true, then we just let everything flow, but injects some silly text on top of the page.
The last two lines of the method you need to remove when using this module, otherwise all pages will contain the text:
Welcome user with the password: xxxx, which is kind of not cool :)

context_BeginRequest:
/// <summary>
/// Handles the BeginRequest event of the context control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> 
/// instance containing the event data.</param>
void context_BeginRequest(object sender, EventArgs e) { HttpApplication context = sender as HttpApplication; if (context.User == null) { if (!TryAuthenticate(context)) { SendAuthHeader(context); return; } } BasicUser bu = context.User.Identity as BasicUser; context.Response.Write(
string
.Format("Welcome {0} with the password:{1}", bu.UserName, bu.Password)); }


The method SendAuthHeader as shown below simply sends the required headers to the browser, making it prompt the user for a user name and password. When using this code change the line where the WWW-Authenticate header is added and change the "Secure Area" to what you want, i.e. your application name.

SendAuthHeader:
/// <summary>
/// Sends the Unauthorized header to the user, telling the user to provide a valid username and password
/// </summary>
/// <param name="context">The context.</param>
private void SendAuthHeader(HttpApplication context)
{
    context.Response.Clear();
    context.Response.StatusCode = 401;
    context.Response.StatusDescription = "Unauthorized";
    context.Response.AddHeader("WWW-Authenticate", "Basic realm=\"Secure Area\"");
    context.Response.Write("401 baby, please authenticate");
    context.Response.End();
}


The login box for the above code will look something like the one below if you are using firefox.



The method below handles the authorization part, i.e. checking whether or not the user is allowed to do what he is trying to do. At this point the user is already logged on, and we know that the user is a valid user, so all we do is grapping the user from the HttpApplication and asking the implementation of the IAuthProvider whether or not the user is allowed to do this request.

If the user is not allowed to do what he is trying to do, we send a http response back indicating that the user have no permissions to do what he is doing.

If the user is allowed, then we just let things flow.

context_AuthorizeRequest:
/// <summary>
/// Handles the AuthorizeRequest event of the context control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/>
/// instance containing the event data.</param>
void context_AuthorizeRequest(object sender, EventArgs e) { HttpApplication context = sender as HttpApplication; BasicUser bu = context.User.Identity as BasicUser; if (!authProvider.IsRequestAllowed(context.Request, bu)) { SendNotAuthorized(context); } }


The method below simply sends the correct headers, telling the browser that the user is not allowed to do what he is trying, and therefore the browser should not retry.

SendNotAuthorized:
/// <summary>
/// Sends the not authorized headers to the user
/// </summary>
/// <param name="context">The context.</param>
private void SendNotAuthorized(HttpApplication context)
{
    context.Response.Clear();
    context.Response.StatusCode = 403;
    context.Response.StatusDescription = "Forbidden";
    context.Response.Write("403 baby, You are not allowed to see this");
    context.Response.End();
}


The method TryAuthenticate is where the "magic" happens, this is where the basic authentication part is checked, and then provided the user actually sent a username and password, we ask the IAuthProvider whether or not the user is a valid user.

If we get a go from the IAuthProvider that the username and pasword is a valid combination, then we inject an implementation of the IBasicUser into the HttpApplication for further use in the application. Then we proceed to ask whether or not the user is allowed to do what he is doing, and if everything checks out okay we return true, otherwise we return false.

Please note that the IBasicUser that we put into HttpApplication can be accessed from any asp.net pages, just by accessing the Page's property called User, so its a neat way to inject information about the current user into the standard objects of asp.net.

TryAuthenticate:
/// <summary>
/// Tries to authenticate the user
/// </summary>
/// <param name="context">The context.</param>
/// <returns></returns>
private bool TryAuthenticate(HttpApplication context)
{
    string authHeader = context.Request.Headers["Authorization"];
    if (!string.IsNullOrEmpty(authHeader))
    {
        if (authHeader.StartsWith("basic ", StringComparison.InvariantCultureIgnoreCase))
        {

            string userNameAndPassword = Encoding.Default.GetString(
Convert.FromBase64String(authHeader.Substring(6))); string[] parts = userNameAndPassword.Split(':'); IBasicUser bu = null; if (authProvider.IsValidUser(parts[0], parts[1], out bu)) { context.Context.User = new GenericPrincipal(bu, new string[] { }); if (!authProvider.IsRequestAllowed(context.Request, bu)) { SendNotAuthorized(context); return false; } return true; } } } return false; }


The method below simply tries to authenticate the user on each authentication event, simple as that, and by using the method TryAuthenticate.

context_AuthenticateRequest:
/// <summary>
/// Handles the AuthenticateRequest event of the context control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> 
/// instance containing the event data.</param>
void context_AuthenticateRequest(object sender, EventArgs e) { HttpApplication context = sender as HttpApplication; TryAuthenticate(context); }


See, that wasen't so hard, so what you need to do to make this work for is simply:

  • Implement IAuthProvider using your own database of users, your own xml structure or what ever means of authenticating and authorizing the users.
  • Add the Module to your application by editing the web.config and putting the following lines into the web.config
Adding module to web.config:
<httpModules>
  <add name="BasicAuthenticationModule" 
type="Smithfamily.Blog.Samples.BasicAuthenticationModule"/> </httpModules>


Naturally there will be other modules present, just inject the module line as the last element in the <httpModules> collection.

  • Configure the module by adding the following lines to the web.config. Please remember to add the full name, i.e. Your.NameSpace.YourClassName

 

Web.config configuration of BasicAuthenticationModule:
<appSettings>
<add key="Smithfamily.Blog.Samples.BasicAuthenticationModule.AuthProvider"
value="<enter fully qualified name for your implementation of IAuthProvider"/>
</appSettings>



That should be in, just allow anonymous access in the IIS configuration and remove all other authentication options in the IIS, and you should be set.

I have seen cases where it still dosen't work, and if thats the case, try adding the following items to the Web.config.

  • Turn on the authentication module by adding the <authentication> element with the mode None, its strange, but it has to be none, otherwise it will use one of the built in, which kind of defeats the purpose of this module :)
  • Put in the <authorization> element and say that all anonymous users is not allowed

 

Turn on authentication in Web.config:
 <system.web>
      <authentication mode="None" />
      <authorization>
        <deny users="?" />
      </authorization>



I hope this gave you an insight in how you can implement basic authentication pretty easily, and remember you can implement your own IBasicUser, and put all other kinds of stuff in there like items from your application, and then you have access to everything by calling the Page.User property, like:

Accessing the current user in asp.net markup:
<%IBasicUser user = User.Identity as IBasicUser;
Response.Write(user.UserName)%>



Please let me know if this example dosen't work for you and I will try to help you make it work :)

Tags: , , , ,

.NET | asp.net | Authentication | c# | logon

DateTime time zone conversion with .NET 3.5

by Administrator 16. August 2008 22:09

Some time ago I wrote a blog post about Timezone conversion and handling within .NET which sucked at that time.

With .NET 3.5 its better, in fact much better, its actually usable :)

In .NET 1.1 and 2.0 there were not way to convert DateTime objects between different time zones to handle all the hassle of adding minutes, handling summer winter time, etc.

There is now. Its not perfect, but it does the job.

Its pretty straightforward.

I will provide an example, which should give you an idea of how to use in real life.

The example below takes two DateTime objects. One UTC Datetime, and one Danish DateTime.

Both DateTime object are created with the same numbers, one is just specified as UTC, the other one as local time.

//Create DateTime with UTC Kind specified, and with Current time in UTC
DateTime utcNow = new DateTime(2008, 8, 16, 21, 42, 32, DateTimeKind.Utc);

//Create danish local DateTime
DateTime dkNow = new DateTime(2008, 8, 16, 21, 42, 32, DateTimeKind.Local); ;
//Find timezone info for egypt
TimeZoneInfo egypt = TimeZoneInfo.FindSystemTimeZoneById("Egypt Standard Time");
//Convert danish local time to egypt time
DateTime egyptTime1 = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dkNow, "Egypt Standard Time");
//Convert utc time to egypt local time
DateTime egyptTime2 = TimeZoneInfo.ConvertTimeFromUtc(utcNow, egypt);

//Write out initial DateTime objects
Console.WriteLine("{0} {1}", dkNow, dkNow.ToString("%K"));
//Writes out 16-08-2008 21:42:32 +02:00
Console.WriteLine("{0} {1}", utcNow, utcNow.ToString("%K"));
//Writes out 16-08-2008 21:42:32 Z
//Write out the results
Console.WriteLine("Danish NOW converted to Eqypt time:{0} {1}", egyptTime1,

DateTime.SpecifyKind(egyptTime1, DateTimeKind.Local).ToString("%K"));
//Writes out Danish NOW converted to Eqypt time:16-08-2008 22:42:32 +02:00
Console.WriteLine("UTC NOW converted to Eqypt time:{0} {1}", egyptTime2,
DateTime.SpecifyKind(egyptTime2, DateTimeKind.Local).ToString("%K"));
//Writes out UTC NOW converted to Eqypt time:16-08-2008 00:42:32 +02:00

As you can clearly see of the example it is fairly easy to convert DateTime's between timezones, but there is just one question that springs to mind.

Where do you get the list of Timezone ID's?

Well I will provide you with one here, but its a crappy solution Microsoft have chosen for timezone names.

 

Timezone IDUTC offset offset
Morocco Standard Time 0:0
GMT Standard Time 0:0
Greenwich Standard Time 0:0
W. Europe Standard Time 1:0
Central Europe Standard Time 1:0
Romance Standard Time 1:0
Central European Standard Time 1:0
W. Central Africa Standard Time 1:0
Jordan Standard Time 2:0
GTB Standard Time 2:0
Middle East Standard Time 2:0
Egypt Standard Time 2:0
South Africa Standard Time 2:0
FLE Standard Time 2:0
Israel Standard Time 2:0
E. Europe Standard Time 2:0
Namibia Standard Time 2:0
Arabic Standard Time 3:0
Arab Standard Time 3:0
Russian Standard Time 3:0
E. Africa Standard Time 3:0
Georgian Standard Time 3:0
Iran Standard Time 3:30
Arabian Standard Time 4:0
Azerbaijan Standard Time 4:0
Caucasus Standard Time 4:0
Armenian Standard Time 4:0
Afghanistan Standard Time 4:30
Ekaterinburg Standard Time 5:0
Pakistan Standard Time 5:0
West Asia Standard Time 5:0
India Standard Time 5:30
Sri Lanka Standard Time 5:30
Nepal Standard Time 5:45
N. Central Asia Standard Time 6:0
Central Asia Standard Time 6:0
Myanmar Standard Time 6:30
SE Asia Standard Time 7:0
North Asia Standard Time 7:0
China Standard Time 8:0
North Asia East Standard Time 8:0
Singapore Standard Time 8:0
W. Australia Standard Time 8:0
Taipei Standard Time 8:0
Tokyo Standard Time 9:0
Korea Standard Time 9:0
Yakutsk Standard Time 9:0
Cen. Australia Standard Time 9:30
AUS Central Standard Time 9:30
E. Australia Standard Time 10:0
AUS Eastern Standard Time 10:0
West Pacific Standard Time 10:0
Tasmania Standard Time 10:0
Vladivostok Standard Time 10:0
Central Pacific Standard Time 11:0
New Zealand Standard Time 12:0
Fiji Standard Time 12:0
Tonga Standard Time 13:0
Azores Standard Time -1:0
Cape Verde Standard Time -1:0
Mid-Atlantic Standard Time -2:0
E. South America Standard Time -3:0
Argentina Standard Time -3:0
SA Eastern Standard Time -3:0
Greenland Standard Time -3:0
Montevideo Standard Time -3:0
Newfoundland Standard Time -3:-30
Atlantic Standard Time -4:0
SA Western Standard Time -4:0
Central Brazilian Standard Time -4:0
Pacific SA Standard Time -4:0
Venezuela Standard Time -4:-30
SA Pacific Standard Time -5:0
Eastern Standard Time -5:0
US Eastern Standard Time -5:0
Central America Standard Time -6:0
Central Standard Time -6:0
Central Standard Time (Mexico) -6:0
Mexico Standard Time -6:0
Canada Central Standard Time -6:0
US Mountain Standard Time -7:0
Mountain Standard Time (Mexico) -7:0
Mexico Standard Time 2 -7:0
Mountain Standard Time -7:0
Pacific Standard Time -8:0
Pacific Standard Time (Mexico) -8:0
Alaskan Standard Time -9:0
Hawaiian Standard Time -10:0
Samoa Standard Time -11:0
Dateline Standard Time -12:0

 

Naturally the best solution would have been to use the Zoneinfo names for timezones since they are a lot more intuitive, and a lot of websites already use them out there, and oh btw all unix/linux/macos out there as well :) http://en.wikipedia.org/wiki/Zoneinfo

Tags: , , , ,

.NET | c# | DateTime | time zone | timezone

ASP.NET http authentication header rewrites

by Bjørn Bouet Smith 21. May 2008 20:45

I were recently a victim of asp.net's browser detection and on the fly content change.

The story is:

I work for a company called ZYB, and for a new feature we are developing we have created some HttpModules, which basically provides means of authenticating our users against their usual ZYB account using either Bacic Authentication or Digest Authentication.

This is all fine, and since both Basic Authentication and Digest Authentication are pretty straightforward to implement we were done in a few days.

We tested the modules, simply by invoking the urls that were protected by the web.config sections:

<authorization>
<deny users="?" />
</authorization>
<authentication mode="None" />

Please note that when developing your own authentication modules, you have to allow Anonymous users in IIS, and remove all other authentication options, and in the web.config, you have to set the

<authentication mode="None" />

Otherwise your modules wont kick in.

But back on track, this is not the reason why I am writing this blog post, its simply because we suddenly discovered that for some user agents, asp.net was modifying the HTTP 401 Unauthorized status code to 200 OK, but still sent the WWW-Authenticate header anyway.

This does seem like a bug, and I traveled many paths before finding out that it was the user-agent header that triggered the Status rewrite.

I am pretty sure asp.net should never rewrite the status codes, at least not for authentication, since it pretty much screws up authentication.

Since changing the User-Agent was not an option, I tried to change the Request headers, but microsoft have made that impossible with a recent fix to .NET.

So I was getting desperate, and I tried to use some of the .browser files you can place in the App_Browsers directory, but I could not find any options for "Do not fuck up my status http headers", so no luck there.

In a desperate measure, I looked at the clientTarget xml elements you can put into the web.config, but no luck there as well, so my last try before rewriting the entire feature, to use in place authentication within the http body, was the

browserCaps section in system.web in the web.config.

I found that if I added the following section:

    <browserCaps>
      <result type="System.Web.HttpBrowserCapabilities"/>
      <use var="HTTP_USER_AGENT"/>
    </browserCaps>

asp.net stopped fucking up my headers, and returned the proper 401 status code.

The user agent that fucked everything up, was more or less any mobile device out there, and ZYB being a mobile company, its damn hard to just ignore that.

So this blog post is hopefully a help for people stuck in the same situation.

 

Tags: , , , ,

.NET | asp.net | Authentication | c# | HTTP_USER_AGENT

Extension methods

by Bjørn Bouet Smith 20. May 2008 20:22
As promised way back in 2007 I will try to show some of the coolness of extension methods.

Extension methods are simply said, methods that can extend existing classes whether or not you have access to the original code.

You cannot access private member variables etc, but from all other views and use it will look as it was a method that was created originally in the class it self.

To use an extension method, you have to import the namespace that contains the class with the method, and have a variable of the type the method works on.

Lets say you always wanted a Reverse() method on a string because you always use that nice feature in some obscure project you are the maintainer of.

No sweat.

The principles of extension methods are simple. Just create a static class, put a static method in that class, with a special signature, and voilá you can access that method in your other class as it was natively written for that.

Let me give you an example with the Reverse() method on string.

    /// <summary>
    /// Class with useful extensions to System.String
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        /// Reverses the specified string
        /// </summary>
        /// <param name="s">The s.</param>
        /// <returns></returns>
        public static string Reverse(this string s)
        {
            StringBuilder sb = new StringBuilder(s.Length);
            char[] chars = s.ToCharArray();
            for (int x = chars.Length - 1; x > -1; x--)
            {
                sb.Append(chars[x]);
            }
            return sb.ToString();
        }
    }
Please note the use of this in the method signature, the this signifies that its should be interpreted as an extension method, and then you just use the parameter as it was a normal method.

To use the method above, just create a string variable and call Reverse() on it. Just as easy as:

string s = "OMG";
Console.WriteLine(s.Reverse());
And its really as simple as that.

Another example could be System.DateTime which sometimes can be a bitch to get to know the different string formats for outputting. Why not just create an extension method with your favorite format:

 /// <summary>
 /// Class with useful extensions to System.DateTime
 /// </summary>
 public static class DateTimeExtensions
 {
     /// <summary>
     /// Returns an ISO8601 string representation of the date time object
     /// as used in e.g. VEVENT
     /// </summary>
     /// <param name="dt">The dt.</param>
     /// <returns></returns>
     public static string ToISO8601String(this DateTime dt)
     {
         if (dt.Kind == DateTimeKind.Utc)
         {
             return dt.ToString("yyyyMMddThhmmssZ");
         }
         else
         {
             return dt.ToString("yyyyMMddThhmmss");
         }
     }
Which in turn is used as easily as:

DateTime dt = DateTime.Now;
Console.WriteLine(dt.ToISO8601String());
See how easy it is :-)

Extension methods can naturally have parameters just like normal methods, and its as simple as creating normal parameters, the only rule is to have the class that the method should be an extension to as the first parameter, i.e. public static bool MatchModulus(this int x, int modulus).

A more elaborate example could be another string extention method called Slice:

        /// <summary>
        /// Slices the specified string into the specified number of parts
        /// </summary>
        /// <param name="s">The string to slice into parts</param>
        /// <param name="parts">The number of parts</param>
        /// <returns></returns>
        public static string[] Slice(this string s, int parts)
        {
            if (string.IsNullOrEmpty(s))
            {
                throw new ArgumentException("String to be sliced cannot be null or empty");
            }
            if (parts < 1)
            {
                throw new ArgumentException("Number of parts to slice into must be greater than 0");
            }
            string[] slices = new string[parts];
            int charsInSlice = (int)s.Length / parts;
            int charsRemoved = 0;
            for (int x = 0; x < parts; x++)
            {
                slices[x] = s.Substring(charsRemoved, charsInSlice);
                charsRemoved += charsInSlice;
            }
            if (charsRemoved != s.Length)
            {
                slices[parts - 1] += s.Substring(charsRemoved);
            }
            return slices;
        }
Which in this example slices the string into the specified number of parts. The example is not a perfect method, because if you specify more parts than characters in the string it will return a string array with only the last element of the string array containing the entire string. Feel free to rewrite the method, its very simple to change :-p.

I hope this gave a little insight into extension methods and that they can in fact be useful.





Tags: , ,

.NET | c# | extension methods

first glance at lambda functions in c# 3.0

by Bjørn Bouet Smith 18. February 2008 23:01
When I first heard about lambda functions in c# 3.0, I were a bit sceptical, since the syntax is like nothing else I have seen.

I am still sceptical, but I can see places where they have their use, like in very simple selects from lists, simple string manipulations etc.

Like
	    string[] abs = new string[] { "Ab", "ab", "aB", "AB" };

            var abSelected = abs.Where(str => str == "ab");

            foreach (string p in abSelected)
            {
                Console.WriteLine(p);
            }

            var allAbs = abs.Where(str => str.ToLower() == "ab");
            foreach (string p in allAbs)
            {
                Console.WriteLine(p);
            }
Which shows an array of strings, where we first select those that matches "ab", lowercase, and then writes each one found out. Then it selects the same again, but ignores the case, and more or less selects everything.

Or a simple string manipulation:

	    var allCAPS = abs.Select(cap => cap.ToUpper());
            Console.WriteLine("ab all upper case\r\n");
            foreach (string p in allCAPS)
            {
                Console.WriteLine(p);
            }
Which basically converts all the strings to uppercase. In this example pretty useless, but it could be other string manipulations done.

objects are more or less the same syntax. Consider the following simple classes:

 public enum Sex
 {
     Female,
     Male,
     YesPlease
 }

 public class Person
 {
     public string Name
     {
         get;
         set;
     }

     public int Age
     {
         get;
         set;
     }

     public Sex Sex
     {
         get;
         set;
     }

     
 }
And the following snippets of code:

 List<Person> people = new List<Person>();
 
 Person person = new Person();
 person.Name = "Bjørn Smith";
 person.Age = 34;
 person.Sex = Sex.Male;
 people.Add(person);

 person = new Person();
 person.Name = "Female beauty hungry for sex";
 person.Age = 35;
 person.Sex = Sex.YesPlease;
 people.Add(person);

 person = new Person();
 person.Name = "Female beauty";
 person.Age = 18;
 person.Sex = Sex.Female;

 people.Add(person);

 person = new Person();
 person.Name = "Female blonde";
 person.Age = 25;
 person.Sex = Sex.Female;

 people.Add(person);

 person = new Person();
 person.Name = "Female brunette";
 person.Age = 38;
 person.Sex = Sex.Female;

 people.Add(person);
First a simple setup, to get some data to work with. I know the dataset is sparse, but it should be enough to show some ways of using lambda.

And then some simple queries to the list:

 Console.WriteLine("Female of all ages");
 var females = people.Where(a => a.Sex == Sex.Female || a.Sex == Sex.YesPlease);
 foreach (Person sexpartner in females)
 {
     Console.WriteLine(string.Format("{0}, {1} years", sexpartner.Name, sexpartner.Age));
 }

 Console.WriteLine("Order by age ascending"); females = people.Where(a => a.Sex == Sex.Female || a.Sex == Sex.YesPlease).OrderBy(a => a.Age); foreach (Person sexpartner in females) { Console.WriteLine(string.Format("{0}, {1} years", sexpartner.Name, sexpartner.Age)); } //For those really hungry we only want objects with name and sex var hungry = people.Where(a => a.Sex == Sex.YesPlease).Select(hu => new { hu.Name, hu.Age }); Console.WriteLine("Hungry only"); foreach (var femalehungry in hungry) { Console.WriteLine(string.Format("{0}, {1} years", femalehungry.Name, femalehungry.Age)); }

First query is just selecing all Person objects that have Sex as Female or YesPlease.

Please note the "strange" syntax of creating the "query" object by doing a: a => a.Sex ==  Sex.Female, which is exately the same as an anonymous delegate like delegate(string a) {return a.Sex == Sex.Female;}. I tend to like the last anonymous delegate more, since in my eyes its obvious what it does, but I'm sure that in time, I will embrace lambda functions where they make sense.

Second query is basically the same as the first one, but with the twist that we are ordering the list by Age ascending, just by doing a .OrderBy(a => a.Age), thats quite nifty I think, and if you compare to anonymous delegates, you would have had to do something like the following to have the same result:

 List<Person> femalePeople = people.FindAll(delegate(Person p)
 {
     return p.Sex == Sex.Female;
 }).Sort(delegate(Person ps1, Person ps2)
 {
     return ps1.Age.CompareTo(ps2.Age);
 });
So when you compare the two blocks of code, I see the benefit of lambda functions, but I still think they clutter the code, anonymous delegates easier to understand, but then again, it might just need some getting used to :)


The last select to the people list is basically the same, but we only select those that have YesPlease as Sex, and we create a new class on the fly with only two Properties, Name and Sex. Thats less usefull if you ask me, since you cannot return an object to the caller of a method, and get the type safety etc. But naturally you can manipulate the newly created objects, and you get intellisense and all the works, thats quite nice :)

This was my first glance at lambda functions, and it might be useful, I still need to see the definitive proof of their usefullness, in particular the feature to create anonymous types on the fly, but I am open to enlightenment :)

Tags: , , ,

.NET | c# | delegates | lambda

enable clr integration in SQL server 2005

by Bjørn Bouet Smith 3. January 2008 15:51
Run the following query:

sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO

Tags: , ,

.NET | SQL Server | CLR

VS 2008 released

by Bjørn Bouet Smith 22. November 2007 19:39
A few days ago Microsoft released Visual Studio 2008.

Thats great news, since with the release of VS 2008, c# 3.0 and .NET 3.5 is released as well.

.NET have some really exiting new features, like

LINQ
Extension methods
and lambda functions

I will take a look at them and make a few examples on how to use each of the those items above.

Tags: , , , ,

.NET | c# | extension methods | lambda | LINQ

.NET TimeZone

by Bjørn Bouet Smith 20. September 2007 20:06
Everyone working with .NET and TimeZones have at one point thought, why the #%&#&% can't I instantiate another TimeZone than the current one, i.e. why is it not possible to create a .NET TimeZone object in the following simple way.

TimeZone zone = new TimeZone("Europe/Copenhagen");

TimeZone zone = new TimeZone("CET");

It seems like Microsoft did not think of, or decided not to implement multi timezone support in .NET, and thats too bad, because Timezone handling, Daylight savings are just a bitch to work with.

Timezones are not so bad, since its pretty easy to identify what timezone a given country is in. There are numerous sources for this on the internet, such as http://www.timeanddate.com/worldclock/, and with a little manual work, or a little screen scraping you can have a combined country/timezone list in no time.

The real problems occurs when you want to find out whether or not a given TimeDate object is within the Daylight savings time for a given country and timezone, and in that, the timezone are of no use, since it says nothing about the daylight savings of the date.

I have tried some solutions where I try to identify the daylight savings time for the most used countries, for a few years in advance, but that won't help me with dates in the past, and is really not a good solution, since the completeness of the solution is at best lacking.

I have searched a lot of places on the internet for a proper solution, and someone have made a solution for retrieving the timezones from the windows registry combined with some dll imports fromt he win32 API, but those are not perfect either.

So having almost tossed the towel into the ring, I stumpled upon another page on the internet http://www.codeplex.com/publicdomain/, and I thought, hmm, another crappy implementation, but no, its a full .NET implementation of the tz database http://www.twinsun.com/tz/tz-link.htm. I had looked at that timezone database myself a few times, but the sheer size and format of the database was just such a daunting task, that I have never fathomed to even be able to read that into a sensible .NET format.

The .NET library called PublicDomain is very easy to work with, much intuitive, and handles timezones and daylight savings very nice.

Its as simple as:

// Get the local computer's time zone
TzTimeZone dkZone = TzTimeZone.GetTimeZone("Europe/Copenhagen");

TzTimeZone ausZone = TzTimeZone.GetTimeZone("Australia/Adelaide");

DateTime dkNow = DateTime.UtcNow; //When in danish timezone

DateTime auzNow = ausZone.ToLocalTime(dkNow);
Gracefully right :)

Too bad Microsoft did not implement this.

The good part is that they will in .NET 3.5. I'm not sure of the extend of the implementation, or how well the daylight saving rules for each country is implemented, but at least its good that Microsoft at least have started looking in this direction.

Tags: , , ,

.NET | c# | timezone | olsen

multi-cast delegates and Predicate<T>

by Bjørn Bouet Smith 31. August 2007 19:22
Since Predicate<T> that is used for findind stuff in a generics list is in fact a multi-cast delegate, I thought it might be possible to chain several Predicates to simplify multiple requirements for the elements returned.

Consider the following code:

Predicate<int> greaterThan5 = delegate(int x) { return x > 5; };
Predicate<int> lessThan10 = delegate(int x) { return x < 10; };

It would be cool if it would be possible to chain them, by doing a simple:

Predicate<int> combined = lessThan10 + greaterThan5;

And then:

List<int> resulting = allInts.FindAll(combined);

Unfortunately it dosen't work, or more precicely, it is only the last delegate that gets invoked.

It seems like MS did not envision people wanting to use multi-cast delegates for their predicates, and when looking at the List.FindAll implementation, its very clear, since it only invokes the delegate as it were a single cast one:

public List<T> FindAll(Predicate<T> match)
{
    if (match == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
    }
    List<T> list = new List<T>();
    for (int i = 0; i < this._size; i++)
    {
        if (match(this._items[i]))
        {
            list.Add(this._items[i]);
        }
    }
    return list;
}


So unfortunately you still need to do the old fashion way:

List<int> resulting = allInts.FindAll(lessThan10).FindAll(greaterThan5);

Lets hope they change it in c# 3.0

Tags: , , ,

.NET | c# | delegates | generics

Delegates

by Bjørn Bouet Smith 7. August 2007 22:10
Some years ago, when someone mentioned delegates I would shudder, and think back of all the times when I had tried to use them to something useful, and All I could think of at the time was to use them for events that other objects could subscribe to. This is also a nice feature, but when you think about it delegates is so much more.

I have started using delegates more heavily, and primarily to do Lazy Loading of data from a database. Lazy Loading is a technique where you only load the data when the application need it.  Lets say you have a class Customer, with a lot of properties, including an Orders collection. Instead of loading all orders and all other data that is related to the Customer, why not just load the data when the application makes a request for it, by invoking the get method of the Orders collection.

People would perhaps argue that it would require for the business objects to know the database structure, or if done a little more clever, need a reference to a Data Access Layer, but no, thats not neccesary, since you can use delegates for it.

consider the following delegate:

public delegate List<T> LoadDataDelegate<T>();


This delegate states that it will return a list of objects of type T.

okay then consider the following class

public class Customer
{

    /// <summary>
    /// Creates a new instance of the Customer class
    /// </summary>
    /// <param name="ordersDelegate"></param>
    public Customer(LoadDataDelegate<Order> ordersDelegate)
    {
        this.ordersDelegate = ordersDelegate;
    }

    private LoadDataDelegate<Order> ordersDelegate;

    private List<Order> orders;
    /// <summary>
    /// Gets a List of orders for the current Customer
    /// </summary>
    public List<Order> Orders
    {
        get
        {
            if (orders == null)
            {
                orders = ordersDelegate();
            }
            return orders;
            }
    }
   
    
}


And the following Mock data layer

public class DAL
{
    public List<Order> GetAllOrdersForCustomer(long customerID)
    {
        string sql = "select * from orders where customer_id=@customer_id";
        //etc
        //load into list
        }

        public Customer GetCustomer(long customerID)
        {
            Customer c = new Customer(delegate() { return GetAllOrdersForCustomer(customerID); });
            //load other data from the database

            return c;
        }
}


These two classes and the delegates, show a very simple way of using delegates for something intelligent and create an object that is capable of loading data from the database on demand, without knowing anything about Datalayers, SQL or anything else.

Nice right :)

Consider implementing all methods that can create, read, update and delete an object as delegates and all you would ever need to expose to your application is the business objects, and perhaps a few factory methods that could create new instances of objects with the delegates assigned to actual methods in your data layers :)

Tags: , , ,

.NET | c# | generics | delegates

About me

Even though I have been working with programming for 15 years now, I still get amazed of how little I know :)

That is one of the great things in computers, there are always someone better than you. Someone you can ask for help.

Follow me on twitter

Ads