Showing posts with label NWSGI. Show all posts
Showing posts with label NWSGI. Show all posts

Wednesday, August 11, 2010

NWSGI 3.0 Plans

It looks like it's just about time for another major release of NWSGI - the last two Decembers have had major releases, and I see no need to break the trend this year. There are going to be a few major changes this time around, so if anyone has any objections, let me know as soon as possible.

Most importantly, it will only support IronPython 2.7 and thus will require .NET 4.0. Like the IronPython team, I'm not going out of my way to break compatibility with .NET 2.0 (or IronPython 2.6, for that matter), but I won't be distributing anything but IronPython 2.7/.NET 4.0 binaries.

Similarly, I will not be supporting IIS 6 (Windows Server 2003) anymore. Again, I won't go out of my way to break it, but I won't be testing against it either. This means I can get rid of the wildcard handling for good, since IIS 7 has a good URL rewriter available.

The biggest change is that I am decoupling the WSGI processing from the ASP.NET pipeline. All of the functionality is currently part of an IHttpHandler implementation, which restricts it to be used with IIS (and Cassini) only. NWSGI 3.0, on the other hand, will allow NWSGI to be used with HttpListener or other servers such as Kayak by moving all WSGI processing into a separate class with no ASP.NET dependencies. The redesign will also allow me to improve the test coverage from zero to, well, something.

Finally, the licence will change to the Apache Licence 2.0 to match IronPython. The basic terms are identical to the Ms-PL licence that was used previously; the Apache licence is just more explicit and also more widely used.

As with the previous versions, I expect to release the final version shortly after IronPython 2.7 is released.

Tuesday, January 26, 2010

IronPython Web Roles for Windows Azure

Following up to my previous post on IronPython worker roles, I'm going to discuss how to implement web roles using IronPython. The code discussed here is on bitbucket, as usual.

There are currently two ways to implement IronPython web roles on Azure: using the ASP.NET Dynamic Language Support or using NWSGI. Someday I hope the IronRubyMVC project matures to be an option as well.

Using ASP.NET Dynamic Language Support

This example can be found in the PyWebRole folder of the project.

First, you'll need to download the ASP.NET Dynamic Language Support (ASP.NET DLS) files. Next, create a standard C# web role and delete all of the .cs files except WebRole.cs. After that, there's really not much to it – drop the assemblies from the ASP.NET DLS package into the project's bin folder and add the following bits to the web.config file (alternatively, just copy the Web.config from the project):

<configSections>
    <!-- Add this to the existing <configSections> element -->
    <section name="microsoft.scripting" type="Microsoft.Scripting.Hosting.Configuration.Section, Microsoft.Scripting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false"/>
</configSections>

<system.web>
    <!-- Replace the existing <pages> element (if any) -->
    <pages compilationMode="Auto" pageParserFilterType="Microsoft.Web.Scripting.UI.NoCompileCodePageParserFilter" pageBaseType="Microsoft.Web.Scripting.UI.ScriptPage" userControlBaseType="Microsoft.Web.Scripting.UI.ScriptUserControl">
        <controls>
            <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
            <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        </controls>
    </pages>
</system.web>

<system.webserver>
    <modules>
        <!-- Add this to the existing <modules> element -->
        <add name="DynamicLanguageHttpModule" preCondition="integratedMode" type="Microsoft.Web.Scripting.DynamicLanguageHttpModule"/>
    </modules>
</system.webserver>

<!-- Add this whole section -->
<microsoft.scripting debugMode="true">
    <languages>
        <language names="IronPython;Python;py" extensions=".py" displayName="IronPython 2.6" type="IronPython.Runtime.PythonContext, IronPython, Version=2.6.10920.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </languages>
</microsoft.scripting>

From here, just follow the directions on the ASP.NET DLS page and in the package to create an ASP.NET Dynamic Language site.

NWSGI

First, download NWSGI 2.0. Next, deploying NWSGI to Azure is exactly the same as deploying it to any other server using xcopy. That's about it. You can see this example in the PyHelloWorld folder of the project.

Now What?

