具有多个端点和依赖注入的Service Fabric

时间:2018-06-11 13:09:52

标签: dependency-injection autofac azure-service-fabric

我目前正致力于POC项目,并且我试图找出如何在不同端点之间共享服务依赖关系来控制应用程序状态和处理所有服务请求(让我们称之为ControlService) - 特别是当其中一个端点是KestrelCommunicationListener / HttpSysCommunicationListener并与FabricTransportServiceRemotingListener(或任何其他类型的自定义侦听器)结合时

Autofac看起来很有希望但是这些示例并未显示如何在启动而不是主入口点构建容器时使HTTP侦听器工作 - 我是否需要将容器传递给MyFabricService以便它可以传入启动注册并添加到其中吗?

我已经看到过使用container.Update()或使用container.BeginLifetimeScope()动态添加注册的引用,但他们都使用了main中构建的容器,然后我不确定我是怎么做的将HTTP侦听器创建的API添加到原始容器中。

我可能没有那么好解释,总而言之,我希望有类似下面的服务,可以通过n接收通信。不同的端点 - 处理消息,然后通过n发送消息。客户端(也称为其他服务端点)

Control Service Endpoints

enter image description here

很高兴澄清是否有任何不清楚的地方 - 甚至可能使用其他创意图表:)

更新:

来自Program.Main()

   ServiceRuntime.RegisterServiceAsync("ManagementServiceType",
                                context => new ManagementService(context)).GetAwaiter().GetResult();

这是我的面料服务

public ManagementService(StatefulServiceContext context)
        : base(context)
    {
        //this does not work but is pretty much what I'm after
        _managementService = ServiceProviderFactory.ServiceProvider.GetService(typeof(IManagementService)) as IManagementService;
    }

    protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners() =>
       new ServiceReplicaListener[]
       {
           //create external http listener
            ServiceReplicaListenerFactory.CreateExternalListener(typeof(Startup), StateManager, (serviceContext, message) => ServiceEventSource.Current.ServiceMessage(serviceContext, message), "ServiceEndpoint"),

            //create remoting listener with injected dependency
            ServiceReplicaListenerFactory.CreateServiceReplicaListenerFor(() => new RemotingListenerService(_managementService), "ManagmentServiceRemotingEndpoint", "ManagementServiceListener")

       };

ServiceReplicaListener

public static ServiceReplicaListener CreateExternalListener(Type startupType, IReliableStateManager stateManager, Action<StatefulServiceContext, string> loggingCallback, string endpointname)
    {
        return new ServiceReplicaListener(serviceContext =>
        {
            return new KestrelCommunicationListener(serviceContext, endpointname, (url, listener) =>
            {
                loggingCallback(serviceContext, $"Starting Kestrel on {url}");

                return new WebHostBuilder().UseKestrel()
                            .ConfigureServices((hostingContext, services) =>
                            {
                                services.AddSingleton(serviceContext);
                                services.AddSingleton(stateManager);

                                services.AddApplicationInsightsTelemetry(hostingContext.Configuration);
                                services.AddSingleton<ITelemetryInitializer>((serviceProvider) => new FabricTelemetryInitializer(serviceContext));
                            })
                            .ConfigureAppConfiguration((hostingContext, config) =>
                            {
                                config.AddServiceFabricConfiguration(serviceContext);
                            })
                            .ConfigureLogging((hostingContext, logging) =>
                            {
                                logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                                logging.AddDebug();
                            })
                            .UseContentRoot(Directory.GetCurrentDirectory())
                            .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                            .UseStartup(startupType)
                            .UseUrls(url)
                            .Build();
            });
        });
    }

启动

public class Startup
{
    private const string apiTitle = "Management Service API";
    private const string apiVersion = "v1";

    private readonly IConfiguration configuration;

    public Startup(IConfiguration configuration)
    {
        this.configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        var modules = new List<ICompositionModule>
                      {
                          new Composition.CompositionModule(),
                          new BusinessCompositionModule()
                      };

        foreach (var module in modules)
        {
            module.AddServices(services, configuration);
        }

        services.AddSwashbuckle(configuration, apiTitle, apiVersion, "ManagementService.xml");
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddApplicationInsights(app.ApplicationServices);

        // app.UseAuthentication();
        //  app.UseSecurityContext();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
          //  app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();

        app.UseCors("CorsPolicy");

        app.UseMvc();

        app.UseSwagger(apiTitle, apiVersion);

        //app.UseMvc(routes =>
        //{
        //    routes.MapRoute(
        //        name: "default",
        //        template: "{controller=Home}/{action=Index}/{id?}");
        //});

    }
}

