Usability, MVC, ASP.NET

24. Januar 2012 11:08
by Henrik Stenbæk
1 Kommentare

ASP.NET 4.0 acting strange when User-Agent equals Safari 5.1

24. Januar 2012 11:08 by Henrik Stenbæk | 1 Kommentare

During the last couple of days I have spend my working hours trying to resolve a strange problem on one of our production sites. I used a lot of time trying to figure out what coursed the problems and searched the web without any result. As part of the troubleshooting I also prepared a question for stackoverflow.com. It turned out when I started to post the question that stackoverflow was able to suggest a question with similar content and that this other question contained the answer – it has been the all the time but I wasn’t able to find it because I have googled the wrong keywords. In the hope that this could help other people that is googling with the wrong keywords I herby post the text that original prepared for stackoverflow (including a link to the correct answer).

“We have a website running on ASP.NET 4.0 Webforms (IIS 7). The site has been online for years (since 2008) running under ASP.NET 2.0. Recently (like October 2011) we lifted it to 4.0, and after that we have started to get complaints from Safari 5.x users that they can’t sign in to the site, but keep on getting redirected to the login page.

The site is running in a farm with four servers. When the problem occurs it’s not on all 4 servers at once. When a node starts redirecting the user, the situation will persist for an unknown amount of time and then the node will return to normal – we haven’t yet discovered how long this amount of time is, it could be equal to app pool recycling. After all we have experienced that recycling the app pole seems to solve the problem.

We have experienced that when we hit one of the servers that is “infected” with the problem, we don’t really need to use a native Safari 5.x browser. All browsers that is showing the Safari User-Agent is redirected. The problem exists when User-Agent is:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50

If we spoof a Chrome or Firefox to display this User-Agent the problem will occur. 

If the same browsers are showing their native User-Agent they have no problem in signing in and browsing the site. As if we spoof a Chrome or Firefox to display an older Safari User-Agent: 

Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; nl-nl) AppleWebKit/533.16 (KHTML, like Gecko) Version/4.1 Safari/533.16

they have no problem browsing the site.

The fact that any browser that impersonates as Safari 5.1 does experience the problem, have lead us to the conclusion that it is a 100% server related problem.

For some reason the server will decide that a Safari 5.1 browser is not suitable to browse the site as a logged in user and issue a 302 redirect to the login page.

This led us to look at the safari.browser file. When digging into this file it seems that there is no entry taking care of Safari browsers after version 4. We haven’t been able to verify this. But we can see that browsing the site with any of the above “User-Agents” results in different results when looking at System.Web.HttpBrowserCapabilities

The Safari 4.1 header returns

  • Platform = MacPPC
  • JavaScript Version = 1.7

The Safari 5.1 header returns

  • Platform = Unknown
  • JavaScript Version = 1.6

But if the problem is related to a missing entry in safari.browser why isn’t the problem persistent?

Could it be that if ASP.NET couldn’t recognize the browser it won’t bother checking the credentials cookie?

Does anybody have had any experience like this and have you solved it?”

Some of the words I used wend googling includes:

  • "safari.browser" asp.net
  • safari.browser file asp net
  • Request.Browser.Adapters renders
  • ASP.NET 4.0 keep on getting redirected to the login page

I searched stackoverflow for 

  • asp.net safari iis
  • CONFIG Browsers

The correct search is something like

  • applewebkit .net 4 user-agents

because it will lead one to the correct answer:

http://stackoverflow.com/questions/5478181/net-4-0-website-cannot-identify-some-applewebkit-based-browsers

It seems that I have found the root cause of the problem. The UserAgent -> BrowserCaps resolving mechanism uses a cache to temporarily store mappings. Unfortunately it uses (by default) the first 64 characters of the UserAgent string as cache key and THAT is just BS... Occasionally a user agent pops up that looks like a Safari, but really isn't and that one is not resolved properly (Mozilla 0.0), but the mapping is still stored in the cache, which means that all UserAgent strings with the same 64 character prefix are now incorrectly mapped as well until that cache entry expires (sliding window with 1 minute). The key length used for caching can fortunately be configured with

<browserCaps userAgentCacheKeyLength="..." />

in the config section. I've upped the key length to 256 and since that the problem has disappeared..”

31. März 2011 01:06
by Henrik Stenbæk
0 Kommentare

Dynamic robots.txt with ASP.NET MVC

31. März 2011 01:06 by Henrik Stenbæk | 0 Kommentare

If you have one application on your IIS and several domain names pointing to it, it’s possible to have different robots.txt files served based on the current domain name.

1. Add a route

CropperCapture[1]

2. Create the RobotsController

CropperCapture[2]

3. The SeoHelper just implements a simple way of determine what robots.txt file to return

CropperCapture[3]

4. Add the different versions of the robot.txt to the site root – remark the content for the robots.txt could be served from any source, I have just chosen a simple model to keep it simple

CropperCapture[4]

5. Run the site and request robots.txt

CropperCapture[5]

CropperCapture[6]

Get the source code: DynamicRobotsTxt.rar (21,66 kb)

16. März 2008 01:34
by Henrik Stenbæk
2 Kommentare

The prop snippet and Visual Studio 2008

16. März 2008 01:34 by Henrik Stenbæk | 2 Kommentare