Unfortunately, now you're pretty much on your own. So far, none of the big Python web frameworks work 100% on IronPython, there is no Python library to access Azure's storage tables, blobs, or queues, and the .NET storage client library relies on LINQ support (which IronPython doesn't have, yet).

Personally, I plan to implement the data access in C# and call that from IronPython, running my own web framework. We'll see how it goes.

Wednesday, December 30, 2009

NWSGI 2.0 Release

I'm very pleased to announce the release of the final version of NWSGI 2.0. It's been a long road since it was first shown as "NWSGI 1.1 Preview1" way back in March. Since then most of the code has been overhauled to make maintenance easier and improve performance. IronPython has also come  a long way; the 2.6 release is a fantastic piece of work with much better performance and compatibility than 2.0. Both IronPython and NWSGI are reaching the point where it will soon be feasible to run most Python web apps with little to no modification – I'm hoping by this time next year that everything will "just work".

What's New

NWSGI 2.0 is mostly a lot of little changes that add up to a much better experience:

  • Easier configuration: In v1.0 there were different ways to configure NWSGI depending on your configuration. Now there is only one way to do it. The ambiguous options with multiple meanings are gone, and new options added to support the extra optional features of IronPython 2.6.
  • Better management UI: The new management UI is both easier to use and easier to maintain.
  • Performance improvements: NWSGI will now cache the WSGI callable and associated modules instead of reloading it each time. IronPython 2.6 is also much faster then 2.0.

More Information

My blog posts from earlier in the year are still relevant:

I'll be moving the information in these over to Codeplex soon, so that it's easier to find.

Please let me know what you think of the new release, and what it's being used for – I'm always curious to hear what people think.

Sunday, November 22, 2009

NWSGI 2.0 Release Candidate 2

The final release candidate of NWSGI 2.0 is now available. Except for version numbers, this is what will become NWSGI 2.0 as soon as IronPython 2.6 is released.

NWSGI 2.0 Release Candidate 2 includes all of the features of NWSGI 2.0 Release Candidate 1, and adds support configuring tracing, lightweight scopes, and the profiler. It is built against IronPython 2.6 RC3.

The following issues are fixed in this release:

Monday, September 28, 2009

NWSGI 2.0 Release Candidate 1 Released

To coincide with IronPython 2.6 RC1, NWSGI 2.0 RC1 is now available.

This release is identical to Beta 2, except for the version of IronPython is uses.

Friday, September 25, 2009

Using NWSGI 2.0 Beta 2 with IronPython 2.6 RC1

UPDATE: This won't work. The IronPython team made some changes that break the ABI (Microsoft.Dynamic, I'm looking at you) which renders this fix unworkable.

NWSGI is linked against specific versions of IronPython, so every time the IronPython team changes the AssemblyVersion, I need to respin NWSGI. In the meantime, an <assemblyBinding/> section can be used in web.config to make previous NWSGI version work with newer IronPython versions.

Thanks to Markus Törnqvist for coming up the specific elements for this case:

    <runtime>
       <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
           <dependentAssembly>
               <assemblyIdentity name="IronPython" publicKeyToken="31bf3856ad364e35" culture="neutral" />
               <bindingRedirect oldVersion="2.6.0.20" newVersion="2.6.10920.0" />
           </dependentAssembly>
           <dependentAssembly>
               <assemblyIdentity name="Microsoft.Scripting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
               <bindingRedirect oldVersion="0.9.6.20" newVersion="1.0.0.0" />
           </dependentAssembly>
       </assemblyBinding>
   </runtime>

I’ll try to get an update of NWSGI out as soon as possible.

Saturday, August 15, 2009

NWSGI 2.0 Beta 2 Released

NWSGI 2.0 Beta 2 is now available. This release in linked against IronPython 2.6 Beta 2, and also fixes a couple of bugs. The big change is that the install does not add NWSGI to the GAC; without IronPython also installed to the GAC, it doesn't make much sense to put NWSGI there.

Thursday, July 2, 2009

NWSGI 2.0: Removing URL Warts

The normal procedure for configuring NWSGI leaves an unsightly URL wart: the URL must contain the .wsgi file. There are two ways to get rid of that wart: URL rewriting and wildcards.

URL Rewriting

When using URL rewriting, the web server changes ("rewrites") the incoming URL into something NWSGI can understand. IIS 7 has a URL rewriting extension to do just that. It's quite easy to use, too:

<rewrite> 
    <rules> 
        <clear /> 
        <rule name="Redirect Warty Requests" stopProcessing="true"> 
            <match url="simple.wsgi/(.*)" /> 
            <conditions logicalGrouping="MatchAll" /> 
            <action type="Redirect" url="{R:1}" redirectType="Permanent" /> 
        </rule> 
        <rule name="Remove WSGI Wart"> 
            <match url="^(.*)$" /> 
            <conditions logicalGrouping="MatchAll" /> 
            <action type="Rewrite" url="simple.wsgi/{R:1}" appendQueryString="true" /> 
        </rule> 
    </rules> 
