在带有 WCF 服务的 C# 服务器中使用穷人的 DI [重复]

Posted

技术标签:

【中文标题】在带有 WCF 服务的 C# 服务器中使用穷人的 DI [重复]【英文标题】:Using Poor man's DI in C# server with WCF services [duplicate] 【发布时间】:2016-03-05 19:52:14 【问题描述】:

我正在用 C# 和 WCF 构建服务器。我有我的 ServiceContract 以及客户端应用程序使用的方法。但是整个逻辑被分离在不同的类中:BusinessLogic。我将在 BussinessLogic 中注入我需要的所有内容,例如存储库/数据库提供程序或存储在内存中的其他数据。我使用 穷人的依赖 来构建我的 BussinessLogic(这是我的作文根)。它是一个控制台应用程序,因此在 Main(string[] args) 方法中创建/解析了 BussinessLogic。

我的问题是 WCF 服务是使用无参数构造函数创建的,独立于服务器的其余部分。它们每次都被创建,当用作客户端时。

这是我的服务器的样子:

    static void Main(string[] args)
    
        ServiceHost host = new ServiceHost(typeof(ServiceLayer), new Uri("net.tcp://localhost:8005"));
        host.Open();

        Console.WriteLine("Running... Press key to stop");
        Console.ReadKey();
    

我的服务:

[ServiceContract]
public interface IServiceContract

    [OperationContract]
    ...


public class ServiceLayer : IServiceContract

    IBusinessLogic _businessLogic;
    public ServiceLayer(IBusinessLogic businessLogic)
    
        _businessLogic = businessLogic;
    

    // Here, I would like to use IBusinessLogic
    ...

我发现了如何使用 IoC here 做到这一点(我没有测试它),但我正在寻找一个具有 穷人依赖 的最佳解决方案,无需任何容器或工具,只有 C# 和 .NET。如果没有任何像 IoC 一样好的或接近它的解决方案,请发表评论。

【问题讨论】:

【参考方案1】:

如果您围绕commands 和queries 为您的应用程序建模,那么将您的WCF 服务创建为thin maintenance free layer with just one service class 将变得非常容易。

当您只有一个服务类时,您可以将此服务类本身用作Composition Root 或Humble Object,这意味着您不需要将任何依赖项注入服务类。当涉及到依赖注入时,这完全可以防止您在 WCF 管道中进行任何集成!

当您应用这些模式时,您可以将您的服务简化为以下代码:

[ServiceKnownType(nameof(GetKnownTypes)]
public class CommandService

    [OperationContract, FaultContract(typeof(ValidationError))]
    public void Execute(dynamic command) 
        CreateCommandHandler(command.GetType()).Handle(command);
    

    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider cap) 
        yield return typeof(ShipOrder);
        yield return typeof(CancelOrder);
        yield return typeof(ConfirmOrder);
    

    // Singletons
    private static IUserContext userContext = new WcfUserContext();

    private static dynamic CreateCommandHandler(Type commandType)
    
        var context = new DbContext();

        if (commandType == typeof(ShipOrder))
            return Decorate(new ShipOrderHandler(context));
        if (commandType == typeof(CancelOrder))
            return Decorate(new CancelOrderHandler(context));
        if (commandType == typeof(ConfirmOrder))
            return Decorate(new ConfirmOrderHandler(context, userContext));

        throw new ArgumentException("Unknown: " + commandType.FullName);
    

    private static ICommandHandler<T> Decorate<T>(ICommandHandler<T> handler) 
        return new WcfExceptionTranslatorCommandHandlerDecorator(
            new LoggingCommandHandlerDecorator(
                new Logger(),
                new AuditTrailingCommandHandlerDecorator(
                    new PermissionCheckerCommandHandlerDecorator(
                        new ValidationCommandHandlerDecorator(
                            new TransactionCommandHandlerDecorator(
                                handler))))));
    

【讨论】:

感谢@Steven,我将不得不阅读您的几篇文章才能完全理解您的答案,这有点......不完全清楚。但据我现在所见,您拥有CommandService 而没有实现其接口(合同),这有点奇怪。第二件事,我现在正在查看solidservices 项目,这个 Bootstrapper 静态类看起来有点像 Service Locator。不是注入的,是全局静态类 嗨@Tom,WCF 可以在不使用界面的情况下完美地工作,但是如果界面真的与您相关,您可以简单地添加它。我从来不需要它。关于服务定位器,请尝试理解Composition Root和when something is and isn't a Service Locator的概念。在solidservices 项目中,CommandService 类是一个 Humble Object,可以看作是 Composition Root 的一部分。【参考方案2】:

Poor man 的 DI 现在称为 Pure DI。

您可以使用 Pure DI 来编写 WCF 应用程序。您需要在Composition Root 中执行此操作。

在 WCF 应用程序中,Composition Root 是一个自定义的 ServiceHostFactory。

This answer 展示了如何执行此操作的示例。

您可以自定义该答案中的代码以添加更多依赖项。

【讨论】:

第一件事:如果我错了,请纠正我,但是当我想自我托管时,我不需要MyServiceHostFactory。根本不用碰ServiceHostFactory,对吧?在 IIS 中托管时需要它。第二件事:如果我想要更多而不是一个ServiceLayer。例如我可以有SecondServiceLayer : ISecondServiceContract service :/ 添加到我的“第一件事”:我可以说MyInstanceProvider 是我的“组合根”。它是由MyServiceHost 创建的,但IDependency 对象(这将是我的服务器逻辑)“存储”在我的MyInstanceProvider 提供程序中。因此,每次从客户端发送新请求并且需要创建我的ServiceLayer 服务时,它不会创建新的IDependency,这很好。 IDependency 在服务器的整个生命周期中只有一个实例。我写的对吗? @Tom,你对 IIS 和 ServiceHostFactory 的看法是正确的。在 IIS 之外托管时,您有更多选择。如果您在控制台应用程序中托管您的 WCF 服务(例如),则组合根将成为 main 方法,您将在那里创建您的依赖项并将任何依赖项注入您为 WCF 服务创建的自定义实例提供程序。您可以为您拥有的两个服务创建两个实例提供程序类。 一个问题。是否已经有实现IInstanceProviderIContractBehavior 的具体类?我的意思是,现在我必须编写大量代码(MyInstanceProvider 类)来实现我的构造函数(使用注入)和GetInstance(InstanceContext instanceContext) 方法来新建我的服务。我可以从实现这两个接口的类派生,只需覆盖这个单一方法并添加我的构造函数注入。这会更容易。当然如果存在这样的类

以上是关于在带有 WCF 服务的 C# 服务器中使用穷人的 DI [重复]的主要内容,如果未能解决你的问题,请参考以下文章

C# Restful WCF 服务。无法在帖子正文中反序列化 XML

如何通过 Jquery 调用 C# WCF 服务来修复“ERR_ABORTED 400 (Bad Request)”错误?

如何使用 WCF 在 C# 中调试 localhost 客户端/服务

在另一个项目 c# 中使用引用项目的 WCF 服务

在 WCF 服务 C# 的服务器端获取客户端的 Mac 地址不重复(在 WCF 3.0 中获取客户端 IP 地址)

在 WCF 和 .NET 4.0 中使用 TLS 1.1 或 1.2?