BlogEngine.NET migrating to IIS 7

This blog running on BlogEngine.NET (and the its parent/main site) is now running on IIS 7 Integrated Mode and would like to share a little of my experience.

There were two major issues with I migrated these blog to IIS 7 [more]

1) Server Error in / Application – Request is not available in this context when I accessed the sites

    *Of course I had customErrors ON so I had to turn it OFF before I was able to see this detail

   Interesting, since the site obviously worked fine in IIS 6 and no changes were made. But after a few google clicks I ran into this written specifically for the error. IIS7 Integrated mode: Request is not available in this context exception in Application_Start from Mike Volodarsky. Implemented the suggestion and that did it.

    Because of IIS 7 architectural changes the request context is not available in the Application Start. And since BlogEngine.NET loads extensions in the Application_Start event and the extension makes extensive use of the request context in path related code (also determining protocol et al) the error occured.

    Based on the article

    "Basically, if you happen to be accessing the request context in Application_Start, you have two choices:

   1. Change your application code to not use the request context (recommended).
   2. Move the application to Classic mode (NOT recommended).
"

    I chose option one otherwise I would have stayed with IIS 6. So what I did is follow his recommended solution and move the Extension loading part of BlogEngine.NET to the BeginRequest but made provisions so that it is only loaded on the first request (and once).

Copying from the article:

void Application_BeginRequest(Object source, EventArgs e)

{

    HttpApplication app = (HttpApplication)source;

    HttpContext context = app.Context;

    // Attempt to peform first request initialization

    FirstRequestInitialization.Initialize(context);

}


class
FirstRequestInitialization

{

    private static bool s_InitializedAlready = false;

    private static Object s_lock = new Object();

    // Initialize only on the first request

    public static void Initialize(HttpContext context)

    {

        if (s_InitializedAlready)

        {

            return;

        }

        lock (s_lock)

        {

            if (s_InitializedAlready)

            {

                return;

            }

            // *** Perform first-request initialization here … ***

            s_InitializedAlready = true;

        }

    }

}

 

And that's it for the FIRST issue.

 

2) Site worked, but hmmm.. the styles are not being applied. Looking at the code, BlogEngine.NET uses httpHandlers to link to the stylesheets. Something like (depending on the theme name you have)

<link href="/blog/themes/BrightSide/css.axd?name=style.css" rel="stylesheet" type="text/css" />
Accessing the link directly in the browser didn't return anything (not found) while doing the same on the old hosting account (IIS 6) returned the style info succesfully. So there must be something wrong with the
handlers and modules. 

Luckily I found this IIS 7.0 Integrated Mode Configuration Changes from BE.NET forum

 

