Service Fabric Stateful Service Remoting V2 - azure-service-fabric

I have a Stateful Service called by a Stateless service, in .Net Standard Asp.net Core 2.0 running on Visual Studio 15.4.
I can't make the Service Remoting V2 work.
The old code in the Stateful service that worked for V1 is not valid anymore
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new List<ServiceReplicaListener>()
{
new ServiceReplicaListener((context) =>this.CreateServiceRemotingListener(context))
};
I tried to follow this tutorial but the example is for the stateless one.
I tried to change the code in this without success.
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new List<ServiceReplicaListener>()
{
new ServiceReplicaListener((c) =>new FabricTransportServiceRemotingListener(c, this))
};
}
Also there are no instructions on how or where to use this code in the tutorial
var proxyFactory = new ServiceProxyFactory((c) =>
{
return new FabricTransportServiceRemotingClientFactory();
});
I'm stuck, could someone show me how to make it work?

In your stateful service, in method CreateServiceReplicaListeners, use this code:
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return this.CreateServiceRemotingReplicaListeners();
}
And in the file that defines your remoting service interface, add this:
[assembly: FabricTransportServiceRemotingProvider(RemotingListener = RemotingListener.V2Listener, RemotingClient = RemotingClient.V2Client)]
(for example, just below the using namespaces list.)
Add the endpoint:
<Endpoint Name="ServiceEndpointV2" />
And rebuild the client.

Related

Adding Autofac to .NET core 6.0 using the new single file template

I am trying to add Autofac to a .Net 6.0 web API.
I'm using the latest ASP.NET Core Web API template that generates a single start-up Program.cs file.
Installed Autofac versions:
Autofac 6.3.0
Autofac.Extensions.DependancyInjection (7.2.0-preview.1)
Installed .Net 6.0 versions:
Microsoft.AspNetCore.App 6.0.0-rc.2.21480.10
Microsoft.NETCore.App 6.0.0-rc.2.21480.5
Microsoft.WindowsDesktop.App 6.0.0-rc.2.21501.6
Just in case of doubt, this is the entire content of the Program.cs file (yes, no namespaces or class definition. Only a Program.cs file and no StartUp class or Startup.cs file)
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run()
I've tried looking through the latest Autofac documentation but the examples there, despite saying for .Net Core 3.x and later don't seem to fit with .Net 6.0 code. I can't figure out how to add Autofac into the middleware pipeline.
Any help is greatly appreciated.
Code snippet from Autofac website
public class Program
{
public static void Main(string[] args)
{
// ASP.NET Core 3.0+:
// The UseServiceProviderFactory call attaches the
// Autofac provider to the generic hosting mechanism.
var host = Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webHostBuilder => {
webHostBuilder
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>();
})
.Build();
host.Run();
}
}
Autofac documention:
https://docs.autofac.org/en/latest/integration/aspnetcore.html#asp-net-core-3-0-and-generic-hosting
I found this.
https://learn.microsoft.com/en-us/aspnet/core/migration/50-to-60-samples?view=aspnetcore-5.0
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
// Register services directly with Autofac here. Don't
// call builder.Populate(), that happens in AutofacServiceProviderFactory.
builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new MyApplicationModule()));
var app = builder.Build();
At "Program.cs"
You'll find
var builder = WebApplication.CreateBuilder(args);
Add below
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer<ContainerBuilder>(builder =>
{
builder.RegisterModule(new AutofacBusinessModule());
});
Answer above, I've assumed that you had everything else set up.
I'm using Autofac and Autofact.Extras.DynamicProxy
Sharing below my AutofacBusinessModule just for clarification.
public class AutofacBusinessModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ProductManager>().As<IProductService>().SingleInstance();
builder.RegisterType<EfProductDal>().As<IProductDal>().SingleInstance();
}
}
I have attached examples of both manual declarations and Reflection API of how to add Autofac to .NET Core 6.0
Call UseServiceProviderFactory on the Host sub-property
Call ConfigureContainer on the Host sub-property
Declare your services and their lifetime
Example of a manual services declaration
var builder = WebApplication.CreateBuilder(args);
// Call UseServiceProviderFactory on the Host sub property
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
// Call ConfigureContainer on the Host sub property
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
// Declare your services with proper lifetime
builder.RegisterType<AppLogger>().As<IAppLogger>().SingleInstance();
builder.RegisterType<DataAccess>().As<IDataAccess>().InstancePerLifetimeScope();
});
Example of Assembly scanning "Reflection API"
var builder = WebApplication.CreateBuilder(args);
// Call UseServiceProviderFactory on the Host sub property
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
// Call ConfigureContainer on the Host sub property
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
builder.RegisterAssemblyTypes(Assembly.Load(nameof(DemoLibrary))).Where(t => t.Namespace?.Contains("Practicing.Services") == true)
.As(t => t.GetInterfaces().FirstOrDefault(i => i.Name == "I" + t.Name));
});

EF Core Migrations in Azure Function startup

