Capturing HTML generated from ASP.NET - asp.net

How do I best capture the HTML (in my instance, for logging) rendered by an aspx-page?
I dont want to have to write back to the page using Response.Write, since it messes up my site layout.
Using the Response.OutputStream or Response.Output's stream results in an ArgumentException ({System.ArgumentException: Stream was not readable.)

Good question, i had to try out and see if i could create a HttpModule to do what you are describing.
I didnt have any luck trying to read from the responsestream, but using the ResponseFilter gave me a way to capture the content.
The following code seems to work pretty good, and i figured maybe you could use the code as a base. But remember this is just something i threw together fast, it has not been tested in any way. So dont use it in any production environment without proper reviewing/testing and such. Feel free to comment on it though ;)
public class ResponseLoggerModule : IHttpModule
{
private class ResponseCaptureStream : Stream
{
private readonly Stream _streamToCapture;
private readonly Encoding _responseEncoding;
private string _streamContent;
public string StreamContent
{
get { return _streamContent; }
private set
{
_streamContent = value;
}
}
public ResponseCaptureStream(Stream streamToCapture, Encoding responseEncoding)
{
_responseEncoding = responseEncoding;
_streamToCapture = streamToCapture;
}
public override bool CanRead
{
get { return _streamToCapture.CanRead; }
}
public override bool CanSeek
{
get { return _streamToCapture.CanSeek; }
}
public override bool CanWrite
{
get { return _streamToCapture.CanWrite; }
}
public override void Flush()
{
_streamToCapture.Flush();
}
public override long Length
{
get { return _streamToCapture.Length; }
}
public override long Position
{
get
{
return _streamToCapture.Position;
}
set
{
_streamToCapture.Position = value;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
return _streamToCapture.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _streamToCapture.Seek(offset, origin);
}
public override void SetLength(long value)
{
_streamToCapture.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
_streamContent += _responseEncoding.GetString(buffer);
_streamToCapture.Write(buffer, offset, count);
}
public override void Close()
{
_streamToCapture.Close();
base.Close();
}
}
#region IHttpModule Members
private HttpApplication _context;
public void Dispose()
{
}
public void Init(HttpApplication context)
{
_context = context;
context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
context.PreSendRequestContent += new EventHandler(context_PreSendRequestContent);
}
void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
_context.Response.Filter = new ResponseCaptureStream(_context.Response.Filter, _context.Response.ContentEncoding);
}
void context_PreSendRequestContent(object sender, EventArgs e)
{
ResponseCaptureStream filter = _context.Response.Filter as ResponseCaptureStream;
if (filter != null)
{
string responseText = filter.StreamContent;
// Logging logic here
}
}
#endregion
}

Many load testers will allow you to log the HTTP responses generated, but bear in mind with ASP.NET those could be some very large log-files.
Edit: Response.Filter as per Tom Jelen's code is designed to give this kind of oversight and Response.Outputstream is otherwise unreadable.
Edit 2: For a page rather than a HTTPModule
public class ObserverStream : Stream
{
private byte[] buffer = null;
private Stream observed = null;
public ObserverStream (Stream s)
{
this.observed = s;
}
/* important method to extend #1 : capturing the data */
public override void Write(byte[] buffer, int offset, int count)
{
this.observed.Write(buffer, offset, count);
this.buffer = buffer; //captured!
}
/* important method to extend #2 : doing something with the data */
public override void Close()
{
//this.buffer available for logging here!
this.observed.Close();
}
/* override all the other Stream methods/props with this.observed.method() */
//...
}
and in your Page_Load (or before your response is written anyway)
Response.Filter = new ObserverStream(Response.Filter);

One way to to make server-side XMLHTTP request to your own server. Grab the result and save it to a file or DB.
Alternately you can use AJAX on the client, grab the result, and POST it back to the server.

Related

Observablevalue check for new and old values equally

