Skip to content

Handler Method Selection

scottlittlewood edited this page Dec 24, 2010 · 11 revisions

The methods on a handler get selected through multiple stage in the pipeline. It’s important to note that every method will get processed until only one is left.

Filters

The first step of the selection process uses a list of filters to narrow down the number of methods being matched.

By default, two filters are automatically registered.
HttpMethodHandlerMethodSelector::

  • All methods starting with the HTTP method name. For example, for a GET HTTP method, both a Get() and a GetCustomer() method will be selected.
  • All methods containing the HttpOperationAttribute with a matching HTTP method name.

UriNameHandlerMethodSelector::

  • If the request URI is not associated with a name (through the AtUri().Named() method), all the methods will be selected.
  • If there is a URI name,
    • If there are methods with an HttpOperationAttribute with a ForUriName property matching the URI name, those methods will be selected
    • Otherwise, all the methods will be selected

URI parameter matching

In the following step, the pipeline will take the URI parameters defined in the URI templates, and will try to assign the properties to the parameters of the method. An error is thrown if the parameterized portion of the URI ({page}) cannot be converted to the method parameter type.

In the following example, the value of the {page} URI template parameter will be assigned to the page parameter of the Get method.

The import bit to remember is that the parameterized sections of the URI should match a parameter name in a public method that starts with Get.

ResourceSpace.Has.ResourcesOfType<Page>().AtUri("/pages/{page}")
...
public OperationResult Get(int page)

Another example might be:
ResourceSpace.Has.ResourcesOfType<List<Page>>().AtUri("/pages?pagesNamedLike={pagesNamedLike}")
...
public OperationResult GetByPagesNamedLike(string pagesNamedLike)

Here, the method name GetByPagesNamedLike is not important, but the parameter pagesNamedLike is.

Class matching for POST operations

If an HTTP POST method contains form data in the body of the request, it can be matched to a Post method which defines an object parameter whose public property names match the form element names.

The following example first defines a simple HTML form, a CustomerPost class which matches some of those form elements, and a handler with a Post method using the CustomerPost class.

<form method="post" action="/customer">
    First Name: <input type="text" name="firstname" ><br>
    Last Name: <input type="text" name="lastname" ><br>
    <input type="submit">
</form>
...
ResourceSpace.Has.ResourcesOfType<CustomerPost>().AtUri("/customer").HandledBy<CustomerHandler>();
...
public class CustomerPost
{
    public string firstname { get; set; }
    public string lastname { get; set; }
    public int balance { get; set; } // will not affect selection
}
...
public class CustomerHandler
{
    public object Post(CustomerPost formdata)
    {
        return new CustomerResource(formdata.firstname, formdata.lastname);
    }
}

Sending a Delete request via Ajax

The following JQuery method sends an HTTP DELETE request to the server. OpenRasta will match it to a ‘Delete’ method with a single ID parameter.

function onDelete(theId) {
  $.ajax({
     url: 'Customer',
     type: 'DELETE',
     data: ({ id: theId }),
     success: function () { alert('DELETE completed'); }
  });
}
...
ResourceSpace.Has.ResourcesOfType<Customer>().AtUri("/customer").HandledBy<CustomerHandler>();
...
public class CustomerPost
{
    public string firstname { get; set; }
    public string lastname { get; set; }
    public int balance { get; set; } // will not affect selection
    public int ID;
}
...
public class CustomerHandler
{
    public void Delete( int customerID)
    {
    }
}

Uploading a file

The following form will be able to post to the given handler and read a file.

<form action="/documentlist"
      enctype="multipart/form-data" method="post">
      <p>
       Type some text (if you like):<br />
       <input type="text" name="textline" size="30" />
      </p>
      <p>
       Please specify a file, or a set of files:<br />
       <input type="file" name="document" size="40" />
      </p>
      <div>
       <input type="submit" value="Send" />
      </div>
</form>
...
        public OperationResult Post( IEnumerable<IMultipartHttpEntity> entities)
        {
            foreach (var entity in entities)
            {
                if (entity.Stream != null && entity.ContentType != null)
                {
                    var memoryStream = new MemoryStream();
                    entity.Stream.CopyTo(memoryStream);

                    memoryStream.Seek(0, SeekOrigin.Begin);
                }
            }
            return new OperationResult.Created();
        }

Note that you must read the streams the first time entities is iterated.

Clone this wiki locally