UserPreferences

RestAspNetExample


Rest ASP.NET Example

This page describes how to get an ASP.NET application to work with the PUT and DELETE verbs under IIS on Windows XP Professional. Other versions of IIS / Windows may vary in configuration, but the process should be almost identically.

IIS configuration

File system configuration

The requesting webform

VerbTest1.aspx

<%@ Page language="C#" Codebehind="VerbTest1.aspx.cs" AutoEventWireup="false" Inherits="VerbTest1" %>

VerbTest1.aspx.cs

using System;
using System.Net;
using System.IO;

public class VerbTest1 : System.Web.UI.Page {
  private void Page_Load(object sender, System.EventArgs e) {
    Response.ContentType = "text/plain";

    const string data = "<feed><title>Hello!</title></feed>";

    HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create("http://localhost/test/verbtest2.aspx");
    req.ContentType = "multipart/form-data; charset=ISO-8859-1";
    req.Method = "PUT";

    StreamWriter sw = new StreamWriter(req.GetRequestStream());
    sw.Write(data);
    sw.Close();

    HttpWebResponse resp = (HttpWebResponse) req.GetResponse();

    using (resp) {
      StreamReader sr = new StreamReader(resp.GetResponseStream());
      Response.Write(sr.ReadToEnd());
      sr.Close();
      resp.Close();
    }
  }

  override protected void OnInit(EventArgs e) {
    InitializeComponent();
    base.OnInit(e);
  }

  private void InitializeComponent() {    
    this.Load += new System.EventHandler(this.Page_Load);
  }
}

The receiving webform

Using System.Web.IHttpHandler

Note: IHttpHandler may be a better choice than System.Web.Page for the receiver. Using System.Web.Page may incur unnecessary overhead. See for example, this article on using [WWW]Custom Http Handlers To Improve Performance in ASP.NET.

VerbTest2.ashx
<%@ webhandler language="C#" class="Sample.VerbHandler" %>

using System; 
using System.Web; 

namespace Sample
{
  public class VerbHandler : IHttpHandler
  {
    public bool IsReusable { get { return true; } }

    public void ProcessRequest(HttpContext ctx)
    {
      switch (ctx.Request.HttpMethod)
        {
        case "DELETE":
          ProcessDelete(ctx);
          break;
        case "GET":
          ProcessGet(ctx);
          break;
        case "PUT":
          ProcessPut(ctx);
          break;
        case "POST":
          ProcessPost(ctx);
          break;
        }
    }
  }

  public virtual void ProcessGet(HttpContext ctx) { ... }
  public virtual void ProcessPut(HttpContext ctx) { ... }
  public virtual void ProcessPost(HttpContext ctx) { ... }
  public virtual void ProcessDelete(HttpContext ctx) { ... }
}

Using System.Web.Page

VerbTest2.aspx
<%@ Page language="c#" Codebehind="VerbTest2.aspx.cs" AutoEventWireup="false" Inherits="VerbTest2" %>
VerbTest2.aspx.cs
using System;
using System.Net;
using System.IO;

public class VerbTest2 : System.Web.UI.Page {
  private void Page_Load(object sender, System.EventArgs e) {
    Stream stream = Request.InputStream;
    StreamReader sr = new StreamReader(stream);
    Response.Write(sr.ReadToEnd());
  }

  override protected void OnInit(EventArgs e) {
    InitializeComponent();
    base.OnInit(e);
  }

  private void InitializeComponent() {    
    this.Load += new System.EventHandler(this.Page_Load);
  }
}

Discussion

[MartinAtkins] Has anyone managed to get a PUT to a 'real URL' to work in IIS? By this, I mean not PUTting directly to the URL of the script which will handle it, but rather PUTting (or DELETEing) to a URL which reflects what is to be PUT or DELETEd. A comparable term in Apache would be "extra path information". (Feel free to refactor/remove this. I put it here for want of a better place.)

[AsbjornUlsberg] This can be easilly accomplished by configuring the IIS web application to give all HTTP requests to the ASP.NET framework, and then, in Global.asax.cs, plug in a little rewrite-code. See [WWW]URL Rewriting with ASP.NET for more information.

[MartinAtkins] Well, I guess I meant to post this to the example for plain old ASP, not ASP.NET. Since you're dealing with both, and the results of this discussion will hopefully be refactored elsewhere at some point, I'll just ask here to avoid making a lot of noise: I can see how a similar technique could be used to map everything to the plain old ASP ISAPI extension, but does it have the URL rewriting thing?

[AsbjornUlsberg] If I'm not totally lost, rewriting plain old ASP can also be done in ASP.NET. If I'm lost or ASP.NET isn't available, it must be done with the dreadful ISAPI filters, yes.

[MartinAtkins] I'll also note that this requires special server configuration, which I'm assuming most users whose sites live on other people's Windows servers will not be able to change.

[AsbjornUlsberg] Special server configuration will be required in almost all cases, but it's probably more likely that Apache users will have access to it than IIS users, yes.

[KenMacLeod] The URL rewriting/"real" URL/PATH_INFO question and answer appear to be talking about different things. This goes to the note in CarrorVsOrange: if the ASP script is "at a URL" that accepts GET/POST, can not that same script "at that URL" also accept additional path information after the script? By comparison, in the CGI spec (both IIS and Apache), that "extra path information" comes in the PATH_INFO environment variable.

POST /path/to/my.asp
PUT /path/to/my.asp/with/extra/path/info

[AsbjornUlsberg] The latter example isn't possible in traditional ASP, but it is in ASP.NET. To get the /with/extra/path/info portion of the request, you can use Request.PathInfo.

[KenMacLeod] In that context (ASP-only, refactoring requested), can you confirm or further describe what the URL-space will look like for the publishing system? I'm guessing if it's not using PathInfo, it'll be using URL query arguments or similar:

PUT /path/to/my.asp?entry=4328
DELETE /path/to/my.asp?comment=321

[AsbjornUlsberg] URL queries work, of course. You can also pass an ad hoc PathInfo to the ASP script if you add a question mark before it, like this:

POST /path/to/my.asp
PUT /path/to/my.asp?/with/extra/path/info

If the script isn't separated from the query/PathInfo with a question mark, IIS won't understand what script is to be accessed and can't find the path, so it throws a 404. When separated like above, the PathInfo can be received with Request.QueryString in the ASP script.


[KenMacLeod] I'm not familiar with either IIS or ASP[.NET], so I'm drawing a parallel from Apache and CGI:


Original Author: AsbjornUlsberg


CategoryApi, CategoryRest