Httphandler for WebDav requests - asp.net

I am trying to write a asp.net httphandler for handling webdav requests with IIS.
I am extending the IHttpHandler interface and implementing the ProcessRequest.
public class clsMyHandler : IHttpHandler
{
public void ProcessRequest(System.Web.HttpContext context)
{
StreamWriter sw = new StreamWriter(#"C:\requestLog.txt",true);
sw.WriteLine("Got a request at " + DateTime.Now.ToString());
sw.Close();
}
public bool IsReusable
{
get
{
return true;
}
}
}
It's a simple handler for my test purpose to just log into a file when I get the webdav request for a file of given name. I can see the handler listed in the Handler mappings.
This is the web.config
<handlers>
<add name="testhandler" verb="*" path="*e.txt" type="MyPipeLine.clsMyHandler, MyPipeLine" />
</handlers>
It works fine when the request is a http from browser. My handler gets executed and logs in the file. But when the request is webdav(I have enabled webdav with IIS and mapped the website root as a network drive) editing a file of the pattern *e.txt fails which I would expect as I am overriding the webdav handler, but I do not see it getting logged in my file.
I am not sure if there is a server log that I can check to get some clue as to whether or not the handler was invoked and if there is an error in the handler. I am new to this.
I am not finding much materials/guides online regarding httphandlers for webdav.
Appreciate any help.

Related

Basic custom Http Handler is not even executed

I am trying to learn about the custom Http Handlers. Using VS2019 Community, I created the default ASP.NET Web App with MVC option, target for .NET Framework 4.7.2. Then I defined the custom Http Handler as
namespace WebApplication25
{
public class CustomHandler : IHttpHandler
{
public bool IsReusable
{
get
{
return true;
}
}
public void ProcessRequest(HttpContext context)
{
context.Response.Write("<h1>WelCome</h1>");
}
}
}
In the file Web.config
<system.webServer>
<handlers>
<add verb="*" path="*.curry" name="CustomHandler" type="WebApplication25.CustomHandler"/>
</handlers>
</system.webServer>
Then during the standard run with localhost I enter
https://localhost:44325/notes.curry
but the code for CustomHandler is not even run. In the browser I get
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404.....

HTTP modules and HTTP handlers in ASP.Net MVC?

I was asked a question in interview that how to implement HTTP module and HTTP handler in ASP.Net MVC. I know that they are used in ASP.Net to write pre-processing logic before the aspx page is called. But in ASP.Net MVC we have filters for that so i told them we use Filters for that. Did i gave the right answer?
Action Filters allow you to hook into MVC specific events only, whereas HTTP Modules allow you to hook into ASP.Net events. So even in MVC, to implement a HTTP Module and HTTP handler, you will need to implement corresponding interface.
If you want your functionality to only be executed once per Http Request, you should use an HttpModule.
ActionFilters may be executed several times in a single trip to the server.
To explain HTTP Modules and HTTP Handlers, HTTP module and HTTP handler are used by MVC to inject pre-processing logic in the request chain.
HTTP Handlers are extension based pre-processor whereas HTTP Module are event based preprocessor.
For example: if you want to change how jpg files are processed, you will implement custom HTTP handler versus if you want to execute additional logic during processing of the request, you will implement a custom HTTP module. There is always only one HTTP handler for a specific request but there can be multiple HTTP modules.
To Implement an HTTP Handler:
You implement IHttpHandler class and implement ProcessRequest method and IsResuable property. IsResuable property determines whether handler can be reused or not.
public class MyJpgHandler: IHttpHandler
{
public bool IsReusable => false;
public void ProcessRequest(HttpContext context)
{
// Do something
}
}
Next we need to specify which kind of request will be handled by our custom handler in web.config file:
<httpHandlers>
<add verb="*" path="*.jpg" type="MyJpgHandler"/>
</httpHandlers>
To implement an HTTP module:
We need to implement IHttpModule and register the required events in Init method. As a simple example, if we wanted to log all requests:
public class MyHttpModule: IHttpModule
{
public MyHttpModule() {}
public void Init(HttpApplication application)
{
application.BeginRequest += new EventHandler(this.context_BeginRequest);
application.EndRequest += new EventHandler(this.context_EndRequest);
}
public void context_BeginRequest(object sender, EventArgs e)
{
StreamWriter sw = new StreamWriter(# "C:\log.txt", true);
sw.WriteLine("Request began at " + DateTime.Now.ToString());
sw.Close();
}
public void context_EndRequest(object sender, EventArgs e)
{
StreamWriter sw = new StreamWriter(# "C:\log.txt", true);
sw.WriteLine("Request Ended at " + DateTime.Now.ToString());
sw.Close();
}
public void Dispose() {}
}
And register our module in web.config file:
<httpModules>
<add name="MyHttpModule " type="MyHttpModule " />
</httpModules>

HttpModule isn't processing request authentication

I have an HttpHandler that I'm trying to use to put a little security layer over a certain directory in my site, but it's behaving strangely.
I've got it registered like this in my Web.Config: no longer valid since I'm in IIS 7.5
<httpHandlers>
<add verb="*" path="/courses/*" type="CoursesAuthenticationHandler" />
I can't tell if it's actually being called or not, because regardless of the code, it always seems to do nothing. On the flip side, if there are any errors in the code, it does show me an error page until I've corrected the error.
Here's the handler itself:
using System;
using System.Web;
public class CoursesAuthenticationHandler : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
if (!context.Request.IsAuthenticated)
context.Response.Redirect("/");
}
}
So... that's pretty much it. The handler is being registered and analyzed at compile time, but doesn't actually do what it's expected to.
Edit: I realized that I'm using IIS 7.5 and that does indeed have an impact on this implementation.
For IIS 7, here's the Web.Config registration I used:
<handlers accessPolicy="Read, Execute, Script">
<add name="CoursesAuthenticationHandler"
verb="*"
path="/courses/*"
type="CoursesAuthenticationHandler"
resourceType="Unspecified" />
Edit 2: Progress! When not logged in, requests made to the /courses/ directory are redirected to the login page. However, authenticated requests to the /courses/ directory return empty pages...
Edit 3: Per #PatrickHofman's suggestion, I've switched to using an HttpModule.
The Web.Config registration:
<modules>
<add name="CourseAuthenticationModule" type="CourseAuthenticationModule" />
The code:
using System;
using System.Web;
public class CourseAuthenticationModule : IHttpModule
{
public void Dispose() { }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(BeginRequest);
}
public void BeginRequest(Object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpContext context = app.Context;
HttpRequest request = context.Request;
HttpResponse response = context.Response;
if (request.Path.ToLower().StartsWith("/courses/") && !request.IsAuthenticated)
{
response.Redirect("/");
}
}
}
Now the problem is that !request.IsAuthenticated is always false. If I'm logged in, and navigate to the /courses/ directory, I'm redirected to the homepage.
What's the deal?
I think the last problem lies in the fact that a HttpHander handles stuff. It is the end point of a request.
Since you didn't add anything to the request, the response will end up empty.
Are you looking for HttpModules? They can be stacked.
As a possible solution when only files are necessary: read the files yourself in the request by either reading and writing to response or use TransmitFile. For ASP.NET pages you need modules.

