Stateless service cannot be accessed with ServiceProxy + ASP.NET 5 Web API project causes a health status error

I am new to microsoft azure web service. For my master's degree, I need to develop a prototype approach to microservice in the service structure. After hours of research, I still do not solve the problem (s).

I want to access my stateless (in a local cluster cluster) service in the web interface, for example, at https://azure.microsoft.com/en-us/documentation/articles/service-fabric-add-a -web-frontend / . The easiest way to do this is to add the ASP.NET 5 Web Api project to the Service Fabric application and make a call to the ServiceProxy method in ValuesController . So I added this code to my solution:

ValuesController.cs:

 [Route("api/[controller]")] public class ValuesController : Controller { // GET api/values/IObject [HttpGet("{interfaceName}")] public async Task<string> Get(string interfaceName) { var serviceName = "fabric:/DataServiceFabric/MasterDataMService"; var masterDataService = ServiceProxy.Create<IMasterDataMService>(new Uri(serviceName)); var result = await masterDataService.GetMasterDataByName(interfaceName); return result.Content; } } 

After deploying F5, my browser does not automatically go to my web interface. Studying the Service Fabric Explorer, my ASP.NET 5 application throws a health status error:

 Kind Health State Description ============================================================================= Partitions Error Unhealthy partitions: 100% (1/1), MaxPercentUnhealthyPartitionsPerService=0%. Partition Error Unhealthy partition: PartitionId='413...', AggregatedHealthState='Error'. Event Error Error event: SourceId='System.FM', Property='State'. Partition is below target replica or instance count. 

After this , the question: “The partition is below the target replica or instance of the instance” means that the unhandled exception in my service does not allow it to run. But I can not find the strace stack in my services browser to debug this error. This is my ServiceManifest.xml my ASP.NET web service:

ServiceManifest.xml (Web1):

 <?xml version="1.0" encoding="utf-8"?> <ServiceManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="Web1" Version="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric"> <ServiceTypes> <StatelessServiceType ServiceTypeName="Web1Type"> <Extensions> <Extension Name="__GeneratedServiceType__"> <GeneratedNames xmlns="http://schemas.microsoft.com/2015/03/fabact-no-schema"> <DefaultService Name="Web1Service" /> <ServiceEndpoint Name="Web1TypeEndpoint" /> </GeneratedNames> </Extension> </Extensions> </StatelessServiceType> </ServiceTypes> <CodePackage Name="C" Version="1.0.0"> <EntryPoint> <ExeHost> <Program>approot\runtimes\dnx-clr-win-x64.1.0.0-rc1-update1\bin\dnx.exe</Program> <Arguments>--appbase approot\src\Web1 Microsoft.Dnx.ApplicationHost Microsoft.ServiceFabric.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener</Arguments> <WorkingFolder>CodePackage</WorkingFolder> <ConsoleRedirection FileRetentionCount="5" FileMaxSizeInKb="2048" /> </ExeHost> </EntryPoint> </CodePackage> <Resources> <Endpoints> <Endpoint Name="Web1TypeEndpoint" Protocol="http" Type="Input" Port="80" /> </Endpoints> </Resources> </ServiceManifest> 

And here is my ApplicationManifest.xml my service solution:

ApplicationManifest.xml:

 <?xml version="1.0" encoding="utf-8"?> <ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="DataServiceFabricType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric"> <Parameters> <Parameter Name="ActorTestServiceActorService_PartitionCount" DefaultValue="10" /> <Parameter Name="MasterDataMService_InstanceCount" DefaultValue="-1" /> </Parameters> <ServiceManifestImport> <ServiceManifestRef ServiceManifestName="Web2Pkg" ServiceManifestVersion="1.0.0" /> <ConfigOverrides /> </ServiceManifestImport> <ServiceManifestImport> <ServiceManifestRef ServiceManifestName="Web1" ServiceManifestVersion="1.0.0" /> </ServiceManifestImport> <ServiceManifestImport> <ServiceManifestRef ServiceManifestName="ActorTestServicePkg" ServiceManifestVersion="1.0.0" /> </ServiceManifestImport> <ServiceManifestImport> <ServiceManifestRef ServiceManifestName="MasterDataMServicePkg" ServiceManifestVersion="1.0.0" /> <ConfigOverrides /> </ServiceManifestImport> <DefaultServices> <Service Name="Web1Service"> <StatelessService ServiceTypeName="Web1Type"> <SingletonPartition /> </StatelessService> </Service> <Service Name="ActorTestServiceActorService" GeneratedIdRef="761ee3cf-5a3a-49d8-9c57-aa3480d1acf1"> <StatelessService ServiceTypeName="ActorTestServiceActorServiceType"> <UniformInt64Partition PartitionCount="[ActorTestServiceActorService_PartitionCount]" LowKey="-9223372036854775808" HighKey="9223372036854775807" /> </StatelessService> </Service> <Service Name="MasterDataMService"> <StatelessService ServiceTypeName="MasterDataMServiceType" InstanceCount="[MasterDataMService_InstanceCount]"> <SingletonPartition /> </StatelessService> </Service> </DefaultServices> </ApplicationManifest> 

So, I created a new solution with an ASP.NET 5 web application and the same ValuesController.cs . I guaranteed that my stateless service was running on my local cluster, and then I started a new web application. After calling the GET method in my controller, I received the following exception:

 Exception thrown: 'System.Fabric.FabricException' in mscorlib.dll Microsoft.AspNet.Hosting.Internal.HostingEngine: Information: Request finished in 0,2593ms 500 Microsoft.AspNet.Server.Kestrel: Error: An unhandled exception was thrown by the application. System.Fabric.FabricException: Invalid partition key/ID '{0}' for selector {1} 

My stateless service is a SingletonPartition, so do I need a section key here? And if so, how do I get the key? Fabric Explorer does not provide me with this information for my stateless service. Here is the ServiceManifest.xml my stateless service:

ServiceManifest.xml (MasterDataMService):

 <?xml version="1.0" encoding="utf-8"?> <ServiceManifest Name="MasterDataMServicePkg" Version="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ServiceTypes> <!-- This is the name of your ServiceType. This name must match the string used in RegisterServiceType call in Program.cs. --> <StatelessServiceType ServiceTypeName="MasterDataMServiceType" /> </ServiceTypes> <!-- Code package is your service executable. --> <CodePackage Name="Code" Version="1.0.0"> <EntryPoint> <ExeHost> <Program>MasterDataMService.exe</Program> </ExeHost> </EntryPoint> </CodePackage> <!-- Config package is the contents of the Config directoy under PackageRoot that contains an independently-updateable and versioned set of custom configuration settings for your service. --> <ConfigPackage Name="Config" Version="1.0.0" /> <Resources> <Endpoints> <!-- This endpoint is used by the communication listener to obtain the port on which to listen. Please note that if your service is partitioned, this port is shared with replicas of different partitions that are placed in your code. --> <Endpoint Name="ServiceEndpoint" Type="Input" Protocol="http" Port="80"/> </Endpoints> </Resources> </ServiceManifest> 

After that, I decided to set up a service connection with OWIN:

MasterDataMService.cs:

 internal sealed class MasterDataMService : StatelessService, IMasterDataMService { [...] protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners() { return new[] { new ServiceInstanceListener(initParams => new OwinCommunicationListener("MasterDataMService", new StartUp(), initParams)) }; } } 

Now I can execute my microservice using the HttpClient in my DefaultController :

 var client = new HttpClient(); var request = "http://localhost:80/MasterDataMService/api/values/query"; var result = string.Empty; HttpResponseMessage response = await client.GetAsync(request); if (response.IsSuccessStatusCode) { result = await response.Content.ReadAsStringAsync(); } 

But this is not what I originally wanted. I do not want to specify the service endpoint in my request. Instead, I would like to communicate with my stateless service through ServiceProxy . How do I achieve this? What am I wrong? And how can I solve this health status error with my ASP.NET 5 application that is deployed to my production network cluster?

Thank you for your time.

Edit:

Extended stitch for invalid key section exclusion:

 Exception thrown: 'System.Fabric.FabricException' in mscorlib.dll Microsoft.AspNet.Hosting.Internal.HostingEngine: Information: Request finished in 1,35ms 500 Microsoft.AspNet.Server.WebListener.MessagePump: Error: ProcessRequestAsync System.Fabric.FabricException: Invalid partition key/ID '{0}' for selector {1} ---> System.Runtime.InteropServices.COMException: exception of HRESULT: 0x80071BBF at System.Fabric.Interop.NativeClient.IFabricServiceManagementClient4.EndResolveServicePartition(IFabricAsyncOperationContext context) at System.Fabric.FabricClient.ServiceManagementClient.ResolveServicePartitionEndWrapper(IFabricAsyncOperationContext context) at System.Fabric.Interop.AsyncCallOutAdapter2`1.Finish(IFabricAsyncOperationContext context, Boolean expectedCompletedSynchronously) --- End of inner exception stack trace --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.ServiceFabric.Services.Client.ServicePartitionResolver.<ResolveAsyncHelper>d__2a.MoveNext() --- End of stack trace from the previous location where the exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.ServiceFabric.Services.Communication.Client.CommunicationClientFactoryBase`1.<GetClientAsync>d__a.MoveNext() 

Please give me feedback if you need more. (full stack trace 82 lines long)

Invalid schema stack trace:

 Exception thrown: 'System.ArgumentException' in mscorlib.dll Microsoft.AspNet.Hosting.Internal.HostingEngine: Information: Request finished in 1,45ms 500 Microsoft.AspNet.Server.WebListener.MessagePump: Error: ProcessRequestAsync System.ArgumentException: the provided uri scheme 'http' is invalid; expected 'net.tcp'. Parametername: via at System.ServiceModel.Channels.TransportChannelFactory`1.ValidateScheme(Uri via) at System.ServiceModel.Channels.ConnectionOrientedTransportChannelFactory`1.OnCreateChannel(EndpointAddress address, Uri via) at System.ServiceModel.Channels.ChannelFactoryBase`1.InternalCreateChannel(EndpointAddress address, Uri via) at System.ServiceModel.Channels.ServiceChannelFactory.ServiceChannelFactoryOverDuplexSession.CreateInnerChannelBinder(EndpointAddress to, Uri via) at System.ServiceModel.Channels.ServiceChannelFactory.CreateServiceChannel(EndpointAddress address, Uri via) at System.ServiceModel.Channels.ServiceChannelFactory.CreateChannel(Type channelType, EndpointAddress address, Uri via) at System.ServiceModel.DuplexChannelFactory`1.CreateChannel(InstanceContext callbackInstance, EndpointAddress address, Uri via) at System.ServiceModel.DuplexChannelFactory`1.CreateChannel(InstanceContext callbackInstance, Binding binding, EndpointAddress endpointAddress) at Microsoft.ServiceFabric.Services.Communication.Wcf.Client.WcfCommunicationClientFactory`1.<CreateClientAsync>d__2.MoveNext() --- End of stack trace from the previous location where the exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.ServiceFabric.Services.Communication.Client.CommunicationClientFactoryBase`1.<CreateClientWithRetriesAsync>d__1e.MoveNext() 
+5
source share
6 answers

I ran into the same problem after learning about Service Fabric. It turned out that providing only the URI was not enough - I also had to specify the section key as a magic value:

 IHelloService service = ServiceProxy.Create<IHelloService>(new Uri("fabric:/Application1/HelloService"), new ServicePartitionKey(1)); 

Kudos to this thread on disq.us. There is also a deeper explanation provided by Microsoft engineer Oana Plato regarding why value 1 works:

Diogo, take a look at this article that explains the separation: link In particular, look at the range (otherwise known as UniformInt64Partition): “This is used to indicate an integer range (identified by low key and high key) and a series of partitions (n). It creates n partitions, each responsible for the non-overlapping sub-range of the full range of partition keys. For example, a split partition scheme with a low key of 0, a high key of 99, and a number of 4 will create four partitions, as shown below. " Then look at your service manifest and find out how it is configured - how many partitions and what range (low key - high key). If you have one partition, any key in this range goes to the (one) partition, so it does not matter which key you specify. If you have more than one section, you need to find out which client should talk to. Specify the section key in the range that the section serves.

I must admit that I myself have to study the partition in more detail in order to understand this explanation.

+4
source

In the initial examples, there is the ServiceUriBuilder class. Initialize this class by passing the service name in the constructor.

 var proxyLocation = new ServiceUriBuilder("MasterDataMService"); var masterDataService = ServiceProxy.Create<IMasterDataMService>(proxyLocation.ToUri()); var result = await masterDataService.GetMasterDataByName(interfaceName); 

Also, in the MasterDataMService CreateServiceInstanceListeners method, make sure it looks something like this:

  protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners() { return new[] { new ServiceInstanceListener(context => new FabricTransportServiceRemotingListener(context, this)) }; } 
+3
source

I ran into the same problem using ServiceProxy using Stateless service. I have services with government services that work well, but the stateless got:

 System.Fabric.FabricException: Invalid partition key/ID '{0}' for selector {1} 

As Allan T mentioned above, you also need to use the third constructor overload for ServiceProxy.Create ():

Instead:

 ServiceProxy.Create<IMasterDataMService>(0, new Uri("fabric:/DataServiceFabric/MasterDataMService")); 

using:

 ServiceProxy.Create<IMasterDataMService>(new Uri("fabric:/DataServiceFabric/MasterDataMService")); 

... simply, do not specify a section. This made a mistake for me.

https://msdn.microsoft.com/en-us/library/mt628402.aspx

+2
source

I ran into the same unpleasant problems and solved them.

Few things to check

1) Make sure your ASP.NET 5 web project does not reference any X64 libraries.

2) Port Clash .. when deploying ASP.NET 5 web api in the cluster, make sure that there are no 2 websites that use the same port. You can change the port inside the [ASP.NET 5] /PackageRoot/ServiceManifest.xml .. project at the bottom

** 3) “wrap” the folder with madness! Make sure that your application folder (in the root folder) contains only .net 4.5.1 class libraries. My problems disappeared when I deleted the “Newtonsoft.Json” folder inside the cover folder. Then you will need to start dnu recovery in the solution so that it will recreate the project.lock.json files.

4) Make sure nothing explodes in your startup.cs class. Run the web api locally to make sure it loads; it is normal that the service proxy class is not loading.

0
source

Judging by your second stack trace:

 System.ArgumentException: the provided uri scheme 'http' is invalid; expected 'net.tcp'. 

It looks like you are trying to use ServiceProxy to connect to a service that is listening on an HTTP endpoint. ServiceProxy expects a Remoting Listener Service that uses the binary protocol, not HTTP.

The first exception is still a mystery:

 System.Fabric.FabricException: Invalid partition key/ID '{0}' for selector {1} 

This will happen if you try to allow a uniform internal or named partitioned service without providing a partition key. In your configuration, it looks like you have the target service configured as a singleton partition, in which case you should not see this error, so you can double check that the service you are trying to connect to is actually created as a singleton service partition?

0
source

In my case, none of this happened. Or more precisely, my solution was a combination / modification of the solutions above.

I needed to do 2 things: first, make sure that I registered my services:

  protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners() { return new[] { new ServiceReplicaListener(context => this.CreateServiceRemotingListener(context)) };} 

And secondly, refer to the first service (the "magic" value is 0)

  ServiceProxy.Create<IMasterDataMService>(new Uri("fabric:/DataServiceFabric/MasterDataMService"), new ServicePartitionKey(0)); 

I hope this helps

0
source

Source: https://habr.com/ru/post/1245565/


All Articles