2015-03-18 7 views
7

पर इंजेक्शन ऑब्जेक्ट बदलें IUserRepository के गुणक कार्यान्वयन करना चाहते हैं प्रत्येक कार्यान्वयन डेटाबेस प्रकार या तो मोंगोडीबी या किसी भी SQL डेटाबेस के साथ काम करेगा। ऐसा करने के लिए मेरे पास इटेनेंट इंटरफ़ेस है जिसमें एक कनेक्शन स्ट्रिंग और अन्य किरायेदार कॉन्फ़िगरेशन है। किरायेदार को आईयूसर रिपोजिटरी या तो मोंगोडीबी या किसी भी एसक्यूएलडीबी कार्यान्वयन में इंजेक्शन दिया गया है। मुझे यह जानने की ज़रूरत है कि किरायेदार पर डेटाबेस बेस चुनने के लिए इंजेक्शन रिपोजिटरी को सही ढंग से कैसे बदला जाए।रनटाइम

इंटरफेस

public interface IUserRepository 
{ 
    string Login(string username, string password); 
    string Logoff(Guid id); 
} 

public class User 
{ 
    public Guid Id { get; set; } 
    public string Username { get; set; } 
    public string Password { get; set; } 
    public string LastName { get; set; } 
    public string FirstName { get; set; } 

} 

public interface ITenant 
{ 
    string CompanyName { get; } 
    string ConnectionString { get; } 
    string DataBaseName { get; } 
    string EncriptionKey { get; } 

} 

महत्वपूर्ण है पता चला है कि किरायेदार आईडी हैडर अनुरोध के माध्यम से एक एपीआई के पास किया गया है

StartUp.cs

// set inject httpcontet to the tenant implemantion 
services.AddTransient<IHttpContextAccessor, HttpContextAccessor>(); 

// inject tenant 
services.AddTransient<ITenant, Tenant>(); 

// inject mongo repository but I want this to be programmatically 
services.AddTransient<IUserRepository, UserMongoRepository>(); 

नमूना मोंगो कार्यान्वयन

public class UserMongoRepository : IUserRepository 
{ 

    protected ITenant Tenant 

    public UserMongoRepository(ITenant tenant) : 
     base(tenant) 
    { 
     this.Tenant = tenant; 
    } 

    public string Login(string username, string password) 
    { 

     var query = new QueryBuilder<User>().Where(x => x.Username == username); 
     var client = new MongoClient(this.Tenant.ConnectionString);var server = client.GetServer(); 
     var database = client.GetServer().GetDatabase(this.Tenant.DataBaseName); 
     var user = database.GetCollection<User>.FindAs<User>(query).AsQueryable().FirstOrDefault(); 

     if (user == null) 
      throw new Exception("invalid username or password"); 

     if (user.Password != password) 
      throw new Exception("invalid username or password"); 

     return "Sample Token"; 

    } 

    public string Logoff(Guid id) 
    { 

     throw new NotImplementedException(); 
    } 

} 

किरायेदार

public class Tenant : ITenant 
{ 

    protected IHttpContextAccessor Accesor; 
    protected IConfiguration Configuration; 

    public Tenant(IHttpContextAccessor accesor, IDBConfiguration config) 
    { 
     this.Accesor = accesor; 
     this.Configuration = new Configuration().AddEnvironmentVariables(); 
     if (!config.IsConfigure) 
      config.ConfigureDataBase(); 
    } 


    private string _CompanyName; 
    public string CompanyName 
    { 
     get 
     { 
      if (string.IsNullOrWhiteSpace(_CompanyName)) 
      { 
       _CompanyName = this.Accesor.Value.Request.Headers["Company"]; 
       if (string.IsNullOrWhiteSpace(_CompanyName)) 
        throw new Exception("Invalid Company"); 
      } 
      return _CompanyName; 
     } 
    } 

    private string _ConnectionString; 
    public string ConnectionString 
    { 
     get 
     { 
      if (string.IsNullOrWhiteSpace(_ConnectionString)) 
      { 
       _ConnectionString = this.Configuration.Get(this.CompanyName + "_" + "ConnectionString"); 
       if (string.IsNullOrWhiteSpace(_ConnectionString)) 
        throw new Exception("Invalid ConnectionString Setup"); 
      } 
      return _ConnectionString; 
     } 
    } 

    private string _EncriptionKey; 
    public string EncriptionKey 
    { 
     get 
     { 
      if (string.IsNullOrWhiteSpace(_EncriptionKey)) 
      { 
       _EncriptionKey = this.Configuration.Get(this.CompanyName + "_" + "EncriptionKey"); 
       if (string.IsNullOrWhiteSpace(_EncriptionKey)) 
        throw new Exception("Invalid Company Setup"); 
      } 
      return _EncriptionKey; 
     } 
    } 

