thoughts on programming and computer related stuff RSS 2.0
# Friday, June 05, 2009
I have recently been working on a project where we reimplement an old web application with a new one. Since there has been an page on the same address before, there are also some old applications in other places linking to pages on the old site. For instance, the login.aspx file is linked to in a lot of places.

I will in my example use a link to the page login.aspx in my solution.

To get these links to work, I had (as far as I'm aware of) two options. To make a login.aspx and redirect in this file and add login.aspx to global.asax IgnoreRoute, or to map a new route in global.asax and redirect to my new login. The latter is the solution i went for.

To accomplish this all I had to do was to add the following to RegisterRoutes method in global asax:

routes.MapRoute("Handle login", "login.aspx", new { controller = "Login", action = "Index", id = "" });


Very easy, and now, every request for http://myapp/login.aspx is handled by http://myapp/login/index/

Friday, June 05, 2009 4:43:20 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
.NET | ASP.NET | ASP.NET MVC
# Sunday, February 08, 2009
A while back I decided I wanted to try Windows 7 Beta, but since I had Windows Server 2008 installed already, I decided to try Windows Server 2008 R2 instead and just upgrade my existing installation.

So I did an upgrade on my work laptop, a HP Compaq 6910p. The upgrade went without any problems. I have been using the machine every day for about 6 weeks now, and not one bluescreen and I can't remember having any other problems either. The only "problem" I had, is after upgrading, I had to do the same hacks to get bluetooth working again as I did on Server 2008.

Conclusions:

I'm very happy with Windows Server 7 or 2008 R2. Things have only become better since Vista and Server 2008. I must say I don't notice any performance differences, but I hope they will come after a fresh install. I have been using the OS every day in my job as a programmer, and there has been no complications. I think this is the best OS I have ever used.

Sunday, February 08, 2009 5:59:30 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
Windows Server
# Tuesday, December 09, 2008
Often I have had problems logging in to remote desktops because the two user sessions Microsoft allows you to have are occupied. This is very annoying and until Windows Server 2008, you got no choice to log of the other users. There is however a smart little command line tool to do this.

To see logged in users, type: qwinsta /server:SERVERNAME
To log out an existing session, type: rwinsta /server:SERVERNAME SESSIONNAME

Here is an example from my machine:
C:\Users\gm>qwinsta /server:kraftwerk
 SESSIONNAME       USERNAME                 ID  STATE   TYPE        DEVICE
 services                                    0  Disc
 console                                     1  Conn
 rdp-tcp#0         gm                        2  Active  rdpwd
 rdp-tcp                                 65536  Listen
C:\Users\gm>rwinsta /server:kraftwerk rdp-tcp#0

Tuesday, December 09, 2008 5:35:12 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
Windows Server
# Monday, December 08, 2008
Last week I had to make a SQL Procedure go faster and a new join in the same operation. From the execution plan I could see that the thing that cost most time was a call to an external function made as a .NET CLR that got all the groups a person was member of, and returned it as a comma separated string. This tok a couple of milliseconds, each time, and with some of the users input resulting in over 8000 calls in a single statement, the procedure took to long time. I also had the requirement to add an other column in the result, showing a comma separated list of functions each persons had. Doing this the same way as before, would turn the procedure almost twice as sluggish as before.

To get the result wanted, a small trick was used. Here is a simplified version of what I wrote:
SELECT TOP 10
        substring(O.Functions,2,500)
FROM    dbo.Tp_Person P
CROSS APPLY ( SELECT    ',' + CAST(FunctionName AS varchar) AS [text()]
              FROM      dbo.Tp_Function F
              WHERE     F.Personid = P.Personid
              FOR XML PATH('')
             ) O( Functions )


This trick actually reduced the time of the procedure on 5000 people from about 30 seconds to 1,5 seconds. Made my day.

Monday, December 08, 2008 6:55:56 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
T-SQL
# Friday, October 31, 2008
This week I finally got around to install Windows Server 2008 on my laptop. I have a HP Compaq 6910p laptop, which is a good laptop with 64 bit dual core processor and 4 gb of RAM.

Since I have a 64-bit CPU and have been running Vista 64 for some time without any problems, I installed the 64 bit enterprise edition.

I followed the blogpost: Using Windows Server 2008 as a SUPER workstation OS to get the OS configured. Which got me pretty far, but not all the way there.

For drivers I downloaded the Vista drivers from HP's support page. They worked good except for the bluetoouth driver. But apparently, Microsoft has decided that bluetooth is not for servers, so there is no support. Both my bluetooth mouse and keyboard works with the supplied dongle, but not with the built in device.

I also turned of Internet Explorer Enhanced Security, which is nice on a production server, but extremly annoying on your desktop. This is done in Server Manager - Security Information - Configure IE ESC.

I also use virtual pc's a bit and figured Hyper-V would be cool instead of Virtual PC or Virtual Server, but when I activated this, the sleep function on my laptop no longer worked. I did find a good hack for enabling sleep with Hyper-V. Works ok, but it's not 100% ideal solution.

The current version of Live Messenger would not install either, but the MSI-version of Messenger 8.1 would install. Apparantly you can also copy the installed files from a Vista machine to get newer versions running, but I haven't tried.

Visual Studio 2008, SQL Server 2008, Office 2007, Firefox, Daemon tools all installed wihout any problems.

Final thoughts
All in all, I am very happy with my transition to Server 2008. It seems faster than Vista, and the fact that you have to turn all the bloat on instead of the opposite makes it great.

Update: I got bluetooth devices working using this blog post: Installing the Microsoft Bluetooth Stack on Windows Server 2008

Friday, October 31, 2008 1:45:09 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
Windows Server
# Tuesday, October 28, 2008
Today I got an error on a web application after upgrading it from .Net 2.0 and Visual Studio 2005 to .Net 3.5. The project uses Telerik radcontrol, a few releases old version. After upgrading, every page that uses the radcontrol DatePicker failed to load, and the dreaded "Yellow screen of death" was shown instead.

It wasen't my code that failed, it was the radcontrols own prerender-event that threw the exception. Since I don't have the source code for this control and due to the fact that the fault only appaired on one test server without Visual Studio installed, it was hard to debug. Luckily a colleague had experienced a similair problem some weeks ago, and I remembered that changing the locale settings helped him (He is swedish, and used a swedish locale in an otherwise homogenic norwegian development team).

I logged in to the server and tried to change the system locale of the admin user. No help.
I tried to change the user running the application pool from NETWORK SERVICE to the admin I logged in as. Suddenly everything worked.

I did however want to run the process as NETWORK SERVICE and not administrator or have to make another account just for this reason. Therefore I wanted to change the network services locale settings, but since this is a user you can't log in as, this seemed hard.

Luckily I found this blog post: IIS6: Changing the Locale ID when Regional Settings Won't Work
I followed the description to change the settings. For some reason this didn't quite work. Probably due to a typo. I tried to export the regedit settings for HKEY_USERS\S-1-5-20 and just manually change the sShortDate, from the English setting and to norwegian settings. Now everything is working again!

Tuesday, October 28, 2008 8:20:13 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
.NET | ASP.NET
# Thursday, October 23, 2008

Checking if a email addresses is valid in SQL can be very convinient from time to time. Here are two ways to do it in SQL, and a bit about them.

 

Here is a full SQL way to do this:

 

Create function VALIDEMAIL(@s varchar(255)) 
--Returns true if the string is a valid email address.
returns bit
as
BEGIN
DECLARE @u VARCHAR(60), @v VARCHAR(60), @x VARCHAR(60), @i int, @j int, @result bit
SET @result=1
set @s = rtrim(ltrim(@s))
SET @i=len(@s)-CHARINDEX('@',reverse(@s))+1
if @i <= 1 or len(@s) < 5
begin
  set @result = 0
  goto done
end
SET @u=LEFT(@s,@i-1)
SET @j=len(@s)-CHARINDEX('.',reverse(@s))+1
SET @v=RIGHT(@s,LEN(@s)-@j)
if @j < 3 or @j < @i
begin
  set @result = 0
  goto done
end
SET @x=substring(@s,@i+1,@j-@i-1)
IF LEN(@x)<2
 BEGIN
 SET @result=0
 GOTo done
 END
IF (LEN(@x)=3) AND (@x NOT LIKE '[a-zA-Z][a-zA-Z][a-zA-Z]'Collate  Latin1_General_BIN)
 BEGIN
 SET @result=0
 GOTo done
 END
IF (LEN(@x)=2) AND (@x NOT LIKE '[a-zA-Z][a-zA-Z]' Collate  Latin1_General_BIN)
 BEGIN
 SET @result=0
 GOTo done
 END
SET @i=1
WHILE (@i<LEN(@u))
 BEGIN
 IF SUBSTRING(@u,@i,1) NOT LIKE '[a-zA-Z0-9_\-.+=/!#$&''*%?^`{|}"@\\ ]' escape '\' Collate  Latin1_General_BIN
  BEGIN
  SET @result=0
  GOTo done
  END
 SET @i=@i+1
 END
SET @i=1
WHILE (@i<LEN(@v))
 BEGIN
 IF SUBSTRING(@v,@i,1) NOT LIKE '[a-zA-Z]' Collate Latin1_General_BIN
  BEGIN
  SET @result=0
  GOTo done
  END
 SET @i=@i+1
 END
SET @i=1
WHILE (@i<LEN(@x))
 BEGIN
 IF SUBSTRING(@x,@i,1) NOT LIKE N'[a-zA-Z\-.0-9]' escape '\' Collate  Latin1_General_BIN
  BEGIN
  SET @result=0
     goto done
  END
 SET @i=@i+1
 END
done:
return @result
END
GO

Here is another way, where you insert .NET CLR code in the database. Here I use the .NET RegEx.Ismatch, so I can use it for tons of other stuff as well with the right input.


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Text.RegularExpressions;

namespace SQLSignature
{
    public class SqlFunctions
    {

        [SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.None)]
        public static SqlBoolean fn_RegexIsMatch(SqlString input, SqlString pattern)
        {
            return (SqlBoolean)Regex.IsMatch(input.Value, pattern.Value);
        }

    }
}
In SQL:
CREATE ASSEMBLY SQLSignature
FROM 'C:\CLR Assemblies\Performance\SQLFunctions\bin\SQLFunctions.dll';
GO
-- Create fn_SQLSigCLR and fn_RegexReplace functions
CREATE FUNCTION dbo.fn_RegexIsMatch(@input AS NVARCHAR(MAX),@pattern AS NVARCHAR(MAX))RETURNS BIT 
WITH RETURNS NULL ON NULL INPUT 
EXTERNAL NAME SQLSignature.SQLFunctions.fn_RegexIsMatch;
GO
This can be run with a command like:

    select *
    from [AW].[person].emailaddress as p
    where dbo.fn_RegexIsMatch(RTRIM(LTRIM(lower(P.emailaddress))),
'^[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$')=1