</rewrite>

Replace simple.wsgi with the name of the .wsgi file you would normally use. Now, http://example.com/simple/simple.wsgi/Products/Widgets can be accessed as http://example.com/simple/Products/Widgets. The first rule ("Redirect Warty Requests") will redirect any uses of http://example.com/simple/simple.wsgi/Products/Widgets to http://example.com/simple/Products/Widgets to ensure that only one set of URLs is used (which is important for search engines). However, most modern applications expect to have their URLs rewritten and can be configured to generate the "clean" URLs by default.

If you are using IIS 6, you'll need to use something like ISAPI_Rewrite to achieve the same effect. The following should have the same effect as the above rules:

RewriteEngine On
RewriteRule ^hello.wsgi/(.*) $1 [NC, R=301]
RewriteRule ^(.*)$ hello.wsgi/$1 [NC]

Wildcards

Normally, IIS dispatches requests by extension; this is why we have the .wsgi file in the first place. However, it can be configured to pass all requests to a specific handler by configuring a wildcard extension. Unlike URL rewriting, which is transparent to NWSGI, NWSGI needs to know that it has been configured as a wildcard handler. To do this, add a <wildcard> element to the configuration:

<wsgi>
    <wildcard physicalPath="C:\simple\simple.wsgi" callable="simple_app" />
</wsgi>

<system.web>
    <httpHandlers>
        <add verb="*" path="*" type="NWSGI.WsgiHandler, NWSGI, Version=2.0.0.0, Culture=neutral, PublicKeyToken=41e64ddc1bf1fc86" />
    </httpHandlers>
</system.web>
<system.webServer>
    <handlers>
        <add name="WsgiHandler" path="*" verb="*" type="NWSGI.WsgiHandler, NWSGI, Version=2.0.0.0, Culture=neutral, PublicKeyToken=41e64ddc1bf1fc86" resourceType="Unspecified" />
    </handlers>
    <validation validateIntegratedModeConfiguration="false" />
</system.webServer>

The physicalPath and callable attributes have the same meaning as on the <scriptMapping> element. If the configuration includes a <wildcard> element, any <scriptMapping> elements are ignored. Also, make sure that the path attribute of the handler mappings in set to *.

Ultimately, the effect is the same as URL rewriting: http://example.com/simple/simple.wsgi/Products/Widgets can be accessed as http://example.com/simple/Products/Widgets.

Which to Choose

If possible, you should prefer URL rewriting, as it should be faster than using wildcard mappings; however, it requires support from the application. If you're on IIS 6 or IIS 7 without a URL Rewrite extension installed, or your application doesn't support rewritten URLs, then wildcard mappings are available.

Tuesday, June 30, 2009

NWSGI 2.0: Advanced Dispatching

Function Callables

Let’s say we’re dealing with a much larger Python application, coolapp, that is installed at C:\coolapp-1.1\. Unfortunately, coolapp doesn’t provide a ready-made .wsgi file for us, but it does provide a function(coolapp.dispatchers.wsgi_application) that we can use by writing a little wrapper that looks something like:

import sys
sys.path.append("C:\coolapp-1.1")
import coolapp.dispatchers.wsgi_application
application = coolapp.dispatchers.wsgi_application

We could save this as coolapp.wsgi and follow either of two methods from last time, but since we’re not doing anything fancy in the wrapper, NWSGI provides a shortcut:

<wsgi>
    <pythonPaths>
        <path path="C:\coolapp-1.1" />
    </pythonPaths>
    <scriptMappings>
        <scriptMapping scriptName="coolapp.wsgi" callable="coolapp.dispatchers.wsgi_application" />
    </scriptMappings>
</wsgi>

First, we add C:\coolapp-1.1 to Python’s path so that we can import it. Next, we tell it that any requests for coolapp.wsgi should be dispatched to the function coolapp.dispatchers.wsgi_application. This is completely equivalent to the wrapper file, but saves us from creating it. Visiting http://example.com/coolapp.wsgi/ will run coolapp.

Class Callables

Functions aren’t the only things in Python that are callable; classes are also callable (it creates an instance of the class). Let’s say we upgrade coolapp to version 2.0 (installed in C:\coolapp-2.0). The team has made some changes, and their WSGI application is now a class, WsgiApplication. This class has a __call__ method (making its instances callable as well!), so our WSGI application is an instance of the WsgiApplication class. We could use a coolapp.wsgi wrapper again:

