using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Text; using System.Threading; using System.Web; namespace Svg.Web { /// /// A handler to asynchronously render Scalable Vector Graphics files (usually *.svg or *.xml file extensions). /// /// /// If a crawler requests the SVG file the raw XML will be returned rather than the image to allow crawlers to better read the image. /// Adding "?raw=true" to the querystring will alos force the handler to render the raw SVG. /// public class SvgHandler : IHttpAsyncHandler { Thread t; /// /// Gets a value indicating whether another request can use the instance. /// /// /// true if the instance is reusable; otherwise, false. public bool IsReusable { get { return false; } } /// /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the interface. /// /// An object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests. public void ProcessRequest(HttpContext context) { // Not used } /// /// Initiates an asynchronous call to the HTTP handler. /// /// An object that provides references to intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests. /// The to call when the asynchronous method call is complete. If is null, the delegate is not called. /// Any extra data needed to process the request. /// /// An that contains information about the status of the process. /// public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { string path = context.Request.PhysicalPath; if (!File.Exists(path)) { throw new HttpException(404, "The requested file cannot be found."); } SvgAsyncRenderState reqState = new SvgAsyncRenderState(context, cb, extraData); SvgAsyncRender asyncRender = new SvgAsyncRender(reqState); ThreadStart ts = new ThreadStart(asyncRender.RenderSvg); t = new Thread(ts); t.Start(); return reqState; } /// /// Provides an asynchronous process End method when the process ends. /// /// An that contains information about the status of the process. public void EndProcessRequest(IAsyncResult result) { } /// /// The class to be used when /// protected sealed class SvgAsyncRender { private SvgAsyncRenderState _state; public SvgAsyncRender(SvgAsyncRenderState state) { this._state = state; } private void RenderRawSvg() { this._state._context.Response.ContentType = "image/svg+xml"; this._state._context.Response.WriteFile(this._state._context.Request.PhysicalPath); this._state._context.Response.End(); this._state.CompleteRequest(); } public void RenderSvg() { this._state._context.Response.AddFileDependency(this._state._context.Request.PhysicalPath); this._state._context.Response.Cache.SetLastModifiedFromFileDependencies(); this._state._context.Response.Cache.SetETagFromFileDependencies(); this._state._context.Response.Buffer = false; // Allow crawlers to see the raw XML - they can get more information from it that way if (this._state._context.Request.Browser.Crawler || !string.IsNullOrEmpty(this._state._context.Request.QueryString["raw"])) { this.RenderRawSvg(); } else { try { Dictionary entities = new Dictionary(); NameValueCollection queryString = this._state._context.Request.QueryString; for (int i = 0; i < queryString.Count; i++) { entities.Add(queryString.Keys[i], queryString[i]); } SvgDocument document = SvgDocument.Open(this._state._context.Request.PhysicalPath, entities); using (Bitmap bitmap = document.Draw()) { using (MemoryStream ms = new MemoryStream()) { bitmap.Save(ms, ImageFormat.Png); this._state._context.Response.ContentType = "image/png"; ms.WriteTo(this._state._context.Response.OutputStream); } } } catch (Exception exc) { System.Diagnostics.Trace.TraceError("An error occured while attempting to render the SVG image '" + this._state._context.Request.PhysicalPath + "': " + exc.Message); } finally { this._state._context.Response.End(); this._state.CompleteRequest(); } } } } /// /// Represents the state of a request for SVG rendering. /// protected sealed class SvgAsyncRenderState : IAsyncResult { internal HttpContext _context; internal AsyncCallback _callback; internal object _extraData; private bool _isCompleted = false; private ManualResetEvent _callCompleteEvent = null; /// /// Initializes a new instance of the class. /// /// The of the request. /// The delegate to be called when the rendering is complete. /// The extra data. public SvgAsyncRenderState(HttpContext context, AsyncCallback callback, object extraData) { _context = context; _callback = callback; _extraData = extraData; } /// /// Indicates that the rendering is complete and the waiting thread may proceed. /// internal void CompleteRequest() { _isCompleted = true; lock (this) { if (this.AsyncWaitHandle != null) { this._callCompleteEvent.Set(); } } // if a callback was registered, invoke it now if (_callback != null) { _callback(this); } } /// /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. /// /// /// A user-defined object that qualifies or contains information about an asynchronous operation. public object AsyncState { get { return (_extraData); } } /// /// Gets an indication of whether the asynchronous operation completed synchronously. /// /// /// true if the asynchronous operation completed synchronously; otherwise, false. public bool CompletedSynchronously { get { return (false); } } /// /// Gets an indication whether the asynchronous operation has completed. /// /// /// true if the operation is complete; otherwise, false. public bool IsCompleted { get { return (_isCompleted); } } /// /// Gets a that is used to wait for an asynchronous operation to complete. /// /// /// A that is used to wait for an asynchronous operation to complete. public WaitHandle AsyncWaitHandle { get { lock (this) { if (_callCompleteEvent == null) { _callCompleteEvent = new ManualResetEvent(false); } return _callCompleteEvent; } } } } } }