Convert a image handler from ASPX to asynchronus ASHX - asp.net

Im struggling with bad performance on one of my websites. It is handling a lot of images, and I serve images through an image handler. When I created it I did a mistake and created a ASPX file to handle the images, I should have used an generic handler (ASHX).
I found this good site, which looks promising. It is about creating an asynchronus image handler. But I have very little knowledge about this, and need some help.
Help site:
http://msdn.microsoft.com/en-us/magazine/cc163463.aspx
This is how my ShowImage.aspx file looks now:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Configuration;
using System.Drawing;
using System.Drawing.Imaging;
using System.Web.Caching;
using System.Collections;
public partial class ShowImage : System.Web.UI.Page
{
Gallery gal = new Gallery();
private void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// Start with empty Response object.
Response.Clear();
// Get the image path from the URL.
string imagePath = Request.QueryString["image"];
// Set the size of the image
int maxHeight = 1000;
if (Request.QueryString["maxHeight"] != null)
{
string mh = Request.QueryString["maxHeight"];
maxHeight = int.Parse(mh);
}
int maxWidth = 1000;
if (Request.QueryString["maxWidth"] != null)
{
string mw = Request.QueryString["maxWidth"];
maxWidth = int.Parse(mw);
}
string thumbPath = gal.ThumbnailPath(Server.MapPath(imagePath), maxHeight, maxWidth);
byte[] buffer = null;
System.Drawing.Image img = System.Drawing.Image.FromFile(thumbPath);
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, img.RawFormat);
buffer = ms.ToArray();
}
Response.ContentType = "image/" + Path.GetExtension(thumbPath).Remove(0, 1);
Response.OutputStream.Write(buffer, 0, buffer.Length);
img.Dispose();
Response.End();
}
}
}
I have started with the handler ShowImage.ashx, but im a bit stuck. Any help is appreciated. Im not sure where I should merge my code with this.
using System;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.IO;
public class ShowImage : IHttpAsyncHandler
{
//private ShowImageService _ts;
private ShowImageServiceAsyncResult _ar;
private HttpContext _context;
private Exception _ex;
public void ProcessRequest (HttpContext context)
{
// Never used
}
public bool IsReusable { get { return false; } }
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object state)
{
_context = context;
_ar = new ShowImageServiceAsyncResult(cb, state);
// SHOULD I PLACE CODE HERE?
return _ar;
}
public void EndProcessRequest(IAsyncResult ar)
{
if (_ex != null)
{
// If an exception was thrown, rethrow it
throw _ex;
}
else
{
// Otherwise return the generated image
}
}
}
class ShowImageServiceAsyncResult : IAsyncResult
{
private AsyncCallback _cb;
private object _state;
private ManualResetEvent _event;
private bool _completed = false;
private object _lock = new object();
public ShowImageServiceAsyncResult(AsyncCallback cb, object state)
{
_cb = cb;
_state = state;
}
public Object AsyncState { get { return _state; } }
public bool CompletedSynchronously { get { return false; } }
public bool IsCompleted { get { return _completed; } }
public WaitHandle AsyncWaitHandle
{
get
{
lock (_lock)
{
if (_event == null)
_event = new ManualResetEvent(IsCompleted);
return _event;
}
}
}
public void CompleteCall()
{
lock (_lock)
{
_completed = true;
if (_event != null) _event.Set();
}
if (_cb != null) _cb(this);
}
}

You're not making any asynchronous calls to retrieve your Image, so you don't need an asynchronous handler.
Derive from IHttpHandler and just put your code in ProcessRequest.

Related

Why is ExecuteResult not called?