import sys
sys.path.append("C:\coolapp-2.1")
import coolapp.dispatchers.WsgiApplication
application = coolapp.dispatchers.WsgiApplication()

Again, our little wrapper doesn’t do much, so NWSGI provides a shortcut:

<wsgi>
    <pythonPaths>
        <path path="C:\coolapp-2.0" />
    </pythonPaths>
    <scriptMappings>
        <scriptMapping scriptName="coolapp.wsgi" callable="coolapp.dispatchers.WsgiApplication()" />
    </scriptMappings>
</wsgi>

This time, NWSGI will create an instance of WsgiApplication, and then call the instance and return the result to IIS. This shortcut will only work if the class doesn’t require any arguments; if it does, it needs to be wrapped in a .wsgi file (when in doubt, you can always use a wrapper file). Again, visit http://example.com/coolapp.wsgi/ to run the application.

There’s actually one more case: Python classes that implement the iterator protocol, but I don’t think two many applications are implemented that, so I’ll skip it. PEP 333 gives an example if you’re really interested.

Monday, June 29, 2009

NWSGI 2.0: Dispatching

NWSGI has a fairly simple task: given a URL, call some Python code that produces some output. The devil, as always, is in the details.

What is WSGI?

NWSGI is an implementation of the Python WSGI specification (PEP 333). WSGI is the Web Server Gateway Interface, “a simple and universal interface between web servers and web applications or frameworks”, as defined in PEP 333.

OK, so what does that mean?

The purpose of WSGI is to define how web servers (i.e. Apache, IIS, etc.) talk to Python web application or frameworks (i.e. Trac, Django, etc.). In theory, a web server with a WSGI implementation (such as mod_wsgi for Apache, or NWSGI for IIS) should be able to run any web application that is implemented as a WSGI application (prior to WSGI, many applications/frameworks were server-specific). Of course, that doesn’t always pan out in practice, but it’s a start.

What is a WSGI application?

A WSGI application is surprisingly simple:

def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type','text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

The simple_app function is the entire application! A WSGI application is a callable (a function, mostly) that takes two arguments and returns an iterable (a list or generator, mostly). There’s some extra goo in there as well (start_response, for example) that’s not really relevant as far as dispatching is concerned. Writing WSGI applications is probably a book’s worth of content, so I’ll leave it at that for now.

Finding Callables in .wsgi Files

Local Files

Now that we have a callable for our application, NWSGI needs to know how to find it. The simplest way is to simply drop the file (let’s call it simple.wsgi) into the application root (i.e. C:\inetpub\wwwroot\, next to web.config). If you make a request to http://example.com/simple.wsgi/, IIS will see that .wsgi is associated with NWSGI and pass the request to it. NWSGI will then open simple.wsgi, try to find a variable called application (which is, by convention, the name of WSGI callables), call it, and return the result to IIS.

In this case, however, our callable is named simple_app, not application. To be able to run our app, NWSGI needs to know this! To do this, there needs to be a script mapping telling NWSGI how to run simple.wsgi.

<wsgi>
    <scriptMappings>
        <scriptMapping scriptName="simple.wsgi" callable="simple_app" />
    </scriptMappings>
</wsgi>

This configuration tells NWSGI that for the script simple.wsgi, it should use simple_app as the callable instead of application. (NOTE: This exact syntax requires 2.0b2 or later).

Other Files

Best practices for WSGI applications say that you should not put your application files in the web-exposed directory. This means that simple.wsgi should really live somewhere else; let’s say C:\simple\simple.wsgi. Of course, now NWSGI doesn’t have the slightest clue where it is, so we have to tell it:

<wsgi>
    <scriptMappings>
        <scriptMapping scriptName="simple.wsgi" physicalPath="C:\simple\simple.wsgi" callable="simple_app" />
    </scriptMappings>
</wsgi>

There is no longer a .wsgi in our application folder, but IIS doesn’t care. If you visit http://example.com/simple.wsgi/ with this configuration, IIS still happily passes the simple.wsgi script onto NWSGI. NWSGI looks at the script mappings and finds that simple.wsgi maps to C:\simple\simple.wsgi, so it loads that file instead (without looking for simple.wsgi in the application directory), looks up simple_app, and calls it.

Using .wsgi files is the simplest way to deploy an application, but NWSGI has a couple of shortcuts to make things easier for certain applications.