    private string _DataBaseName; 
    public string DataBaseName 
    { 
     get 
     { 
      if (string.IsNullOrWhiteSpace(_DataBaseName)) 
      { 
       _DataBaseName = this.Configuration.Get(this.CompanyName + "_" + "DataBaseName"); 
       if (string.IsNullOrWhiteSpace(_DataBaseName)) 
        throw new Exception("Invalid Company Setup"); 
      } 
      return _DataBaseName; 
     } 
    } 
} 

नियंत्रक

public class UsersController : Controller 
{ 
    protected IUserRepository DataService; 

    public UsersController(IUserRepository dataService) 
    { 
     this.DataService = dataService; 
    } 

    // the controller implematation 

} 

उत्तर

4

आप वास्तविक भंडार के बजाय एक कारखाने इंजेक्शन लगाने की कोशिश कर सकते हैं। वर्तमान उपयोगकर्ता पहचान के आधार पर सही भंडार बनाने के लिए कारखाना जिम्मेदार होगा।

इसे थोड़ा और बॉयलर प्लेट कोड की आवश्यकता हो सकती है लेकिन यह आप जो चाहते हैं उसे प्राप्त कर सकते हैं। विरासत का थोड़ा सा नियंत्रक कोड को भी सरल बना सकता है।

+1

लेकिन यदि आप ऐसा करते हैं तो आप नियंत्रक में किस वस्तु को इंजेक्ट करेंगे? –

+0

एक 'IUserRepositoryFactory' जिसमें एक विधि है जो वर्तमान किरायेदार के भंडार को हल कर सकती है –

7

आपको IUserRepository के लिए प्रॉक्सी कार्यान्वयन को परिभाषित करना चाहिए और इस प्रॉक्सी के पीछे वास्तविक कार्यान्वयन को छिपाना चाहिए और रनटाइम पर कॉल को अग्रेषित करने के लिए कौन सा भंडार तय करना है। उदाहरण के लिए:

public class UserRepositoryDispatcher : IUserRepository 
{ 
    private readonly Func<bool> selector; 
    private readonly IUserRepository trueRepository; 
    private readonly IUserRepository falseRepository; 

    public UserRepositoryDispatcher(Func<bool> selector, 
     IUserRepository trueRepository, IUserRepository falseRepository) { 
     this.selector = selector; 
     this.trueRepository = trueRepository; 
     this.falseRepository = falseRepository; 
    } 

    public string Login(string username, string password) { 
     return this.CurrentRepository.Login(username, password); 
    } 

    public string Logoff(Guid id) { 
     return this.CurrentRepository.Logoff(id); 
    } 

    private IRepository CurrentRepository { 
     get { return selector() ? this.trueRepository : this.falseRepository; 
    } 
} 

इस प्रॉक्सी वर्ग का उपयोग करते हुए आप आसानी से एक क्रम विधेय जो भंडार का उपयोग करने का फैसला करता है कि बना सकते हैं। उदाहरण के लिए:

services.AddTransient<IUserRepository>(c => 
    new UserRepositoryDispatcher(
     () => c.GetRequiredService<ITenant>().DataBaseName.Contains("Mongo"), 
     trueRepository: c.GetRequiredService<UserMongoRepository>() 
     falseRepository: c.GetRequiredService<UserSqlRepository>())); 
+0

उत्तर @steve के उत्तर के लिए धन्यवाद, मैं प्रेषक का उपयोग करने का लाभ देख सकता हूं, केवल एक चीज जो मुझे पता है कि निर्माता वास्तव में बड़ा होगा क्योंकि मैं गुणक डीबी प्रकार का समर्थन करने की योजना बना रहा हूं, क्या मैं किरायेदार को प्रेषक को पास कर सकता हूं और डिस्पैचर –

+0

हाय @ स्टेवन में चयन कर सकता हूं, आप सीधे "MMROMOS: "UserRongository: new UserMongoRepository()" जैसे उपयोगकर्ताMongoRepository क्लास का उदाहरण क्यों नहीं बनाते । क्या ऐसा इसलिए है क्योंकि इस कक्षा में कुछ इंजेक्शन दिया जा सकता है? –

+1

@ बरबरोसएल्प: मुझे लगता है कि आपने अपने प्रश्न का उत्तर दिया है। 'UserMongoRepository' को कंटेनर द्वारा भी बनाया जा सकता है, क्योंकि इसकी अपनी निर्भरताएं हैं। – Steven