I'm trying to implement a JSONP response in my ASP.NET MVC 5 web application. I've followed this tutorial:
http://www.ingeniumweb.com/blog/post/using-jsonp-calls-in-asp.net-mvc/1216/
The problem is that the ExecuteResult method is never called:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
namespace subscribe.ActionResults
{
public class JsonpResult : JsonResult
{
object Data = null;
public JsonpResult()
{
}
public JsonpResult(object Data)
{
this.Data = Data;
}
public override void ExecuteResult(ControllerContext ControllerContext)
{
if (ControllerContext != null)
{
HttpResponseBase Response = ControllerContext.HttpContext.Response;
HttpRequestBase Request = ControllerContext.HttpContext.Request;
string callbackfunction = Request["callback"];
if (string.IsNullOrEmpty(callbackfunction))
{
throw new Exception("Callback function name must be provided in the request!");
}
Response.ContentType = "application/x-javascript";
if (Data != null)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Response.Write(string.Format("{0}({1});", callbackfunction, serializer.Serialize(Data)));
}
}
}
}
}
In my controller I have:
public JsonpResult Get(string emailaddress, string callback, string jsonp)
{
var slist = from u in db.subscriptions
select u;
if (!String.IsNullOrEmpty(emailaddress))
slist = slist.Where(s => (s.emailaddress == emailaddress));
if (slist.Count() > 0)
{
JsonpResult result = new JsonpResult(slist.ToList());
return result; //json list of matches
}
else
{
JsonpResult result = new JsonpResult(new List<Subscription>());
return result; //empty json list
}
}

Is it possible to use and httphandler to download image, serve to browser and repeat process?

I was wondering if it is possible to use an httphandler to download an image, serve that image to the browser and then do it again.
I currently have access to a url that produces a snapshot image from an ip camera that I would like to continue to pull from. Essentially making a slide show of the snapshots indefinitely.
I have already figured out how to download the image and display it. The next step would to, for a lack of better terms, recursively repeat the process.
I certainly can do this with Ajax calls from the client but would much rather remove handle it at the server.
Thanks,
Chad
using Newtonsoft.Json.Linq;
using System;
using System.Net;
using System.Web;
using System.Threading;
namespace Something.App_Code
{
class CameraSnapshotHandler : IHttpAsyncHandler
{
public bool IsReusable { get { return false; } }
public CameraSnapshotHandler() { }
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
{
SnapshotAsynchOperation asynch = new SnapshotAsynchOperation(cb, context, extraData);
asynch.StartAsyncWork();
return asynch;
}
public void EndProcessRequest(IAsyncResult result) { }
public void ProcessRequest(HttpContext context)
{
throw new InvalidOperationException();
}
}
class SnapshotAsynchOperation : IAsyncResult
{
private bool _completed;
private Object _state;
private AsyncCallback _callback;
private HttpContext _context;
bool IAsyncResult.IsCompleted { get { return _completed; } }
WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
Object IAsyncResult.AsyncState { get { return _state; } }
bool IAsyncResult.CompletedSynchronously { get { return false; } }
public SnapshotAsynchOperation(AsyncCallback callback, HttpContext context, Object state)
{
_callback = callback;
_context = context;
_state = state;
_completed = false;
}
public void StartAsyncWork()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);
}
private void StartAsyncTask(Object workItemState)
{
using (var client = new WebClient())
{
// Get Json data
string username;
string password;
using (var credClient = new WebClient())
{
dynamic stuff = JObject.Parse(credClient.DownloadString(new Uri("http://www.some-url.com/servicestack/equipment-credentials.json?equipmentId=" + _context.Request.QueryString["id"])));
username = stuff.Username;
password = stuff.Password;
}
// Wait until we have full buffer before displaying
_context.Response.BufferOutput = true;
// Set content type to match
_context.Response.ContentType = "image/png";
// Digest Authenticate
client.Credentials = new NetworkCredential(username, password);
// Download into bit array
byte[] content = client.DownloadData("http://some-url/cgi/image.php?type=snapshot");
// Output stream to client
_context.Response.OutputStream.Write(content, 0, content.Length);
}
_completed = true;
_callback(this);
}
}
}

Supporting nested elements in ASP.Net Custom Server Controls