Friday, June 26, 2009

NWSGI 2.0: Configuration Details

For the most part, NWSGI can be used without any configuration. All you have to do is create a .wsgi file, throw it in a directory, let IIS know what’s going on, and you’re good to go! Of course, if it was always that easy, configuration wouldn’t exist. To really work with NWSGI, you need to understand its configuration. It helps if you’re already familiar with web.config files; if not, check this out (but hurry back!).

First Things First

NWSGI uses .NET’s built-in configuration system (System.Configuration), so the first thing that needs to be done is to let the .NET Framework know about the custom NWSGI configuration section:

<configSections>
    <section name="wsgi" type="NWSGI.WsgiSection" />
</configSections>

This must be the first entry in web.config, directly under the <configuration> element.

The <wsgi> element

All of the configuration options for NWSGI are under the <wsgi> element. The first ones we will look at are specified as attributes of the <wsgi> element: enableExtensions, adaptiveCompilation and frames.

enableExtensions
Enable extensions to NWSGI. Relying on these will make your application nonportable to other WSGI implementations. Required to use ASP.NET's built-in Session support, for example. Choices: true, false.
compilation
Control how IronPython compiles code. Choices: Adaptive, Compiled.
frames
Control sys._getframe. Enabling sys._getframe causes a performance hit. Choices: Off, On, Full.

Example:

<wsgi adaptiveCompilation="false" frames="Full" />

Adding Python Search Paths

If your application needs to access Python modules that are not in the default NWSGI search paths (~/, ~/Bin/ and ~/Bin/Lib/), you can use the <pythonPaths> element to add them. The <pythonPaths> element contains a set of <path> elements that are added (in order) to sys.path before the application is run. The <path> element has one required attribute – path – that contains the full path to a folder on disk containing the modules you want to use.

Example:

<wsgi>
    <pythonPaths>
        <path path="C:\django" />
    </pythonPaths>
</wsgi>

Adding WSGI Environment Variables

Most applications will require some configuration of their own; these options are passed in the environ parameter of the WSGI application. You can add entries to this list by using the <wsgiEnviron> element, which contains a set of <variable> elements. Each <variable> element has two required attributes, name and value.

Example:

<wsgi>
    <wsgiEnviron>
        <variable name="trac.env_path" value="C:\trac\projects" />
    </wsgiEnviron>
</wsgi>

Advanced Script Usage

There are cases where you may need to configure how NWSGI handles a particular script file. In these cases you need a virtual script mapping; NWSGI will always check script mappings before looking for a file on disk. Not surprisingly, these are stored in the <scriptMappings> element, which contains a set of <scriptMapping> elements. There are three parts to a script mapping:

scriptNamerequired
The name of the virtual script; overrides any scripts on disk.
physicalPath
The path to the actual file to execute. This can be a full path (i.e. C:\myapp\myapp.wsgi) or an app-relative path (i.e. ~/scripts/myapp.wsgi).
callable
If physicalPath is set, the name of the callable object in that file; if it is not set, an entry point for the application.

Entry points are used to specify a particular function in a Python module on sys.path (see the <pythonPaths> element above for how to control sys.path). For example, for Django the entry point would be "django.core.handlers.wsgi.WSGIHandler()". This mimics the standard Python syntax for creating an object; it is this object that is used as the application. If, instead, the application provides a function (like trac), the entry point would be "trac.web.main.dispatch_request".

Example:

<scriptMappings>
    <scriptMapping scriptName="myapp.wsgi" physicalPath="C:\myapp\myapp.wsgi" callable="myapp" />
</scriptMappings>

Wildcard Settings

When IIS is configured in wildcard mode, all requests for an application are passed to NWSGI, instead of only requests for .wsgi files. You can enable this by setting path="*" in the handler/httpHandler definition. Because NWSGI normally expects there to be a .wsgi file in the URL, but in wildcard mode there isn't one, the <wildcard> element is required to tell NWSGI what script to execute. The available settings – physicalPath and callable – have the same meaning as the same settings for script mappings (above). If the <wildcard> element is present, the <scriptMappings> element is ignored.

Example:

<wildcard physicalPath="C:\HelloWorld\hello.wsgi" callable="hello" />

Conclusion

NWSGI is extremely configurable; in many cases, you don't even need a .wsgi file. That said, the configuration can be complex, so please ask if you run into any problems. A later post will go into more detail on the mechanics of callables.

Wednesday, June 24, 2009

NWSGI 2.0: Configuration Changes

