I know we could simply use an app_offline.htm file to do this.
But I want to be able access the website if my IP is 1.2.3.4 (for example), so that I can do a final testing.
if( IpAddress != "1.2.3.4" )
{
return Redirect( offlinePageUrl );
}
How can we implement this in ASP.NET MVC 3?
You can use a catch-all route with a RouteConstraint with the IP check:
Make sure you put the offline route first.
routes.MapRoute("Offline", "{controller}/{action}/{id}",
new
{
action = "Offline",
controller = "Home",
id = UrlParameter.Optional
},
new { constraint = new OfflineRouteConstraint() });
and the constraint code:
public class OfflineRouteConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
// return IpAddress != "1.2.3.4";
}
}
Per Max's suggestion here is an actual implementation.
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CheckForDownPage());
}
//the rest of your global asax
//....
}
public sealed class CheckForDownPage : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var path = System.Web.Hosting.HostingEnvironment.MapPath("~/Down.htm");
if (System.IO.File.Exists(path) && IpAddress != "1.2.3.4")
{
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.Redirect("~/Down.htm");
return;
}
base.OnActionExecuting(filterContext);
}
}
You can define a global filter that stop all the requests if they don't come from your IP. you can enable the filter by configuration.
I got an infinite loop on colemn615's solution, so I added a check for the offline page.
Also, for later versions of ASP.NET this is split into a FilterConfig.cs file in the App_Start folder.
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CheckForDownPage());
}
public sealed class CheckForDownPage : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (HttpContext.Current.Request.RawUrl.Contains("Down.htm"))
{
return;
}
var path = System.Web.Hosting.HostingEnvironment.MapPath("~/Down.htm");
if (System.IO.File.Exists(path) && IpAddress != "1.2.3.4")
{
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.Redirect("~/Down.htm");
return;
}
base.OnActionExecuting(filterContext);
}
}
I add an AppSetting in the Web.Config file:
<add key="MaintenanceMsg" value="We are currently performing some routine maintenance. We expect to be back up at around 01:00." />
I then update the global.asax file's Application_BeginRequest method to check if the appsetting has a value, if it does, I redirect everything to the maintenance page:
private void Application_BeginRequest(object sender, EventArgs e)
{
if(!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["MaintenanceMsg"]) && !Request.Url.ToString().Contains("UndergoingMaintenance"))
Response.Redirect("~/Home/UndergoingMaintenance");
** Do whatever you do when you don't want to show your maintenance page here**
}
Finally, create your view and controller action.
If you use Azure you can simply add and delete the value for the AppSetting in the portal so you can suspend your site in a matter of minutes without a deployment.
Related
I've a custom AuthorizeAttribute in my website. It has some logic about the Result created for unathorized requests.
In some cases, I want to trigger its validation manually*. I don't know if its possible. As I haven't found how to do that, I thought that I could extract the logic to get the Result to a diferrent method, and call it when I want. But then I don't know how to execute the ActionResult (outside de controllers).
How can I do to manually execute authorize validation? If not possible, how can I do to execute an ActionResult outside a controller?
*I need to trigger it manually because some request may pass the validation (because the session is created) and then, when accessing my services, found that the session was closed by someone else. I wouldn't like to add a call to the services in OnAuthorization to reduce services calls.
I'm not sure if its the best, but I've found a way to get it working (still listening for better answers).
When I call the services and notice that the work session has expired, all I do is removing the active user in the web session.
My custom authorize attribute also implements IResultFilter and IExceptionFilter.
In both OnResultExecuted and OnException I validate the active user once more. If the session was removed, then apply the same ActionResult that I would apply in OnAuthorization.
Here is the final class:
public class CustomAuthorizeAttribute : AuthorizeAttribute, IResultFilter, IExceptionFilter
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
ActionResult result = Validate(filterContext.HttpContext);
if (result != null)
filterContext.Result = result;
}
public void OnResultExecuted(ResultExecutedContext filterContext)
{
ActionResult result = Validate(filterContext.HttpContext);
if (result != null)
filterContext.Result = result;
}
public void OnResultExecuting(ResultExecutingContext filterContext)
{
}
public void OnException(ExceptionContext filterContext)
{
ActionResult result = Validate(filterContext.HttpContext);
if (result != null)
{
filterContext.Result = result;
filterContext.ExceptionHandled = true;
}
}
public static ActionResult Validate(HttpContextBase httpContext)
{
if (UserActiveInSession)
return null;
// Different rules to build an ActionResult for this specific case.
}
}
I did not get Diego answer's, But Just simply answering the title, I got it to work like that, You can use it as attribute on controllers actions and also trigger it manually at any place in C# or in Razor views.
namespace SomeNameSpace
{
public class CustomAuthorizeAttributeMVC : AuthorizeAttribute
{
private readonly string[] rolesParams;
public CustomAuthorizeAttributeMVC(params string[] roles)
{
this.rolesParams = roles;
}
public bool IsAuthorized { get {
//Do your authorization logic here and return true if the current user has permission/role for the passed "rolesParams"
string[] allowedRoles = new string[] {"role 1", "role 2", "role 3"};
return allowedRoles.Intersect(rolesParams).Any(); //for the example
}
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return this.IsAuthorized;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
//...
}
}
public class AuthorizeHelper
{
public static bool HasPermission(params string[] roles)
{
return new CustomAuthorizeAttributeMVC(roles).IsAuthorized;
}
}
}
Usage example:
[CustomAuthorizeAttributeMVC("role 2")]
public ActionResult SomeAction()
{
return Content("Authorized !");
}
public ActionResult SomeOtherAction()
{
if(AuthorizeHelper.HasPermission("role 2"))
{
return Content("Authorized !");
}
return Content("401 Not Authorized !");
}
And as said, it can be used in Razor views by calling it normally
#if(AuthorizeHelper.HasPermission("role 2")) {
//...
}
Thanks
I made a functionality that prevents multiple-login for one username at the same time and I call it in Actions like this:
int userId = (int)WebSecurity.CurrentUserId;
if ((this.Session.SessionID != dba.getSessionId(userId)) || dba.getSessionId(userId) == null)
{
WebSecurity.Logout();
return RedirectToAction("Index", "Home");
}
So the point is that every time user logins I save his sessionID into database field. So if someone with same username logins over someone already logged in with same username it overwrites that database field with this new session. If sessionID in DB is not the same as current session ID of logined user it log him out.
Is there a possibility to put this part of code in 1 place or do I have to put it in every single Action in my application?
I tried in Global.asax:
void Application_BeginRequest(object sender, EventArgs e)
{
if (Session["ID"] != null)
{
int userId = Convert.ToInt32(Session["ID"]);
if ((this.Session.SessionID != db.getSessionId(userId)) || db.getSessionId(userId) == null)
{
WebSecurity.Logout();
}
}
}
But I can't use Session here nor WebSecurity class if I try like this:
void Application_BeginRequest(object sender, EventArgs e)
{
int userId = (int)WebSecurity.CurrentUserId;
if ((this.Session.SessionID != db.getSessionId(userId)) || db.getSessionId(userId) == null)
{
WebSecurity.Logout();
Response.RedirectToRoute("Default");
}
}
because I get null reference exception.
EDIT
I used this:
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
{
int userId = (int)WebSecurity.CurrentUserId;
using (var db = new UsersContext())
{
string s = db.getSessionId(userId);
if ((filterContext.HttpContext.Session.SessionID != db.getSessionId(userId)) || db.getSessionId(userId) == null)
{
WebSecurity.Logout();
filterContext.Result = new RedirectResult("/Home/Index");
}
}
}
I had to use using statement for context, otherwise db.getSessionId(userId) was returning old sessionId. Method is this:
public string getSessionId(int userId)
{
string s = "";
var get = this.UserProfiles.Single(x => x.UserId == userId);
s = get.SessionId;
return s;
}
Very strange, will have to read about why that happened.
Everything works fine, except one thing. I have one JsonResult action in a controller, which returns Json, but since event(its textbox on enter event) can't trigger POST(I assume it's because it logs out before) redirect doesn't work. It can't even post to that Json action to receive callback and redirect. Any clues on that?
success: function (data) {
if (data.messageSaved) {
//data received - OK!
}
else {
// in case data was not received, something went wrong redirect out
window.location.href = urlhome;
}
}
Before I used ActionFilterAttribute I used code to check different sessions inside of POST and of course it could make callback and therefore redirect if didn't receive the data.. But now since it can't even POST and go into method it just stucks there and doesn't redirect :)
I would derive from AuthorizeAttribute. No need to check this information if you don't need to authorize the request.
public class SingleLoginAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool isAuthorized = base.AuthorizeCore(httpContext);
if (isAuthorized)
{
int userId = (int)WebSecurity.CurrentUserId;
if ((filterContext.HttpContext.Session.SessionID != dba.getSessionId(userId))
|| dba.getSessionId(userId) == null)
{
WebSecurity.Logout();
isAuthorized = false;
filterContext.Result = new RedirectResult("/Home/Index");
}
}
return isAuthorized;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult()
{
Data = FormsAuthentication.LoginUrl,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
I'd also mention that this allows you to short circuit other ActionFilters because they run after OnAuthorization.
Forward Order - OnAuthorization : AuthorizationFilter (Scope Controller)
Forward Order - OnActionExecuting : ActionFilter1 (Scope Global)
Forward Order - OnActionExecuting : ActionFilter2 (Scope Controller)
Forward Order - OnActionExecuting : ActionFilter3 (Scope Action)
Then as Rob Lyndon mentioned, you could in the FilterConfig (MVC4)
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new SingleLoginAuthorizeAttribute());
}
}
Then when you don't want to require any authorization, you can use the AllowAnonymouseAttribute on your ActionResult methods or Controller Class to allow anonymous access.
Update
I added a way for your ajax calls (Get or Post) to work with timeouts. You can do something like:
success: function (jsonResult)
{
if (jsonResult.indexOf('http') == 0)
{
window.location = jsonResult;
}
// do other stuff with the Ajax Result
}
This isn't exactly the best way, but if you want more information on how to do this better I would ask another question instead of appending more questions on this one.
The ActionFilterAttribute is the way to go.
We created an Action Filter called SeatCheck and decorate each controller like this:
[SeatCheck]
public class NoteController : BaseController
{
We use that to get a count of seats and other functions, but it makes it so much easier to control everywhere without thinking about it.
In the proejct ActionFilters folder we have the SeatCheck.cs file that looks like this:
namespace site.ActionFilters
{
public class SeatCheckAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
You can get the SessionID in the Action Filter like this
filterContext.HttpContext.Session.SessionID
Create a custom action filter, and put that code in the filter, then apply the filter to your controller.
Yes, indeed there is. You can use an attribute derived from ActionFilterAttribute.
I would write a class called SessionSecurityAttribute:
public class SessionSecurityAttribute : ActionFilterAttribute
{
public MyDbConn MyDbConn { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var session = filterContext.RequestContext.HttpContext.Session;
if (session["ID"] != null && WebSecurity.IsAuthenticated)
{
int userId = Convert.ToInt32(session["ID"]);
if ((sessionID != MyDbConn.getSessionId(userId)) || MyDbConn.getSessionId(userId) == null)
{
WebSecurity.Logout();
}
}
}
}
The question remains: how can you add these attributes to your actions whilst giving them access to your database? That's easy: in Global.asax you can call into the bootstrapping RegisterGlobalFilters method:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new SessionSecurityAttribute
{
MyDbConn = DependencyResolver.Current.GetService<MyDbConn>()
});
}
This adds your SessionSecurityAttribute, complete with DB connection, to every action by default, without a line of repeated code.
You might try implementing your own custom ISessionIDManager:
http://msdn.microsoft.com/en-us/library/system.web.sessionstate.isessionidmanager.aspx
In the validate, check to see if it's still valid, otherwise return false.
Additional:
Download my project with my failed attempt at converting to AttributeRouting.
The project will run correctly when the message on the home page changes between "No new email." and "You have mail!". In its current errored state that message does not change.
Errors in the javascript console will show.
Navigating directly to /Checkemail with the browser results in 404 error.
Original Post:
This is a question about AttributeRouting (using latest v3.4.1).
I am trying to hook a GET[""] onto the following code.
[GET("")] I get a 404 - resource not found.
[GET("CheckEmail")] I get a 405 - Method not allowed.
I am trying to convert this project to AttributeRouting: source code. The checkemail action is where I am failing.
The method is an asynchronous method as part of an "ajax long polling" technique.
I have the following with my dismal attempts commented:
public class CheckEmailController : AsyncController
{
//
// GET: /CheckEmail/
//tried [GET("")]
//tried [GET("CheckEmail")]
public void IndexAsync()
{
AsyncManager.OutstandingOperations.Increment();
MyAsyncEmailChecker.CheckForEmailAsync(hasEmail =>
{
AsyncManager.Parameters["hasEmail"] = hasEmail;
AsyncManager.OutstandingOperations.Decrement();
});
}
private class IndexResponse
{
public bool d { get; set; }
}
public JsonResult IndexCompleted(bool hasEmail)
{
return this.Json(new IndexResponse() { d = hasEmail });
}
}
Global.asax.cs - as for all my AR projects
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
thank you
If you are on ASP.NET MVC 4 and .NET 4.5 then you should just use the async keyword and Tasks. This should fix your issue with routing and reduce the complexity in your controllers. Here is the a link to whitepaper by microsoft.
http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4
but to sum it up your code would change to this.
public class CheckEmailController : AsyncController
{
//
// GET: /CheckEmail/
[GET("CheckEmail")]
public async Task<ActionResult> Index()
{
return View( new IndexReponse {
d = await MyAsyncEmailChecker.CheckForEmailAsync()
});
}
public class IndexResponse
{
public bool d { get; set; }
}
}
This has had me stumped for a while. None of the commonly encountered similar situations seem to apply here apparently. I've probably missed something obvious but I can't see it.
In my Mvc Web Application I use the Authorize and AllowAnonymous attributes in such a way that you have to explicitly open up an action as publicly available rather than lock down the secure areas of the site. I much prefer that approach. I cannot get the same behaviour in my WebAPI however.
I have written a custom Authorization Attribute that inherits from System.Web.Http.AuthorizeAttribute with the following:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class MyAuthorizationAttribute : System.Web.Http.AuthorizeAttribute
I have this registered as a filter:
public static void RegisterHttpFilters(HttpFilterCollection filters)
{
filters.Add(new MyAuthorizationAttribute());
}
This all works as expected, actions are no longer available without credentials. The problem is that now the following method will not allow the AllowAnonymous attribute to do it's thing:
[System.Web.Http.AllowAnonymous]
public class HomeController : ApiController
{
[GET("/"), System.Web.Http.HttpGet]
public Link[] Index()
{
return new Link[]
{
new SelfLink(Request.RequestUri.AbsoluteUri, "api-root"),
new Link(LinkRelConstants.AuthorizationEndpoint, "OAuth/Authorize/", "authenticate"),
new Link(LinkRelConstants.AuthorizationTokenEndpoint , "OAuth/Tokens/", "auth-token-endpoint")
};
}
}
The most common scenario seems to be getting the two Authorize / AllowAnonymous attributes mixed up. System.Web.Mvc is for web apps and System.Web.Http is for WebAPI (as I understand it anyway).
Both of the Attributes I'm using are from the same namespace - System.Web.Http. I assumed that this would just inherit the base functionality and allow me to inject the code I need in the OnAuthotize method.
According to the documentation the AllowAnonymous attribute works inside the OnAuthorize method which I call immediately:
public override void OnAuthorization(HttpActionContext actionContext)
{
base.OnAuthorization(actionContext);
Any thought's would be really appreciated.
Has anyone encountered this problem before and found the root cause?
In the AuthorizeAttribute there is the following code:
private static bool SkipAuthorization(HttpActionContext actionContext)
{
Contract.Assert(actionContext != null);
return actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()
|| actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
}
Include this method in your AuthorizeAttribute class then add the following to the top of your OnAuthorization method to skip authorization if any AllowAnonymous attributes are found:
if (SkipAuthorization(actionContext)) return;
ASP.NET MVC 4:
bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)
|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
or
private static bool SkipAuthorization(AuthorizationContext filterContext)
{
Contract.Assert(filterContext != null);
return filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any()
|| filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any();
}
Soruce: http://weblogs.asp.net/jongalloway/asp-net-mvc-authentication-global-authentication-and-allow-anonymous
In my case, none of the above solutions worked.
I am using .Net Core 3.1 with a custom IAuthorizationFilter and I had to do the following:
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context.ActionDescriptor.EndpointMetadata.OfType<AllowAnonymousAttribute>().Any()) return;
Using MVC 5
Steps to overcome this issue:-
1. Update your Anonymous attribute of WebAPI project and make it like
[System.Web.Mvc.AllowAnonymous]
Now go to your custom attribute class and write the code
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext filterContext)
{
if (filterContext == null)
{
throw new UnauthorizedAccessException("Access Token Required");
}
base.OnAuthorization(filterContext);
if (filterContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
{
return;
}
if (filterContext.Request.Headers.Authorization != null)
{
var response =
PTPRestClient.GetRequest(filterContext.Request.Headers.Authorization.ToString(),
"api/validate/validate-request");
if (!response.IsSuccessStatusCode)
{
throw new UnauthorizedAccessException();
}
}
else
{
throw new UnauthorizedAccessException("Access Token Required");
}
}
Using C#6.0
Create a static class that extends the ActionExecutingContext.
public static class AuthorizationContextExtensions {
public static bool SkipAuthorization(this ActionExecutingContext filterContext) {
Contract.Assert(filterContext != null);
return filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any()|| filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any();
}
}
Now your override filterContext will be able to call the extension method, just make sure they are in the same namespace, or include the proper using statement.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeCustomAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext.SkipAuthorization()) return;// CALL EXTENSION METHOD
/*NOW DO YOUR LOGIC FOR NON ANON ACCESS*/
}
}
Here is a solution for ASP.NET Core 2+ and ASP.NET Core 3+.
Add it into IAsyncAuthorizationFilter implementation:
private static bool HasAllowAnonymous(AuthorizationFilterContext context)
{
var filters = context.Filters;
return filters.OfType<IAllowAnonymousFilter>().Any();
}
And check like this:
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if(HasAllowAnonymous(context))
return;
}
I must be using a different version of the .net framework or web api but hopefully this helps someone:
bool skipAuthorization = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any() || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
if (skipAuthorization)
{
return;
}
public class MyAuthorizationAuthorize : AuthorizeAttribute, IAuthorizationFilter
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) ||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
if (skipAuthorization) return;
}
else filterContext.Result = new HttpUnauthorizedResult();
}
}
Is there a way for me to catch all incoming requests to my ASP.NET MVC 4 app and run some code before continuing the request onward to the specified controller/action?
I need to run some custom auth code with existing services, and to do this properly, I'll need to be able intercept all incoming requests from all clients to double check some things with the other service.
The most correct way would be to create a class that inherits ActionFilterAttribute and override OnActionExecuting method. This can then be registered in the GlobalFilters in Global.asax.cs
Of course, this will only intercept requests that actually have a route.
You can use a HttpModule to accomplish this. Here is a sample I use to calculate the process time for all requests:
using System;
using System.Diagnostics;
using System.Web;
namespace Sample.HttpModules
{
public class PerformanceMonitorModule : IHttpModule
{
public void Init(HttpApplication httpApp)
{
httpApp.BeginRequest += OnBeginRequest;
httpApp.EndRequest += OnEndRequest;
httpApp.PreSendRequestHeaders += OnHeaderSent;
}
public void OnHeaderSent(object sender, EventArgs e)
{
var httpApp = (HttpApplication)sender;
httpApp.Context.Items["HeadersSent"] = true;
}
// Record the time of the begin request event.
public void OnBeginRequest(Object sender, EventArgs e)
{
var httpApp = (HttpApplication)sender;
if (httpApp.Request.Path.StartsWith("/media/")) return;
var timer = new Stopwatch();
httpApp.Context.Items["Timer"] = timer;
httpApp.Context.Items["HeadersSent"] = false;
timer.Start();
}
public void OnEndRequest(Object sender, EventArgs e)
{
var httpApp = (HttpApplication)sender;
if (httpApp.Request.Path.StartsWith("/media/")) return;
var timer = (Stopwatch)httpApp.Context.Items["Timer"];
if (timer != null)
{
timer.Stop();
if (!(bool)httpApp.Context.Items["HeadersSent"])
{
httpApp.Context.Response.AppendHeader("ProcessTime",
((double)timer.ElapsedTicks / Stopwatch.Frequency) * 1000 +
" ms.");
}
}
httpApp.Context.Items.Remove("Timer");
httpApp.Context.Items.Remove("HeadersSent");
}
public void Dispose() { /* Not needed */ }
}
}
And this is how you register the module in Web.Config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="PerformanceMonitorModule" type="Sample.HttpModules.PerformanceMonitorModule" />
</modules>
<//system.webServer>
I think that what you search for is this:
Application_BeginRequest()
http://www.dotnetcurry.com/showarticle.aspx?ID=126
You put it in Global.asax.cs.
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Request.....;
}
I use this for debugging purposes but I am not sure how good solution it is for your case.
I'm not sure about MVC4 but I think it is fairly similar to MVC5. If you have created a new web project -> look in Global.asax and you should see the following line FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); in the method Application_Start().
RegisterGlobalFilters is a method in the file FilterConfig.cs located in the folder App_Start.
As #YngveB-Nilsen said ActionFilterAttribute is the way to go in my opinion. Add a new class that derives from System.Web.Mvc.ActionFilterAttribute. This is important because System.Web.Http.Filters.ActionFilterAttribute will fail with the following exception for example.
The given filter instance must implement one or more of the following
filter interfaces: System.Web.Mvc.IAuthorizationFilter,
System.Web.Mvc.IActionFilter, System.Web.Mvc.IResultFilter,
System.Web.Mvc.IExceptionFilter,
System.Web.Mvc.Filters.IAuthenticationFilter.
Example that writes the request to the debug window:
public class DebugActionFilter : System.Web.Mvc.ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
Debug.WriteLine(actionContext.RequestContext.HttpContext.Request);
}
}
In FilterConfig -> RegisterGlobalFilters -> add the following line: filters.Add(new DebugActionFilter());.
You can now catch all incoming requests and modify them.