Simple way to calculate Response length in MVC4 - asp.net

I was trying to calculate the length of a HTTP Response.
Seems the stream doesn't want to play. (no read allowed. and the Content-Length doesn't seem set)
I was hoping to simply call some length property on the HttpContent response.
I have since googled and seen what looks to me like convoluted solutions around filters which I don't understand.
Is it possible to access the length (content itself is option extra )
If not I would appreciate a link to an example for 'mvc4/.net 4.5 filter' included
that I should work though till I do understand. :-)
public override void Init()
{
base.Init();
EndRequest += new EventHandler(EndRequestHandler);
}
public void EndRequestHandler(object sender, EventArgs e) {
var admService = new AdminServices();
admService.HTTPTrace(Context);
}
public void HTTPTrace(HttpContext httpContext) {
try {
var eventTrace = new MasterEventTrace();
eventTrace.RemoteAddress = req.UserHostAddress;
eventTrace.RequestLengthBytes = req.ContentLength;
// var targetMemoryStream = new MemoryStream();
// res.OutputStream.CopyTo(targetMemoryStream);
int len;
int.TryParse(res.Headers["Content-Length"], out len );
eventTrace.StatusCode = res.StatusCode;
eventTrace.ResponseLengthBytes = len; // <<<<<<< HOW to calculate this
EDIT: Based on Darin's response I got this working, Thank You Darin
I made a few tweaks to suit the situation, but otherwise as suggested.
It shows a little more from Global.asax.cs, and logging the Request and Response info as required.
//Global.asax.cs
public override void Init() {
base.Init();
BeginRequest += new EventHandler(BeginRequestHandler);
EndRequest += new EventHandler(EndRequestHandler);
}
public void EndRequestHandler(object sender, EventArgs e)
{
var adminService = new AdminServices();
var handler = Context.Response.Filter as ResponseStreamHandler;
adminService.HTTPTrace(Context, handler);
}
public void BeginRequestHandler(object sender, EventArgs e)
{
BootStrapUnauthentiated();
Context.Response.Filter = new ResponseStreamHandler(Context.Response.Filter);
}
public void HTTPTrace(HttpContext httpContext, ResponseStreamHandler responseStreamFilter)
{
try {
var _ILuwMaster = BosGlobal.BGA.ILuwMaster();
var req = httpContext.Request;
var res = httpContext.Response;
var eventTrace = new MasterEventTrace();
eventTrace.EventName = req.RequestType +":"+ req.Url.LocalPath;
eventTrace.EventDateTime = BosGlobal.BGA.Calendar.Now;
eventTrace.RemoteAddress = req.UserHostAddress;
eventTrace.RequestLengthBytes = req.ContentLength;
eventTrace.ResponseLengthBytes = responseStreamFilter.ResponseSize; //<<<<<<HERE
eventTrace.StatusCode = res.StatusCode;
// save trace entry in DB
_ILuwMaster.GetRepository<MasterEventTrace>().Add(eventTrace);
_ILuwMaster.Commit();
}
catch (Exception ex ) {} // DONT KILL Live traffic when logging errors occur
}
public class ResponseStreamHandler : MemoryStream {
private readonly Stream _responseStream;
public long ResponseSize { get; private set; }
public ResponseStreamHandler(Stream responseStream) {
this._responseStream = responseStream;
ResponseSize = 0;
}
public override void Write(byte[] buffer, int offset, int count) {
this.ResponseSize += count;
this._responseStream.Write(buffer, offset, count);
}
public override void Flush() {
base.Flush();
}
}

You could write a custom Response filter:
public class ResponseLengthCalculatingStream: MemoryStream
{
private readonly Stream responseStream;
private long responseSize = 0;
public ResponseLengthCalculatingStream(Stream responseStream)
{
this.responseStream = responseStream;
}
public override void Write(byte[] buffer, int offset, int count)
{
this.responseSize += count;
this.responseStream.Write(buffer, offset, count);
}
public override void Flush()
{
var responseSize = this.responseSize;
// Here you know the size of the response ...
base.Flush();
}
}
and register it in your Global.asax:
protected void Application_BeginRequest()
{
Context.Response.Filter = new ResponseLengthCalculatingStream(Context.Response.Filter);
}
And if you wanted to apply this filter only on particular controller actions you could write a custom action filter instead of applying it in the BeginRequest event in Global.asax:
public class ResponseLengthCapturingAttribute: ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var response = filterContext.HttpContext.Response;
response.Filter = new ResponseLengthCalculatingStream(response.Filter);
}
}
and then all that's left is decorate the controller action with the corresponding action filter:
[ResponseLengthCapturing]
public ActionResult Index()
{
...
return View();
}

