2013年1月10日 星期四

BaseHttpHandler

/// <summary>
/// An abstract base Http Handler for all your
/// <see cref="IHttpHandler"/> needs.
/// </summary>
/// <remarks>
/// <p>
/// For the most part, classes that inherit from this
/// class do not need to override <see cref="ProcessRequest"/>.
/// Instead implement the abstract methods and
/// properties and put the main business logic
/// in the <see cref="HandleRequest"/>.
/// </p>
/// <p>
/// HandleRequest should respond with a StatusCode of
/// 200 if everything goes well, otherwise use one of
/// the various "Respond" methods to generate an appropriate
/// response code. Or use the HttpStatusCode enumeration
/// if none of these apply.
/// </p>
/// </remarks>
public abstract class BaseHttpHandler : IHttpHandler
{
/// <summary>
/// Creates a new <see cref="BaseHttpHandler"/> instance.
/// </summary>
public BaseHttpHandler() {}

/// <summary>
/// Processs the incoming HTTP request.
/// </summary>
/// <param name="context">Context.</param>
public void ProcessRequest(HttpContext context)
{
SetResponseCachePolicy(context.Response.Cache);

if(!ValidateParameters(context))
{
RespondInternalError(context);
return;
}

if(RequiresAuthentication
&& !context.User.Identity.IsAuthenticated)
{
RespondForbidden(context);
return;
}

context.Response.ContentType = ContentMimeType;

HandleRequest(context);
}

/// <summary>
/// Indicates whether or not this handler can be
/// reused between successive requests.
/// </summary>
/// <remarks>
/// Return true if this handler does not maintain
/// any state (generally a good practice). Otherwise
/// returns false.
/// </remarks>
public bool IsReusable
{
get
{
return true;
}
}

/// <summary>
/// Handles the request. This is where you put your
/// business logic.
/// </summary>
/// <remarks>
/// <p>This method should result in a call to one
/// (or more) of the following methods:</p>
/// <p><code>context.Response.BinaryWrite();</code></p>
/// <p><code>context.Response.Write();</code></p>
/// <p><code>context.Response.WriteFile();</code></p>
/// <p>
/// <code>
/// someStream.Save(context.Response.OutputStream);
/// </code>
/// </p>
/// <p>etc...</p>
/// <p>
/// If you want a download box to show up with a
/// pre-populated filename, add this call here
/// (supplying a real filename).
/// </p>
/// <p>
/// </p>
/// <code>Response.AddHeader("Content-Disposition"
/// , "attachment; filename=\"" + Filename + "\"");</code>
/// </p>
/// </remarks>
/// <param name="context">Context.</param>
public abstract void HandleRequest(HttpContext context);

/// <summary>
/// Validates the parameters. Inheriting classes must
/// implement this and return true if the parameters are
/// valid, otherwise false.
/// </summary>
/// <param name="context">Context.</param>
/// <returns><c>true</c> if the parameters are valid,
/// otherwise <c>false</c></returns>
public abstract bool ValidateParameters(HttpContext context);

/// <summary>
/// Gets a value indicating whether this handler
/// requires users to be authenticated.
/// </summary>
/// <value>
/// <c>true</c> if authentication is required
/// otherwise, <c>false</c>.
/// </value>
public abstract bool RequiresAuthentication {get;}

/// <summary>
/// Gets the content MIME type.
/// </summary>
/// <value></value>
public abstract string ContentMimeType {get;}

/// <summary>
/// Sets the cache policy. Unless a handler overrides
/// this method, handlers will not allow a respons to be
/// cached.
/// </summary>
/// <param name="cache">Cache.</param>
public virtual void SetResponseCachePolicy
(HttpCachePolicy cache)
{
cache.SetCacheability(HttpCacheability.NoCache);
cache.SetNoStore();
cache.SetExpires(DateTime.MinValue);
}

/// <summary>
/// Helper method used to Respond to the request
/// that the file was not found.
/// </summary>
/// <param name="context">Context.</param>
protected void RespondFileNotFound(HttpContext context)
{
context.Response.StatusCode
= (int)HttpStatusCode.NotFound;
context.Response.End();
}

/// <summary>
/// Helper method used to Respond to the request
/// that an error occurred in processing the request.
/// </summary>
/// <param name="context">Context.</param>
protected void RespondInternalError(HttpContext context)
{
// It's really too bad that StatusCode property
// is not of type HttpStatusCode.
context.Response.StatusCode =
(int)HttpStatusCode.InternalServerError;
context.Response.End();
}

/// <summary>
/// Helper method used to Respond to the request
/// that the request in attempting to access a resource
/// that the user does not have access to.
/// </summary>
/// <param name="context">Context.</param>
protected void RespondForbidden(HttpContext context)
{
context.Response.StatusCode
= (int)HttpStatusCode.Forbidden;
context.Response.End();
}
}