6

Tôi có một dịch vụ WCF và trên máy khách tôi có:phụ thuộc tiêm với nhiều kho

var service = new ServiceReference1.CACSServiceClient() 

Mã dịch vụ thực tế là:

public CACSService() : this(new UserRepository(), new BusinessRepository()) { } 

public CACSService(IUserRepository Repository, IBusinessRepository businessRepository) 
{ 
    _IRepository = Repository; 
    _IBusinessRepository = businessRepository; 
} 

Vì vậy, tất cả điều này hoạt động tốt, nhưng tôi don không giống như cách tôi đang làm mới tất cả các kho lưu trữ cùng một lúc bởi vì mã máy khách có thể không cần phải làm mới số UserRepository và chỉ quan tâm đến việc làm mới số BusinessRepository. Vì vậy, có cách để chuyển nội dung nào đó cho mã này:
var service = new ServiceReference1.CACSServiceClient()
để cho biết kho lưu trữ nào mới được tạo dựa trên mã đang gọi dịch vụ hoặc bất kỳ lời khuyên nào khác mà tôi cần phải thực hiện khi thiết kế kho khung thực thể của tôi. Thankx

+1

+1 để "làm mới" – Jacob

Trả lời

0

Thay vì khởi tạo ("làm mới") kho lưu trữ khi xây dựng, bạn có thể tải chúng trong thuộc tính của chúng. Điều này sẽ cho phép bạn giữ lại hàm tạo thứ hai của bạn, nhưng có hàm tạo đầu tiên của bạn không làm gì cả.

Sau đó, người dùng có thể gán những thứ này, nếu cần, nếu không.

Ví dụ:

public class CACSService 
{ 
    public CACSService() {} 

    public CACSService(IUserRepository Repository, IBusinessRepository businessRepository) 
    { 
     _IRepository = Repository; 
     _IBusinessRepository = businessRepository; 
    } 

    private IUserRepository _IRepository; 
    public IUserRepository Repository 
    { 
     get { 
      if (this._IRepository == null) 
        this._IRepository = new UserRepository(); 
      return this._IRepository; 
     } 
    } 

    // Add same for IBusinessRepository 
} 
0

làm kho của bạn có trạng thái đối tượng cấp? Có lẽ không, do đó, tạo ra chúng như là đơn và có một container DI cung cấp chúng cho CACService.

Nếu không, chúng thực sự đắt tiền để tạo? Nếu không, tạo một cái mới cho mỗi yêu cầu có chi phí không đáng kể so với RPC và các hoạt động cơ sở dữ liệu.

Sử dụng hộp chứa tiêm phụ thuộc Ninject, CACService của bạn có thể trông giống như sau. Các thùng chứa DI khác có cơ chế gọn gàng như nhau để thực hiện việc này.

public class CACSService 
{ 
    public CACService 
    { 
     // need to do this since WCF creates us 
     KernelContainer.Inject(this); 
    } 

    [Inject] 
    public IUserRepository Repository 
    { set; get; } 

    [Inject] 
    public IBusinessRepository BusinessRepository 
    { set; get; } 
} 

Và trong quá trình khởi động ứng dụng, bạn sẽ nói với Ninject về các loại này.

Bind<IUserRepository>().To<UserRepository>().InSingletonScope(); 
Bind<IBusinessRepository>().To<BusinessRepository>().InSingletonScope(); 
+3

Không cần phải sử dụng Singletons và các nhà thầu mặc định. WCF hoàn toàn có thể hỗ trợ ** Constructor Injection **. –

+0

Việc thực hiện này nghe có vẻ tuyệt vời, tôi sẽ chụp ảnh và thử Mark Seeman nói gì về việc tải xuống kho chứa. – user282807

+0

Bạn bè không cho phép bạn bè viết đơn. –

0

Lời nói đầu: Đây là hướng dẫn chung để đảo ngược sự phụ thuộc. Nếu bạn cần hàm tạo mặc định để thực hiện công việc (ví dụ: nếu nó được tạo mới bằng cách phản chiếu hoặc cái gì đó khác), thì sẽ khó thực hiện việc này một cách rõ ràng hơn.

Nếu bạn muốn làm cho ứng dụng của bạn có thể định cấu hình, điều đó có nghĩa là có thể thay đổi cách biểu đồ đối tượng của bạn được tạo. Trong các thuật ngữ thực sự đơn giản, nếu bạn muốn thay đổi việc thực hiện một cái gì đó (ví dụ: đôi khi bạn muốn một phiên bản của UserRepository, lần khác bạn muốn một phiên bản MemoryUserRepository), thì loại đó sử dụng việc triển khai (CACService trong trường hợp này) nên không bị tính phí khi làm mới nó. Mỗi lần sử dụng new liên kết bạn với một triển khai cụ thể. Misko has written some nice articles about this point.

Nguyên tắc đảo ngược phụ thuộc thường được gọi là "thông số từ trên cao", vì mỗi loại cụ thể nhận được phụ thuộc (đã được khởi tạo) của nó từ người gọi.