Logging server-wide request data (including POST data) in IIS 6 / ASP.NET webforms

Here's the big picture. We're running a server in IIS 6 that hosts several web sites and applications, and we're in the process of moving the whole thing to a different data center with a slightly different setup. We've notified our users and updated our DNS info so that theoretically everyone will be happily hitting the new server from day 1, but we know that someone will inevitably fall through the cracks.
The powers that be want a "Listener" page/handler that will receive all requests to the server and log the entire request to a text file, including (especially) POST data.
That's where I'm stuck. I don't know how to implement a single handler that will receive all requests to the server. I vaguely understand IIS 6 redirection options, but they all seem to lose the POST data on the redirect. I also know a little about IIS 6's built-in logging, but it ignores POST data as well.
Is there a simple(ish) way to route all requests to the server so that they all hit a single handler, while maintaining post data?
EDIT: This is in WebForms, if that matters, but other solutions (if small) are definitely worth considering.
If all the requests are POST's to ASP.NET forms then you could plugin a HttpModule to capture and log this data.
You wouldn't have to rebuild all your applications to deploy this either. All it would take is to drop the HttpModule into each application's /bin folder and add it to the <httpModules> section of your web.config files. For example:
using System;
using System.Diagnostics;
using System.Web;
public class SimpleLogger : IHttpModule
{
private HttpApplication _application;
public void Dispose() { }
public void Init(HttpApplication context)
{
_application = context;
context.BeginRequest += new EventHandler(Context_BeginRequest);
}
void Context_BeginRequest(object sender, EventArgs e)
{
foreach (string key in _application.Request.Form.AllKeys)
{
// You can get everything on the Request object at this point
// Output to debug but you'd write to a file or a database here.
Debug.WriteLine(key + "=" + _application.Request.Form[key]);
}
}
}
In your web.config file add the logger:
<httpModules>
<add name="MyLogger" type="SimpleLogger, SimpleLogger"/>
</httpModules>
Be careful though. If your site captures credit card details or other sensitive data. You may need to ensure this is filtered out or have it encrypted and away from personel who should have no need to see this information.
Also if you're logging to files, make sure the log files are outside any public facing web folders.
Here is code of custom HTTP module we use to log HTTP POST request data.
using System;
using System.Web;
namespace MySolution.HttpModules
{
public class HttpPOSTLogger : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
private void context_BeginRequest(object sender, EventArgs e)
{
if (sender != null && sender is HttpApplication)
{
var request = (sender as HttpApplication).Request;
var response = (sender as HttpApplication).Response;
if (request != null && response != null && request.HttpMethod.ToUpper() == "POST")
{
var body = HttpUtility.UrlDecode(request.Form.ToString());
if (!string.IsNullOrWhiteSpace(body))
response.AppendToLog(body);
}
}
}
}
}
Do not forget to register it in web.config of you application.
Use system.WebServer section for IIS Integrated Model
<system.webServer>
<modules>
<add name="HttpPOSTLogger" type="MySolution.HttpModules.HttpPOSTLogger, MySolution.HttpModules" />
</modules>
</system.webServer>
Use system.web section for IIS Classic Model
<system.web>
<httpModules>
<add name="HttpPOSTLogger" type="MySolution.HttpModules.HttpPOSTLogger, MySolution.HttpModules"/>
</httpModules>
</system.web>
IIS log Before applying module:
::1, -, 10/31/2017, 10:53:20, W3SVC1, machine-name, ::1, 5, 681, 662, 200, 0, POST, /MySolution/MyService.svc/MyMethod, -,
IIS log After applying module:
::1, -, 10/31/2017, 10:53:20, W3SVC1, machine-name, ::1, 5, 681, 662, 200, 0, POST, /MySolution/MyService.svc/MyMethod, {"model":{"Platform":"Mobile","EntityID":"420003"}},
Full article:
https://www.codeproject.com/Tips/1213108/HttpModule-for-logging-HTTP-POST-data-in-IIS-Log

