Accessing Service Fabric stateless service config values outside the service project - configuration-files

Is there a way to access Service Fabric Stateless Service's custom config values from a different class library project? I can access the configurations currently like this from the StatelessService itself.
var configurationPackage = Context.CodePackageActivationContext.GetConfigurationPackageObject("Config");
var connectionStringParameter = configurationPackage.Settings.Sections["QueueConfigSection"].Parameters["QueueName"];
How can I access this Context.CodePackageActivationContext from a different project? Or how can I expose the Stateless Service Context to a different project?

Try this:
var activationContext = FabricRuntime.GetActivationContext();
var configurationPackage = activationContext.GetConfigurationPackageObject("Config");
var connectionStringParameter = configurationPackage.Settings.Sections["QueueConfigSection"].Parameters["QueueName"];
Note that this will only work from within the cluster.

Related

Kubernetes Fabric8 API

I currently use the fabric8 API to read contents of PODs, Services etc.
KubernetesClient client = new DefaultKubernetesClient();
client.configMaps().withName("ConfigMapName");
Is there a way to retrieve contents of HTTPProxy from httpproxies of api group projectcontour.io?
Thanks in advance!!!
HTTPProxy seems to be a Custom Resource. Kubernetes Client provides a Typed API (where you need to provide POJOs for your Custom Resource) and a Typeless API(manipulation of Custom Resouces using raw HashMaps). Here is an example on how you can do this using the Typeless API:
try (KubernetesClient client = new DefaultKubernetesClient()) {
CustomResourceDefinitionContext httpProxyContext = new CustomResourceDefinitionContext.Builder()
.withGroup("projectcontour.io") // <- Group of Custom Resource
.withVersion("v1") // <- Version of Custom Resource
.withPlural("httpproxies") // <- Plural form as specified in CRD
.withScope("Namespaced") // <- Whether Custom Resource is Cluster Scoped or Namespaced
.build();
// List all HTTPProxies
Map<String, Object> httpProxyList = client.customResource(httpProxyContext).list("ns1");
// Get a specific HTTPProxy
Map<String, Object> myHttpProxy = client.customResource(httpProxyContext).get("ns1", "tls-example");
}
You may choose whatever approach you think fits your needs. If interested you can probably check out my blogs about these approaches in detail:
Handling Kubernetes Custom Resources in Java using Fabric8 Kubernetes Client: Part-1(Typeless)
Handling Kubernetes Custom Resources in Java using Fabric8 Kubernetes Client: Part-2(Typed)

Is it possible to have a single frontend select between backends (defined dynamically)?

I am currently looking into deploying Traefik/Træfik on our service fabric cluster.
Basically I have a setup where I have any number of Applications (services), defined with a tenant name and each of these services is in fact a separate Web UI.
I am trying to figure out if I can configure a single frontend to target a backend so I don't have to define a new frontend each time I deploy a new UI app. Something like
[frontend.tenantui]
rule = "HostRegexp:localhost,{tenantName:[a-z]+}.example.com"
backend = "fabric:/WebApp/{tenantName}"
The idea is to have it such that I can just deploy new UI services without updating the frontend configuration.
I am currently using the Service Fabric provider for my backend services, but I am open to using the file provider or something else if that is required.
Update:
The servicemanifset contains labels, so as to let traefik create backends and frontends.
The labels are defined for one service, lets call it WebUI as an example. Now when I deploy an instance of WebUI it gets a label and traefik understands it.
Then I deploy ANOTHER instance with a DIFFERENT set of parameters, its still the WebUI service and it uses the same manifest, so it gets the same labels, and the same routing. But what I would really want was to let it have a label containing some sort of rule so I could route to the name of the service instance (determine at runtime not design time). Specifically I would like for the runtime part to be part of the domainname (thus the suggestion of a HostRegexp style rule)
I don't think it is possible to use the matched group from the HostRegexp to determine the backend.
A possibility would be to use the Property Manager API to dynamically set the frontend rule for the service instance after creating it. Also, see this for a complete example on using the API.

Service Fabric Naming Service not forwarding to endpoint assigned to Guest Executable

