HttpModule and WCF (AspNetCompatibilityRequirementsMode.Allowed) - c#

I'm hosting WCF services in Asp.net web page in ASP.NET Compatibility Mode
(AspNetCompatibilityRequirementsMode.Allowed). I've written simple HttpModule:
public class ExceptionInterceptor : IHttpModule
{
public ExceptionInterceptor()
{
}
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.Error += new EventHandler(context_Error);
}
void context_Error(object sender, EventArgs e)
{
// do something
}
}
web.config:
<httpModules>
<add name="ExceptionInterceptor" type="HttpModules.ExceptionInterceptor, HttpModules"/>
</httpModules>
My question is, why after occurence of unhandled exception in service, the code do not enter in context_Error(object sender, EventArgs e) function in my module.
What's more, the code do not even enter the Application_Error(object sender, EventArgs e) in Globals.asax.
Can someone explain that to me ?
What is the best option for global exception handling in WCF services ?
Regards

WCF is not ASP.NET - it might be able to use some of ASP.NET's infrastructure, but it's not ASP.NET per se.
In order to handle errors in a WCF service globally, you need to implement the IErrorHandler interface on your service - or plug in a WCF behavior that does this for you.
Check out the MSDN documentation on IErrorHandler - it's quite a simple interface, really. The HandleError method is typically used to log the error on the server to keep track of what's going on, while the ProvideFault method is used to turn the .NET exception on the server into an interoperable SOAP fault to send that back to the calling client (which might be a non-.NET client that can't really deal with a .NET-specific exception).
Rory Primrose has a great blog post about how to package up the IErrorHandler into a WCF service behavior which you can easily add to an existing service just in config - pretty close to magic :-) Also, check out another great post on the topic by Steve Barbour.

Related

Can httpModule "capture" outgoing http requests from a web API hosted on IIS?

I have created a class library test project that has one class which implements the IhttpModule interface.
I have a demo web api project that is hosted on my local IIS and has an HttpPost method which inside uses a class that makes outgoing Http requests at third parties.
As of now it works like a charm for the incoming requests but i want to catch every request that comes and goes from my API. I do not care about the responses.
I have already checked the requests made at the third parties and they are correct.
API's web.config :
<system.webServer>
<modules>
<add name="MyIISModule" type="IisTestProject.MyIISModule" />
</modules>
</system.webServer>
MyIISModule.cs :
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(OnBeginRequest);
}
private void OnBeginRequest(object sender, EventArgs e)
{
var app = (HttpApplication) sender;
File.AppendAllLines("C:\\requestHeaders.txt", new List<string>() {$"{DateTime.Now.ToOADate()}_{app.Context.Request.ToString()}" });
}
public void Dispose()
{
}
I made this so i can just check whenever a request happens.
Is there any way to do this without changing my API's code and using only my HttpModule?
Also i have found this:
HTTP modules can only see requests going through IIS/ASP.NET pipeline, while such outbound requests go through Windows sockets directly, and not through IIS/ASP.NET pipeline.
Is there any way to circumvent this?

End response in constructor

I want to do some checking in WCF before calling Operation.
My code is as below
public RESTService()
{
if (ConfigurationManager.AppSettings("BlockLogin") == "1")
{
HttpContext.Current.Response.Write("{""Status"" : ""Service under maintainance""}");
HttpContext.Current.Response.End()
}
}
I was expecting that it would end the request and won't call operation contract (getTokenX in this case) but it does. How to make it stop calling operation contract?
my URL is like
172.16.3.156:81/_RestAPI/RestService.svc/getTokenX
You could also use the Global.asax file to control the validity of the request.
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (Flag==true)
{
Response.End()
}
}
I don’t recommend using httpcontext in the wcf application. In most cases, It is set for the asp.net application domain and its value is empty.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/wcf-services-and-aspnet
I would suggest following thing for solution.
Create custom service behaviour.
In that service behaiour check for specific appsetting the way you do.
if you found some value that indicate service in maintainance then throw exception.

Where to implement Global.asax methods

I am working on an ASP.Net application and currently the Global.asax contains the usual 5 methods:
Application_Start
Application_End
Session_Start
Session_End
Application_Error
However, I needed to implement the Application_AuthenticateRequest method as well, which is not a problem, I have just added it in Global.asax but in an another application I have seen this method being implemented elsewhere in another class which implements the IHttpModule interface.
How is this possible? The same app does not have the Application_AuthenticateRequest in Global.asax, their Global.asax looks like this:
void Application_BeginRequest(object sender, EventArgs e)
{
myConfig.Init();
}
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
myConfig.Init();
if (InstallerHelper.ConnectionStringIsSet())
{
//initialize IoC
IoC.InitializeWith(new DependencyResolverFactory());
//initialize task manager
TaskManager.Instance.Initialize(NopConfig.ScheduleTasks);
TaskManager.Instance.Start();
}
}
void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown
if (InstallerHelper.ConnectionStringIsSet())
{
TaskManager.Instance.Stop();
}
}
What makes the Application_AuthenticateRequest method run?
I would first recommend you read about HTTP handlers and modules in ASP.NET. Then you will know that in an ASP.NET application you could have multiple modules registered which will run for every request and you have the possibility to subscribe to different events of the request lifecycle, the same way you could do it in Global.asax. The advantage of this approach is that you could put the modules into a reusable assembly that you use in multiple applications and which avoids you the need to repeat the same code over and over again.
Basically the example I have been looking at created their own HTTP module and registered it in the web.config file:
They have created a new HTTP module like this:
public class MembershipHttpModule : IHttpModule
{
public void Application_AuthenticateRequest(object sender, EventArgs e)
{
// Fires upon attempting to authenticate the user
...
}
public void Dispose()
{
}
public void Init(HttpApplication application)
{
application.AuthenticateRequest += new EventHandler(this.Application_AuthenticateRequest);
}
}
also added the below to the web.config file:
<httpModules>
<add name="MembershipHttpModule" type="MembershipHttpModule, App_Code"/>
</httpModules>
As explained in the #Darin Dimitrov's link above: Modules must be registered to receive notifications from the request pipeline. The most common way to register an HTTP module is in the application's Web.config file. In IIS 7.0, the unified request pipeline also enables you to register a module in other ways, which includes through IIS Manager and through the Appcmd.exe command-line tool.

