2014-02-10 77 views
1

我正在使用asp.net mvc開發多租戶應用程序。我必須爲每個請求確定承租人,所以我創建了以下類別:如何在mvc c#中處理這種情況?

public class TenantProvider 
    { 
     public static Tenant Tenant 
     { 
      get 
      { 
       Tenant tenant = HttpContext.Current.Items["Tenant"] as Tenant; 

       if (tenant == null) 
       { 
        var tenantUsername = HelperUtility.GetCurrentRequestHost(); 
        //The below line of code is my problem 
        TenantRepository tenantRepository = new TenantRepository(new AppointContext()); 
        tenant = tenantRepository.GetByUsername(tenantUsername); 
        HttpContext.Current.Items.Add("Tenant", tenant); 
       } 

       return tenant; 
      } 
     } 
    } 

此類靜態屬性返回當前請求的承租人。它將首先檢查高速緩存中的Tenant,如果沒有找到,將從數據庫中獲取租戶,初始化緩存並返回Tenant。

爲了得到租客形成數據庫我創建一個TenantRepository實例。 TenantRepository對數據庫上下文具有依賴關係,我在創建實例時傳遞它。

現在,當我必須對當前Tenant執行其他數據庫操作時,我必須在其他某個位置創建新的Repository實例,並且必須通過新的上下文,因此我提取了租戶和新的實際上下文上下文不同,我認爲可能會造成問題。

所以我的問題是我怎麼能處理這種情況,因此在相同情況下例如將使用?

+0

爲什麼不將租戶存儲在索賠中? – Swell

+0

@Swell您能否用一些鏈接或示例代碼來詳細說明您的建議? – user1740381

+0

這是一個關於索賠http://vimeo.com/43549130的迷你速成課程,這是一部來自Dominick Baier的精彩視頻。你也應該看看這個項目https://github.com/brockallen/BrockAllen.MembershipReboot來自Brock Allen。 – Swell

回答

2

您正在尋找的解決方案是工作單元設計模式。來自Martin Fowler:

維護受業務事務影響的對象列表,並協調寫出更改和併發問題的解決方案。

裁判:http://martinfowler.com/eaaCatalog/unitOfWork.html

這種模式允許你註冊多個事務組合成一個單一的環境。這是一個非常常見的模式,這裏有一個可能的實現。首先,創建工作對象的單位將舉行到你的中央上下文的引用,並且將與該上下文初始化的倉庫(該實現使用實體框架):

public class UnitOfWork : IUnitOfWork 
{ 
    internal EntitiesContext _context = new EntitiesContext(); 
    private ITenantRepository _tenantRepository; 
    private IOtherRepository _otherRepository; 

    public ITenantRepository TenantRepository 
    { 
     get 
     { 
      if (_tenantRepository== null) 
      { 
       _tenantRepository= new TenantRepository(_context); 
      } 
      return _tenantRepository; 
     } 
    } 

    public IOtherRepository OtherRepository 
    { 
     get 
     { 
      if (_otherRepository== null) 
      { 
       _otherRepository= new OtherRepository(_context); 
      } 
      return _otherRepository; 
     } 
    } 

    public void Save() 
    { 
     _context.SaveChanges(); 
    } 

    private bool disposed = false; 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!this.disposed) 
     { 
      if (disposing) 
      { 
       _context.Dispose(); 
      } 
     } 
     this.disposed = true; 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

需要注意的是,如果你使用任何存儲庫在這種模式下,他們都將使用相同的上下文。

你的控制器應要麼初始化的工作單元,甚至更好,把它注入到它的構造:

public TenantController(IUnitOfWork unitOfWork) 
    { 
     _unitOfWork = unitOfWork; 
     _tenantRepository = unitOfWork.TenantRepository; 
     _otherRepository = unitOfWork.OtherRepository; 
    } 

如果您需要使用的UnitOfWork到另一層,你通常把它作爲一個參數傳遞給另一個對象的構造函數:

public ActionResult Index() 
{ 
    TenantProvider provider = new TenantProvider(_unitOfWork); 
    _otherRepository.DoWork(); 
    _unitOfWork.Save(); 
} 

現在你TenantProvider可以做各自的倉庫了一些工作,但工作的OtherRepository的單位也可以使用相同的情況下做一些工作。

+0

感謝您的回答以及真正有用的+1,我想知道爲什麼您在示例代碼中使用ITenantRepository等接口。其實我知道界面的理論(合同B/W類和所有),但我真的從來不明白它的真正用途,這意味着我從來沒有像'是的,這是接口的要求'這樣的東西。那麼你能否向我解釋你的示例代碼中接口的真正用途? – user1740381

+0

代碼到接口,而不是實現。在上面的代碼中,我的控制器不知道存儲庫如何保存其數據。雖然我的示例使用實體框架,因爲它在一個接口後面,所以我理論上可以將我的存儲庫換成保存到XML文檔,MySQL,文本文件的存儲庫......解耦您的代碼可確保您的代碼更易於維護,適應變化。 –

+0

感謝您的解釋,它非常有幫助 – user1740381

0

除了@ChrisHardie,我想添加一些MVC的細節:我認爲這是注入工作單元到控制器的一個非常好的做法。爲了做到這一點,你可以創建自DefaultControllerFactory衍生和應用程序啓動時註冊一個自定義的ControllerFactory:

public class CustomControllerFactory : DefaultControllerFactory 
{ 
    protected override IController GetControllerInstance(Type controllerType) 
    { 
     // Analyze whether instance of controllerType should be created directly or 
     // whether the Unit of Work should be injected 
     if (needsUnitOfWork) 
      return (IController)Activator.CreateInstance(controllerType, unitOfWork); 
     else 
      return (IController)Activator.CreateInstance(controllerType); 
    } 
} 

爲了需要一個工作單元控制器和那些不之間的辨別,你可以使用反射(自定義屬性或檢查構造函數參數)。也許你也可以假設每個控制器目前需要一個工作單元。

如果您已經使用Inversion of Control容器,它可以支持您創建實例(IoC容器通常插入MVC中的ControllerFactory中)。如果沒有,你可能會考慮開始使用一個。

你可以這樣註冊的ControllerFactory:

public class MvcApplication : System.Web.HttpApplication 
{ 
    protected void Application_Start() 
    { 
     // ... 
     RegisterCustomControllerFactory(); 
     // ... 
    } 

    private void RegisterCustomControllerFactory() 
    { 
     IControllerFactory factory = new CustomControllerFactory(); 
     ControllerBuilder.Current.SetControllerFactory(factory); 
    } 
} 

由於這個答案是建立在對MVC依賴注入的擴展點,這link可能的幫助。

相關問題