I did some timings on the two functions and as you can see below there are big differences. The .NET CLR one is almost 8 times faster(cpu time) than the T-SQL one. It's also a whole lot easier to read, and can be used for all other RegEx's needed. You do however need to get out of management studio to make it, and 1.5 seconds is for processing almost 20000 email addresses still should be fast enough for most uses.

SET STATISTICS TIME ON

    select *
    from [AW].[person].emailaddress as p
    where dbo.VALIDEMAIL(P.emailaddress)=1

    select *
    from [AW].[person].emailaddress as p
    where dbo.fn_RegexIsMatch(RTRIM(LTRIM(lower(P.emailaddress))),
'^[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$')=1 (19929 row(s) affected) SQL Server Execution Times: CPU time = 1466 ms, elapsed time = 1911 ms. (19972 row(s) affected) SQL Server Execution Times: CPU time = 203 ms, elapsed time = 380 ms.
It's pretty cool to see that .NET performs good within SQL as well. I am primarily a .NET developer but do have to use SQL quite a bit as well, but the fact that .NET outperforms SQL both in readability and speed inside SQL on some actions make my job a lot easier.


Thursday, October 23, 2008 8:48:20 AM (GMT Standard Time, UTC+00:00)  #    Comments [1] - Trackback
.NET | T-SQL
# Wednesday, September 03, 2008