In fact I have a class that performs the job of collecting website post URL.The url article I get when analyzing each page site
+http://dantri.com.vn/xa-hoi.htm
+http://dantri.com.vn/xa-hoi/trang-2.htm
....
+http://dantri.com.vn/xa-hoi/trang-9998.htm
+http://dantri.com.vn/xa-hoi/trang-n.htm
to the Property url is as follows.
public class Pagination {
private final StringProperty postURL = new SimpleStringProperty();
public String getPostURL() {
return postURL.get();
}
public void setPostURL(String value) {
postURL.set(value);
}
public StringProperty postURLProperty() {
return postURL;
}
public void gather() {
for (int i = 0; i < n; i++) {
for (String url : getAllURLToPage("http://dantri.com.vn/xa-hoi/trang-"+i+".htm")) {
setPostURL(url);
}
}
}
}
From page http://dantri.com.vn/xa-hoi/trang-9998.htm===->http://dantri.com.vn/xa-hoi/trang-n.htm.
The post url value is constant, so I want to terminate the program when consecutive url are equal,eg newValue.equals(oldValue) as below
public static void main(String[] args) {
Pagination pagination = new Pagination();
pagination.postURLProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (newValue.equals(oldValue)) {
System.out.println("BREAK");
}
}
});
pagination.gather();
}
That's just the example by newValue and oldValue are always not equal with observableValue.
I hope you help me solve my problem how can i control post url i get
As I noted in the comment, a ChangeListener is invoked in response to a change in a property. If you call postURL.set(...) and pass the same value that is currently held in postURL, the change listener will not be invoked. (TBH it's not really clear what the purpose of the property is here.)
You could just do this in the for loop directly:
public void gather() {
for (int i = 0; i < n; i++) {
for (String url : getAllURLToPage("http://dantri.com.vn/xa-hoi/trang-"+i+".htm")) {
if (Objects.equals(url, getPostURL())) {
System.out.println("BREAK");
}
setPostURL(url);
}
}
}
or perhaps in the set method, assuming you don't call postURL.set(...) anywhere else:
public void setPostURL(String value) {
if (Objects.equals(value, postURL.get())) {
System.out.println("BREAK");
}
postURL.set(value);
}
But there is no way for a ChangeListener to detect a lack of a change.

DateTime.Kind set to unspecified, not UTC, upon loading from database

When I create a Buyin object the response from the ASP.NET MVC controller, (return Json(response, JsonRequestBehavior.AllowGet);, looks like this:
"Buyin": {
"Id": 95,
"PlayerSessionId": 88,
"PlayerId": 45,
"PlayerName": "Alan",
"Amount": 888,
"BuyinType": "Credits",
"Description": null,
"Authorized": true,
"SignPath": "~/Signs/Buyins\\95.png",
"Payment": null,
"CreationDate": "/Date(1477242738042)/"
},
If I convert that on Epoch Converter I get this time: GMT: Sun, 23 Oct 2016 17:12:18.042 GMT
Looking in the database the stored datetime seems to be correct:
95 NULL 1 1 2016-10-23 17:12:18.043
When the response is sent out the Kind is set to UTC.
Now I call a controller to get all my data and all of the dates have several hours added to it:
{
"Id": 95,
"PlayerSessionId": 88,
"PlayerId": 45,
"PlayerName": "Alan",
"Amount": 888,
"BuyinType": "Credits",
"Description": null,
"Authorized": true,
"SignPath": "~/Signs/Buyins\\95.png",
"Payment": null,
"CreationDate": "/Date(1477267938043)/"
}
1477267938043 = GMT: Mon, 24 Oct 2016 00:12:18.043 GMT
However when I request this object I can see that the actual object has the correct date set:
But the Kind is set to Unspecified so I think this is causing the problem.
For the moment I don't have not set any globalization settings.
So basically my question is: When ASP.NET MVC loads the dates from the database is there a way to tell the server to load the dates with Kind set to UTC as I think that is the problem?
The database is saved and loaded using Entity Framework.
Update after the accepted answer
The accepted answer was great however my date values was already stored in the Database as UTC dates so I modified GetDateTime to this:
public override DateTime GetDateTime(int ordinal)
{
var date = base.GetDateTime(ordinal);
var utcDate = DateTime.SpecifyKind(date, DateTimeKind.Utc);
return utcDate;
//return base.GetDateTime(ordinal).ToUniversalTime();
}
Assuming you are using EF6 and you want to set the Kind property of any DateTime value retrieved from the database to Utc.
Similar questions have been asked, and the answers tend to suggest hooking into the ObjectContext.ObjectMaterialized event, but it didn't fire for queries that use projection.
The solution I'm going to propose works for both entity and projection queries, by performing the conversion at the DbDataReader level (which is used by this type of queries).
In order to do that, we need a custom DbDataReader implementation that intercepts the GetDateTime method. Unfortunately implementing DbDataReader derived class requires a lot of boilerplate code. Luckily I already created a base class form my answer to Dynamic Translate to avoid C# syntax errors which simply delegates each method to the underlying DbDataReader instance, so I'll just take it from there:
abstract class DelegatingDbDataReader : DbDataReader
{
readonly DbDataReader source;
public DelegatingDbDataReader(DbDataReader source)
{
this.source = source;
}
public override object this[string name] { get { return source[name]; } }
public override object this[int ordinal] { get { return source[ordinal]; } }
public override int Depth { get { return source.Depth; } }
public override int FieldCount { get { return source.FieldCount; } }
public override bool HasRows { get { return source.HasRows; } }
public override bool IsClosed { get { return source.IsClosed; } }
public override int RecordsAffected { get { return source.RecordsAffected; } }
public override bool GetBoolean(int ordinal) { return source.GetBoolean(ordinal); }
public override byte GetByte(int ordinal) { return source.GetByte(ordinal); }
public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) { return source.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); }
public override char GetChar(int ordinal) { return source.GetChar(ordinal); }
public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) { return source.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); }
public override string GetDataTypeName(int ordinal) { return source.GetDataTypeName(ordinal); }
public override DateTime GetDateTime(int ordinal) { return source.GetDateTime(ordinal); }
public override decimal GetDecimal(int ordinal) { return source.GetDecimal(ordinal); }
public override double GetDouble(int ordinal) { return source.GetDouble(ordinal); }
public override IEnumerator GetEnumerator() { return source.GetEnumerator(); }
public override Type GetFieldType(int ordinal) { return source.GetFieldType(ordinal); }
public override float GetFloat(int ordinal) { return source.GetFloat(ordinal); }
public override Guid GetGuid(int ordinal) { return source.GetGuid(ordinal); }
public override short GetInt16(int ordinal) { return source.GetInt16(ordinal); }
public override int GetInt32(int ordinal) { return source.GetInt32(ordinal); }
public override long GetInt64(int ordinal) { return source.GetInt64(ordinal); }
public override string GetName(int ordinal) { return source.GetName(ordinal); }
public override int GetOrdinal(string name) { return source.GetOrdinal(name); }
public override string GetString(int ordinal) { return source.GetString(ordinal); }
public override object GetValue(int ordinal) { return source.GetValue(ordinal); }
public override int GetValues(object[] values) { return source.GetValues(values); }
public override bool IsDBNull(int ordinal) { return source.IsDBNull(ordinal); }
public override bool NextResult() { return source.NextResult(); }
public override bool Read() { return source.Read(); }
public override void Close() { source.Close(); }
public override T GetFieldValue<T>(int ordinal) { return source.GetFieldValue<T>(ordinal); }
public override Task<T> GetFieldValueAsync<T>(int ordinal, CancellationToken cancellationToken) { return source.GetFieldValueAsync<T>(ordinal, cancellationToken); }
public override Type GetProviderSpecificFieldType(int ordinal) { return source.GetProviderSpecificFieldType(ordinal); }
public override object GetProviderSpecificValue(int ordinal) { return source.GetProviderSpecificValue(ordinal); }
public override int GetProviderSpecificValues(object[] values) { return source.GetProviderSpecificValues(values); }
public override DataTable GetSchemaTable() { return source.GetSchemaTable(); }
public override Stream GetStream(int ordinal) { return source.GetStream(ordinal); }
public override TextReader GetTextReader(int ordinal) { return source.GetTextReader(ordinal); }
public override Task<bool> IsDBNullAsync(int ordinal, CancellationToken cancellationToken) { return source.IsDBNullAsync(ordinal, cancellationToken); }
public override Task<bool> ReadAsync(CancellationToken cancellationToken) { return source.ReadAsync(cancellationToken); }
public override int VisibleFieldCount { get { return source.VisibleFieldCount; } }
}
and build the actual class that we need on top of it:
class UtcDateTimeConvertingDbDataReader : DelegatingDbDataReader
{
public UtcDateTimeConvertingDbDataReader(DbDataReader source) : base(source) { }
public override DateTime GetDateTime(int ordinal)
{
return DateTime.SpecifyKind(base.GetDateTime(ordinal), DateTimeKind.Utc);
}
}
Once we have that, we need to plug it into EF infrastructure using EF interception.
We'll start by creating a custom DbCommandInterceptor derived class:
class UtcDateTimeConvertingDbCommandInterceptor : DbCommandInterceptor
{
public override void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
base.ReaderExecuted(command, interceptionContext);
if (!(interceptionContext.Result is UtcDateTimeConvertingDbDataReader)
&& interceptionContext.Result != null
&& interceptionContext.Exception == null)
interceptionContext.Result = new UtcDateTimeConvertingDbDataReader(interceptionContext.Result);
}
}
register it (for instance from your DbContext derived class static constructor):
public class YourDbContext : DbContext
{
static YourDbContext()
{
DbInterception.Add(new UtcDateTimeConvertingDbCommandInterceptor());
}
// ...
}
and we are done.
Now every DateTime value coming from the database will have Kind property set to Utc.

