When the HTTP headers are already sent? - c#

I have this module:
public class SecureCookieModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.EndRequest += OnEndRequestHandlerExecute;
}
private void OnEndRequestHandlerExecute(object sender, EventArgs e)
{
if (!AppConfig.MachineAppSettingsBool("setSecureCookiesForSecureConnections"))
{
return;
}
try
{
HttpApplication app = sender as HttpApplication;
if (app.Request.IsReallySecureConnection())
{
foreach (string s in app.Response.Cookies.AllKeys)
{
var cookie = app.Response.Cookies[s];
if (cookie.Secure == false)
{
cookie.Secure = true;
app.Response.Cookies.Add(cookie);
}
}
}
}
catch (Exception ex)
{
LogManager.GetLogger("SecureCookieModule").Error("Exception while processing http module. Ex: {0}", ex);
}
}
}
From this what I wrote in some cases the response headers are already sent, so they cannot be modified and exception is thrown because of this. What I miss is in which cases this happens and why? Why in some cases before executing the "OnEndRequestHandlerExecute" event they are sent and in other cases they are not? What is the rule behind this cases resulting in this behavior?
Thanks in advance!

If the response is not buffered, and the headers are already sent, you can't change them during the end request event, because they have already been written back to the data stream to the browser.
To deal with this, you have a choice:
Turn response buffering on. That way your current code will be able to modify the headers in the buffer (This might not be a great idea if you are serving large documents).
Response.BufferOutput = true;
Instead of handling EndRequest, handle PreSendRequestHeaders instead. This event is guaranteed to fire before the headers are written to the response.
public void Init(HttpApplication context)
{
context.PreSendRequestHeaders += OnEndRequestHandlerExecute;
}

Related

How to solve this deadlock?

I have an UWP application in which I am trying to store and retrieve some data from a local text file but no matter how I try to do it the application gets deadlocked. Due to synchronous stuff that needs to happen, I try to use a task and wait for its completion but nevertheless, the application locks.
I have a page in my UWP application called "MainPage" and in it's constructor I have the following code:
var listenkeyViewModel = new ListenkeyViewModel();
listenkeyViewModel.GetKey();
listenkey = listenkeyViewModel.Listenkey;
The get key is the issue here because it calls a method on the ViewModel (which I created to be synchronous because I thought making the call synchronous asap would be preferable.
public void GetKey()
{
try
{
var listenKeyTask = RetrieveListenKey();
_listenkey = listenKeyTask.Result;
}
catch (Exception e)
{
}
}
public static async Task<string> RetrieveListenKey()
{
try
{
var storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
var listenkeyFile = await storageFolder.GetFileAsync("listenkey.txt");
return await Windows.Storage.FileIO.ReadTextAsync(listenkeyFile);
}
catch (Exception e)
{
throw new Exception("Could not load file");
}
}
I know the thing is "async all the way down" but this is not possible here. I cannot make the constructor where the original code lies asynchronous. How are you supposed to not get deadlocked? I do not understand.
Convert GetKey to async/await
public async Task GetKey() {
try {
var listenKeyTask = RetrieveListenKey();
_listenkey = await listenKeyTask;
} catch (Exception e) {
//...should handle/log error
}
}
Move the calling of this out of the constructor and into an event handler. like page load or some other event called early in the lifecycle of the page.
partial class MainPage : Page {
ListenkeyViewModel listenkeyViewModel;
string listenkey;
public MainPage() {
InitializeComponent();
listenkeyViewModel = new ListenkeyViewModel();
// add a handler to be called when the page has been loaded
this.Loaded += OnPageLoaded;
}
async void OnPageLoaded(object sender, RoutedEventArgs e) {
await listenkeyViewModel.GetKey();
listenkey = listenkeyViewModel.Listenkey;
}
// Shown for demonstration purposes only.
// This is typically autogenerated by Visual Studio.
private void InitializeComponent() {
}
}
async void is allowed on event handlers so this should allow the process to flow without deadlock.

Is there any elegant way to call a web page asynchronously ,ignore the response and release resource of thread

I have a case in ASP.NET,that when a request got, a web page (naming it as service.aspx)will be called asynchronously, and I don't care the response of service.aspx, I just need call it .
Right now ,I have two ways.
First one is HttpWebRequest.BeginGetResponse, parameter callback is set as null. And it seems that it's not a good idea , there is no way to call EndGetResponse, so maybe the resource of calling service.aspx thread could not be released.
Second one is WebClient.OpenReadAsync, but I'm not sure whether it could release thread resource if I don't specify OpenReadCompleted event.
Or maybe there is other appropriate way to have what I want.
You can create a class that will make web requests in the background. Create a static instance of this class in your application's HttpApplication class (Global.asax) and then call a method to queue web requests as required.
Class that performs web requests in the background
public class SiteBackgroundCaller : IRegisteredObject, IDisposable
{
private BlockingCollection<string> requestList;
private CancellationTokenSource queueWorkerCts;
private Task queueWorkerThread;
public SiteBackgroundCaller()
{
// Register an instance of this class with the hosting environment, so we can terminate the task gracefully.
HostingEnvironment.RegisterObject(this);
requestList = new BlockingCollection<string>();
queueWorkerCts = new CancellationTokenSource();
queueWorkerThread = new Task(queueWorkerMethod, TaskCreationOptions.LongRunning);
queueWorkerThread.Start();
}
public void QueueBackgroundRequest(string uri)
{
requestList.Add(uri);
}
private void queueWorkerMethod()
{
while (!queueWorkerCts.IsCancellationRequested)
{
try
{
// This line will block until there is something in the collection
string uri = requestList.Take(queueWorkerCts.Token);
if (queueWorkerCts.IsCancellationRequested)
return;
// Make the request
HttpWebRequest r = (HttpWebRequest)HttpWebRequest.Create(uri);
HttpWebResponse response = (HttpWebResponse)r.GetResponse();
}
catch (OperationCanceledException)
{
// This may throw if the cancellation token is Cancelled.
}
catch (WebException)
{
// Something wrong with the web request (eg timeout)
}
}
}
// Implement IRegisteredObject
public void Stop(bool immediate)
{
queueWorkerCts.Cancel();
queueWorkerThread.Wait();
}
// Implement IDisposable
public void Dispose()
{
HostingEnvironment.UnregisterObject(this);
}
}
Instance of the class in HttpApplication (in Global.asax)
public class Global : System.Web.HttpApplication
{
public static SiteBackgroundCaller BackgroundCaller { get; private set; }
protected void Application_Start(object sender, EventArgs e)
{
BackgroundCaller = new SiteBackgroundCaller();
}
}
Queuing a web request from a page
public partial class MyPage: System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
Global.BackgroundCaller.QueueBackgroundRequest("http://www.example.com/service.aspx");
}
}
You can create the HttpWebRequest and not read the response:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("service.aspx");
using (var response = request.GetResponse())
{
// typically here you would call GetResponseStream and read the content
}
you can also use the async variation:
using (var response = await request.GetResponseAsync())
{
}