Để đặt điều này vào thực tế, hãy di chuyển mã tạo đối tượng ra khỏi hàm tạo tham số CACService và đặt nó vào một nhà máy, thay vào đó.

Sau đó bạn có thể chọn để dây lên vật khác nhau dựa trên những thứ như:

  • đọc trong một tập tin cấu hình
  • đi qua trong đối số cho các nhà máy
  • tạo ra một loại khác nhau của nhà máy

Tách các loại thành hai loại (loại tạo những thứ và loại mà làm điều) là một kỹ thuật mạnh mẽ.

Ví dụ: đây là một cách tương đối đơn giản để thực hiện nó bằng cách sử dụng một giao diện nhà máy - chúng tôi chỉ đơn giản là mới lên bất kỳ nhà máy nào phù hợp với nhu cầu của chúng tôi và gọi phương thức Create của nó. Chúng tôi sử dụng một thùng chứa Dependency Injection (Autofac) để làm công cụ này tại nơi làm việc, nhưng nó có thể là quá mức cần thiết cho nhu cầu của bạn.

public interface ICACServiceFactory 
{ 
    CACService Create(); 
} 

// A factory responsible for creating a 'real' version 
public class RemoteCACServiceFactory : ICACServiceFactory 
{ 
    public CACService Create() 
    { 
     return new CACService(new UserRepository(), new BusinessRepository()); 
    }   
} 

// Returns a service configuration for local runs & unit testing 
public class LocalCACServiceFactory : ICACServiceFactory 
{ 
    public CACService Create() 
    { 
     return new CACService(
       new MemoryUserRepository(), 
       new MemoryBusinessRepository()); 
    }  
} 
16

Vẻ đẹp của tinh khiết DI là bạn không nên lo lắng về những kiếp sống phụ thuộc của bạn, bởi vì chúng được quản lý cho bạn bởi bất cứ ai cung cấp cho họ (một DI container, hoặc một số mã khác bạn đã viết cho mình).

(Là một sang một bên, bạn nên thoát khỏi hiện Bastard tiêm nhà thầu của bạn. Vứt bỏ các nhà xây dựng parameterless và giữ một trong đó quảng cáo một cách rõ ràng phụ thuộc của nó.)

Giữ constructor của bạn như thế này, và sử dụng _IRepository và _IBusinessRepository khi cần thiết:

public CACSService(IUserRepository Repository, IBusinessRepository businessRepository) 
{ 
    _IRepository = Repository; 
    _IBusinessRepository = businessRepository; 
} 

Nếu bạn lo lắng rằng một trong những kho sẽ không cần thiết tại thời gian chạy, bạn có thể tiêm một thực hiện lười biếng-nạp, nói, IUserRepsository thay vì một thực bạn đã có trong đầu.

Giả sử rằng IUserRepository trông như thế này:

public interface IUserRepository 
{ 
    IUser SelectUser(int userId); 
} 

Bây giờ bạn có thể thực hiện một triển khai lười biếng nạp như thế này:

public class LazyUserRepository : IUserRepository 
{ 
    private IUserRepository uRep; 

    public IUser SelectUser(int userId) 
    { 
     if (this.uRep == null) 
     { 
      this.uRep = new UserRepository(); 
     } 
     return this.uRep.SelectUser(userId); 
    } 
} 

Khi bạn tạo CACService, bạn có thể làm như vậy bằng cách tiêm LazyUserRepository vào đó, đảm bảo rằng UserRepository thực sẽ chỉ được khởi tạo nếu cần.

Vẻ đẹp của cách tiếp cận này là bạn không phải làm điều này cho đến khi bạn cần nó. Thông thường, điều này thực sự sẽ không cần thiết vì vậy thật tuyệt khi có thể trì hoãn việc tối ưu hóa đó cho đến khi chúng thực sự cần thiết.

Lần đầu tiên tôi mô tả kỹ thuật của Phụ thuộc lười biếngherehere.

+2

đồng ý. Đừng ràng buộc bản thân với ctor mặc định bởi vì đó là những gì WCF gợi ý. sử dụng IInstanceProvider để xây dựng cá thể dịch vụ của bạn. –

+0

Thankx Mark cho câu trả lời. Tôi có thể có 10 hoặc 20 kho lưu trữ cho các lớp miền của tôi, tôi có phải thực hiện tải chậm cho mỗi lớp không? đó sẽ là rất nhiều mã. – user282807

+0

Vâng, một trong những điểm chính của tôi là bạn có thể không phải làm điều này cả. Xem xét cẩn thận cho dù điều này có thể là một tối ưu hóa sớm hay không. Ví dụ, nếu bạn sử dụng LINQ to SQL hoặc LINQ to Entities, bạn có thể kết thúc việc triển khai tất cả các kho lưu trữ của bạn dựa trên cùng một ngữ cảnh, và trong trường hợp này, chi phí tạo ra một số cá thể kho lưu trữ có thể không đáng kể. –