2015-10-06 53 views
1

如果你開始一個新的Web項目,並創建一個新MVC4的應用程序(與子好心「的WebAPI」,您可以粘貼(覆蓋HomeController.cs下面的代碼),以獲得該代碼工作。MVC 4 RedirectToAction沒有看到自定義頁眉

我有一個MVC4應用程序(具有的WebAPI)。

我想設置的MVC控制器方法的自定義標題,然後做一個RedirectToAction,自定義頭是沒見過在第二個mvc控制器方法中。

我能夠在第一個mvc-controller-method中設置一個cookie。方法,並在第二個mvc-controller-method中看到它(在RedirectToAction之後)。

有沒有辦法看到自定義標題我在第二一個RedirectToAction後MVC-控制器方法設置?

謝謝。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Net.Http; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Security; 

namespace MyMvc4WebApiProjectNamespace.Controllers 
{ 
    public class HomeController : Controller 
    { 

     private const string CustomCookieName = "CustomCookieName"; 
     private const string CustomHeaderName = "X-CustomHeaderName"; 
     private const string IISExpressRootUrl = "http://localhost:55937/"; /* open up the project properties and go to the web tab and find the iis-express area to get the correct value for your environment */ 

     public ActionResult Index() 
     { 

      IEnumerable<string> webApiValues = null; 
      string value1 = null; 
      string value2 = null; 

      HttpClientHandler handler = new HttpClientHandler 
      { 
       UseDefaultCredentials = true, 
       PreAuthenticate = true 
      }; 


      using (var client = new HttpClient(handler)) 
      { 

       string valuesUri = IISExpressRootUrl + "api/Values"; 

       webApiValues = client 
          .GetAsync(valuesUri) 
          .Result 
          .Content.ReadAsAsync<IEnumerable<string>>().Result; 

       if (null != webApiValues) 
       { 
        value1 = webApiValues.ElementAt(0); 
        value2 = webApiValues.ElementAt(1); 
       } 
       else 
       { 
        throw new ArgumentOutOfRangeException("WebApi call failed"); 
       } 
      } 


      HttpCookie customCookie = new HttpCookie(CustomCookieName, "CustomCookieValue_ThisShowsUpIn_MyHomeControllerAlternateActionResult_Method"); 
      Response.Cookies.Add(customCookie); 

      HttpContext.Response.AppendHeader(CustomHeaderName, "CustomHeaderValue_This_Does_Not_Show_Up_In_MyHomeControllerAlternateActionResult_Method"); 
      //Response.AppendHeader(CustomHeaderName, value2); 

      return RedirectToAction("MyHomeControllerAlternateActionResult"); 
     } 

     public ActionResult MyHomeControllerAlternateActionResult() 
     { 
      IEnumerable<string> webApiReturnValues = null; 


      CookieContainer cookieContainer = new CookieContainer(); 
      foreach (string cookiename in Request.Cookies) 
      { 
       if (cookiename.Equals(CustomCookieName, StringComparison.OrdinalIgnoreCase)) 
       { 
        var cookie = Request.Cookies[cookiename]; 
        cookieContainer.Add(new Cookie(cookie.Name, cookie.Value, cookie.Path, "localhost")); 
       } 
      } 

      if (cookieContainer.Count < 1) 
      { 
       throw new ArgumentOutOfRangeException("CookieContainer did not find the cookie I was looking for"); 
      } 
      else 
      { 
       Console.WriteLine("This is what actually happens. It finds the cookie."); 
      } 

      HttpClientHandler handler = new HttpClientHandler 
      { 
       UseCookies = true, 
       UseDefaultCredentials = true, 
       PreAuthenticate = true, 
       CookieContainer = cookieContainer 
      }; 


      using (var client = new HttpClient(handler)) 
      { 
       bool customHeaderWasFound = false; 
       if (null != this.Request.Headers) 
       { 
        if (null != this.Request.Headers[CustomHeaderName]) 
        { 
         IEnumerable<string> headerValues = this.Request.Headers.GetValues(CustomHeaderName); 
         client.DefaultRequestHeaders.Add(CustomHeaderName, headerValues); 
         customHeaderWasFound = true; 
        } 
       } 

       /*I wouldn't expect it to be in the below, but I looked for it just in case */ 
       if (null != this.Response.Headers)// 
       { 
        if (null != this.Response.Headers[CustomHeaderName]) 
        { 
         IEnumerable<string> headerValues = this.Response.Headers.GetValues(CustomHeaderName); 
         client.DefaultRequestHeaders.Add(CustomHeaderName, headerValues); 
         customHeaderWasFound = true; 
        } 
       } 

       if (!customHeaderWasFound) 
       { 
        Console.WriteLine("This is what actually happens. No custom-header found. :( "); 
       } 

       string valuesUri = IISExpressRootUrl + "api/Values"; 

       webApiReturnValues = client 
          .GetAsync(valuesUri) 
          .Result 
          .Content.ReadAsAsync<IEnumerable<string>>().Result; 

       if (null == webApiReturnValues) 
       { 
        throw new ArgumentOutOfRangeException("WebApi call failed"); 
       } 

      } 

      return View(); /* this will throw a "The view 'MyHomeControllerAlternateActionResult' or its master was not found or no view engine supports the searched locations" error, but that's not the point of this demo. */ 
     } 
    } 
} 

回答

4

響應頭永遠不會自動複製到請求 - 所以設置在響應任何自定義頁眉不會影響發出處理302重定向一個請求。

需要注意的是,即使使用cookie的情況:響應自帶的「設置此cookie」頭以及所有後續請求將得到「當前曲奇」頭。

如果您有自己的客戶端,則可以手動處理302(如果您使用瀏覽器作爲客戶端,則不可能)。

4

作爲另一個答案所述,響應頭約這個反應,而不是下一個。重定向不是服務器端操作。重定向指示客戶端執行全新的請求,當然在新的請求中,舊請求的響應頭不存在。所以return RedirectToAction("MyHomeControllerAlternateActionResult");保證在瀏覽器發起新的請求時沒有這個響應頭。

在試圖解決這個問題時,可能會考慮嘗試將數據持久化到下一個請求服務器端,比如通過cookie或顯式會話變量,或者隱式地使用ViewBag/ViewData/TempData 。但是,我不建議這樣做,因爲使用會話狀態會在大型/高使用率網站中嚴重影響性能,此外還有其他負面和細微的副作用,您可能會在後面遇到。例如,如果一個人有兩個瀏覽器窗口對同一個網站開放,他們就不能可靠地採取不同的行動,因爲一個窗口的會話數據可能最終被送達另一個窗口。在您的網站設計中儘可能避免會話使用 - 我保證這會讓您順利進行。

稍微好一點的辦法,雖然還是有它的問題,是重定向到包含一個有效載荷查詢字符串參數的URL。而且,代替整個數據集,您可以從提供一個可以從會話中拉出的密鑰(只要它也綁定到它們的IP地址並且像GUID或兩個一樣大)。但是,依靠會話狀態仍然不是如前所述的理想狀態。

相反,請考慮使用服務器端重定向,如子動作。如果你發現很難,因爲你要調用的是一個主控制器,你有幾種選擇:

  1. 如果您使用依賴注入,添加一個參數,以電流控制器(從構造函數保存它,在請求方法中使用它)是您想要「重定向」到的所需控制器。然後您可以直接調用該控制器。這可能並不理想(因爲所有對這個控制器的調用也都需要新增一個副本),但它確實是的工作。嘗試手動更新其他控制器也可以,但由於我沒有完全記住的原因,我認爲這會帶來一些額外的問題。在任何情況下,這種方法可以給訪問的HttpRequest方面的問題和其他上下文對象正確,雖然這可以圍繞工作。

  2. 重新構建應用程序,以便控制器是不是哪裏整個頁面呈現的地方。相反,將它們用作「智能路由器」,可以調用子動作來執行實際工作。然後,您可以調用控制器中的任何相同的子操作。但是這仍然有問題。

  3. 也許最好的方式是通過行動過濾器或其它手段(在網絡上搜索!),以便正確的控制器首先命中添加自定義路由邏輯!這可能並不總是可能的,但有時需要重定向到另一個控制器中程序實際上指向更大的設計問題。着眼於如何讓流水線中較早使用哪個控制器(例如路由期間)的知識可以揭示架構問題,並且可以向他們揭示可能的解決方案。

有可能是我沒有想到的其他選項,但至少你有幾個備選方案,以簡單的「沒有辦法做到這一點。」