在startup.cs中使用Microsoft.Extensions.DependencyInjection(不是autofac)在CompositionModules中添加所有服务依赖项

这很好用并创建我的HTTP侦听器 - 我现在只需要一种方法来访问我的http侦听器/ webhost启动期间添加到容器中的服务。

2 个答案:

答案 0 :(得分:0)

您可以使用Autofac.Integration.ServiceFabriс,一个Autofac扩展来支持Service Fabric。您需要在Program.cs中创建一个容器

var builder = new ContainerBuilder();

builder.RegisterServiceFabricSupport();
builder.RegisterType<SomeService>().As<IManagementService>();

builder.RegisterStatelessService<ManagementService>("ManagementServiceType");
using (builder.Build())
{
   // Prevents this host process from terminating so services keep running.
   Thread.Sleep(Timeout.Infinite);
}

然后,您可以将其注入到Fabric服务的构造函数中。您可以在https://alexmg.com/posts/introducing-the-autofac-integration-for-service-fabric

上找到有关此主题的更多信息

答案 1 :(得分:0)

@Tim

很抱歉迟到了回复。目前我正在处理我们公司用于内部项目的库包。该库简化了Reliable Services的配置。我认为我们最近的增强功能可以做你需要做的事情(希望我能正确使用用例)。

有关该库的所有信息都可以在GitHub上的project page找到,可以找到NuGet包here(请注意它是预发布版本,但我们计划完成很快就会发布。

如果您有任何疑问或需要更多信息,请随时与我联系。

<强>更新

我创建了一个sample application。请随意尝试。

这是一个代码示例。

public interface IManagementService
{
    string GetImportantValue();
}

public interface IMessageProvider
{
    string GetMessage();
}

public class MessageProvider : IMessageProvider
{
    public string GetMessage()
    {
        return "Value";
    }
}

public class ManagementService : IManagementService
{
    private readonly IMessageProvider provider;

    public ManagementService(
        IMessageProvider provider)
    {
        this.provider = provider;
    }

    public string GetImportantValue()
    {
        // Same instances should have the same hash
        return this.provider.GetMessage() + $"Hash: {this.GetHashCode()}";
    }
}

public interface IRemotingImplementation : IService
{
    Task<string> RemotingGetImportantValue();
}

public class RemotingImplementation : IRemotingImplementation
{
    private readonly IManagementService managementService;

    public RemotingImplementation(
        IManagementService managementService)
    {
        this.managementService = managementService;
    }

    public Task<string> RemotingGetImportantValue()
    {
        return Task.FromResult(this.managementService.GetImportantValue());
    }
}

public class WebApiImplementationController : ControllerBase
{
    private readonly IManagementService managementService;

    public WebApiImplementationController(
        IManagementService managementService)
    {
        this.managementService = managementService;
    }

    [HttpGet]
    public Task<string> WebApiGetImportantValue()
    {
        return Task.FromResult(this.managementService.GetImportantValue());
    }
}

public class WebApiStartup
{
    private readonly IConfiguration configuration;

    public WebApiStartup(
        IConfiguration configuration)
    {
        this.configuration = configuration;
    }

    public void ConfigureServices(
        IServiceCollection services)
    {
        services.AddMvc();
    }

    public void Configure(
        IApplicationBuilder app,
        IHostingEnvironment env,
        ILoggerFactory loggerFactory)
    {
        app.UseMvcWithDefaultRoute();
    }
}

internal static class Program
{
    /// <summary>
    ///     This is the entry point of the service host process.
    /// </summary>
    private static void Main()
    {
        var host = new HostBuilder()
           .ConfigureServices(
                services =>
                {
                    services.AddTransient<IMessageProvider, MessageProvider>();
                    services.AddSingleton<IManagementService, ManagementService>();
                })
           .ConfigureStatefulService(
                serviceBuilder =>
                {
                    serviceBuilder
                       .UseServiceType("StatefulServiceType")
                       .DefineAspNetCoreListener(
                            listenerBuilder =>
                            {
                                listenerBuilder
                                   .UseEndpointName("ServiceEndpoint")
                                   .UseKestrel()
                                   .UseUniqueServiceUrlIntegration()
                                   .ConfigureWebHost(
                                        webHostBuilder =>
                                        {
                                            webHostBuilder.UseStartup<WebApiStartup>();
                                        });
                            })
                       .DefineRemotingListener(
                            listenerBuilder =>
                            {
                                listenerBuilder
                                   .UseEndpointName("ServiceEndpoint2")
                                   .UseImplementation<RemotingImplementation>();
                            });
                })
           .Build()
           .Run();
    }
}