JavaFX webview: How to forward System.out and System.err to the Firebug Lite console?

I've found several examples on how to pipe and redirect messages from System.out and System.err.
Having decided to develop an application using the JavaFX Webview and Dukescript, I've found useful having one place where to display all messages, i.e. the Firebug Lite console.
See below.
PS This is the exact opposite as this
First define an abstract class
public abstract class FirebugConsole extends OutputStream {
abstract void log( String msg );
StringBuilder sb = new StringBuilder();
#Override
public void write(int i) {
sb.append((char)i);
}
#Override
public void flush() {
if( sb.length() >0 && !sb.toString().equals("\r\n"))
log(sb.toString());
sb = new StringBuilder();
}
}
Then extend it with methods that implement native calls into JavaScript. Here's for example how to write log messages
public class FirebugConsoleInfo extends FirebugConsole{
#net.java.html.js.JavaScriptBody(args = { "msg" }, body = ""
+ "Firebug.Console.log(msg);")
public native void log( String msg );
}
Finally, pipe System.out and System.err to those objects
public static void onPageLoad() throws Exception {
...
System.setOut(new PrintStream(new FirebugConsoleInfo(), true));
System.setErr(new PrintStream(new FirebugConsoleError(), true));
...
}
Note: for some reasons the usual console.log() doesn't work for me, I know Firebug doesn't bind a console if a console object is already present, so I suspect the WebFX webview must itself pipe console.log messages to System.out in the first place.
Update
The solution above doesn't work when the messages are generated by a thread other than the browser's. Here's an updated solution based on BrwsrCtx.execute()
public abstract static class FirebugConsole extends OutputStream {
protected final BrwsrCtx ctx;
public FirebugConsole( BrwsrCtx ctx ){
this.ctx = ctx;
}
abstract void logNative( String msg );
void log(String msg) {
ctx.execute(new Runnable(){
#Override
public void run() {
logNative(msg);
}
});
}
StringBuilder sb = new StringBuilder();
#Override
public void write(int i) {
sb.append((char)i);
}
#Override
public void flush() {
if( sb.length() >0 && !sb.toString().equals("\r\n"))
log(sb.toString());
sb = new StringBuilder();
}
}
public static class FirebugConsoleInfo extends FirebugConsole{
public FirebugConsoleInfo(BrwsrCtx ctx) {
super(ctx);
}
#net.java.html.js.JavaScriptBody(args = { "msg" }, body = ""
+ "Firebug.Console.log(msg);")
public native void logNative( String msg );
}
public static class FirebugConsoleError extends FirebugConsole{
public FirebugConsoleError(BrwsrCtx ctx) {
super(ctx);
}
#net.java.html.js.JavaScriptBody(args = { "msg" }, body = ""
+ "Firebug.Console.error(msg);")
public native void logNative( String msg );
}
}
and
public static void onPageLoad() throws Exception {
BrwsrCtx ctx = BrwsrCtx.findDefault(GoGPS_Fx.class);
System.setOut(new PrintStream(new FirebugConsoleInfo(ctx), true));
System.setErr(new PrintStream(new FirebugConsoleError(ctx), true));
}
Note: it's quite slow for large logs, there might be faster alternatives (StringWriter is one). But I suspect the bottleneck is the passing of messages back and forth from Java to JavaScript.

