2016-04-19 115 views
3

我的中間件類在不同的類庫項目中,而控制器在不同的項目中。我試圖做的,如果特定條件不符合然後重定向到中間件的自定義控制器/操作方法。來自中間件的呼叫控制器的操作方法

但是,我不能用Response.Redirect方法做到這一點。

我該如何在中間件類中做到這一點?

對此有任何幫助表示讚賞!

Rohit

+1

條件是什麼?它是認證/授權,還是其他?如果它是auth,你可能想要返回'401'或'403'(取決於它是認證還是授權失敗),如果是別的東西,你可能不想首先在中間件中執行它。你可以再詳細一點嗎? –

+0

@TomasLycken是的,它與認證/授權無關,如果沒有找到特定的客戶端/租戶,則重定向到某些控制器的操作方法以顯示錯誤消息。要從httpcontext獲取客戶名稱,邏輯是寫在中間件 – Rohit

回答

5

看來你是因爲錯誤的原因使用了中間件。

我建議你通過簡單地將它寫入響應流(而不是轉發到Next())來讓中間件返回一個(非常小的)404,或者不要在中間件中完成此操作,而是在在您的MVC應用程序中全球註冊了IActionFilter


我已經解釋了在評論上述建議的理由,但我認爲要提升到實際的答案是足夠重要:

在中間件管道,希望每個組件是爲儘可能獨立。幾件事情啓用OWIN此鬆耦合:

  • 的輸入,並且輸出從,每個組件具有相同的格式,是否有收到10個其他中間件組件,或者根本沒有

  • 的約定是,該管道的每一部分都可以做的三件事情的一個或多個,順序如下:

    1. 閱讀(修改)傳入的請求。

    2. 決定完全處理請求,或轉發處理到下一個組件。

    3. 寫入響應流。

當粘到這些約定,它變得非常容易編寫,分解和重新組成從可重用中間件組件管線。 (希望請求日誌記錄?只需在管道的起始處連接一箇中間件組件,想要在整個板上使用一些通用的身份驗證邏輯?在管道的auth階段添加一個組件。想要切換到不同的日誌記錄框架?要想在微服務的生態系統中應用相同的日誌記錄,可以重新使用組件Etcetera,ad infinum ...)這很有效,因爲組件都在它們的邊界之內,並且與Web服務器本身可以理解。

ASP.NET WebAPI看起來可能是一個不同的野獸,但實際上它只是另一個OWIN組件,它總是被配置爲處理請求,並且永遠不會轉發到下一個組件(因此它們使它變得困難在管道中的WebApi之後註冊一個組件......)。

你想要做什麼,打破了第二點的合同 - 你想告訴下一個組件如何處理請求。 但這並不取決於你 - 它取決於下一個組件。

+0

能否請你提供一個404和IActionFilter的小例子?謝謝 ! – Rohit

+0

要寫入回覆,請參閱[這個Q/A](http://stackoverflow.com/questions/32532058/how-do-i-ask-owin-katana-to-write-headers-to-the-output-stream)。對於'IActionFilter'的例子,看看[這裏](https://damienbod.com/2014/01/04/web-api-2-using-actionfilterattribute-overrideactionfiltersattribute-and-ioc-injection/) –

+0

你能解釋一下爲什麼他的用例不適合中間件。 –

5

這是檢查請求並重定向的中間件。它適用於嵌入式中間件或中間件類。

public void Configure(IApplicationBuilder app) 
{ 
    // use inline middleware 
    app.Use(async (context, next) => 
    { 
     // if specific condition does not meet 
     if (context.Request.Path.ToString().Equals("/foo")) 
     { 
      context.Response.Redirect("path/to/controller/action"); 
     } 
     else 
     { 
      await next.Invoke(); 
     } 
    }); 

    // or use a middleware class 
    app.UseMiddleware<RedirectMiddleware>(); 

    app.UseMvc(); 
} 

這裏是中間件類。

public class RedirectMiddleware 
{ 
    private readonly RequestDelegate _next; 

    public RedirectMiddleware(RequestDelegate next) 
    { 
     _next = next; 
    } 

    public async Task Invoke(HttpContext context) 
    { 
     // if specific condition does not meet 
     if (context.Request.Path.ToString().Equals("/bar")) 
     { 
      context.Response.Redirect("path/to/controller/action"); 
     } 
     else 
     { 
      await _next.Invoke(context); 
     } 
    } 
} 

有關更多信息,請參閱Docs » Fundamentals » Middleware

+1

你似乎已經提供了啓動類的配置方法?如果發生錯誤,我怎麼能從中間件返回? – Rohit

+0

'app.Use'是中間件。 :-)我添加了另一種方式。 –

+1

@ShaunLatin謝謝你的幫助!它的工作! – Rohit