Are HttpModules utilized when a .Net web service is called through the javascript proxy (AJAX)?

I am making our large set of web services available to AJAX calls. I have added the [System.Web.Script.Services.ScriptService] to each service. We have a registered HttpModule that initializes some objects we use regularly for logging and internationalization in the IHttpModule.Init override. It appears that the IHttpModule.Init is called when I make a SOAP request to any web method, but not when I make a JSON request to any web method. I've confirmed this by writing to a file when it's called.
Are HttpModules utilized when a .Net web service is called through the javascript proxy (AJAX)? If so, am I lacking some sort of configuration? Relevant code bits included below.
-colin-
Web.config:
<httpModules><add name="GlobalApplicationModule" type="Common.GlobalApplicationModule, Common"/></httpModules>
HTTPModules.cs:
class GlobalApplicationModule : IHttpModule
{
public void Dispose()
{
Internationalization.LanguageProvider.ReleaseAllResources();
}
public void Init(HttpApplication application)
{
// DEBUG: Confirm that this method is called
StreamWriter writer = new StreamWriter("c:\\deleteme-HTTP_module_test.txt");
writer.WriteLine("Init called.");
writer.Close();
// Initialize logger
Common.Logger.Initialize("LogAssemblyPath", "LogClassName");
Common.CentralConfiguration.CreateConfiguration(new Common.CentralizedStrategy());
// Initialize language provider
if (!Internationalization.LanguageProvider.Initialized)
{
try
{
string debug = System.Configuration.ConfigurationManager.AppSettings["debugInternationalization"];
string languageAssemblyLocation = System.Configuration.ConfigurationManager.AppSettings["LanguageAssemblyLocation"];
string languageAssemblyBaseName = System.Configuration.ConfigurationManager.AppSettings["LanguageAssemblyBaseName"];
languageAssemblyLocation = System.Web.HttpContext.Current.Server.MapPath(languageAssemblyLocation);
Internationalization.LanguageProvider.Init(languageAssemblyLocation, languageAssemblyBaseName, false);
if (debug != null && bool.Parse(debug))
{
Internationalization.LanguageProvider.PrefixText = "*";
}
}
catch (Exception x)
{
Common.Logger.Instance.LogError("Could not intialize assembly language provider. Error: " + x.Message);
}
}
}
}
That's a very odd debug logging method... Your problem is most likely due to your IIS configuration. It sounds like IIS is not handing off the request to ASP.NET at all. Check your mappings.

Resources