2015-11-19 41 views
1

試圖找出一種方法來建立會話管理DryIoC(V2.0.0-rc4build353),MS OWIN(V3.0.1,WebAPI2(客戶端v5.2.3)上VS2015, .NET 4.5。DryIoC /網絡API 2/OWIN和會話管理

我與包裝REST API一個相當複雜的遺留應用程序。嚴格的API服務器,沒有UI/MVC。據我所知,這是不可能的,我去完全無狀態,因爲我要保持一個「模型」開放的服務器端,用戶必須驗證到模型中,因此會話的概念出現了,我想盡可能使用DI。 ISession提供呃工廠。雖然Ninject有其專業(模塊,一個),但我不喜歡它的複雜性。我無法弄清楚如何從工廠訪問請求對象。經過一番研究,我決定切換到DryIoC。

在下面DryIoC的代碼示例創建一個單獨的會話(見下文再利用),並將其注入到我的RootController。如果我在瞬態範圍中註冊會話,我顯然會根據請求獲得一個會話。我設想一個叫「api/login」的調用會生成一個令牌。客戶端將緩存它並將其隨後的調用提交到頭中(以便啓用API版本)。

如何管理作用域掙扎。

編輯:什麼,我想我需要澄清:我不知道如何實現一個工廠DryIoC將實例化一個控制器,在這裏我想查找會話標識和創建/查找相關ISession實例之前調用。 DryIoC然後將使用它來注入控制器。

編輯:我試圖隱藏所有會話管理樣板,並將所有控制器,已初始化會話注入。如果此請求沒有會話,則單獨的路由會返回錯誤。另外需要注意的是,客戶端必須明確獲取令牌。沒有全球「當前」令牌或會話的概念。

using System; 
using System.Web.Http; 

using Microsoft.Owin.Hosting; 
using Microsoft.Owin.Diagnostics; 

using Owin; 

using DryIoc; 
using DryIoc.WebApi; 

namespace di_test 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var url = "http://localhost:8065"; 

      using (WebApp.Start<Startup>(url)) 
      { 
       Console.WriteLine("Owin host started, any key to exit"); 
       Console.ReadKey(); 
      } 
     } 
    } 

    class Startup 
    { 
     public void Configuration(IAppBuilder app_) 
     { 
      var config = new HttpConfiguration(); 
      config.MapHttpAttributeRoutes(); 

      config.Routes.MapHttpRoute(
       name: "default", 
       routeTemplate: "{controller}" 
       ); 

      var di = new DryIoc.Container(); 
      di.Register<ISession, Session>(Reuse.Singleton); 
      di.WithWebApi(config); 

      app_.UseWebApi(config); 
      app_.UseErrorPage(ErrorPageOptions.ShowAll); 
     } 
    } 

    public interface ISession 
    { 
     string Token { get; } 
    } 

    public class Session : ISession 
    { 
     string m_token = null; 

     public Session() 
     { 
      Console.WriteLine("Session()"); 
     } 

     public string Token => m_token ?? (m_token = Guid.NewGuid().ToString()); 
    } 

    [RoutePrefix("api")] 
    public class RootController : ApiController 
    { 
     readonly ISession m_session; 

     public RootController(ISession session_) 
     { 
      m_session = session_; 
     } 

     [Route()] 
     public IHttpActionResult GetApiRoot() 
     { 
      return Json(
       new 
       { 
        type = "root", 
        token = m_session.Token 
       }); 
     } 
    } 
} 
+0

我不太明白:你想有一個會議_per什麼_? –

+0

@FyodorSoikin Session「something」:)我不確定如何實現DryIoC在實例化控制器之前調用的工廠,在那裏查找會話標記和創建/查找關聯的ISession實例。 DryIoC然後將使用它來注入控制器。 –

+0

我認爲你已經完成了這個複雜化。如果遺留系統具有調用API的能力,那麼它可以調用令牌的API。令牌存儲在客戶端,並在調用資源API時傳遞到頭中。查看JWT和oAuth。 API不應該有會話的概念。 –

回答

3