One of the two areas to see the most changes in NWSGI 2.0 was its configuration. Some of the options in v1.0 were overloaded in strange ways; even I wasn’t entirely sure what some combinations would produce. There was also the small problem of where to put the configuration section; it varied depending on how NWSGI was installed. For v2.0, both problems needed to be fixed. Doing so required a re-think of how configuration was handled.

Configuring Wildcards

In v1.0, configuring NWSGI to operate in wildcard mode required setting options that were designed for other things in particular ways that made no sense. In v2.0, there is a special <wildcard> element under <wsgi> (replacing the wildcardModule option) that is specifically used for configuring these settings. If the <wildcard> element exists, then NWSGI will ignore the <scriptMappings> element.

The callable option has also been removed from the <wsgi> element as it is no longer necessary (it defaults to “application”). To specify a custom callable name for a script, create a <scriptMapping>.

Where to put it?

The first problem was to put the <wsgi> section in the same place all the time. In v1.0 it could be directly under <configuration> (if you were using xcopy deployment) or under <system.webServer> (if you installed it on IIS7). The two could not necessarily coexist in the same web.config file, either! IIS 7 uses a different configuration assembly (Microsoft.Web.Administration) than ASP.NET (System.Configuration), and they’re no compatible, to boot.

The fix is relatively simple: rather than trying to use the appropriate configuration system from the handler, v2.0 always uses System.Configuration. This means that the <wsgi> section is always directly under <configuration>. The only downside is that the section always has to be declared at the top of web.config:

<configSections>
    <section name="wsgi" type="NWSGI.WsgiSection, NWSGI, Version=1.99.1.0, Culture=neutral, PublicKeyToken=41e64ddc1bf1fc86" />
</configSections>

New Options

There are also two new options: compilation and frames. The compilation option controls how IronPython generates code. The frames option is used to control sys._getframe; as tracking frames incurs a performance hit, it must be explicitly enabled.

Wrapping Up

The changes to configuration (which will break any existing configurations) are the main reason for bumping the version to 2.0. The clean up of the options resulted in much cleaner implementations for the management and especially for the handler itself. As always, if you have any comments, let me know.

Monday, June 22, 2009

NWSGI 2.0: Installation & Usage

There are two ways to use NWSGI: by installing it or by using xcopy deployment. Each method has its advantages and disadvantages, but their functionality is the same.

Installation

The quickest way to get NWSGI up and running is to use the MSI installer. This will add NWSGI to the GAC, making it available for all applications. If you are running IIS 7, it will also install the IIS 7 management components. The installer will also put a copy of the NWSGI assembly along with the README and HelloWorld example in C:\Program Files\NWSGI. This is the preferred approach, unless you do not have administrator rights to the server and cannot convince the server administrator to install it.

xcopy Deployment

The term “xcopy deployment” refers to the Windows xcopy command, which is used to (among other things) copy entire directory trees. Using this method is useful if you can’t (or don’t want to) use the installer package. If this is the case, download the .zip package instead of the MSI installer. To use this method, simply copy NWSGI.dll into your application’s Bin/ directory, and then copy the whole application folder to the server.

Setting Up the Hello World Example

Once you have decided which method you are going to use, the easiest way to check that it is working is to use the HelloWorld example that is included with both packages. I’m only going to describe the most common configuration, and I’m also going to assume you have access to the server; if you have a custom setup (such as a hosted site), just ask.

  1. Copy the HelloWorld sample folder to C:\inetpub\wwwroot.
  2. Mark C:\inetpub\wwwroot\HelloWorld as an application.
    • IIS 6/7: From the IIS management UI, mark the folder as an application.
    • IIS 7: From an elevated command prompt, run: appcmd add app /site.name:"Default Web Site" /path:/HelloWorld /physicalPath:C:\inetput\wwwroot\HelloWorld
  3. Visit http://localhost/HelloWorld/hello.wsgi.

If the browser says “Hello, World!”, you’re good to go! If not, please ask in the forum, and I’ll try to help you out.

Thursday, June 18, 2009

NWSGI 2.0 Beta 1

NWSGI 2.0 Beta 1 is now available. This is a major update to NWSGI that makes it easier to install and use and dramatically improves the management story.

So, what happened to 1.1?

Originally, NWSGI 1.1 was going to be a refresh of v1.0 that supported IronPython 2.6 and fixed a few bugs. NWSGI 2.0 was going to completely overhaul large parts of the management UI and make some deeper changes to the handler itself. However, I got a week off with some rain and v2.0 progressed much quicker than expected; v1.1 was obsolete before it was even released.