All most every ASP.NET website I have seen, uses Databinder.Eval(Container.DataItem, "colum1") in repeaters to get the data passed in and show it on screen. The problem with Databinder.Eval is that it uses reflection to evaluate the item. This is time consuming and unnecessary, so instead, one should use casting to obtain the same effect. Try not to do it this way:

<asp:repeater id="rptAccounts" runat="server">
    <itemtemplate>
        <%# Databinder.Eval(Container.DataItem, "colum1") %> <br />
    </itemtemplate>
</asp:repeater>

But use this one instead:

<asp:repeater id="rptAccounts" runat="server">
    <itemtemplate>
        <%# ((BusinessObjects.Object)Container.DataItem).Column1 %> <br />
    </itemtemplate>
</asp:repeater>

This will also give you a compiler warning if the members of a class should change, and
not just runtime fail such as the first example. If you are not using business
objects, but a DataTable, you can  cast
to datarow and get the column right out of there like this:


<asp:repeater id="rptAccounts" runat="server">     <itemtemplate>         <%# ((DataRow)Container.DataItem)["Column1"] %> <br />     </itemtemplate> </asp:repeater>

This both increases speed and makes the application more robust to runtime errors. A win-win situation:)



Wednesday, September 03, 2008 6:42:36 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
.NET | ASP.NET
Navigation
Archive
<June 2009>
SunMonTueWedThuFriSat
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Gaute Magnussen
Sign In
Statistics
Total Posts: 17
This Year: 0
This Month: 0
This Week: 0
Comments: 1
Themes
Pick a theme:
All Content © 2010, Gaute Magnussen
DasBlog theme 'Business' created by Christoph De Baene (delarou)