I want to create a custom server control which looks like this:
<cc:MyControl prop1="a" prop2="b">
<cc:MyItem name="xxx">
<cc:MyItem name="yyy">
<cc:MyItem name="zzz">
</cc:MyControl>
MyControl is of course implemented as a server control, however I do not want MyItem to be child controls. Rather they should exist as simple .Net objects. I have a class called MyItem, and the control has a property called Items, and when MyItem elements are declared in the markup, the objects should be instantiated and added to the collection.
The tutorials on MSDN don't actually explain how this happens. See: http://msdn.microsoft.com/en-us/library/9txe1d4x.aspx
I'd like to know:
How is <cc:MyItem> mapped to the MyItem class? Does the element in the markup have to have the same name as the object's class?
Which constructor of MyItem is called when MyItems are added declaratively, and when?
What collection types am I permitted to use to hold MyItem objects? The link above uses ArrayList, but can I use the strongly typed List instead?
Is it possible for a control to contain multiple collections?
It is so common to use class name for markup, but you can assign another name if you want, I do not explain more, if you want please comment
when asp.net compiles markup, it uses default parameter less constructor
you can use any collection type but if you want to use benefits of viewstate your collection type must implement IStateManager interface (below I wrote source of collection that I created for my self with state managing support)
Yes, your control can have multiple collections, just add required attributes as below:
(I used one of my codes, please replace names with your desired name)
if you want to have collection first of all you must define its property in your control.
imagine we have a control named CustomControl that extends Control as below:
[System.Web.UI.ParseChildrenAttribute(true)]
[System.Web.UI.PersistChildrenAttribute(false)]
public class CustomControl : Control{
private GraphCollection m_graphs;
[Bindable(false)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
[PersistenceMode(PersistenceMode.InnerProperty)]
public GraphCollection Graphs
{
get
{
if (this.m_graphs == null) {
this.m_graphs = new GraphCollection();
if (base.IsTrackingViewState) {
this.m_graphs.TrackViewState();
}
}
return this.m_graphs;
}
}
}
as you can see in above code, CustomControl has a field with name "m_graphs" with type of "GraphCollection", also a property that exposes this field
also please please pay attention to its attribute PersistenceMode that says to asp.net property "Graphs" must persisted as InnerProperty
also please pay attention to two attributes applied to CustomControl class
attribute ParseChildrenAttribute says to asp.net that nested markup, must be treated as properties and attribute PersistChildrenAttribute says to asp.net that nested markups are not control's children
at the final, I bring two source codes for state managing components
first of all GraphCollection that extends from StateManagedCollection (both classes was written by me)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
namespace Farayan.Web.Core
{
public class StateManagedCollection<T> : IList, ICollection, IEnumerable, IEnumerable<T>, IStateManager
where T : class, IStateManager, new()
{
// Fields
private List<T> listItems = new List<T>();
private bool marked = false;
private bool saveAll = false;
// Methods
public void Add(T item)
{
this.listItems.Add(item);
if (this.marked) {
//item.Dirty = true;
}
}
public void AddRange(T[] items)
{
if (items == null) {
throw new ArgumentNullException("items");
}
foreach (T item in items) {
this.Add(item);
}
}
public void Clear()
{
this.listItems.Clear();
if (this.marked) {
this.saveAll = true;
}
}
public bool Contains(T item)
{
return this.listItems.Contains(item);
}
public void CopyTo(Array array, int index)
{
this.listItems.CopyTo(array.Cast<T>().ToArray(), index);
}
public IEnumerator GetEnumerator()
{
return this.listItems.GetEnumerator();
}
public int IndexOf(T item)
{
return this.listItems.IndexOf(item);
}
public void Insert(int index, T item)
{
this.listItems.Insert(index, item);
if (this.marked) {
this.saveAll = true;
}
}
public void LoadViewState(object state)
{
object[] states = state as object[];
if (state == null || states.Length == 0)
return;
for (int i = 0; i < states.Length; i++) {
object itemState = states[i];
if (i < Count) {
T day = (T)listItems[i];
((IStateManager)day).LoadViewState(itemState);
} else {
T day = new T();
((IStateManager)day).LoadViewState(itemState);
listItems.Add(day);
}
}
}
public void Remove(T item)
{
int index = this.IndexOf(item);
if (index >= 0)
this.RemoveAt(index);
}
public void RemoveAt(int index)
{
this.listItems.RemoveAt(index);
if (this.marked) {
this.saveAll = true;
}
}
public object SaveViewState()
{
List<object> state = new List<object>(Count);
foreach (T day in listItems)
state.Add(((IStateManager)day).SaveViewState());
return state.ToArray();
}
int IList.Add(object item)
{
T item2 = (T)item;
this.listItems.Add(item2);
return listItems.Count - 1;
}
bool IList.Contains(object item)
{
return this.Contains((T)item);
}
int IList.IndexOf(object item)
{
return this.IndexOf((T)item);
}
void IList.Insert(int index, object item)
{
this.Insert(index, (T)item);
}
void IList.Remove(object item)
{
this.Remove((T)item);
}
void IStateManager.LoadViewState(object state)
{
this.LoadViewState(state);
}
object IStateManager.SaveViewState()
{
return this.SaveViewState();
}
void IStateManager.TrackViewState()
{
this.TrackViewState();
}
public void TrackViewState()
{
this.marked = true;
for (int i = 0; i < this.Count; i++) {
((IStateManager)this[i]).TrackViewState();
}
}
// Properties
public int Capacity
{
get
{
return this.listItems.Capacity;
}
set
{
this.listItems.Capacity = value;
}
}
public int Count
{
get
{
return this.listItems.Count;
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public bool IsSynchronized
{
get
{
return false;
}
}
public T this[int index]
{
get
{
return (T)this.listItems[index];
}
}
public object SyncRoot
{
get
{
return this;
}
}
bool IList.IsFixedSize
{
get
{
return false;
}
}
object IList.this[int index]
{
get
{
return this.listItems[index];
}
set
{
this.listItems[index] = (T)value;
}
}
bool IStateManager.IsTrackingViewState
{
get
{
return this.marked;
}
}
#region IEnumerable<T> Members
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return this.listItems.GetEnumerator();
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
}
and GraphCollection
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Farayan.Web.Core;
namespace Farayan.Web.AmCharts
{
public class GraphCollection : StateManagedCollection<Graph>
{
}
}
and finally Graph in our example:
using System;
using System.Linq;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Web.UI;
using System.ComponentModel;
using Farayan.Web.AmCharts;
using System.Collections.Generic;
using Farayan.Web.Controls;
using System.Runtime;
using Farayan.Web.Core;
namespace Farayan.Web.AmCharts
{
public class Graph : StateManager
{
#region Colorize Property
[Browsable(true)]
[Localizable(false)]
[PersistenceMode(PersistenceMode.Attribute)]
[DefaultValue(false)]
public virtual bool Colorize
{
get { return ViewState["Colorize"] == null ? false : (bool)ViewState["Colorize"]; }
set { ViewState["Colorize"] = value; }
}
#endregion
//==============================
public override void LoadViewState(object state)
{
base.LoadViewState(state);
}
public override object SaveViewState()
{
return base.SaveViewState();
}
}
}
you may noticed that Graph extends StateManager class
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Web.UI;
using Farayan.Web.AmCharts;
namespace Farayan.Web.AmCharts
{
public class StateManager : IStateManager
{
protected StateBag ViewState = new StateBag();
#region IStateManager Members
public virtual bool IsTrackingViewState
{
get { return true; }
}
public virtual void LoadViewState(object state)
{
if (state != null) {
ArrayList arrayList = (ArrayList)state;
for (int i = 0; i < arrayList.Count; i += 2) {
string value = ((IndexedString)arrayList[i]).Value;
object value2 = arrayList[i + 1];
ViewState.Add(value, value2);
}
}
}
public virtual object SaveViewState()
{
ArrayList arrayList = new ArrayList();
if (this.ViewState.Count != 0) {
IDictionaryEnumerator enumerator = this.ViewState.GetEnumerator();
while (enumerator.MoveNext()) {
StateItem stateItem = (StateItem)enumerator.Value;
//if (stateItem.IsDirty) {
if (arrayList == null) {
arrayList = new ArrayList();
}
arrayList.Add(new IndexedString((string)enumerator.Key));
arrayList.Add(stateItem.Value);
//}
}
}
return arrayList;
}
public virtual void TrackViewState()
{
}
#endregion
#region IStateManager Members
bool IStateManager.IsTrackingViewState
{
get { return this.IsTrackingViewState; }
}
void IStateManager.LoadViewState(object state)
{
this.LoadViewState(state);
}
object IStateManager.SaveViewState()
{
return this.SaveViewState();
}
void IStateManager.TrackViewState()
{
this.TrackViewState();
}
#endregion
}
}

Create a hierarchy custom server control

I have a self-referencing table and I want to visualize it using:
<ol>
<li>
</li>
</ol>
I want to create a custom server data-bound control with templates, I have read the MSDN article:
http://msdn.microsoft.com/en-us/library/aa479322.aspx
But I think that, I have to use different aproach and inherit the
HierarchicalDataBoundControl
or implement
IHierarchicalDataSource
But I cannot find any examples, or something to read from.
Can someone point me to a book or an article, or explain it to me in steps how it needs to be done.
A summary of what is required is this:
A Control which extends HierarchicalDataSourceControl AND DataSourceControl that implements IHeirarchicalDataSource. Believe me working from the documentation provided took A LOT of trial and error but in the end it is worth it. Mines been on hold but shortly I'll complete a project using this which will be able to bind to any n depth structure + navigate it in code using Node.GetParent().GetChildren().Where .. etc. It's complicted and may be overkill for what you need and you may revert back to repeater. Given the posting length allowed at stackoverflow I can't give you full code listing (some 100k chars)
To give you a flavour of whats in my other code here is the generic IHierachicalDataSourceControl:
#region Generic Hierachical DatasourceControl
/// <summary>
/// Datasource control
/// </summary>
public class GenericHierachicalDataSourceControl<TDataContext, TNode, TEntity> : HierarchicalDataSourceControl, IHierarchicalDataSource
where TDataContext : DataContext, new()
where TNode : class,PNS.GenericLinqNodeHeirachy<TDataContext, TNode, TEntity>.IHeirachicalNode, new()
where TEntity : class,PNS.GenericLinqNodeHeirachy<TDataContext, TNode, TEntity>.IHeirachyNodeEntity, new()
{
NodeDataSourceView view;
protected override HierarchicalDataSourceView GetHierarchicalView(string viewPath)
{
view = new NodeDataSourceView(viewPath);
return view;
}
public class NodeDataSourceView : HierarchicalDataSourceView
{
private string _viewPath;
public NodeDataSourceView(string viewPath)
{
_viewPath = viewPath;
}
public override IHierarchicalEnumerable Select()
{
var hierarchy = new HierarchicalEnumerable();
List<TNode> topNodes;
if (String.IsNullOrEmpty(_viewPath))
{
//get all top level nodes (ones without parents)
topNodes = GenericLinqNodeHeirachy<TDataContext, TNode, TEntity>.NodesDAL.GetTopLevelNodes().ToList();
}
else
{
//get the last node in the path
string[] nodes = _viewPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
topNodes = new List<TNode>();
topNodes.Add(GenericLinqNodeHeirachy<TDataContext, TNode, TEntity>.NodesDAL.GetNode(nodes[nodes.Length - 1]));
}
//for each node in the path
foreach (var node in topNodes)
{
if (node.Entity != null)
{
hierarchy.Add(node.Entity);
}
}
return hierarchy;
}
}
public class HierarchicalEnumerable : List<TEntity>, IHierarchicalEnumerable
{
public HierarchicalEnumerable()
: base()
{
}
public IHierarchyData GetHierarchyData(object enumeratedItem)
{
return enumeratedItem as IHierarchyData;
}
}
}
and another part:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Web.UI.HtmlControls;
namespace BootstrapProject.CodeBase
{
public class GenericHierarchicalDataboundControl : HierarchicalDataBoundControl
{
private string _textField;
public string TextField
{
get { return _textField; }
set { _textField = value; }
}
protected override string TagName
{
get
{
return "div";
}
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
protected override void CreateChildControls()
{
if (null != Page && Page.IsPostBack && null != ViewState["_!DataBound"])
{
this.RequiresDataBinding = true;
this.EnsureDataBound();
}
}
protected override void PerformDataBinding()
{
IHierarchicalEnumerable dataSource = GetData(string.Empty).Select();
this.PerformDataBinding(0, this.Controls, dataSource);
this.MarkAsDataBound();
}
protected virtual void PerformDataBinding(int level, ControlCollection controls, IHierarchicalEnumerable dataSource)
{
if (null != dataSource)
{
//controls.Clear();
HtmlGenericControl ul = new HtmlGenericControl("ul");
foreach (object value in dataSource)
{
var itemData = dataSource.GetHierarchyData(value);
Control item = CreateAndBindControl(level, value);
ul.Controls.Add(item);
var data = dataSource.GetHierarchyData(value);
if (data != null && data.HasChildren)
{
IHierarchicalEnumerable childData = data.GetChildren();
PerformDataBinding(1 + level, item.Controls, childData);
}
controls.Add(ul);
}
}
}
protected virtual Control CreateAndBindControl(int level, object dataItem)
{
HtmlGenericControl li = new HtmlGenericControl("li");
string text = String.Empty;
if (!String.IsNullOrEmpty(TextField))
{
text = DataBinder.GetPropertyValue(dataItem, TextField).ToString();
}
else
{
text = dataItem.ToString();
}
li.Attributes.Add("rel", text);
li.Controls.Add(new HyperLink { Text = text });
return li;
}
}
}
And finally:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using BootstrapProject.CodeBase.DAL;
using PNS;
namespace BootstrapProject.CodeBase
{
public class NodeDataSourceControl : HierarchicalDataSourceControl, IHierarchicalDataSource
{
NodeDataSourceView view;
protected override HierarchicalDataSourceView GetHierarchicalView(string viewPath)
{
view = new NodeDataSourceView(viewPath);
return view;
}
}
public class NodeDataSourceView : HierarchicalDataSourceView
{
private string _viewPath;
public NodeDataSourceView(string viewPath)
{
_viewPath = viewPath;
}
public override IHierarchicalEnumerable Select()
{
var hierarchy = new CMSPageHierarchicalEnumerable();
List<DAL.Node> topNodes;
if (String.IsNullOrEmpty(_viewPath))
{
//get all top level nodes (ones without parents)
topNodes = CMS.NodesDAL.GetTopLevelNodes().ToList();
}
else
{
//get the last node in the path
string[] nodes = _viewPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
topNodes = new List<DAL.Node>();
topNodes.AddRange(CMS.NodesDAL.GetNode(nodes[nodes.Length - 1]).NodeChildren);
}
//for each node in the path
foreach (var node in topNodes)
{
if (node.Page != null)
{
hierarchy.Add(node.Page);
}
}
return hierarchy;
}
}
}

Response Length in PostRequestHandlerExecute

I want to find out exactly how long the Response sent to the user was, after the fact, for logging purposes. Is there any way to do this from an HttpModule in asp.net (in the PostRequestHandlerExecute event).
Unfortunately, HttpResponse.OutputStream is write-only, so this is not very straightforward - any attempts to look at the Length property of the output stream will throw an exception.
The only solution to this I've ever seen is by applying a filter to the Response object, so that the filter can count the bytes.
A quick Google search landed me here, which seems close to the implementation I remember.
Wish it Help
context.PostRequestHandlerExecute += delegate(object sender, EventArgs e)
{
HttpContext httpContext = ((HttpApplication)sender).Context;
HttpResponse response = httpContext.Response;
// Don't interfere with non-HTML responses
if (response.ContentType == "text/html")
{
response.Filter = new MyRewriterStream(response.Filter);
}
};
MyRewriterStream Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Web;
namespace ExecutionTime
{
public class MyRewriterStream:Stream
{
#region "Propiedades"
private Stream _sink;
#endregion
public MyRewriterStream(System.IO.Stream stream)
{
_sink = stream;
}
public override void Write(byte[] buffer, int offset, int count)
{
string outStr;
outStr = UTF8Encoding.UTF8.GetString(buffer, offset, count);
strPageSize = strPageSize + outStr;
StringBuilder sb = new StringBuilder(outStr);
if (sb.ToString().LastIndexOf("</html>") > 0)
{
string HtmlResponse = "";//HERE PUT YOUR NEW HTML RESPONSE
sb.AppendLine(HtmlResponse );
byteArray = Encoding.ASCII.GetBytes(sb.ToString());
_sink.Write(byteArray, 0, byteArray.Length);
}
else
{
_sink.Write(buffer, offset, count);
}
}
public override void Flush()
{
_sink.Flush();
}
#region Properites
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
//public override void Flush()
//{
// _sink.Flush();
//}
public override long Length
{
get { return 0; }
}
private long _position;
public override long Position
{
get { return _position; }
set { _position = value; }
}
#endregion
#region Methods
public override int Read(byte[] buffer, int offset, int count)
{
return _sink.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _sink.Seek(offset, origin);
}
public override void SetLength(long value)
{
_sink.SetLength(value);
}
public override void Close()
{
_sink.Close();
}
#endregion
}
}

Resources