I have setup an application with two services, one a standard aspnet core api, and another node express app by following the guide here:
https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-deploy-existing-app
When I deploy the application locally I can use the naming service to hit the AspNetCore application such as:
http://localhost:19081/sf_node_test_02/AspNetCore/api/values
Likewise, I expect to be able to hit the api of my guest executable using this address:
http://localhost:19081/sf_node_test_02/NodeApp
However, this does not work.
If I use the direct url of the service such as:
http://localhost:30032/ I can see the node js app is in fact working as expected.
Now, I know when running the AspNet core application it is explicitly sending it's listening address back to the naming service but the guest executable is not so that explains why they might behave differently. Also, from what I understand the current version of service fabric does not provide the guest executable the information about a dynamically assigned port so it must be hard coded in the service endpoint and also in the application to listen on the same port.
E.g. If I have:
<Endpoint Name="NodeAppTypeEndpoint" Port="30032" Protocol="http" Type="Input" UriScheme="http"/>
Then in the nodejs app I must also have:
const port = process.env.PORT || 30032;
app.listen(port, () => {
console.log(`Listening on port: ${port}`);
});
Noticed 30032 in both places.
From the documentation:
Furthermore you can ask Service Fabric to publish this endpoint to the
Naming Service so other services can discover the endpoint address to
this service. This enables you to be able to communicate between
services that are guest executables. The published endpoint address is
of the form UriScheme://IPAddressOrFQDN:Port/PathSuffix. UriScheme and
PathSuffix are optional attributes. IPAddressOrFQDN is the IP address
or fully qualified domain name of the node this executable gets placed
on, and it is calculated for you.
I interpreted this to mean that if my ServiceManifest.xml has both UseImplicitHost="true" then it should automatically give the naming service the url constructed by the endpoint description.
http://localhost:19081/sf_node_test_02/NodeApp -> http://localhost:30032
Is it correct that service fabric will automatically give the naming service this listening address for this service?
Is there anyway for me to inspect the mapping in the naming service?
This would let me know if it does have an entry for my node application but it is just different than what I expect or if in fact it has no entry.
If it doesn't have an entry then I don't know how this guest executable application would be visible to the public when deployed in the cloud either.
You can use the QueryManager of FabricClient to list registered endpoints for services in your cluster. This should reveal if there is an endpoint for your node service.
var fabricClient = new FabricClient();
var applicationList = fabricClient.QueryManager.GetApplicationListAsync().GetAwaiter().GetResult();
foreach (var application in applicationList)
{
var serviceList = fabricClient.QueryManager.GetServiceListAsync(application.ApplicationName).GetAwaiter().GetResult();
foreach (var service in serviceList)
{
var partitionListAsync = fabricClient.QueryManager.GetPartitionListAsync(service.ServiceName).GetAwaiter().GetResult();
foreach (var partition in partitionListAsync)
{
var replicas = fabricClient.QueryManager.GetReplicaListAsync(partition.PartitionInformation.Id).GetAwaiter().GetResult();
foreach (var replica in replicas)
{
if (!string.IsNullOrWhiteSpace(replica.ReplicaAddress))
{
var replicaAddress = JObject.Parse(replica.ReplicaAddress);
foreach (var endpoint in replicaAddress["Endpoints"])
{
var endpointAddress = endpoint.First().Value<string>();
Console.WriteLine($"{service.ServiceName} {endpointAddress} {endpointAddress}");
}
}
}
}
}
}

Not able to find my stateless service that uses the WcfCommunicationListener

I am trying to find my stateless service using IServiceProxyFactory CreateServiceProxy method. It seems to find the service instance but when I invoke a method it gets an error "Client is trying to connect to invalid address net.tcp://localhost...". The stateless service uses WcfCommunicationListener.
The default implementation of IServiceProxyFactory is ServiceProxyFactory, that creates an instance of FabricTransportServiceRemotingClientFactory which in turn gives you an FabricTransportServiceRemotingClient. This one communicates (as the name suggests) using Fabric transport over TCP. Fabric transport expects the Service to have a fabric transport listener FabricTransportServiceRemotingListener on a address like fabric:/applicationname/servicename.
If you want to connect to your service that is listening to connections using the WcfCommunicationListener then you need to connect to it using WcfCommunicationClient that you can create like this:
// Create binding
Binding binding = WcfUtility.CreateTcpClientBinding();
// Create a partition resolver
IServicePartitionResolver partitionResolver = ServicePartitionResolver.GetDefault();
// create a WcfCommunicationClientFactory object.
var wcfClientFactory = new WcfCommunicationClientFactory<IMyService>
(clientBinding: binding, servicePartitionResolver: partitionResolver);
var myServiceClient = new WcfCommunicationClient(
wcfClientFactory,
ServiceUri,
ServicePartitionKey.Singleton);
The above sample is from the documentation https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-wcf
So, either change your service to use fabric transport if you want to use ServiceProxy to create a client, or change your client side to use WcfCommunicationClient instead.

WCF Web API Configuration File to IIS

I have implemented a restful service with WCF Web API and I want to publish it in IIS.
During developing process I was using the service as Console Application and all configuration was made through API.
Now I'm trying to publish the service as ASP.NET application and the only way I see is somehow to move all configuration into web config file.
Here the coded configuration:
var cfg = HttpHostConfiguration.Create()
.AddMessageHandlers(typeof(AllowCrossDomainRequestHandler));
using (var host = new HttpConfigurableServiceHost(typeof(RESTfulService), cfg , new Uri("http://localhost:8081")))
{
var endpoint = ((HttpEndpoint)host.Description.Endpoints[0]); //Assuming one endpoint
endpoint.TransferMode = TransferMode.Streamed;
endpoint.MaxReceivedMessageSize = 1024 * 1024 * 10; // Allow files up to 10MB
host.Open();
Console.WriteLine("Host opened at {0} , press any key to end", host.Description.Endpoints[0].Address);
Console.ReadKey();
}
How should my web.config look to reflect this configuration?
Or is there any other approach instead of using ASP.NET?
Any help is appreciated.
If you want to preserve your existing config, you can put all your config set up stuff into a method, and call it from global.asax Application_Start() method. All the Global.asax methods will get called in WCF the same as they do for ASP.NET.
Or, you can wire your services to a custom ServiceHostFactory and ServiceHost that has all the configuration in it (this is the approach I am using in my current app).