According to https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection the service provider should not be used until AFTER the startup has completed running. Indeed, if I try to get a registered service it will fail.
Example:
[assembly: FunctionsStartup(typeof(Startup))]
namespace Fx {
public sealed class Startup : FunctionsStartup {
public override void Configure(IFunctionsHostBuilder builder) {
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddEnvironmentVariables();
var configuration = configurationBuilder.Build();
builder.Services.AddInfrastructure(configuration);
builder.Services.AddApplication();
var serviceProvider = builder.Services.BuildServiceProvider();
DependencyInjection.AddDatabase(serviceProvider).GetAwaiter().GetResult();
}
}
}
public static class DependencyInjection {
public static async Task AddDatabase(IServiceProvider services) {
using var scope = services.CreateScope();
var serviceProvider = scope.ServiceProvider;
var context = serviceProvider.GetRequiredService<ApplicationDbContext>();
//Error generated here
if (context.Database.IsSqlServer()) {
await context.Database.MigrateAsync();
}
await ApplicationDbContextSeed.SeedSamplePersonnelDataAsync(context);
}
public static IServiceCollection AddInfrastructure(
this IServiceCollection services,
IConfiguration configuration) {
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));
services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());
return services;
}
}
This produces the following error
Microsoft.EntityFrameworkCore: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
Is there a good option for migrating and seeding during startup?
The easiest way I found to run code after startup was by registering a custom IWebJobsStartup by using the WebJobsStartupAttribute (the FunctionsStartupAttribute actually also inherits from this attribute). In the WebJobsStartup class you'll need to register your extension using the AddExtension where you are able to use dependency injection and seed your database. My code:
[assembly: WebJobsStartup(typeof(DbInitializationService), "DbSeeder")]
namespace Our.Database.Seeder
{
public class DbInitializationService : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
builder.AddExtension<DbSeedConfigProvider>();
}
}
[Extension("DbSeed")]
internal class DbSeedConfigProvider : IExtensionConfigProvider
{
private readonly IServiceScopeFactory _scopeFactory;
public DbSeedConfigProvider(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public void Initialize(ExtensionConfigContext context)
{
using var scope = _scopeFactory.CreateScope();
var dbContext = scope.ServiceProvider.GetService<YourDbContext>();
dbContext.Database.EnsureCreated();
// Further DB seeding, etc.
}
}
}
According to your code, I assume that you're building something aligned to the CleanArchitecture Repository on Github. https://github.com/jasontaylordev/CleanArchitecture
The main difference between this repo and your apporach, is that you're obviously not using ASP.NET, which is not a problem at all, but requires a little bit more configuration work.
The article already mentioned (https://markheath.net/post/ef-core-di-azure-functions) refers another blogpost (https://dev.to/azure/using-entity-framework-with-azure-functions-50aa), which briefly explains that EntityFramework Migrations are not capable of auto-discovering your migrations in an Azure Function. Therefore, you need to implement an instance of IDesignTimeDbContextFactory. I also stumbled upon it in the microsoft docs:
https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli#from-a-design-time-factory
You could for example place it inside your Infrastructure\Persistence\Configurations folder. (Once again, I'm only assuming that you're following the CleanArchitecture repo structure)
DI in AZURE Functions
Caveats
A series of registration steps run before and after the runtime processes the startup class. Therefore, keep in mind the following items:
The startup class is meant for only setup and registration. Avoid using services registered at startup during the startup process. For instance, don't try to log a message in a logger that is being registered during startup. This point of the registration process is too early for your services to be available for use. After the Configure method is run, the Functions runtime continues to register additional dependencies, which can affect how your services operate.
The dependency injection container only holds explicitly registered types. The only services available as injectable types are what are setup in the Configure method. As a result, Functions-specific types like BindingContext and ExecutionContext aren't available during setup or as injectable types

Calling services from other application in the cluster

Is it possible to call services or actors from one application to another in a Service Fabric Cluster ? When I tryed (using ActorProxy.Create with the proper Uri), I got a "No MethodDispatcher is found for interface"
Yes, it is possible. As long as you have the right Uri to the Service (or ActorService) and you have access to the assembly with the interface defining your service or actor the it should not be much different than calling the Service/Actor from within the same application. It you have enabled security for your service then you have to setup the certificates for the exchange as well.
If I have a simple service defined as:
public interface ICalloutService : IService
{
Task<string> SayHelloAsync();
}
internal sealed class CalloutService : StatelessService, ICalloutService
{
public CalloutService(StatelessServiceContext context)
: base(context) { }
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
yield return new ServiceInstanceListener(this.CreateServiceRemotingListener);
}
public Task<string> SayHelloAsync()
{
return Task.FromResult("hello");
}
}
and a simple actor:
public interface ICalloutActor : IActor
{
Task<string> SayHelloAsync();
}
[StatePersistence(StatePersistence.None)]
internal class CalloutActor : Actor, ICalloutActor
{
public CalloutActor(ActorService actorService, ActorId actorId)
: base(actorService, actorId) {}
public Task<string> SayHelloAsync()
{
return Task.FromResult("hello");
}
}
running in a application like this:
Then you can call it from another application within the same cluster:
// Call the service
var calloutServiceUri = new Uri(#"fabric:/ServiceFabric.SO.Answer._41655575/CalloutService");
var calloutService = ServiceProxy.Create<ICalloutService>(calloutServiceUri);
var serviceHello = await calloutService.SayHelloAsync();
// Call the actor
var calloutActorServiceUri = new Uri(#"fabric:/ServiceFabric.SO.Answer._41655575/CalloutActorService");
var calloutActor = ActorProxy.Create<ICalloutActor>(new ActorId(DateTime.Now.Millisecond), calloutActorServiceUri);
var actorHello = await calloutActor.SayHelloAsync();
You can find the right Uri in the Service Fabric Explorer if you click the service and look at the name. By default the Uri of a service is: fabric:/{applicationName}/{serviceName}.
The only tricky part is how do you get the interface from the external service to your calling service? You could simply reference the built .exe for the service you wish to call or you could package the assembly containing the interface as a NuGet package and put on a private feed.
If you don't do this and you instead just share the code between your Visual Studio solutions the Service Fabric will think these are two different interfaces, even if they share the exact same signature. If you do it for a Service you get an NotImplementedException saying "Interface id '{xxxxxxxx}' is not implemented by object '{service}'" and if you do it for an Actor you get an KeyNotfoundException saying "No MethodDispatcher is found for interface id '-{xxxxxxxxxx}'".
So, to fix your problem, make sure you reference the same assembly that is in the application you want to call in the external application that is calling.

Recommended way to register custom serializer with StateManager

In the pre-GA version of Service Fabric I was registering a custom serializer like this:
protected override IReliableStateManager CreateReliableStateManager()
{
IReliableStateManager result = new ReliableStateManager(
new ReliableStateManagerConfiguration(
onInitializeStateSerializersEvent: InitializeStateSerializers));
return result;
}
private Task InitializeStateSerializers()
{
StateManager.TryAddStateSerializer(new KFOBinarySerializer());
return Task.FromResult(false);
}
However, the CreateReliableStateManager method was removed in the GA version. I've struggled to get something working in its place. Currently I'm calling
StateManager.TryAddStateSerializer(new KFOBinarySerializer());
from within the service's RunAsync method, which appears to work fine.
What is the recommended way to register a custom serializer?
TryAddStateSerializer is deprecated. Anyone know if this is because custom serialization support will go away or if it will simply be supported through some other mechanism?
You can create the state manager in the StatefulService's constructor (full example here):
class MyService : StatefulService
{
public MyService(StatefulServiceContext serviceContext)
: base(serviceContext, CreateReliableStateManager()) { }
private static IReliableStateManager CreateReliableStateManager() { ... }
}
Regarding the deprecated API, Microsoft says it's safe to use, but it will change in the future.

Issue using AutofacWebApiDependencyResolver with OWIN and WebAPI 2.1

I can't seem to use the DependencyResolver in my OAuthAuthorizationServerProvider.
DependencyResolver.Current
returns the MVC one which I don't use, and
GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IXXX))
throws the following error:
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
Any ideas if I am doing something wrong or I simply can't use a dependency where I'm trying?
This is what my Startup.Auth.cs looks like:
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<XXX>().As<IXXX>().InstancePerRequest();
var container = builder.Build();
//I've tried both approached here!
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(webApiConfig);
app.UseWebApi(webApiConfig);
And this is my OAuth provider code:
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public SimpleAuthorizationServerProvider(string publicClientId)
{
if (publicClientId == null)
throw new ArgumentNullException("publicClientId");
_publicClientId = publicClientId;
}
public IXXX XXX
{
get { return (IXXX)(_xxx??GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IXXX))); }
set { _xxx= value; }
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//Dependency IXXX used here
}
private readonly string _publicClientId;
private IXXX _xxx;
}
You can use OwinContext.GetAutofacLifetimeScope()
See the nuget package:
http://alexmg.com/owin-support-for-the-web-api-2-and-mvc-5-integrations-in-autofac/
Funnily enough I'm working through a similar problem at the minute and using the following OSS library to achieve this: https://github.com/DotNetDoodle/DotNetDoodle.Owin.Dependencies
This is an IoC container adapter for OWIN middleware, which puts a request level container into the environment dictionary of the OWIN middleware. The container can then be accessed from within your OWIN middleware implementation from which per-request scoped services can be resolved.
This is taken from the documentation from the github repository:
public override async Task Invoke(IOwinContext context)
{
IServiceProvider requestContainer = context.Environment.GetRequestContainer();
IRepository repository = requestContainer.GetService(typeof(IRepository)) as IRepository;
// use repos
}
The following additional links may be useful for you:
A gist discussing this issue: https://gist.github.com/tugberkugurlu/9054704. Specifically this comment: https://gist.github.com/tugberkugurlu/9054704#comment-1172998
The blog entry relating to the DotNetDoodle.Owin.Dependencies library: http://www.tugberkugurlu.com/archive/owin-dependencies--an-ioc-container-adapter-into-owin-pipeline
Hope some of this may be of help to you.