C# 如何对服务结构应用程序进行版本设置和分离?

C# 如何对服务结构应用程序进行版本设置和分离?,c#,.net,visual-studio,azure,azure-service-fabric,C#,.net,Visual Studio,Azure,Azure Service Fabric,所有服务结构都描述了单个解决方案服务结构示例。这似乎与微服务的理念背道而驰,在微服务中,您希望在服务之间实现完全的依赖隔离。虽然您可以手动遵循此模式,但更常见的做法是通过使每个服务成为自己的存储库和解决方案/项目来实施此模式 如何使用多个解决方案(在多个Git存储库中)管理和部署服务结构服务,并强制执行服务契约(ServiceInferfaces) 例如 1) 作为开发人员,我希望签出并构建所有当前版本的应用程序/服务。我想启动管理所有清单的ServiceFabric项目,并将其部署到本地开发人

所有服务结构都描述了单个解决方案服务结构示例。这似乎与微服务的理念背道而驰,在微服务中,您希望在服务之间实现完全的依赖隔离。虽然您可以手动遵循此模式,但更常见的做法是通过使每个服务成为自己的存储库和解决方案/项目来实施此模式

如何使用多个解决方案(在多个Git存储库中)管理和部署服务结构服务,并强制执行服务契约(ServiceInferfaces)

例如

1) 作为开发人员,我希望签出并构建所有当前版本的应用程序/服务。我想启动管理所有清单的ServiceFabric项目,并将其部署到本地开发人员集群。我希望在解决方案之间实施相同的服务接口。我不明白您是如何做到这一点的,因为应用程序是服务外部的

2) 作为一个DevOps团队,我希望能够自动拉下应用程序,构建它们并部署到Azure

我们如何通过单独的解决方案“强制”隔离,同时使它们能够轻松地组合在一起并部署到集群中,同时也使为开发人员、质量保证人员和产品环境专门配置的每个集群部署管道变得容易


实现这一点的工作流/流程/项目结构是什么?有可能吗?

是的,有可能——我以前做过类似的事情。这些都是立即浮现在脑海中的想法

在每个服务结构解决方案中,都有一个“公共”项目,其中只包含您希望从该应用程序中的服务公开的接口。此项目的输出可以打包为nuget包,并推送到私有存储库中。你可以称之为“接口”项目,但如果你想考虑应用程序内部的一些接口,就不必公开所有的接口;这些可以在单独的、未公开的项目中定义

其他想要引用由另一个应用程序公开的服务的解决方案只需下拉相关的nuget包即可获得对服务接口的引用

现在这并非没有问题:

  • 消费应用程序仍然需要知道服务的地址,以便为它们构造代理。您可以将它们公开为nuget包中某个地方定义的常量,或者如果您正在进行完整的DI过程,并且不介意在任何地方将自己耦合到DI容器(或者尝试将其抽象出来),您可以从nuget包中公开一个模块,该模块可以将服务接口注册为lambda,该lambda代表依赖应用程序创建服务代理
  • 你更容易违约。在更新方法签名时,您需要非常小心,因为您现在负责应用程序/服务部署的粒度和协调
  • 您可能会变得过于细粒度—正如您所提到的,服务结构工具将引导您在一个解决方案中拥有多个服务。即使采用上述方法,我仍会尝试在某种程度上对我的服务进行逻辑分组,也就是说,不要在应用程序和服务之间进行一对一的映射——这肯定会让我感到非常痛苦
希望有帮助

编辑:

在DI模块中注册服务接口的示例(Autofac样式)

这将是您从公共nuget包中公开的DI模块:

using System;
using Autofac;
using Microsoft.ServiceFabric.Services.Remoting.Client;

public class MyAppModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.Register(component => ServiceProxy.Create<IMyService>(new Uri("fabric:/App/MyService"))).As<IMyService>();
        // Other services...
    }
}
使用系统;
使用Autofac;
使用Microsoft.ServiceFabric.Services.Remoting.Client;
公共类MyAppModule:模块
{
受保护的覆盖无效负载(ContainerBuilder builder)
{
builder.Register(component=>ServiceProxy.Create(新Uri(“fabric:/App/MyService”)).As();
//其他服务。。。
}
}
在消费应用程序的Program.cs中,您将包括以下内容:

public static void Main()
{
    try
    {
        var container = ConfigureServiceContainer();

        ServiceRuntime.RegisterServiceAsync(
            "MyConsumingServiceType",
            context => container.Resolve<MyConsumingService>(new TypedParameter(typeof(StatefulServiceContext), context))).GetAwaiter().GetResult();
        ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(MyConsumingService).Name);

        Thread.Sleep(Timeout.Infinite);
    }
    catch (Exception e)
    {
        ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
        throw;
    }
}

private static IContainer ConfigureServiceContainer()
{
    var containerBuilder = new ContainerBuilder();

    // Other registrations...

    containerBuilder.RegisterModule<MyAppModule>();

    return containerBuilder.Build();
}
publicstaticvoidmain()
{
尝试
{
var container=ConfigureServiceContainer();
ServiceRuntime.RegisterServiceAsync(
“MyConsumingServiceType”,
context=>container.Resolve(新的TypedParameter(typeof(StatefulServiceContext),context)).GetAwaiter().GetResult();
ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id,typeof(MyConsumingService).Name);
Thread.Sleep(Timeout.Infinite);
}
捕获(例外e)
{
ServiceEventSource.Current.ServiceHostInitialization失败(例如ToString());
投掷;
}
}
专用静态IContainer ConfigureServiceContainer()
{
var containerBuilder=新的containerBuilder();
//其他注册。。。
containerBuilder.RegisterModule();
返回containerBuilder.Build();
}

当然,只有在不划分服务的情况下,这种方法才会起作用。

您还可以使用松散耦合较少的协议,例如使用xml\wsdl或json\swagger和自动生成或手动创建的httpclient代理的基于http的协议


管理金块库、nuspec等的成本很高。

这很好。我希望MSDN/Azure能够添加更多的SF示例,这些示例超出了他们的会议演示材料的范围。您提到有一个包“可以将服务接口注册为lambda,用于创建服务代理…”您知道这个样板会是什么样子,或者可以为我指出正确的方向吗?我在这方面的研究正在打开我已经点击过的所有链接=)谢谢!编辑后包含一个简单的示例。非常感谢您提供了这个很棒的示例和您的答案@MikeGoatly我想知道我们如何在微服务中对BLL进行版本化?服务A需要调用服务B的v1,但服务B已升级到v2。请注意,没有合同变更,唯一的变更是服务B的BLL。我们如何版本这样的场景?@l--“
public static void Main()
{
    try
    {
        var container = ConfigureServiceContainer();

        ServiceRuntime.RegisterServiceAsync(
            "MyConsumingServiceType",
            context => container.Resolve<MyConsumingService>(new TypedParameter(typeof(StatefulServiceContext), context))).GetAwaiter().GetResult();
        ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(MyConsumingService).Name);

        Thread.Sleep(Timeout.Infinite);
    }
    catch (Exception e)
    {
        ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
        throw;
    }
}

private static IContainer ConfigureServiceContainer()
{
    var containerBuilder = new ContainerBuilder();

    // Other registrations...

    containerBuilder.RegisterModule<MyAppModule>();

    return containerBuilder.Build();
}