views:

223

answers:

4

Haven't done ASP.NET development since VS 2003, so I'd like to save some time and learn from other's mistakes.

Writing a web services app, but not a WSDL/SOAP/etc. -- more like REST + XML.

Which of the many "New Item" options (Web Form, Generic Handler, ASP.NET Handler, etc.) makes the most sense if I want to handle different HTTP verbs, through the same URI, separately. In a perfect world, I'd like the dispatching done declaratively in the code rather than via web.config -- but if I'm making life too hard that way, I'm open to change.

+1  A: 

If you're not using the built in web services (.asmx), then you should probably use a generic handler (.ashx).

Joel Coehoorn
A: 

Probably MVC if you need rest.

Vasil
A: 

I agree with the ashx, gives you the most control. you could also go more complex and create a custom Http Handler. that way you can intercept any extension you decide. Of course you could add an Http Module and rewrite any request to a generic ashx handler.

mattlant
+1  A: 

This is an idea I've been playing with... use at your own risk, the code is in my "Sandbox" folder ;)

I think I want to move away from using reflection to determine which method to run, it might be faster to register a delegate in a dictionary using the HttpVerb as a key. Anyway, this code is provided with no warranty, blah, blah, blah...

Verbs to use with REST Service

public enum HttpVerb
{
    GET, POST, PUT, DELETE
}

Attribute to mark methods on your service

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=false)]
public class RestMethodAttribute: Attribute
{
    private HttpVerb _verb;

    public RestMethodAttribute(HttpVerb verb)
    {
        _verb = verb;
    }

    public HttpVerb Verb
    {
        get { return _verb; }
    }
}

Base class for a Rest Service

public class RestService: IHttpHandler
{
    private readonly bool _isReusable = true;
    protected HttpContext _context;
    private IDictionary<HttpVerb, MethodInfo> _methods;

    public void ProcessRequest(HttpContext context)
    {
        _context = context;

        HttpVerb verb = (HttpVerb)Enum.Parse(typeof (HttpVerb), context.Request.HttpMethod);

        MethodInfo method = Methods[verb];

        method.Invoke(this, null);
    }

    private IDictionary<HttpVerb, MethodInfo> Methods
    {
        get
        {
            if(_methods == null)
            {
                 _methods = new Dictionary<HttpVerb, MethodInfo>();
                BuildMethodsMap();
            }
            return _methods;
        }
    }

    private void BuildMethodsMap()
    {
        Type serviceType = this.GetType();
        MethodInfo[] methods = serviceType.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public);

        foreach (MethodInfo info in methods)
        {
            RestMethodAttribute[] attribs =
                info.GetCustomAttributes(typeof(RestMethodAttribute), false) as RestMethodAttribute[];
            if(attribs == null || attribs.Length == 0)
                continue;

            HttpVerb verb = attribs[0].Verb;

            Methods.Add(verb, info);
        }

    }

    public bool IsReusable
    {
        get { return _isReusable; }
    }
}

Sample REST Service

public class MyRestService: RestService
{
    [RestMethod(HttpVerb.GET)]
    public void HelloWorld()
    {
        _context.Current.Response.Write("Hello World");
     _context.Current.Response.End();
    }
}
NerdFury