Related

Using CefBrowser.ExecuteScriptAsync with BindObjectAsync Not Working

I am using the below code to try to bind a c# class that has been registered but do not see "dwgData" anywhere under Scope when debugging the webpage. What would dwgData be bound to?
private void ChromiumBrowserForm_Load(object sender, EventArgs e)
{
CefSettings settings = new CefSettings();
ChromiumWebBrowser browser = new ChromiumWebBrowser("http://localhost:3000");
this.Controls.Add(browser);
browser.Dock = DockStyle.Fill;
browser.JavascriptObjectRepository.Register("dwgData", new DwgData(), true, null);
browser.IsBrowserInitializedChanged += Browser_IsBrowserInitializedChanged;
browser.LoadingStateChanged += Browser_LoadingStateChanged;
}
private async void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e)
{
ChromiumWebBrowser browser = (ChromiumWebBrowser)sender;
if (e.IsLoading == false)
{
await Task.Run(() => browser.ExecuteScriptAsync("CefSharp.BindObjectAsync(\"dwgData\");"));
}
}
private void Browser_IsBrowserInitializedChanged(object sender, EventArgs e)
{
ChromiumWebBrowser browser = (ChromiumWebBrowser)sender;
if (browser.IsBrowserInitialized)
{
browser.ShowDevTools();
}
}
public class DwgData
{
public void showMessage()
{
MessageBox.Show("HELLO FROM JS");
}
}

Logging Request and response to Application Insight

I'm trying to log API request payload and response data to Azure Application Insight. Using trace I can able to log. but I want to know what is the best way to log request and response data to application insight. Because data is huge, no.of API calls will be more. I can't just trace hundreds of thousands of request and response data using tracing. I tried some of the blogs like using ITelemetryInitializer/ httpcontext.feature,get, but no luck.
I want to log from c# .Net framework, Web API, not .NET Core.
Sample code which I tried.
public class AzureRequestResponseInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
var requestTelemetry = telemetry as RequestTelemetry;
if (requestTelemetry != null && (HttpContext.Current.Request.HttpMethod == HttpMethod.Post.ToString() || HttpContext.Current.Request.HttpMethod == HttpMethod.Get.ToString()))
{
using (var reader = new StreamReader(HttpContext.Current.Request.InputStream))
{
string requestBody = reader.ReadToEnd();
requestTelemetry.Properties.Add("body", requestBody);
}
}
You can achieve it by implementing IHttpModule that using Application Insight's TelemtryClient, see the following code:
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
using Contoso.Services.Logging.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace Contoso.Services.Logging.Modules
{
public class CaptureTrafficModule : IHttpModule
{
public TelemetryClient Telemetry { get; set; }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
context.EndRequest += new EventHandler(context_EndRequest);
Telemetry = new TelemetryClient();
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
HttpResponse response = HttpContext.Current.Response;
OutputFilterStream filter = new OutputFilterStream(response.Filter);
response.Filter = filter;
app.Context.Items["Filter"] = filter;
StringBuilder request = new StringBuilder();
// Write All The Headers too :
//foreach (string key in app.Request.Headers.Keys)
//{
// request.Append(key);
// request.Append(": ");
// request.Append(app.Request.Headers[key]);
// request.Append("\n");
//}
//request.Append("\n");
byte[] bytes = app.Request.BinaryRead(app.Request.ContentLength);
if (bytes.Count() > 0)
request.Append(Encoding.ASCII.GetString(bytes));
app.Request.InputStream.Position = 0;
string operationName = $"{app.Request.HttpMethod} {app.Request.FilePath}";
string activityId = System.Diagnostics.Activity.Current.RootId;
app.Context.Items["OperationName"] = operationName;
app.Context.Items["ActivityId"] = activityId;
using (var logRequest = Telemetry.StartOperation<RequestTelemetry>(operationName, System.Diagnostics.Activity.Current.RootId, System.Diagnostics.Activity.Current.RootId))
{
try
{
//logRequest.Telemetry.Id = $"10-{activityId}";
logRequest.Telemetry.Url = app.Request.Url;
logRequest.Telemetry.Properties["RequestBody"] = request.ToString();
}
catch (Exception ex)
{
logRequest.Telemetry.Success = false;
Telemetry.TrackException(ex);
//throw;
}
}
}
void context_EndRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
OutputFilterStream filter = null;
string operationName = "", activityId = Guid.Empty.ToString(), responseStr = "NONE";
if (app.Context.Items.Contains("OperationName"))
operationName = app.Context.Items["OperationName"].ToString();
if (app.Context.Items.Contains("ActivityId"))
activityId = app.Context.Items["ActivityId"].ToString();
if (app.Context.Items.Contains("Filter"))
{
filter = (OutputFilterStream)app.Context.Items["Filter"];
responseStr = filter.ReadStream();
}
using (var logResponse = Telemetry.StartOperation<RequestTelemetry>(operationName, activityId, activityId))
{
try
{
//logResponse.Telemetry.Id = $"20-{activityId}";
logResponse.Telemetry.Url = app.Request.Url;
logResponse.Telemetry.Properties["ResponseBody"] = responseStr.ToString();
}
catch (Exception ex)
{
logResponse.Telemetry.Success = false;
Telemetry.TrackException(ex);
//throw;
}
}
}
public void Dispose()
{
//Does nothing
}
}
}
This question is answered in https://thirum.wordpress.com/2019/08/19/logging-the-http-response-body-in-application-insights/
Please take a look.

