In my app, I am checking if some config file is available or not, if it's not then I want to redirect to install page.
在我的应用程序中,我正在检查是否有一些配置文件可用,如果不是,那么我想重定向到安装页面。
To me the best place to accomplish this is application_start
. Because it's happening for only one time. If I do the checking in application_start
and write Response.Redirect
I will get Response is not available in this context
.
对我来说,实现这一目标的最佳位置是application_start。因为它只发生了一次。如果我在application_start中进行检查并编写Response.Redirect,我将在此上下文中获得Response。
I tried other answers in stack overflow to redirect in application_start
like HttpContext.Current.Response.Redirect
; none worked for me.
我尝试了堆栈溢出中的其他答案,以便在application_start中重定向,如HttpContext.Current.Response.Redirect;没有人为我工作。
I don't want to do it in a base controller
or a filter
because the checking logic will happen for every single request.
我不想在基本控制器或过滤器中执行此操作,因为检查逻辑将针对每个请求发生。
My goal is to check it only once and it's best to be when the app start.
我的目标是只检查一次,最好是应用程序启动时。
Update 1
更新1
I added response.redirect to the application_start but got error like this:
我将response.redirect添加到application_start但是得到了如下错误:
application start:
申请开始:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Response.RedirectToRoute(
new RouteValueDictionary {
{ "Controller", "Home" },
{ "Action", "about" }
});
}
but i am receiving an error like this:
但我收到这样的错误:
Response is not available in this context.
在这种情况下无法获得响应。
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
描述:执行当前Web请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。
Exception Details: System.Web.HttpException: Response is not available in this context.
异常详细信息:System.Web.HttpException:响应在此上下文中不可用。
3 个解决方案
#1
3
If you really want to avoid having a filter run for every request after setup then you can do something like this:
如果您真的想避免在安装后为每个请求运行过滤器,那么您可以执行以下操作:
RedirectAttribute.cs (generic example)
RedirectAttribute.cs(通用示例)
public class RedirectAttribute : ActionFilterAttribute
{
private readonly string _controller;
private readonly string _action;
public RedirectAttribute(string controller, string action)
{
_controller = controller;
_action = action;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.ActionDescriptor.ActionName != _action ||
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName != _controller)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(new {controller = _controller, action = _action})
);
}
}
}
In Global.asax.cs above "FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);"
在Global.asax.cs上面的“FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);”
if (/*Insert logic to check if the config file does NOT exist*/)
{
//Replace "Setup" and "Index" with your setup controller and action below
GlobalFilters.Filters.Add(new RedirectAttribute("Setup", "Index"));
}
Now, after your user has fully completed setup, you can unload the app domain:
现在,在用户完全完成设置后,您可以卸载应用程序域:
HttpRuntime.UnloadAppDomain();
Please note: you will need to make sure that your app has permission to unload the AppDomain. If it does not, you can try File.SetLastWriteTimeUtc(...) on the configuration file (AppDomain.CurrentDomain.SetupInformation.ConfigurationFile.) This will also unload the AppDomain.
请注意:您需要确保您的应用有权卸载AppDomain。如果没有,您可以在配置文件(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile)上尝试File.SetLastWriteTimeUtc(...)。这也将卸载AppDomain。
Unloading the AppDomain will "restart" the web app and call Application_Start() again. The filter will not be added to your requests since your if statement will determine that the app has already been configured.
卸载AppDomain将“重新启动”Web应用程序并再次调用Application_Start()。过滤器不会添加到您的请求中,因为您的if语句将确定该应用程序已经配置。
#2
0
As a workaround, you could use lazy initialization in a static variable inside a filter. The actual file operations to check for the config file will only happen once during the first request. After that the value of the check for the config file is saved in the static Lazy
variable. As an added bonus it's also threadsafe.
作为一种解决方法,您可以在过滤器内的静态变量中使用延迟初始化。检查配置文件的实际文件操作仅在第一次请求期间发生一次。之后,配置文件的检查值保存在静态Lazy变量中。作为额外的奖励,它也是线程安全的。
In the end the check still happens on every request, but the operation is fast after the initial check because the result of the check is saved in memory.
最后,检查仍然在每个请求上发生,但是在初始检查后操作很快,因为检查结果保存在内存中。
public class ConfigFileCheckAttribute : ActionFilterAttribute
{
//Lazy<> is threadsafe and will call the Func in the constructor just once
private static Lazy<bool> _configFileExists = new Lazy<bool>(ConfigFileExists);
private static bool ConfigFileExists()
{
//Logic to check for config file here
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!_configFileExists.Value)
{
//set your redirect here
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Setup", action = "Configure" }));
}
}
}
The last bit is to register the filter in your App_Start/FilterConfig.cs:
最后一点是在App_Start / FilterConfig.cs中注册过滤器:
public static class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//...
filters.Add(new ConfigFileCheckAttribute());
}
}
#3
0
If you need this feature for a specific page, use cookies like bellow inside the action:
如果您需要针对特定页面使用此功能,请在操作中使用以下Cookie:
public ActionResult Index()
{
string cookieName = "NotFirstTime";
if(this.ControllerContext.HttpContext.Request.Cookies.AllKeys.Contains(cookieName))
// not first time
return View();
else
{
// first time
// add a cookie.
HttpCookie cookie = new HttpCookie(cookieName);
cookie.Value = "anything you like: date etc.";
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
// redirect to the page for first time visit.
return View("FirstTime");
}
}
If you want to use it for each action method, You need to write an ActionFilterAttribute
to call it every time needed.
如果要将其用于每个操作方法,则需要编写ActionFilterAttribute以在每次需要时调用它。
Note that the Request.Context
is not longer available to the Application_Start
event
请注意,Application_Start事件不再可用Request.Context
#1
3
If you really want to avoid having a filter run for every request after setup then you can do something like this:
如果您真的想避免在安装后为每个请求运行过滤器,那么您可以执行以下操作:
RedirectAttribute.cs (generic example)
RedirectAttribute.cs(通用示例)
public class RedirectAttribute : ActionFilterAttribute
{
private readonly string _controller;
private readonly string _action;
public RedirectAttribute(string controller, string action)
{
_controller = controller;
_action = action;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.ActionDescriptor.ActionName != _action ||
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName != _controller)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(new {controller = _controller, action = _action})
);
}
}
}
In Global.asax.cs above "FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);"
在Global.asax.cs上面的“FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);”
if (/*Insert logic to check if the config file does NOT exist*/)
{
//Replace "Setup" and "Index" with your setup controller and action below
GlobalFilters.Filters.Add(new RedirectAttribute("Setup", "Index"));
}
Now, after your user has fully completed setup, you can unload the app domain:
现在,在用户完全完成设置后,您可以卸载应用程序域:
HttpRuntime.UnloadAppDomain();
Please note: you will need to make sure that your app has permission to unload the AppDomain. If it does not, you can try File.SetLastWriteTimeUtc(...) on the configuration file (AppDomain.CurrentDomain.SetupInformation.ConfigurationFile.) This will also unload the AppDomain.
请注意:您需要确保您的应用有权卸载AppDomain。如果没有,您可以在配置文件(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile)上尝试File.SetLastWriteTimeUtc(...)。这也将卸载AppDomain。
Unloading the AppDomain will "restart" the web app and call Application_Start() again. The filter will not be added to your requests since your if statement will determine that the app has already been configured.
卸载AppDomain将“重新启动”Web应用程序并再次调用Application_Start()。过滤器不会添加到您的请求中,因为您的if语句将确定该应用程序已经配置。
#2
0
As a workaround, you could use lazy initialization in a static variable inside a filter. The actual file operations to check for the config file will only happen once during the first request. After that the value of the check for the config file is saved in the static Lazy
variable. As an added bonus it's also threadsafe.
作为一种解决方法,您可以在过滤器内的静态变量中使用延迟初始化。检查配置文件的实际文件操作仅在第一次请求期间发生一次。之后,配置文件的检查值保存在静态Lazy变量中。作为额外的奖励,它也是线程安全的。
In the end the check still happens on every request, but the operation is fast after the initial check because the result of the check is saved in memory.
最后,检查仍然在每个请求上发生,但是在初始检查后操作很快,因为检查结果保存在内存中。
public class ConfigFileCheckAttribute : ActionFilterAttribute
{
//Lazy<> is threadsafe and will call the Func in the constructor just once
private static Lazy<bool> _configFileExists = new Lazy<bool>(ConfigFileExists);
private static bool ConfigFileExists()
{
//Logic to check for config file here
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!_configFileExists.Value)
{
//set your redirect here
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Setup", action = "Configure" }));
}
}
}
The last bit is to register the filter in your App_Start/FilterConfig.cs:
最后一点是在App_Start / FilterConfig.cs中注册过滤器:
public static class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//...
filters.Add(new ConfigFileCheckAttribute());
}
}
#3
0
If you need this feature for a specific page, use cookies like bellow inside the action:
如果您需要针对特定页面使用此功能,请在操作中使用以下Cookie:
public ActionResult Index()
{
string cookieName = "NotFirstTime";
if(this.ControllerContext.HttpContext.Request.Cookies.AllKeys.Contains(cookieName))
// not first time
return View();
else
{
// first time
// add a cookie.
HttpCookie cookie = new HttpCookie(cookieName);
cookie.Value = "anything you like: date etc.";
this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);
// redirect to the page for first time visit.
return View("FirstTime");
}
}
If you want to use it for each action method, You need to write an ActionFilterAttribute
to call it every time needed.
如果要将其用于每个操作方法,则需要编写ActionFilterAttribute以在每次需要时调用它。
Note that the Request.Context
is not longer available to the Application_Start
event
请注意,Application_Start事件不再可用Request.Context