How do you abstract page session properties?

I was following this example
example code:
public class Global : HttpApplication
{
private Poster _posterDetails;
private Posting _postingDetails;
private Property _propertyDetails;
protected void Application_PostRequestHandlerExecute(object sender, EventArgs e)
{
if (HttpContext.Current.Session == null) return;
_posterDetails = HttpContext.Current.Session["Poster"] as Poster;
_postingDetails = HttpContext.Current.Session["Posting"] as Posting;
_propertyDetails = HttpContext.Current.Session["Property"] as Property;
}
}
these session variables are littered throughout the app and I need to abstract the retrieval of them. Say, later I get them from a db instead of the current session.
Session is baked into the Page or Context. How do I inject that dependency into the concrete implementation of a possible current property getter.
Create an abstraction around HttpContext:
public interface IHttpContextFactory
{
HttpContextBase Create();
}
public class HttpContextFactory
: IHttpContextFactory
{
public HttpContextBase Create()
{
return new HttpContextWrapper(HttpContext.Current);
}
}
Then inject it into a specialized service for these settings.
public interface ISettings
{
T GetValue<T>(string key);
void SetValue<T>(string key, T value);
}
public class ContextSettings
: ISettings
{
private readonly IHttpContextFactory httpContextFactory;
private HttpContextBase context;
public RequestCache(
IHttpContextFactory httpContextFactory
)
{
if (httpContextFactory == null)
throw new ArgumentNullException("httpContextFactory");
this.httpContextFactory = httpContextFactory;
}
protected HttpContextBase Context
{
get
{
if (this.context == null)
{
this.context = this.httpContextFactory.Create();
}
return context;
}
}
public virtual T GetValue<T>(string key)
{
if (this.Context.Session.Contains(key))
{
return (T)this.Context.Session[key];
}
return default(T);
}
public virtual void SetValue<T>(string key, T value)
{
this.Context.Session[key] = value;
}
}
It will later be possible to replace the service with another storage mechanism by implementing ISettings and providing different constructor dependencies. Note that changing the constructor signature does not require a different interface.
That said, you should provide another service (or perhaps more than one) that takes ISettings as a dependency so you can make explicit properties. You should aim to provide focused sets of related properties for specific purposes. Your application also shouldn't have to know the type of property in order to retrieve its value - it should just call a property that hides those details.
public class SomeSettingsService: ISomeSettingsService
{
private readonly ISettings settings;
public SomeSettingsService(ISettings settings)
{
if (settings == null)
throw new ArgumentNullException("settings");
this.settings = settings;
}
public Poster Poster
{
get { return this.settings.GetValue<Poster>("Poster"); }
set { this.settings.SetValue<Poster>("Poster", value); }
}
public Posting Posting
{
get { return this.settings.GetValue<Posting>("Posting"); }
set { this.settings.SetValue<Posting>("Posting", value); }
}
public Property Property
{
get { return this.settings.GetValue<Property>("Property"); }
set { this.settings.SetValue<Property>("Property", value); }
}
}
Not sure if this is what you are asking... What I often do is create a service:
public interface ISessionService
{
object Get(string key);
void Save(string key, object value);
}
And then I implement this, which calls HttpContext.Current.Session[key] and returns the value. It shouldn't be hard to create a Get<T>(string key) to return an object either. Break all of your dependencies to use this (which is the hard part).
There is no seamless way to break the dependency... it has to be through a manual change.

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