Pass values to a button from function

I have a function which is receiving parameters from another function and I have to pass these parameters to a button when it's execution get's complete !
async void CallCompanyApi(String CompanyGp, string CompanyId)
{
First.IsVisible = false;
Second.IsVisible = true;
// Next_Clicked(CompanyGp,CompanyId)
}
private void Next_Clicked(object sender, EventArgs e)
{
}
I have to pass these 2 parameters to that button !
you need to create class level variables to store these values
string _CompanyGp;
string _CompanyId;
async void CallCompanyApi(String CompanyGp, string CompanyId)
{
First.IsVisible = false;
Second.IsVisible = true;
// store the parameters in the class level variables
_CompanyGp = CompanyGp;
_CompanyId = CompanyId;
}
private void Next_Clicked(object sender, EventArgs e)
{
// you can now just reference _CompanyGp and _CompanyId
}
FYI, this is basic C# and really has nothing specific to do with Xamarin
Welcome to SO!
If CallCompanyApi and Next_Clicked located in different class, you can store them in Xamarin Forms by using Preferences.
using Xamarin.Essentials;
async void CallCompanyApi(String CompanyGp, string CompanyId)
{
First.IsVisible = false;
Second.IsVisible = true;
//Next_Clicked(CompanyGp,CompanyId)
Preferences.Set("CompanyGp", CompanyGp);
Preferences.Set("CompanyId", CompanyId);
}
Then in another class, click button will get them:
private void Next_Clicked(object sender, EventArgs e)
{
var CompanyGp = Preferences.Get("CompanyGp", "default_value");
var CompanyId = Preferences.Get("CompanyId", "default_value");
}
Else if they are in the same class, you can use the way as Jason's said.
============================Update=========================
You can set a default value if needed, such as follow:
var CompanyGp = Preferences.Get("CompanyGp", "Company_A");
var CompanyId = Preferences.Get("CompanyId", "1");
Defalut CompanyGp is Company_A, and default CompanyId is 1.

how to check string value and refresh the page in asp.net

i have a static string in static class, its getting value from desktop application,
on asp.net i have to check that its null or have value, if it has value , i want to
show it on label (on aspx page) , i have put a backgroud worker in global.asax,
public static BackgroundWorker worker = new BackgroundWorker();
public static int ID = 0;
// public static List<Person> personList = new List<Person>();
public static string personList;
public static bool stopWorker = false;
void Application_Start(object sender, EventArgs e)
{
worker.DoWork += new DoWorkEventHandler(DoWork);
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted);
// Calling the DoWork Method Asynchronously
worker.RunWorkerAsync();
private static void DoWork(object sender, DoWorkEventArgs e)
{
//foreach (Person p in personList)
//{
personList = Class1.GetDataFromDesktop;
//}
}
its checking value time to time, but i am unable to show the response on label which is on aspx page
, what to do, is there any other process or i can do it using global.asax

ASP.NET: How to persist Page State accross Pages?