Webservice/WCF (timer update engine)

I am trying to build (csharp) one webservice /WCF engine that make two actions:
Have one timer (thread), that will run in each 10-10 minutes, requesting some information (connecting with other server to grab some info - status) to update in one database. (This must be automatic and no human action will be available). The idea is the webservice automaticaly (10x10 minutes) update the database with the recent information status.
One service method that get some information from one database. (This is one simple method that gives the information when someone request it). This method will responsible to select the status info from database.
The problem is the step 1, because step 2 is very easy.
Can anyone help me, with ideas or some code, how to the step 1.
Any pattern should be used here?
Since it's a webapp (for instance, a "WCF Service Application" project type in VS2010), you can hook into the application events.
By default that project template type doesn't create a Global.asax, so you'll need to "add new item" and choose "Global Application Class" (it won't be available if you already have a Global.asax, FWIW).
Then you can just use the start and end events on the application to start and stop your timer, so something like:
public class Global : System.Web.HttpApplication
{
private static readonly TimeSpan UpdateEngineTimerFrequency = TimeSpan.FromMinutes(10);
private Timer UpdateEngineTimer { get; set; }
private void MyTimerAction(object state)
{
// do engine work here - call other servers, bake cookies, etc.
}
protected void Application_Start(object sender, EventArgs e)
{
this.UpdateEngineTimer = new Timer(MyTimerAction,
null, /* or whatever state object you need to pass */
UpdateEngineTimerFrequency,
UpdateEngineTimerFrequency);
}
protected void Application_End(object sender, EventArgs e)
{
this.UpdateEngineTimer.Dispose();
}
}
The Single Responsibility Principle suggests that you should split these two responsibilities into two services. One (a Windows Service) would handle the Timer. The second, the WCF Service, would have the single operation to query the database and return the data.
These are independent functions, and should be implemented independently.
Additionally, I would recommend against depending on IIS or Application_Start and similar methods. That will prevent your WCF service from being hosted in WAS or some other environment. Keep in mind that WCF is much more flexible than ASMX web services. It doesn't restrict where you host your service. You should think carefully before you place such restrictions on your own service.

Analyze the use of a ASP.NET webservice

long time ago I wrote webservice that is still in use. Now I plan to refactor it. The webservice is full of most likely unused functions and I have no idea how it is used by the clients. In order to strip away the unused functions I need to analyze the function calls and data of currently installed webservice.
Is there a (free/opensource) tool that will enable me to log all activities of the webservice.
The ideal output of the tool I'm looking for could be a database containing all the called functions and a list of the data that was send to it for each call.
Solution
With the help of Martins answer I created this HttpModule which does exactly what I wanted:
public class LoggingModule : IHttpModule
{
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(BeginRequest);
}
private void BeginRequest(object sender, EventArgs e)
{
TryAppendLog("Content-Type");
TryAppendLog("SOAPAction");
}
void TryAppendLog(string key)
{
string value = HttpContext.Current.Request.Headers[key];
if (string.IsNullOrEmpty(value)) { return; }
HttpContext.Current.Response
.AppendToLog(string.Format("{0}: {1} ", key, value));
}
#region IHttpModule Member
public void Dispose() { }
#endregion
}
As Kobi wrote, you can find the required information in the IIS log files (i.e. in c:\WINDOWS\system32\LogFiles\W3SVC1).
If you want to log the usage into a database, you could write a simple HttpModule, which checks every request, and logs it into the DB if it is a call to your web service.
E.g. here's the relevant parts of a very simple HttpModule, which logs calls to mywebservice.asmx:
public class MyWebServiceDiagnosticsModule : IHttpModule
{
public MyWebServiceDiagnosticsModule ()
{
}
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(BeginRequest);
}
private void BeginRequest(object sender, EventArgs e)
{
HttpContext ctx = HttpContext.Current;
string url = ctx.Request.Url.ToString().ToLower();
if (url.Contains("mywebservice.asmx"))
{
LogMethodCall(url); // parse URL and write to DB
}
}
}
You can potentially write your own IHttpHandler that would log all the information and then delegate the call to appropriate .NET HTTP Handler, but that wouldn't be a simple task.
And a word on terminology. "Refactoring" is not about changing external behavior, so if refactoring is really what you're heading for, I'd recommend to keep the public contract (interface) of the web service intact. Instead, roll out a new version of the same service with only core functionality.
You can enable logging in the IIS, they can get very detailed depending on your choices.
There are tools made specifically for analyzing IIS logs.
Depending a little bit on your load/criticality and similar constraints you could also probably just route the traffic through as Soap Proxy like SoapUI to capture and analyze traffic for a period of time. If you set up the proxy and re-route at the firewall level it should be transparent for end-users.
I have not tried this for a system with heavy load; be warned.

Categories