Asp.net mvc 3 &引用;“停机维修”;Asp.net MVC web应用的页面

Asp.net mvc 3 &引用;“停机维修”;Asp.net MVC web应用的页面,asp.net-mvc-3,iis-7.5,httpmodule,action-filter,Asp.net Mvc 3,Iis 7.5,Httpmodule,Action Filter,我有以下要求 在web.config中设置一个值并启用维护模式 所有非ajax请求都应该显示一个自定义错误页面,http状态代码设置为503。应保留页面的url 所有ajax请求都应使用http状态代码503进行响应 我应该有机会对一个文件做一些基本的日志记录。如果他碰巧登录到应用程序,请记录url和用户身份 我正在使用ELMAH跟踪/记录所有未处理的异常。实现维护模式的机制不需要我不使用ELMAH 我已将“runAllManagedModulesForAllRequests”设置为true。

我有以下要求

  • 在web.config中设置一个值并启用维护模式
  • 所有非ajax请求都应该显示一个自定义错误页面,http状态代码设置为503。应保留页面的url
  • 所有ajax请求都应使用http状态代码503进行响应
  • 我应该有机会对一个文件做一些基本的日志记录。如果他碰巧登录到应用程序,请记录url和用户身份
  • 我正在使用ELMAH跟踪/记录所有未处理的异常。实现维护模式的机制不需要我不使用ELMAH
  • 我已将“runAllManagedModulesForAllRequests”设置为true。这最初是用于RequestReduce的。我们不再使用它,但我不愿意将其值重置为false。我不确定是否有其他图书馆需要它
一旦我意识到没有支持上述要求的内置功能,我就觉得我面前有以下两个选项(App_offile.html对我不起作用)

  • HttpModule
  • MVC
    ActionFilter
我放弃了MVC
ActionFilter
,因为我不知道如何保证它在任何身份验证/授权过滤器之前运行。我有一个自定义的身份验证过滤器,它可以访问数据库。维护模式背后的想法是db可能处于脱机状态,但web应用程序不应该显示500个自定义错误页面,而应该显示503个自定义错误页面

我编写了以下
httpmodule
,并将其添加到我的web.config中。它适用于ajax请求。它对非ajax请求有点有效。所有请求都被重定向到503错误页面。副作用是所有对静态内容的请求也会导致503。因此,我的错误页面显示为非样式:(

这种方法的问题

  • 每个非ajax请求都会得到302和503的响应
  • 不保留浏览器请求的URL
  • 它还为所有静态资产返回503
  • 我编写的代码和启用的web.config设置都是从各种来源拼凑而成的。我不完全确定这些设置的作用或建议的方法是什么。请随意使用完全不同的方法回答,只要它能够满足所述要求

    // the http module
    
    public class MaintenanceModeModule : IHttpModule
    {
        private static bool _isUnderMaintenance;
        static MaintenanceModeModule()
        {
            var valueStr = (ConfigurationManager.AppSettings["UnderMaintenance"] ?? (false).ToString());
            bool underMaintenance;
            bool.TryParse(valueStr, out underMaintenance);
            _isUnderMaintenance = underMaintenance;
        }
    
        public void Init(HttpApplication application)
        {
            application.BeginRequest += OnBeginRequest;
        }
    
        private void OnBeginRequest(object sender, EventArgs e)
        {
            var application = (HttpApplication) sender;
            var request = application.Request;
            var response = application.Response;
    
            if (_isUnderMaintenance == false)
            {
                return;
            }
            application.Context.Items["under_maintenance"] = true; // used later
            if (request.Url.PathAndQuery == "/503") // the url of the action that renders the custom error page
            {
                return;
            }
    
            const int statusCode = (int) HttpStatusCode.ServiceUnavailable;
            const string statusMessage = "Temporarily down for maintenance";
    
            var requestWrapper = new HttpRequestWrapper(request);
            if (requestWrapper.IsAjaxRequest())
            {
                response.Clear();
                response.ClearContent();
                response.ClearHeaders();
                response.StatusCode = statusCode;
                response.TrySkipIisCustomErrors = true;
                response.StatusDescription = statusMessage;
                response.End();
                return;
            }
    
            // doesn't work, shows the Yellow Screen of Death (YSoD)
            // application.Context.Server.Transfer("~/503", preserveForm: true);
    
            // doesn't work, shows the Yellow Screen of Death (YSoD)
            // throw new HttpException(statusCode, statusMessage); 
    
            response.Redirect("~/503");
        }
    
        public void Dispose()
        {
    
        }
    }
    
    // web.config
    // only the relevant portions of each section is shown
    
    <appSettings>
        <add key="UnderMaintenance" value="true" />
    </appSettings>
    <customErrors mode="On">  <!-- Custom errors are on, even then I was seeing YSoDs during my attempts -->
        <error statusCode="404" redirect="404" />
        <error statusCode="503" redirect="503" />
    </customErrors>
    <system.webServer>
        <httpErrors existingResponse="PassThrough">
        </httpErrors>
        <modules runAllManagedModulesForAllRequests="true">
          <add name="MaintenanceMode" type="WebApp.Code.MvcInfrastructure.MaintenanceModeModule" />
        </modules>
    </system.webServer>
    
    // route config
    
    routes.MapRoute("503Error", "503", new { controller = "Error", action = "UnderMaintenance" });
    
    // error controller
    
    // the authentication filter skips authentication if the allowanonymous attribute is present
    [AllowAnonymous]
    public class ErrorController : CustomBaseController
    {
        public ErrorController(AppConfig appConfig)
            : base(appConfig)
        {
        }
    
        public ActionResult UnderMaintenance()
        {
            // behind the scenes reads the value from HttpContext.Items. 
            // This was set during the execution of the httpmodule
            if (AppConfig.UnderMaintenance == false) 
            {
                return new RedirectResult("~/");
            }
    
            Response.StatusCode = (int) HttpStatusCode.ServiceUnavailable;
            Response.TrySkipIisCustomErrors = true;
    
            // the actual content of the view is not relevant now
            return View("Error503");
        }
    }