8

Tôi đang nhìn vào bộ điều khiển trong trang web của tôi, và hầu hết các nhà thầu của họ trông như thế này:Củng cố ASP.NET MVC Controller Dependencies (StructureMap)

public SomeController(
    IServiceOne serviceOne, 
    IServiceTwo serviceTwo, 
    ILoggingService loggingService, 
    IGeospatialService geoSpatialService) 
{ 
    // copy to class variables. 
} 

Nói cách khác, đó là rất nhiều lông và làm cho refactoring khó khăn. Một số bộ điều khiển có khoảng 8 phụ thuộc.

Có cách nào tôi có thể bằng cách nào đó "nhóm" những phụ thuộc này vào một trong nhiều nhóm hơn không?

Ví dụ, ILoggingService là bắt buộc trong mọi bộ điều khiển, IGeospatialService là bắt buộc bởi bộ điều khiển làm công cụ không gian và IServiceOneIServiceTwo chỉ bắt buộc trong một số trường hợp nhất định.

Tôi muốn nhìn thấy một cái gì đó như thế này:

public SomeController(
     ICoreServicesGroup coreGroup, 
     ISomeNameForServicesGroup serviceGroup) 
    { 
     // copy to class variables. 
    } 

Tôi nghĩ nó sẽ là tốt để giới thiệu một số kỹ thuật OO, chẳng hạn như có một "cơ sở" class depedency, trong đó có một ILoggingService trong nó bảo vệ ctor. Sau đó, bạn có thể có một phụ thuộc con khác mà thừa kế, v.v.

Có ai đã làm điều này trước đây không? Đây có phải là thứ mà StructureMap có thể làm cho tôi hay chỉ đơn giản là tôi đang cuộn mã cơ bản của riêng mình?

+2

tôi sẽ trả lời nhưng tôi sẽ chỉ nói một cái gì đó như thế này: http://stackoverflow.com/a/6026515/373378 –

Trả lời

13

Logging

Khi một phụ thuộc là cần thiết trong mỗi điều khiển đó là một chỉ số khá chắc chắn rằng nó không phải là một 'norma l 'phụ thuộc, nhưng thay vào đó là Mối quan tâm cắt ngang. Ghi nhật ký là ví dụ điển hình về Mối quan tâm xuyên suốt, vì vậy, ILoggingService nên được xử lý giống như bất kỳ Mối quan tâm xuyên suốt nào khác.

Trong SOLID OO cách thích hợp để giải quyết mối quan tâm Cross-cutting sẽ là sử dụng Decorator (trong đó can be generalized towards AOP). Tuy nhiên, các phương thức hành động của ASP.NET MVC Controller không phải là một phần của bất kỳ giao diện nào, vì vậy đó là một giải pháp ít lý tưởng.

Thay vào đó, khung MVC cung cấp Action Filters cho mục đích chặn. Nếu bạn muốn triển khai bộ lọc được ghép lỏng lẻo, hãy tự làm một điều và implement it as a global filter instead of an attribute.

phụ thuộc khác

Đối với phụ thuộc khác nó làm cho tinh thần để refactor them to Facade Services. Điều này liên quan đến việc xác định các cụm dịch vụ liên quan tự nhiên, vì vậy chính xác cách thức này được thực hiện cụ thể cho từng cơ sở mã.

0

Tôi thấy một vài lựa chọn:

  1. dịch vụ Fascade như @ 32bitkid đề cập.
  2. Tách bộ điều khiển của bạn thành các nhóm hành động hạt mịn hơn có phụ thuộc phổ biến hơn.
  3. Điểm vào tĩnh. (Tôi biết nhiều người không thích chúng, nhưng tôi thấy chúng khá hữu ích cho các dịch vụ cốt lõi của tôi mà không bao giờ thay đổi, ngay cả với DI.) Dưới đây là một ví dụ sử dụng Định vị dịch vụ chung.

public class Logger 
{ 
    public static Func<ILoggerService> Instance =() => ServiceLocator.Current.GetInstance<ILoggerService>(); 
} 

Cách sử dụng: Logger.Instance().Log(message);

Thử nghiệm: Logger.Instance =() => new TestLogger();

3

Tôi biết tôi đã chấp nhận câu trả lời của @Mark Seeman một thời gian trước đây, nhưng cuối cùng tôi chỉ có thời gian để thực hiện điều này ngay bây giờ, vì vậy tôi nghĩ chia sẻ những gì tôi thực sự đã làm, vì lợi ích của người khác.

Về cơ bản, tôi đã tạo giao diện trình bao bọc cho "nhóm" phụ thuộc trong ứng dụng của mình.

Ví dụ:

public interface ICoreServicesDependencyGroup 
{ 
    IUnitOfWork UnitOfWork { get; } 
    IAspNetMvcLoggingService LoggingService { get; } 
} 

Và việc thực hiện:

public class CoreServicesDependencyGroup : ICoreServicesDependencyGroup 
{ 
    private readonly IAspNetMvcLoggingService _loggingService; 
    private readonly IUnitOfWork _unitOfWork; 

    public CoreServicesDependencyGroup(
     IAspNetMvcLoggingService loggingService, 
     IUnitOfWork unitOfWork) 
    { 
     Condition.Requires(loggingService).IsNotNull(); 
     Condition.Requires(unitOfWork).IsNotNull(); 
     _loggingService = loggingService; 
     _unitOfWork = unitOfWork; 
    } 

    public IUnitOfWork UnitOfWork { get { return _unitOfWork; } } 
    public IAspNetMvcLoggingService LoggingService { get { return _loggingService; } } 
} 

Khá đơn giản thực sự.

Sau đó, tôi đã cập nhật bộ điều khiển của mình.

Ví dụ ctor Trước:

public LocationController(
    IUnitOfWork unitOfWork, 
    IAspNetMvcLoggingService loggingService, 
    ILocationService locationService, 
    ICachedLocationService cachedLocationService) 
{ 
    _unitOfWork = unitOfWork; 
    _loggingService = loggingService; 
    _locationService = locationService; 
    _cachedLocationService = cachedLocationService; 
} 

Sau:

public LocationController(
    ICoreServicesDependencyGroup coreServicesDependencyGroup, 
    ILocationDependencyGroup locationDependencyGroup) 
{ 
    _unitOfWork = coreServicesDependencyGroup.UnitOfWork; 
    _loggingService = coreServicesDependencyGroup.LoggingService; 
    _locationService = locationDependencyGroup.Service; 
    _cachedLocationService = locationDependencyGroup.CachedService; 
} 

Không có gì đặc biệt thực sự, chỉ cần đặt các giấy gói. Dưới mui xe, các bộ điều khiển vẫn sử dụng cùng một phụ thuộc, nhưng chữ ký ctor nhỏ hơn nhiều, dễ đọc hơn, và nó cũng làm cho việc kiểm tra đơn vị dễ dàng hơn.

Các vấn đề liên quan