So, v1.1 was dropped and v2.0 will be the first IronPython 2.6-compatible release. It’s easy to make breaking changes when you have no customers :).

What’s New

  • Easier configuration. In v1.0 there were different ways to configure NWSGI depending on your configuration. Now there is only one way to do it. Some of the more ambiguous options have also been cleaned up, and new ones added to support IronPython 2.6.
  • Better management UI. IIS 7 includes a rich UI framework for developing management extensions, but doesn’t have much documentation on it. Some spelunking with reflector showed me better ways to do pretty much everything; not much of the v1.0 management code is left.
  • Performance improvements. NWSGI will now cache the WSGI callable instead of reloading it each time.
  • Other misc. fixes. I really need to get into the habit of adding a Codeplex issue for each bug so that I can keep track of what I’ve fixed.

Give it a spin

The Codeplex wiki needs to be updated to reflect the new documentation, but the included readme is up to date. I’ll also be posting a series of blogs posts over the next few weeks that will explain all the features of NWSGI and provide some helpful examples. Remember, this is a Beta release, so please let me know if you encounter any issues.

Sunday, March 29, 2009

NWSGI 1.1 Preview 1

A preview of NWSGI 1.1 is now available on Codeplex. This preview is linked against IronPython 2.6a1 so that I can start testing against 2.6 with enough lead time to actually get any bugs fixed before release :). There are also some enhancements to the configuration that can simplify some common scenarios; see the release notes or changes.txt for more information. I'll write up more detailed instructions on how to take advantage of those changes in the future.

Saturday, December 27, 2008

NWSGI 1.0

I'm very pleased to announce the release of NWSGI 1.0. NWSGI is an implementation of the WSGI specification (PEP 333) for IronPython. It is implemented as an ASP.NET HttpHandler and is supported on IIS 6 and IIS 7 (and should work on any other ASP.NET-capable web server). NWSGI allows the integration of Python applications with existing ASP.NET facilities such as caching, sessions, and user management.

This release does not mean that any Python application will work. The underlying IronPython 2.0 engine is not yet complete. It is a nearly-complete implementation of the NWSGI specification, and any app that takes IronPython's limitations into account should work just fine.

NWSGI fully supports xcopy deployment and medium trust environments (with the caveat that parts of the Python standard library are not supported). There is also an installer available that provides a managment UI for IIS 7.

NWSGI requires IIS (6 or 7), IronPython 2.0, and .NET Framework 2.0 SP1. All downloads include the NWSGI assembly, basic documentation, and a HelloWorld sample. The installers also include the IIS management UI.

Documentation is currently a weak spot, but I hope to improve that in the near future. In the meantime there is a README included, as well as some basic documentation at the NWSGI website.

Thursday, December 4, 2008

NWSGI 0.7 Released

NWSGI 0.7 is now available on Codeplex. This release mainly deals with cleaning up some rough edges and incompatibilities with PEP 333, although there are some new features. If you used the installer for NWSGO 0.6, you must manually uninstall it before installing NWSGI 0.7.

Session Support

ASP.NET HttpHandlers must inherit from IRequiresSessionState1 in order to have access to the Session state. This has been added to NwsgiHandler. Now, HttpContext.Session can be used to access the Session state. However, because the Session module adds a cookie, the entire response must be buffered, which is against the WSGI spec. See the section on Extensions for more details.

1 Why did they have to add the first "s"? IRequireSessionState is too clever to pass up.

Proper Unicode Handling

IronPython does not distinguish between str and unicode (and neither does Jython). WSGI requires apps to return str objects, but allows Unicode if there is no other option and only the bottom 8 bits are used. Previously, NWSGI used the incorrect encoding (and not even consistently; I had both ASCII and UTF-8 in different places). PEP 333 specifies ISO 8859-1 (aka Latin1) for all Unicode conversions, as is maps precisely to the first 256 Unicode characters and thus preserves raw bytes (ASCII and UTF-8 mappings are required to move things around).

As a result, raw files can now be passed through NWSGI without the use of wsgi.file_wrapper, such is when generating images on the fly.

Wildcard Mappings

All HttpHandlers must have a target extension so that they can be used; NWSGI uses *.wsgi. This results in URLs such as http://www.example.com/hello/hello.wsgi/Jeff. There are two ways to handle this: URL rewriting, which is the preferred way, and wildcard mapping, which is more of a last resort as it can hurt performance for static files.2