Go ahead and read the article, but the bottomline is : in the web.config move the module and handler configuration sections from the <system.web> to <system.webserver> and a few minor changes. Resulting in (assuming you didn't make changes in this section since you downloaded BlogEngine.NET)

 

<system.webServer>
     <modules>
        <add name="UrlRewrite" type="BlogEngine.Core.Web.HttpModules.UrlRewrite" preCondition="managedHandler" />
        <add name="ReferrerModule" type="BlogEngine.Core.Web.HttpModules.ReferrerModule" preCondition="managedHandler" />
       
<add name="CompressionModule"
type="BlogEngine.Core.Web.HttpModules.CompressionModule"
preCondition="managedHandler" />
        <add
name="WwwSubDomainModule"
type="BlogEngine.Core.Web.HttpModules.WwwSubDomainModule"
preCondition="managedHandler" />
        <!–The CleanPageModule below removes whitespace which makes the page load faster in IE. Enable at own risk –>
        <!–<add name="CleanPageModule" type="BlogEngine.Core.Web.HttpModules.CleanPageModule, BlogEngine.Core"/>–>

        <!–Remove the default ASP.NET modules we don't need–>
        <remove name="Profile" />
        <remove name="AnonymousIdentification" />
    </modules>

    <handlers>
       
<add name="FileHandler" verb="*" path="file.axd"
type="BlogEngine.Core.Web.HttpHandlers.FileHandler, BlogEngine.Core"
/>
        <add name="ImageHandler" verb="*" path="image.axd"
type="BlogEngine.Core.Web.HttpHandlers.ImageHandler,
BlogEngine.Core"/>
        <add name="SyndicationHandler" verb="*"
path="syndication.axd"
type="BlogEngine.Core.Web.HttpHandlers.SyndicationHandler,
BlogEngine.Core"/>
        <add name="SiteMap" verb="*" path="sitemap.axd" type="BlogEngine.Core.Web.HttpHandlers.SiteMap, BlogEngine.Core" />
       
<add name="TrackbackHandler" verb="*" path="trackback.axd"
type="BlogEngine.Core.Web.HttpHandlers.TrackbackHandler,
BlogEngine.Core" />
        <add name="PingbackHandler" verb="*"
path="pingback.axd"
type="BlogEngine.Core.Web.HttpHandlers.PingbackHandler,
BlogEngine.Core" />
        <add name="OpenSearchHandler" verb="*"
path="opensearch.axd"
type="BlogEngine.Core.Web.HttpHandlers.OpenSearchHandler,
BlogEngine.Core" />
        <add name="MetaWeblogHandler" verb="*"
path="metaweblog.axd"
type="BlogEngine.Core.API.MetaWeblog.MetaWeblogHandler,
BlogEngine.Core" />
        <add name="RsdHandler" verb="*"
path="rsd.axd" type="BlogEngine.Core.Web.HttpHandlers.RsdHandler,
BlogEngine.Core" />
        <add name="CssHandler" verb="*"
path="css.axd" type="BlogEngine.Core.Web.HttpHandlers.CssHandler,
BlogEngine.Core" />
        <add name="JavaScriptHandler" verb="*"
path="js.axd" type="BlogEngine.Core.Web.HttpHandlers.JavaScriptHandler,
BlogEngine.Core" />
        <add name="RatingHandler" verb="*"
path="rating.axd" type="BlogEngine.Core.Web.HttpHandlers.RatingHandler,
BlogEngine.Core" />
        <add name="OpmlHandler" verb="*"
path="opml.axd" type="BlogEngine.Core.Web.HttpHandlers.OpmlHandler,
BlogEngine.Core" />
        <add name="MonsterHandler" verb="*"
path="monster.axd"
type="BlogEngine.Core.Web.HttpHandlers.MonsterHandler, BlogEngine.Core"
/>
        <add name="BlogMLExportHandler" verb="*" path="blogml.axd"
type="BlogEngine.Core.Web.HttpHandlers.BlogMLExportHandler,
BlogEngine.Core" />
    </handlers>
</system.webServer>

And that did it for me 🙂

 

SubSonic and Club Starter Kit

If you don't code generate your DAL or use OR/M or anything that would
make you worry less about DataAccess like LINQtoSQL, Entity Framework, NHibernate, Castle
ActiveRecord then you should definitely give SubSonic a shot.

On the side I'm currently working on a C# version of Extended Club Starter Kit Version 3 Beta 1 for one club that I was part of in college (and probably a few others) and one thing to note is that the project has opted to use SubSonic. It's an open source project developed by Rob Connery and a few other popular developers in the .NET. It simplifies generation of Data Access code and some utility functions common to development. And don't forget about the cool Scaffolding support. As I've heard this is one of the popular features of the Rails framework where pages are generated on the fly to serve as you're admin tool for add/edit operations against your database table. They could be considered your admin pages or at least help during development. Bottom line is, all these features will save your time (which is what SubSonic aims for). [more]

You can opt to have the DAL generated on the fly using ASP.NET build providers, generate them using command line or as of the current version a GUI tool called "SubStage" (it is also were I view the auto scaffolding).

You can also download the SubSonic Starter Kit and get a web site already configured to work with SubSonic, UrlRewriter.NET (which is also keeping me busy considering that IIS 7.0 now allows httpmodule to run for all requests simply by configuring web.config) and a built in Content Management System. Not as complicated (a good thing) as other full blown CMS but will probably integrate this with the Club Starter Kit (so the club won't need to know programming or get back to me if they need some new pages or the sort).

It would be a good practice for me to leave the ClubSK on VB.NET and make some modifications but since I'm new with SubSonic and intend to use it for other projects, will have to remove the language barrier first so C# it is 🙂

I will definitely post the code here (or some other open source hosting like CodePlex) and try my best to keep this version abreast with the original ClubSK once I'm done. So far I have the DAL (separate project), App_Code and some pages converted to C# already and using SubSonic 2.1. Hopefully I'll have enough time to finish sometime soon.

Sys.ArgumentException: Value must not be null for Controls and Behaviors

I was going thru some pages for my current project today when I ran into the said error "Sys.ArgumentException: Value must not be null for Controls and Behaviors". It was the first time I've encountered it and since it was working the last time I browsed it I didn't have a clue what was causing it so had to dig around. [more]

I have tested the page though I have to admit that not thoroughly (yeah I know, don't check in not well tested code) and there was no automated UI tests for it, took me sometime to stop the cause. I had to consider what applications I installed on my machine recently or other changes.

After some digging it turns out that it is related to a modalPopupExtender (part of AJAXControlToolkit) in the page.

Moving on, the extender's TargetControlID was set to let's say "linkAddItem" control.

Now, the catch is that recently I added an inline condition (ok, not really sure what is the right term for this but something like the one below):

<% if(MyCondition) { %>

<asp:LinkButton ID="linkAddItem" (definition here…. plus some other text) 

<% } %> 

So as you might have guessed, the page was looking for "linkAddItem" but in case MyCondition is true, it would not be rendered thus causing the error. I had read somewhere that if you have the TargetControl's (eg. linkAddItem) Visible attribute equals to "false", the AJAX control toolkit code would be able to detect with no problems. But not this one. The "Valu" mentioned in the error is likely the TargetControlID or at least related to it. You could verify by debugging the client script if this wouldn't solve the problem but fortunately enough not to go that far.

To cut this short story even shorter, my work-around was to instead have that block wrapped inside a panel (<asp:Panel…) and on Page PreRender, set the Panel.Visible = MyCondition. To simplify you could set just the control (eg. linkAddItem) Visibility but since there are other controls in that block, in my case the panel would be good.

I believe you can also set Visible='<%= MyCondition %>' of the panel in the ASPX page rather than at runtime/code for as long as you have the Page databound. : this.DataBind(); (but be careful, this is recursive and would rebind all other controls in your page you have bound previously).

Next time you run into this error, it is likely that one of the possible suspect is control visibility.

Considerations for AJAX UpdatePanel, Page Methods and Web Services

I would not even pretend to be all knowing here but I couldn't stop myself from sharing this chain of interesting links which should remind all of us of the dangers of abusing UpdatePanels thinking that using it in any way will make our old non asynchronous pages work like magic. [more]

My journey starting with this post : Why do ASP.NET AJAX page methods have to be static? which happened to be included in ScottGu's April 28th links.

I have known and heard page methods before but haven't really used it as much as I use UpdatePanel but you ought to read that link and from there you should view the link on Why ASP.NET AJAX UpdatePanels are dangerous (the text being linked in the article is actually "They are especially performant compared to the UpdatePanel’s partial postbacks.") but I find the real title more interesting. It might not be true as "danger" is indeed relatively. But to give you a short note, UpdatePanel is still posting back to the server (including ViewState et al), it just does that asynchronously but bottom line is that a lot of information is still being sent back and forth from server-client and in some cases that is a lot of unnecessary information. I would suggest going through the article including the comments as there really are cases where Page Methods or UpdatePanel is more appropriate but bottom line is we ought to know them and just because we use UpdatePanels it doesn't mean we have the best AJAX solution.

This reminded of a case where I had a calendar control inside an UpdatePanel and looks fast locally but when deployed to a test server was considerably slower. Turns out that the page itself has a large viewstate and async postback triggered by the UpdatePanel brings that large viewstate to the server. In addition, the page will also be reconstructed (control values/properties) thus an additional overhead.

The asynchronous processing is likely to help but think again as a pure Javascript solution might be better, or PageMethods (which is sort of a easier/or at least a close alternative to having ASMX (web services)).

Check out this link on Exposing Web Services to Client Script which includes a discussion, source and sample for Page Methods.

And also if you want to hook client side events of UpdatePanels (eg. Begin/End Requests) check out this link : Use the PageRequestManager to Get More Control of Your UpdatePanels

This stuff is also a good review for upcoming ASP.NET 3.5 MCTS as there were a lot of items involving Client Scripts (more than knowing what UpdatePanel's are and which property to set for which).

Updating ASP cookie from ASP.NET (vice versa)

You might encounter a case where updating an ASP (classic/3.0) cookie from ASP.NET code (or vice versa) doesn't work. That is despite updating the cookie value, the old value still remains. [more]

I was working on a having an ASP page communicate some information to an ASP.NET (2.0) page and vice versa and since the information was not that critical/confidential a cookie would do (** for critical information, it is usually done using a common datastore/database or session though that not secure. will not discuss here for now). I expect it to be seamless since they're accessing the same set of cookies after all. However to my surprise it was acting weird.

After a review of some code and I was certain that each of them updates the cookie correctly, it was time to bring up fiddler (or any cookie viewer) and it's when I started getting more clues.

To illustrate better I came up with the following simple ASP and ASP.NET pages

<!– start of ASP code (VBScript) –>

<html>
<body>
    <%

    Response.Write("Old Value = " & Request.Cookies("a"))
   
    dim newValue
    newValue = "Classic"
    Response.Cookies("a") = newValue
    Response.Write("<br/>")
    Response.Write("Attempted New Value = " & newValue)

    %>
    <br />
    <br />
    <a href="Default.aspx">ASP.NET Page</a>
</body>
</html>

<!– end of ASP code –>

<!– start of ASPX markup –>

<%@ Page AutoEventWireup="true" Codebehind="Default.aspx.cs" Inherits="ASPCookieASPNETCookie._Default"
    Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <a href="Default.asp">Classic ASP Page</a>
    </form>
</body>
</html>

<!– end of ASPX markup –> 

And the codebehind (C#)

    1 using System;

    2 

    3 namespace ASPCookieASPNETCookie

    4 {

    5     public partial class _Default : System.Web.UI.Page

    6     {

    7         protected void Page_Load(object sender, EventArgs e)

    8         {

    9             Response.Write("Old Value = " + (Request.Cookies["a"] != null ? Request.Cookies["a"].Value : ""));

   10 

   11             string newValue = "DotNet";

   12             Response.Cookies["a"].Value = newValue;

   13             Response.Write("<br/>");

   14             Response.Write("Attempted New Value = " + newValue);

   15         }

   16     }

   17 }

 

So as you can see I'm trying to manipulate a cookie named "a". This is what appeared in Fiddler after loading the two pages one after the other.

Now that is two cookies with the same name. My initial reaction was it shouldn't have been possible but I trusted fiddler enough so I roamed around the web and finally got my answers especially from here

Despite belonging to the same domain, the uniqueness of the cookie is also affected by the cookie's Path property. That is two cookies with the same name and from the same domain (or subdomain) can exists if they belong to different paths (application path).

So to make the long story short if you want make the cookie updateable from both ASP and ASP.NET the path has to be identical (and reasonable ofcourse not just some random path)

Either:

1. Add this to the ASP code : Response.Cookies("a").Path = "/"

2. Or Add this to the ASP.NET code : Response.Cookies["a"].Path = "/<yourApplicationName>"; 

You can use Page.ResolveUrl("~") to determine application name but make sure to remove the trailing "/" in the resulting string (.NET 2.0 seems to add a trailing "/" but not .NET 1.1 if I remember well) 

or ofcourse the equivalents if you're not using VBScript/C#.

That's it and you're good.


Other Info:

1. Attached sample download project here : ASPCookieASPNETCookie.zip (5.33 kb) ** Note that this is a Web Application project that uses IIS as web server (right click on Project –> Properties –> Web tab and set accordingly and see attached screenshot too for more info UseIISWebServer.gif (20.06 kb). Also note that creating a virtual directory from the page would not automatically set Integrated Windows Authentication on for the created virtual directory (it inherits from the website properties) and running F5 from Visual Studio would throw a dialog saying such should be enabled. To enable, open IIS Manager –> site/virtual directory properties –> Directory Security tab –> Edit –> Check Integrated Windows Authentication.

2. Note that using IE7 and localhost will not register any traffic in Fiddler. Work around is to use machine name or add a "." after localhost (eg. http://localhost./AppName/TestPage.aspx)* note the dot "." after localhost. You can do this by manually editing the URL/address bar of the browser or setting it in the Web Properties page mentioned in item 1 above. 

Button doesn’t postback after clicking Back Button in Firefox

I ran into this behavior (which I think is weird) where a button no longer posts back to ther server after I click on a the Firefox's back button. [more]

I'm not sure if I'm missing some incorrect settings whatsoever but it works on IE7.  I'm hoping someone who runs into this might verify or some thoughts on why is behaves that way. Using Firefox 2.0.0.14, ASP.NET 2.0

Here is my code

ASPX (sorry no formatting but it's just a simple page with an ASP button)

<%@ Page AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" UseSubmitBehavior="false" /></div>
    </form>
</body>
</html>

Code behind

    1 using System;

    2 using System.Web.UI;

    3 

    4 public partial class _Default : Page

    5 {

    6     protected void Page_Load(object sender, EventArgs e)

    7     {

    8         //if (Request.Browser.MSDomVersion.Major == 0) // Non IE Browser?

    9         //    Response.Cache.SetNoStore(); // No client side cashing

   10     }

   11 

   12     protected void Button1_Click(object sender, EventArgs e)

   13     {

   14         Response.Write(Guid.NewGuid());

   15     }

   16 }

1. Load the page

2. Click on the button. Click event handler in server side runs and a GUID is displayed after page reloads

3. Click Back button. As far as my machine/browser behaves, no postback happens.

On the other hand, if using IE (7), step 3 still causes a postback.

It does seem that it has something to do with client side caching since if you uncomment the code in Page_Load, step 3 causes a postback. The only difference with IE though is that if say you have a textbox in the same page, you place some text in the textbox and you click the back button since no client side caching is made, you loose the contents of the textbox.

Installed FireBug to get some hint but for some reason it caused some intermittent behavior. Sometimes it works (posts back) sometimes it doesn't. Not sure though if it's FireBug causing the intermittent behavior but the "no postback behavior" predates the FireBug installation.

Haven't got the chance to dig deeper into this yet. Gotta get back to work 🙂 I hope I'm just not missing something obvious here…

Resources:

Prevent client caching in browsers other that Internet Explorer 

__doPostBack and the Back Button by Rick Strahl – some possibly relevant information but not quite since in his case, the button click and checkbox check changed event both fire in the server side, in my case the page doesn't postback at all.

Page ViewState, Control ViewState and ControlState

Just a quick note. I was working on some Web User Control and needed to persist information across postbacks and thought of using ViewState. But while I was working on it, I realized that I was using the same key for saving another information in the parent Page's (the Page containing the user control) ViewState.

I did a little verification and it turns out that despite having the same key being used for saving different values to ViewState, having it assigned inside the Web User Conrol and inside the Page results to two different ViewState items.[more] I verified by assigning ViewState to the Page's and the User Control's Page_Load event handler, then since the user control's page load fires later than the two, placed a breakpoint after it, checked the ViewState (while inside the User Control code) and it returned the value assigned inside it, while calling Page.ViewState and the same key, it retrieved the value that was previously assigned from the Page_Load of the parent Page. 

This is the behavior as far as my little test has shown but feel free to verify in your machine and let us know how it goes especially if the behavior is different from above. 

This is not to be confused with Control State which is discussed more clearly from the links below:

Control state in ASP.NET 2.0 by Fritz Onion (PluralSight)

Control State vs. View State Example on MSDN

ControlState Property Demystified 

 

Hand editing web.config or not

I've come across a number of issues in the past where the cause of the issue is that someone hand edited the web.config and resulted to a not well formed XML (missing tags, unclosed quotes et al).

The recommended way of doing it is [more]to minimize these issues is to use the ASP.NET Configuration Settings Dialog which is available to IIS (not sure if there is a stand alone executable for this). Here are simple steps to do it.

1. Open IIS

2. Right Click on target site/virtual directory and select Properties

 

3. The Properties dialog should show up. Select ASP.NET tab.

 

4. At the ASP.NET tab, you should see and click Edit Configuration. (if you're opening Properties of a website, you should also see an "Edit Global Configuration" button which corresponds to the machine wide web.config). Doing so should display the Configuration Settings Dialog

 

5. Make your modifications without fear of unclosed quotes whatsoever. You could likely still mess up some settings but I can assure you that it would be easier to do when you're manually hand editing the file.

 

Also note that when adding a web.config in Visual Studio (using Add New Item) you will get a comment somewhere at the top stating: 

<!–

    Note: As an alternative to hand editing this file you can use the

    web admin tool to configure settings for your application. Use

    the Website->Asp.Net Configuration option in Visual Studio.

    A full list of settings and comments can be found in

    machine.config.comments usually located in

    WindowsMicrosoft.NetFrameworkv2.xConfig

–>


The "Website->Asp.Net Configuration option in Visual Studio" mentioned are items in the toolbar and appears if you have the website project (or its files) open/selected (see image below)

And you should see something similar to image below

 

You can also check the "How do I use this tool" link at the top right of the page.

This is also a recommended way of doing it for web site projects (not available in Web Application Projects).

Editing web.config is likely inevitable for development but as much as possible I would recommend not hand-edit them unless you (or others in the team) really have to (especially for those with not much experience with XML/HTML – it is trivial but could minimize some headaches)

UPDATE: I've also cross posted this on weblogs.asp.net and getting some useful comments so you might also want to check it out using the following link : post on weblogs.asp.net 

PlaceHolder/Panel Visibility, ViewState on Security and Performance

It is not unusual to see a solution where use of asp:Placeholder and asp:Panel Visibility is employed to show/hide certain details from the user.

When implementing a simple Authorization/Permission features[more], it would also be tempting to use such approach. (mentioned simple since there are likely more complicated but better ways to do it) Of course you could always implement declarative authorization features in ASP.NET but I believe it would cause the user to be redirected to the page identified as the login url. (hmmm, does other authorization types support authorization rules? not sure myself, i wonder).

So if you simply perform checks in code.

eg. Does User.Indentity.Name have permission to view this page? Yes/No? If yes, display contents of panel/placeholder, if no set their visibility to false.

Simple and might do the trick.

BUT never forget that although they are invisible, some values might be present in the viewstate (eg. values bound to gridview inside the panel/placeholder). Although viewstate might look cryptic, remember that it is just base 64 encoded string. And although you could have employ encrypted ViewState, it would still be not a good idea and you will have unnecessary overhead.

So just a quick note to self (and possibly others) that settings PlaceHolder/Panel visibility to false doesn't stop it from saving information in viewstate. Obvious to some but not to all so if you're guilty, better fix that code before someone gets to see something they shouldn't.

I'm also interested how best to implement this in code (not using ASP.NET built-in declarative authorization rules – ie. in web.config). HttpModule maybe? But note that I would want the resulting page to have the same look and feel (still use master page) rather than simply a text in the page (and nothing more) or worst an exception throw because user doesn't have view permission for example, nor redirected to a generic page. I'll try to explore this but someone who might have a good idea out there comes across this and shares his/her notes.

UPDATE: Aside from the security consideration, note that disabling viewstate when not need could significant improve performance (dependent on how items you have in your page makes use of viewstate – eg. disabling view state when hiding a gridview is significant) so will be adding "Performance" to the title as well

Also, be cautious about disabling view state. It is used by control to
persist information across postbacks so if you do disable them make
sure you test your page well.

Smile

 

Built-in ASP.NET Development Server cannot be accessed using non-localhost URL

Alvin, a coworker of mine raised an interesting point about the ASP.NET Development Server (previously named "Cassini") hours ago.

Forgive my ignorance but it seems that the said builtin server was constrained to be accessed only with localhost or 127.0.0.1 and [more]would not work when using your IP (non loopback) nor machine name.

For IE you get : Internet Explorer cannot display the webpage

For Firefox : Unable to connect. Firefox can't establish a connection to the server at 192.168.1.xxx:PPPP (port number). The page title appears as Problem loading page 

Not much there but if you use Fiddler you would see that it is returning an HTTP Error 500 which refers to "Bad Gateway".

Somehow that tells me, it's not your code but something with the server or the machine.

Looking around this is what I found. 

Troubleshooting the ASP.NET Development Server  


Furthermore, from Web Servers in Visual Web Developer link you will find:

If you cannot or do not want to use IIS as your Web server, you can
still test your ASP.NET pages by using the ASP.NET Development Server.
The ASP.NET Development Server, which is included with Visual Web
Developer, is a Web server that runs locally on Windows operating
systems, including Windows XP Home Edition. It is specifically built to
serve, or run, ASP.NET Web pages under the local host scenario
(browsing from the same computer as the Web server). In other words,
the ASP.NET Development Server will serve pages to browser requests on
the local computer. It will not serve pages to another computer.

Additionally, it will not serve files that are outside of the
application scope. The ASP.NET Development Server provides an efficient
way to test pages locally before you publish the pages to a production
server running IIS.

Although it may seem that accessing the site from the same machine but using your IP would seem like accessing it locally, it doesn't seem to be the case. Could be that technically it would go out of your local machine first then, find which machine the IP points to so effectively it's being accessed externally already (sorry can't explain better than that). What's interesting though is that accessing the machine results in the same behavior for some reason. Maybe someone can clear it up for us. Or maybe Cassini is accessible this way and I'm just missing something.

Anyways, might seem pretty obvious but for those of us who haven't known this before then that's something to add to our knowledge base (or if I'm missing something, at least something to spark your curiousity)

One last thing, for those who wish to specify a specific port to use with ASP.NET Development Server here's a link : How to: Specify a Port for the ASP.NET Development Server 

Smile