In Visual Studio 2005 typing "prop[tab][tab]" will give you something like this:

vs2005

This is fine and one of the most time saving code snippets ever invented. If one type the same in Visual Studio 2008 it's ends out a little different:

vs2008

This is due to the new Automatic Properties Feature in .NET 3.0/VS 2008. This is somehow also fine as long as one don't want to maintain a .NET 2.0 project with VS 2008, doing this will end up with an compile time error saying:".. must declare a body because it is not marked abstract or extern"

must declare a body because it is not marked abstract or extern

A solution to this is to download this file:

prop.zip (604,00 bytes)

place in your "My Code Snippets" folder:

C:\users\*your user name*\Documents\Visual Studio 2008\Code Snippets\Visual C#\My Code Snippets

Now you can simply type propp[tab][tab] in Visual Studio 2008 and get the VS 2005 style property snippet. Why propp? After typing porp your finger is over the [p] button so I thought it would be the fastest solution. If you don't like it: open the prop.snippet file with Visual Studio or any text editor and edit the shortcut tag:

<Shortcut>propp</Shortcut>

19. Februar 2008 23:42
by Henrik Stenbæk
1 Kommentare

FlickrRSS user control (for BlogEngine.Net)

19. Februar 2008 23:42 by Henrik Stenbæk | 1 Kommentare

When I started out creating this control my idea was to create a Flickr photo plug-in for BlogEngine.Net but after a while I realised that I could just create a traditional ASP.NET user control for reading RSS streams from Flickr. So here it is:

FlickrRSS.ascx the user control that allows you to display Flickr photos on your weblog, homepage or wherever you have an ASP.NET based web application.

The user control supports user, public and group photostreams.

 

How to use the control

Download the control FlickrRSS.ascx.zip (1,96 kb) and unzip the files to your project (FlickrRSS.ascx and FlickrRSS.ascx.cs).

Register the control in the page where you want to show the pictures:

<%@ Register src="FlickrRSS.ascx" tagname="FlickrControl" tagprefix="onesoft" %>

Add the control to the page:
<onesoft:FlickrControl ID="FlickrControl1" runat="server" />

Properties

RssType The type of rss read from flickr the options are: User, Group, Allpublic
FlickrId Optional if RssType=Allpublic. Required if RssType is User or Group. This must be a valid Flickr userid or groupid, this is not the same as username or groupname the format is something like 12345678@00,
Tags Optional. a comma separated list of tags with no spaces eg.: Tags="adam,laura" – find photos tagged with Adam AND Laura
NumberOfImages The maximum number of images to appear in the control.
CacheDuration The time in minutes that the RSS result is cached on the server

Output

The control returns a list of thumbnails in the format:

<ul>
   <li>....</li>
   <li>....</li>
</ul>

And can easy be formatted with CSS ;-)

<onesoft:FlickrControl ID="FlickrControl1" runat="server" RssType="user"
        CacheDuration="10" FlickrId="34434281@N00" NumberOfImages="8"
        Tags="celina" />

returns this (after some formatting):

flickr

 

Download

FlickrRSS.ascx.zip (1,96 kb)

 

Improvements

This control could be better - but how? Any comments and suggestions are welcome.

  • The XML read must be asynchronous

20. Juli 2007 01:13
by Henrik Stenbæk
6 Kommentare

ASP.NET AJAX username availability with suggestions

20. Juli 2007 01:13 by Henrik Stenbæk | 6 Kommentare

Based on my resent post, I have rewritten the code and turned it in to a custom control:

  • It is no longer depending on the Futures CTP.
  • If the username isn&rsquo;t available it&rsquo;s possible to get suggestions with available names.
  • The web service UsernameResult is now returning a class which is automatically JSON serialized by ASP.NET AJAX and passed into JavaScript as a parameter.
  • Fully integrated with the asp.net 2.0 membership.

Try out the online demo.

 

How to use the control

Register the control on the page:

<%@ Register TagPrefix="one" Namespace="onesoft.common.controls" %>

Then add the control

Remember to set ControlToTest - just like on a validator control :-). All the other properties has defaults as shown above.

Add a ScriptManager to your page (before the usernameAvailability control) and define a ServiceReferance:

<one:usernameAvailability runat="server" ID="IsAvalible" 
ControlToTest="Username" 
ForeColor="DimGray" 
NotAvailableTextColor="Red" 
AvailableTextColor="CornflowerBlue" 
StartUpTextColor="DimGray" 
AvailableText="{0} is available" 
NotAvailableText="{0} is not available" 
StartUpText="Type a username" 
SuggestionLinkText="Suggest" 
UseSuggestion="true"></one:usernameAvailability> 

The webservice has 2 functions: 

IsAvailable - checking the availability of the current name
suggestAvailable &ndash; returning suggestions for available name.

Remember to include the file UsernameService.asmx to your root and add UsernameService.cs to App_Code.

That's it - now start checking for available usernames.

Try it out with the online demo - type your preferred name, if it's available create the new user and retry with the same name - now try the suggestion link.... ok I know it isn't clever, but it is available usernames ;-)


Download the full sourcecode including the demo.

AJAXUsernameControl.zip (257,01 kb)

I welcome any comments and suggestions.

Enjoy ;-

Henrik