SharePoint 2013 - redirection when session ends

I created Global.asax file and put it into my web application, which works on SharePoint 2013.
In Global.asax.cs file, I inherited SPHttpApplication class and override
BeginRequest event. It does not work, the Global.asax file is ignored by SharePoint, or I miss something else to add.
The goal is to create redirection when session expires. What am I doing wrong?
This is my code in code behind:
namespace PhoenixHR.Global
{
public class PhenixHRHttpApplication : SPHttpApplication
{
public override void Init()
{
try
{
base.Init();
this.BeginRequest += new EventHandler(Moj_BeginRequest);
}
catch (Exception ex)
{
}
}
private void Moj_BeginRequest(object sender, EventArgs e)
{
try
{
if (HttpContext.Current.Session["TPL"] == null)
Response.Redirect("~/PhoenixHR/start.aspx");
}
catch (Exception ex)
{
}
}
}
}
Global.asax
<%# Assembly Name="Microsoft.SharePoint"%>
<%# Application Language="C#" Inherits="PhoenixHR.Global.PhenixHRHttpApplication,PhoenixHR.Global,Version=1.0.0.0,Culture=neutral,PublicKeyToken=a0bd8fabe3543dc0" %>
As you have some exception swallowing in your code can you prove the change is not working? or is it raising an exception every request and just ignoring it?
You will be better off with binding to a different event. The HttpApplication class has quite a few events you can bind and BeginRequest is very early (first) in the processing of the request pipeline. This will not have access to the Session State. I would suggest using AcquireRequestState or PostAcquireRequestState.
In order for this to work you will need to create an HttpModule.
namespace PhoenixHR.Global
{
public class SessionMissingRedirectHttpModule : IHttpModule
{
private const string LAYOUTS_SUBFOLDER = "/PhoenixHR.Global";
private const string START_PAGE = "/start.aspx";
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.PostAcquireRequestState += context_PostAcquireRequestState;
}
void context_PostAcquireRequestState(object sender, EventArgs e)
{
// get required contexts
SPHttpApplication application = (SPHttpApplication)sender;
HttpContext context = application.Context;
HttpSessionState session = context.Session;
if (session == null)
return;
if (session["TPL"] != null)
return;
// get SharePoint context and current SPWeb.
SPContext sharepointContext = SPContext.GetContext(context);
SPWeb currentWeb = sharepointContext.Web;
// build a url to the redirect page.
string layoutsFolder =
SPUtility.GetLayoutsFolder(currentWeb);
string url = string.Format("{0}/{1}{2}{3}", currentWeb.Url, layoutsFolder, LAYOUTS_SUBFOLDER, START_PAGE);
// prevent redirection loop
if (context.Request.Url.AbsoluteUri.Equals(url, StringComparison.InvariantCultureIgnoreCase))
return;
SPUtility.Redirect(url, SPRedirectFlags.Trusted, context);
}
}
}
To register the HttpModule you will need to edit the web.config of the Web Application that it will run in.
In the /Configuration/system.webServer/modules path add the following
<add name="SessionMissingRedirectHttpModule" type="PhoenixHR.Global.SessionMissingRedirectHttpModule, PhoenixHR.Global,Version=1.0.0.0,Culture=neutral,PublicKeyToken=a0bd8fabe3543dc0" />
There are some best guesses for paths to the required application pages so you may need to alter the variables to suit.