I need a way to save and load the Page State in a persistent manner (Session). The Project i need this for is an Intranet Web Application which has several Configuration Pages and some of them need a Confirmation if they are about to be saved. The Confirmation Page has to be a seperate Page. The use of JavaScript is not possible due to limitations i am bound to. This is what i could come up with so far:
ConfirmationRequest:
[Serializable]
public class ConfirmationRequest
{
private Uri _url;
public Uri Url
{ get { return _url; } }
private byte[] _data;
public byte[] Data
{ get { return _data; } }
public ConfirmationRequest(Uri url, byte[] data)
{
_url = url;
_data = data;
}
}
ConfirmationResponse:
[Serializable]
public class ConfirmationResponse
{
private ConfirmationRequest _request;
public ConfirmationRequest Request
{ get { return _request; } }
private ConfirmationResult _result = ConfirmationResult.None;
public ConfirmationResult Result
{ get { return _result; } }
public ConfirmationResponse(ConfirmationRequest request, ConfirmationResult result)
{
_request = request;
_result = result;
}
}
public enum ConfirmationResult { Denied = -1, None = 0, Granted = 1 }
Confirmation.aspx:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.UrlReferrer != null)
{
string key = "Confirmation:" + Request.UrlReferrer.PathAndQuery;
if (Session[key] != null)
{
ConfirmationRequest confirmationRequest = Session[key] as ConfirmationRequest;
if (confirmationRequest != null)
{
Session[key] = new ConfirmationResponse(confirmationRequest, ConfirmationResult.Granted);
Response.Redirect(confirmationRequest.Url.PathAndQuery, false);
}
}
}
}
PageToConfirm.aspx:
private bool _confirmationRequired = false;
protected void btnSave_Click(object sender, EventArgs e)
{
_confirmationRequired = true;
Response.Redirect("Confirmation.aspx", false);
}
protected override void SavePageStateToPersistenceMedium(object state)
{
if (_confirmationRequired)
{
using (MemoryStream stream = new MemoryStream())
{
LosFormatter formatter = new LosFormatter();
formatter.Serialize(stream, state);
stream.Flush();
Session["Confirmation:" + Request.UrlReferrer.PathAndQuery] = new ConfirmationRequest(Request.UrlReferrer, stream.ToArray());
}
}
base.SavePageStateToPersistenceMedium(state);
}
I can't seem to find a way to load the Page State after being redirected from the Confirmation.aspx to the PageToConfirm.aspx, can anyone help me out on this one?
If you mean view state, try using Server.Transfer instead of Response.Redirect.
If you set the preserveForm parameter
to true, the target page will be able
to access the view state of the
previous page by using the
PreviousPage property.
use this code this works fine form me
public class BasePage
{
protected override PageStatePersister PageStatePersister
{
get
{
return new SessionPageStatePersister(this);
}
}
protected void Page_PreRender(object sender, EventArgs e)
{
//Save the last search and if there is no new search parameter
//Load the old viewstate
try
{ //Define name of the pages for u wanted to maintain page state.
List<string> pageList = new List<string> { "Page1", "Page2"
};
bool IsPageAvailbleInList = false;
foreach (string page in pageList)
{
if (this.Title.Equals(page))
{
IsPageAvailbleInList = true;
break;
}
}
if (!IsPostBack && Session[this + "State"] != null)
{
if (IsPageAvailbleInList)
{
NameValueCollection formValues = (NameValueCollection)Session[this + "State"];
String[] keysArray = formValues.AllKeys;
if (keysArray.Length > 0)
{
for (int i = 0; i < keysArray.Length; i++)
{
Control currentControl = new Control();
currentControl = Page.FindControl(keysArray[i]);
if (currentControl != null)
{
if (currentControl.GetType() == typeof(System.Web.UI.WebControls.TextBox))
((TextBox)currentControl).Text = formValues[keysArray[i]];
else if (currentControl.GetType() == typeof(System.Web.UI.WebControls.DropDownList))
((DropDownList)currentControl).SelectedValue = formValues[keysArray[i]].Trim();
else if (currentControl.GetType() == typeof(System.Web.UI.WebControls.CheckBox))
{
if (formValues[keysArray[i]].Equals("on"))
((CheckBox)currentControl).Checked = true;
}
}
}
}
}
}
if (Page.IsPostBack && IsPageAvailbleInList)
{
Session[this + "State"] = Request.Form;
}
}
catch (Exception ex)
{
LogHelper.PrintError(string.Format("Error occured while loading {0}", this), ex);
Master.ShowMessageBox(enMessageType.Error, ErrorMessage.GENERIC_MESSAGE);
}
}
}

Resources