By setting the handler path to "*", all file requests will be sent through NWSGI. To tell NWSGI that this is what you want, set the wildcardModule attribute like so:

<wsgi wildcardModule="~/hello.wsgi">

The equivalent URL would be http://www.example.com/hello/Jeff. NWSGI will handle all requests to that app by remapping SCRIPT_NAME to the application (/hello) and PATH_INFO to the remainder (/Jeff).

The wildcardModule attribute can be either absolute (C:\…) or app-relative (~/…). Using wildcardModule will bypass any script mappings, as they are unnecessary.

2 One option is to move static files to a separate virtual directory or even separate server that does not use NWSGI.

WSGI Extensions

NWSGI implements a couple of non-conforming extensions to WSGI. In the interest of compatibility, these are off by default. To enable them, use the enableExtensions attribute:

<wsgi enableExtensions="true">

The current extensions are:

  • nwsgi.context – provide access to the HttpContext via environ["nwsgi.context"]. This is somewhat moot as it can always be reached from HttpContext.Current.
  • Responses are not flushed – PEP 333 requires the response to be flushed after every iteration of the WSGI callable. This breaks the use of ASP.NET Sessions, and possibly other IIS modules.

IronPython Version

NESGI 0.7 is linked against IronPython 2.0RC2, but RC1 should work as well – the assembly versions are the same. This hasn't been tested, however.

Thursday, November 20, 2008

NWSGI on Window Azure

I have had a couple of people ask about NWSGI on Windows Azure. Architecturally (as far as NWSGI is concerned), Azure is just IIS7 running in medium trust. You have to use xcopy deployment, which makes me glad I went to the effort of supporting it.

NWSGI 0.6 actually supports medium trust. I only discovered after the release that the error I was hitting was a bug in Cassini; it works fine in medium trust on IIS7. With that hurdle out of the way, there's no reason NWSGI shouldn't work on Azure.

And, what do you know, it works just fine: NWSGI "Hello, World" for Windows Azure. You'll need the Azure SDK and the Visual Studio tools to run it.

The big downside is that every NWSGI app would have to include its entire framework and the Python standard library (or whatever subset that it uses).

Sunday, November 2, 2008

NWSGI 0.6 Released

NWSGI 0.6 has been released on Codeplex. This release has some possibly breaking changes and a whole host of new features. There is also an installer available along with the zip archive. The HelloWorld example has been rolled into the zip file.

There is one minor feature addition: wsgi.file_wrapper is now supported for faster file transfers. It uses HttpResponse.TransmitFile to send the file directly.

The major new feature is IIS7 management integration, including a UI editor. This is a huge addition and one I'm quite proud of. It makes configuring NWSGI a breeze from the command line (appcmd) or from the UI. The IIS7 integration is only available through the installer.

The changes are in the configuration system to support the IIS7 management system. Unfortunately, IIS7 doesn't use System.Configuration; instead, it has its own assembly, Microsoft.Web.Administration. This caused some complications for configuration. There are now three possible usage scenarios (IIS6, IIS7 xcopy, and IIS7 installed) that require slightly different web.config settings; I will detail these in an upcoming post.

Monday, September 22, 2008

NWSGI 0.5 Released

The latest version of NWSGI, built for IronPython 2.0 Beta 5, has been posted. There are a couple of changes in this version: one breaking change and one new feature.

Configuraton Changes

To fit with convention, the configuration elements now start with lowercase letters - i.e. Wsgi => wsgi, OSEnviron => osEnviron, etc. This has a consequence because XML is case-sensitive, so the old configuration elements will not be picked up and the defaults will be used instead.

Script Mappings

Script mappings can be used to create a virtual .wsgi file that points to a file elsewhere on the filesystem. For example:

<scriptmappings>
    <scriptmapping scriptname="dispatch.wsgi" physicalpath="C:\myapp\dispatch.wsgi">
</scriptmappings>

Rather than copy the dispatch.wsgi file into the web aplication directory, any request to dispatch.wsgi will be mapped to c:\myapp\dispatch.wsgi instead. This example is a bit trivial, as an IIS virtual directory could probably be used, but it could be useful for any application that ships a .wsgi file.

Future Directions

I'm working on building an IIS7 admin interface for all of this; it's a bit of a mess right now because the advanced UI tricks aren't really documented that well. I'm hoping to have the IIS7 admin and the installer ready by the time IronPython goes 2.0.