首先,我不是一個Web人(但是DryIoc維護者),並沒有完全獲得您想要實現的會話管理。但如果你想利用這個請求,你能做到這一點如下:

public class Startup 
{ 
    public void Configuration(IAppBuilder app_) 
    { 
     var config = new HttpConfiguration(); 
     config.MapHttpAttributeRoutes(); 

     config.Routes.MapHttpRoute(
      name: "default", 
      routeTemplate: "{controller}" 
      ); 

     var di = new DryIoc.Container(); 

     // NOTE: Registers ISession provider to work with injected Request 
     di.Register<ISession>(Made.Of(() => GetSession(Arg.Of<HttpRequestMessage>()))); 

     di.WithWebApi(config); 

     app_.UseWebApi(config); 
     app_.UseErrorPage(ErrorPageOptions.ShowAll); 
    } 

    public static ISession GetSession(HttpRequestMessage request) 
    { 
     // TODO: This is just a sample. Insert whatever session management logic you need. 
     var session = new Session(); 
     return session; 
    } 
} 

DryIoc將注入電流HttpRequestMessageGetSession。然後GetSession將用於將結果會話注入控制器。

這裏有更多的細節如何使用DryIoc factory methods

順便說一下我已將此示例應用推送到DryIoc dev分行,作爲DryIoc.WebApi.Owin.Sample app。我希望你沒事。給我,如果你不是。

+0

回覆:示例應用程序 - 非常好。 Re:注入HttpRequestMessage,這就是我錯過的!謝謝,我會試驗這個和評論。現在這將是答案。我感謝你看着它! –

0

如果你只是想爲這一個特定的接口做一次,你不介意手動管理其一生中,你可以從字面上使用RegisterDelegate創建一個工廠:

var sessions = new ConcurrentDictionary<Token, Session>(); 

di.RegisterDelegate<ISession>(_ => { 
    var token = GetCurrentToken(); 
    return sessions.GetOrAdd(token, t => new Session(t)); 
}); 

或者,如果你想讓這個「每令牌」的想法適用於各種各樣的組件,你可以實現自定義的IReuse,這是一個可以查看「當前範圍」的東西,而「範圍」只是一個緩存實例。

然而,我不會推薦這種設計。這是這種邏輯的錯誤層。

一個例子:當沒有當前令牌你會怎麼做?你當然可以拋出一個異常,但是無處可以捕捉到這個異常 - 你仍然只是在這個時候構造你的組件圖,所以客戶端只會看到任何WebApi自動生成的異常消息。醜陋。更不用說,你不會做任何恢復,記錄事件,等等,等等。

又如:在你的開發後期階段,你將很可能要構建在會前做與該令牌的東西。說,驗證它,或檢查它是否已過期或已被召回,或其他。現在您正在爲您的DI接線代碼添加更高級別的業務邏輯。醜陋。難以維護。

更好的方法是將一個叫做ISessionManager的單件組件注入控制器,然後讓控制器調用ISessionManager.GetCurrentSession()或其他東西。然後你就不會把自己束縛住了:以後你可以選擇擴展GetCurrentSession做的事情,或者你可以選擇改變它的返回類型來包含可能的錯誤(例如「no token」,「token expired」等),並且控制器向消費者報告。

想一想。

+0

我已經考慮過一個會話管理器的方法,甚至寫了一些測試代碼。這個問題(據我瞭解,我可能是錯的)仍然在於: - 將HTTP頭映射到會話(如果有的話) - 將映射會話的實例注入到所有控制器中。那麼這應該成爲定製中間件的工作嗎? –

+0

不要注入會話的實例。注入會話管理器本身。然後讓控制器調用該實例的方法來獲取當前會話。 –

+0

沒錯,但在飛行中可以有多個會話。另外,會話管理器如何訪問當前請求? ..哦,我明白了,你提議每個REST端點在開始時都會有一些樣板代碼 - 「查找會話或退出」。嘆了口氣,我試圖隱藏它,讓控制器忘記了會話管理的「如何」。我們正在談論一些控制器 –