Call StaticFileHandler

I have an HttpHandler mapped to aspnet_isapi.dll to perform a custom authentication check on static files (.pdf files) using IIS 7.5 in Classic mode:
void IHttpHandler.ProcessRequest(HttpContext context)
{
if(!User.IsMember) {
Response.Redirect("~/Login.aspx?m=1");
}
else {
//serve static content
}
}
The above code works fine, except for the else statement logic. In the else statement, I simply want to allow the StaticFileHandler to process the request, but I haven't been able to sort this out. Any suggestions on how to simply "hand off" the file back to IIS to serve the request as a normal StaticFile request, would be appreciated.
To answer your question directly, you can create a StaticFileHandler and have it process the request:
// Serve static content:
Type type = typeof(HttpApplication).Assembly.GetType("System.Web.StaticFileHandler", true);
IHttpHandler handler = (IHttpHandler)Activator.CreateInstance(type, true);
handler.ProcessRequest(context);
But a better idea might be to create an HTTP module instead of an HTTP handler:
public class AuthenticationModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication application)
{
application.AuthorizeRequest += this.Application_AuthorizeRequest;
}
private void Application_AuthorizeRequest(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
if (!User.IsMember)
context.Response.Redirect("~/Login.aspx?m=1");
}
}

Idiomatic way to throw exceptions to a delegate

I have a monitor class which monitors a device and reports if that device successfully receives usable data. This can happen anytime.
A client creates its own monitor by passing delegates, starts it and waits for either the successfully read data or a kind of domain specific exception type (one base exception type)
What would be the idiomatic way of throwing subtypes of the base exception type and enable the client to respond to each subtype individually?
public class MyMonitor
{
private SuccessHandler _successHandler;
private ErrorHandler _errorHandler;
public delegate void SuccessHandler(MyDTO result);
public delegate void ErrorHandler(MyBaseException exception);
public MyMonitor(SuccessHandler successHandler, ErrorHandler errorHandler) {
_successHandler = successHandler;
_errorHandler = errorHandler;
}
public void start() {
try {
_successHandler(new MyDTP().doSomethingRisky());
} catch(Exception e) {
_errorHandler(e);
}
}
}
public class Client {
static void Main(string[] args) {
MyMonitor monitor = new MyMonitor(new MyMonitor.SuccessHandler(handleSuccess), new MyMonitor.ErrorHandler(handleException));
monitor.start();
}
static void handleSuccess(MyDTO result) {
// do something with result
}
static void handleException(MyBaseException e) {
try {
throw e;
} catch(UserException mbe) {
// present message to user
} catch(DataNotFoundException se) {
// log error and show generic error message
} catch(UnexpectedException ue) {
// log error and try to hide it from the user
}
}
}
So, why don't you handle the exceptions in your main instead of the monitor-class?
If that isn't an option, you have (at least) two alternatives:
static void handleException(MyBaseException e)
{
if (e is UserException)
{
// present message to user
}
else if (e is DataNotFoundException)
{
// log error and show generic error message
}
elseif (e is UnexpectedException)
{
// log error and try to hide it from the user
}
else
{
// might want to rethrow the exception, do a general handling,...
}
}
That way you don't have to rethrow the exception, just to catch it again.
But this can get ugly if you have many subtypes to handle and here is where multidispatch comes in.
static void HandleException(MyBaseException e)
{
HandleSubException((dynamic)e);
}
static void HandleSubException(MyBaseException e)
{
// might want to rethrow the exception, do a general handling,...
}
static void HandleSubException(DataNotFoundExceptione)
{
// log error and show generic error message
}
static void HandleSubException(UnexpectedException e)
{
// log error and try to hide it from the user
}
static void HandleSubException(UserExceptione)
{
// present message to user
}
Now you can tend to each exception in its own method and is much easier to read and maintain.
Having said that, I'm not entirely sure if this falls under best practice.

Categories

Resources