响应重定向在MVC中使用

时间:2016-08-22 11:48:04

标签: c# asp.net-mvc asp.net-mvc-4

我想在global.asax和我的控制器之间建立连接。我们在我们的网站上使用了一个数据库。我们有一个代码来检查数据库是否存在。如果它不存在,我们希望显示一条消息,如"数据库初始化"等等。

数据库检查 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");
        }
    }
}

但我们在使用响应重定向时遇到问题。它返回

  

{&#34;在此上下文中无法响应。&#34;}。

我们有一个控制器,它是LoadingController,它有这个代码;

public class LoadingController : Controller
{
    // GET: Loading
    public ActionResult LoadingScreen()
    {

        return View();
    }
}

但我们无法跳到这一部分。我怎样才能建立联系?感谢

6 个答案:

答案 0 :(得分:2)

首先,Application_Start不处理任何用户请求。它只是执行一些启动初始化。应用程序启动时仅调用一次。要根据用户的操作进行一些检查并正确回复,您需要将这些检查移至Application_BeginRequest方法。

其次,您还需要在响应重定向到该页面之前检查用户是否已请求/Loading/LoadScreen。否则,在创建数据库之前,您将获得无限重定向。

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");
        }
    }
}

您可以进一步将检查移至ActionFilter,因为您可以使用RouteData并检查actioncontroller参数而不是网址。与nameof相结合,在路由更改,重命名,重构等方面不易出错。

答案 1 :(得分:0)

我认为这个答案会给你你想要的东西:Return different views in a controller

在你的情况下,而不是response.redirect使用return View(&#34; / Loading / LoadScreen&#34;); ......或类似的东西

答案 2 :(得分:0)

试试这个

HttpContext.Current.Response.Redirect("/Loading/LoadScreen");

beacuse响应对象在global.asax的application_start方法中不可用。 你必须在任何情况下使用HttpContext.Current。

答案 3 :(得分:0)

Application_Start在ASP.Net开始处理请求之前发生。

您可以设置一个全局静态标志来指示错误情况,然后处理Application_BeginRequest并检查标志并重定向。

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");
    }
}

答案 4 :(得分:0)

由于RequestResponse在您的Application_Start事件中无法使用,您可能会考虑在MVC请求 - 响应管道中的某处使用此代码。动作过滤器是个好地方。

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);
    }
}

这里我们首先检查应用程序变量是否具有&#34; DbSetDate&#34;的有效条目。键。默认情况下,它不会在那里。然后,您必须执行自定义代码以检查您的数据库是否存在。如果没有,请重定向到LoadScreen操作。

全局注册此过滤器,以便对来自您的应用程序的任何请求执行此过滤器。

GlobalFilters.Filters.Add(new VerifySetupIsGood());

现在,当您完成设置数据库时,请更新此应用程序变量以获得有效值。

HttpContext.Application["DbSetDate"] = DateTime.Now.ToString();

请记住,应用程序变量状态也会被重置。所以不要只依赖它。您应该运行自定义代码来检查您的数据库是否存在于if条件中。如果条件是阻止您对每个请求进行自定义数据库检查。

答案 5 :(得分:0)

您还可以使用“自动启动功能”(have added:Darins答案)。在网站准备好提供请求之前,这将执行一次。缺点是您无法向用户显示“请稍候”窗口。我个人不会检查每个请求是否存在数据库。只是执行它;数据库更新不应该花很长时间我猜?