Reputation: 1664
I want to create connection between global.asax and my controller. We are using a database in our website. We have a code to check whether the database exists or not. If it doesn't not exist, we want to display a message like "database initializing" etc..
Database check in GLOBAL.ASAX :
public class MvcApplication : System.Web.HttpApplication
{
public static bool flag;
protected void Application_Start()
{
Database.SetInitializer<PhoneDexContext>(null);
var connString = ConfigurationManager.ConnectionStrings["DatabaseConnection"].ConnectionString;
using (PhoneDexContext db = new PhoneDexContext())
{
if (!db.Database.Exists())
{
flag = true;
db.Database.CreateIfNotExists();
}
}
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
protected void Application_BeginRequest()
{
if (flag)
{
Response.Redirect("Loading/LoadingScreen");
}
}
}
But we have a problem with using response redirect. It returns
{"Response is not available in this context."}.
We have a controller which is LoadingController and it has this code;
public class LoadingController : Controller
{
// GET: Loading
public ActionResult LoadingScreen()
{
return View();
}
}
But we can't jump to this part. How can i make connection?? Thanks
Upvotes: 2
Views: 6651
Reputation: 3896
First, Application_Start
does not handle any user requests. It is just perform some start up initialization. It invoked only once when app starts. To do some checks based on user's actions and properly respond you need to move these checks into Application_BeginRequest
method.
Second, you also need to check if user already requesting /Loading/LoadScreen
before responding with redirect to that page. Otherwise you will get an infinite redirects until database created.
public class MvcApplication : HttpApplication
{
private static bool dbInitialized;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// We can do it asynchronously to not block other initialization code.
Task.Run((Action)CreateDataBase);
}
private static void CreateDataBase()
{
Database.SetInitializer<PhoneDexContext>(null);
using (PhoneDexContext db = new PhoneDexContext())
{
if (!db.Database.Exists())
db.Database.CreateIfNotExists();
}
dbInitialized = true;
}
protected void Application_BeginRequest()
{
if (!dbInitialized && !this.Request.Url.LocalPath.StartsWith("/Loading/LoadingScreen", StringComparison.OrdinalIgnoreCase))
{
this.Response.Redirect("/Loading/LoadingScreen");
}
}
}
You can to further and move checks into the ActionFilter
as you will able to work with RouteData
and check action
and controller
parameters instead of url. Combined with nameof
that would be less error-prone to route changes, renaming, refactoring and so on.
Upvotes: 3
Reputation: 218722
Since Request
and Response
won't be available in your Application_Start
event, You might consider having this code somewhere in the MVC request-response pipeline. An action filter is a good place.
public class VerifySetupIsGood : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var dbSetDate = context.HttpContext.Application["DbSetDate"] as string;
if (String.IsNullOrEmpty(dbSetDate))
{
//to do : Execute your custom code to check db existence here
var values = new Dictionary<string, string> { { "action", "LoadScreen" },
{ "controller", "Loading" } };
var r = new RouteValueDictionary(values);
//redirect the request to MissingDatabase action method.
context.Result = new RedirectToRouteResult(r);
}
base.OnActionExecuting(context);
}
}
Here we are first checking whether the application variable has a valid entry for "DbSetDate" key. By default, it will not be there. Then you have to execute your custom code to check whether your db exist. If not, Redirect to the LoadScreen action.
Register this filter globally so that it will be executed for any request coming to your application.
GlobalFilters.Filters.Add(new VerifySetupIsGood());
Now in when you are done with setting up your database, update this application variable to have a valid value.
HttpContext.Application["DbSetDate"] = DateTime.Now.ToString();
Remember, Application variable states will also gets reset. So don't just rely on that. You should run your custom code to check your db exists inside the if condition. If condition is to prevent your custom db check for every single request.
Upvotes: 0
Reputation: 586
Application_Start
happens before ASP.Net starts processing the request.
You could set a global static flag to indicate the error condition, then handle Application_BeginRequest
and check the flag and redirect.
static bool _isDbLoaded;
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start(){
Database.SetInitializer<PhoneDexContext>(null);
var connString = ConfigurationManager.ConnectionStrings["DatabaseConnection"].ConnectionString;
using (PhoneDexContext db = new PhoneDexContext())
{
if (!db.Database.Exists())
{
_isDbLoaded = false;
db.Database.CreateIfNotExists();
}
}
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
protected void Application_BeginRequest(){
if(!_isDbLoaded){
Response.Redirect("Loading/LoadingPage");
}
}
Upvotes: 0
Reputation: 23615
You can also use the 'Auto-Start feature' (How to warm up an ASP.NET MVC application on IIS 7.5? : Darins answer). This will execute once, before the website is ready to serve requests. The downside is you can't show the user a 'please wait' window. Personally I would not check at every request if the database is existent or not. Just execute it; the database update should not take very long I guess?
Upvotes: 0
Reputation: 138
try this
HttpContext.Current.Response.Redirect("/Loading/LoadScreen");
beacuse Response object is not avaliable in application_start method of global.asax. you must use HttpContext.Current for any situation.
Upvotes: 0
Reputation: 469
I think this answer will give you what you want: Return different views in a controller
In your case instead of the response.redirect use return View("/Loading/LoadScreen"); ...or something simular
Upvotes: 0