public async Task InitializeFromStoreTest() { // Arrange var iterator = new Mock <IServiceIdentitiesIterator>(); iterator.Setup(i => i.HasNext).Returns(true); iterator.Setup(i => i.GetNext()).ThrowsAsync(new InvalidOperationException("Some error")); var serviceProxy = new Mock <IServiceProxy>(); serviceProxy.Setup(s => s.GetServiceIdentitiesIterator()).Returns(iterator.Object); var store = GetEntityStore("cache"); var serviceAuthentication = new ServiceAuthentication(ServiceAuthenticationType.None); var si1 = new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled); var si2 = new ServiceIdentity("d2", "m1", "2345", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled); var storedSi1 = new DeviceScopeIdentitiesCache.StoredServiceIdentity(si1); await store.Put(si1.Id, storedSi1.ToJson()); var storedSi2 = new DeviceScopeIdentitiesCache.StoredServiceIdentity(si2); await store.Put(si2.Id, storedSi2.ToJson()); // Act IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromHours(1)); Option <ServiceIdentity> receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1"); Option <ServiceIdentity> receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1"); // Assert Assert.True(si1.Equals(receivedServiceIdentity1.OrDefault())); Assert.True(si2.Equals(receivedServiceIdentity2.OrDefault())); }
async Task <EdgeHubScopeResult> HandleDevicesAndModulesInTargetDeviceScopeAsync(string actorDeviceId, string actorModuleId, NestedScopeRequest request) { Events.ReceivedScopeRequest(actorDeviceId, actorModuleId, request); Preconditions.CheckNonWhiteSpace(request.AuthChain, nameof(request.AuthChain)); if (!this.TryGetTargetDeviceId(request.AuthChain, out string targetDeviceId)) { return(new EdgeHubScopeResultError(HttpStatusCode.BadRequest, Events.InvalidRequestAuthchain(request.AuthChain))); } // Check that the actor device is authorized to act OnBehalfOf the target IEdgeHub edgeHub = await this.edgeHubGetter; IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); if (!await this.AuthorizeActorAsync(identitiesCache, actorDeviceId, actorModuleId, targetDeviceId)) { return(new EdgeHubScopeResultError(HttpStatusCode.Unauthorized, Events.UnauthorizedActor(actorDeviceId, actorModuleId, targetDeviceId))); } // Get the children of the target device and the target device itself; IList <ServiceIdentity> identities = await identitiesCache.GetDevicesAndModulesInTargetScopeAsync(targetDeviceId); Option <ServiceIdentity> targetDevice = await identitiesCache.GetServiceIdentity(targetDeviceId); targetDevice.ForEach(d => identities.Add(d)); // Construct the result from the identities Events.SendingScopeResult(targetDeviceId, identities); return(MakeResultFromIdentities(identities)); }
internal static async Task <EdgeHubScopeResult> HandleDevicesAndModulesInTargetDeviceScopeAsync(string actorDeviceId, string actorModuleId, NestedScopeRequest request, IDeviceScopeIdentitiesCache identitiesCache) { Events.ReceivedScopeRequest(actorDeviceId, actorModuleId, request); if (!AuthChainHelpers.TryGetTargetDeviceId(request.AuthChain, out string targetDeviceId)) { return(new EdgeHubScopeResultError(HttpStatusCode.BadRequest, Events.InvalidRequestAuthchain(request.AuthChain))); } // Get the children of the target device and the target device itself; Option <string> authChainToTarget = await identitiesCache.GetAuthChain(targetDeviceId); (bool validationResult, string errorMsg) = ValidateAuthChainForRequestor(actorDeviceId, targetDeviceId, authChainToTarget); if (!validationResult) { return(new EdgeHubScopeResultError(HttpStatusCode.Unauthorized, errorMsg)); } IList <ServiceIdentity> identities = await identitiesCache.GetDevicesAndModulesInTargetScopeAsync(targetDeviceId); Option <ServiceIdentity> targetDevice = await identitiesCache.GetServiceIdentity(targetDeviceId); targetDevice.ForEach(d => identities.Add(d)); // Construct the result from the identities Events.SendingScopeResult(targetDeviceId, identities); return(MakeResultFromIdentities(identities)); }
async Task <EdgeHubScopeResult> HandleDevicesAndModulesInTargetDeviceScopeAsync(string actorDeviceId, string actorModuleId, NestedScopeRequest request) { Events.ReceivedScopeRequest(actorDeviceId, actorModuleId, request); if (!AuthChainHelpers.TryGetTargetDeviceId(request.AuthChain, out string targetDeviceId)) { return(new EdgeHubScopeResultError(HttpStatusCode.BadRequest, Events.InvalidRequestAuthchain(request.AuthChain))); } // Get the children of the target device and the target device itself; IEdgeHub edgeHub = await this.edgeHubGetter; IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); IList <ServiceIdentity> identities = await identitiesCache.GetDevicesAndModulesInTargetScopeAsync(targetDeviceId); Option <ServiceIdentity> targetDevice = await identitiesCache.GetServiceIdentity(targetDeviceId); targetDevice.ForEach(d => identities.Add(d)); // Construct the result from the identities Events.SendingScopeResult(targetDeviceId, identities); return(MakeResultFromIdentities(identities)); }
public async Task GetServiceIdentityTest_Module() { // Arrange var store = GetEntityStore("cache"); var serviceAuthenticationNone = new ServiceAuthentication(ServiceAuthenticationType.None); var serviceAuthenticationSas = new ServiceAuthentication(new SymmetricKeyAuthentication(GetKey(), GetKey())); var si1_initial = new ServiceIdentity("d1", "m1", "1234", Enumerable.Empty <string>(), serviceAuthenticationNone, ServiceIdentityStatus.Enabled); var si1_updated = new ServiceIdentity("d1", "m1", "1234", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Disabled); var si2 = new ServiceIdentity("d2", "m2", "5678", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Enabled); var si3 = new ServiceIdentity("d3", "m3", "0987", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Enabled); var iterator1 = new Mock <IServiceIdentitiesIterator>(); iterator1.SetupSequence(i => i.HasNext) .Returns(true) .Returns(false); iterator1.SetupSequence(i => i.GetNext()) .ReturnsAsync( new List <ServiceIdentity> { si1_initial, si2 }); var serviceProxy = new Mock <IServiceProxy>(); serviceProxy.Setup(s => s.GetServiceIdentitiesIterator()) .Returns(iterator1.Object); serviceProxy.Setup(s => s.GetServiceIdentity("d1", "m1")).ReturnsAsync(Option.Some(si1_updated)); serviceProxy.Setup(s => s.GetServiceIdentity("d2", "m2")).ReturnsAsync(Option.None <ServiceIdentity>()); serviceProxy.Setup(s => s.GetServiceIdentity("d3", "m3")).ReturnsAsync(Option.Some(si3)); var updatedIdentities = new List <ServiceIdentity>(); var removedIdentities = new List <string>(); // Act IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromHours(1)); deviceScopeIdentitiesCache.ServiceIdentityUpdated += (sender, identity) => updatedIdentities.Add(identity); deviceScopeIdentitiesCache.ServiceIdentityRemoved += (sender, s) => removedIdentities.Add(s); // Wait for refresh to complete await Task.Delay(TimeSpan.FromSeconds(3)); Option <ServiceIdentity> receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1/m1"); Option <ServiceIdentity> receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m2"); Option <ServiceIdentity> receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3/m3"); // Assert Assert.True(si1_initial.Equals(receivedServiceIdentity1.OrDefault())); Assert.True(si2.Equals(receivedServiceIdentity2.OrDefault())); Assert.False(receivedServiceIdentity3.HasValue); // Get the identities with refresh receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1/m1", true); receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m2", true); receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3/m3", true); // Assert Assert.True(si1_initial.Equals(receivedServiceIdentity1.OrDefault())); Assert.True(si2.Equals(receivedServiceIdentity2.OrDefault())); Assert.True(si3.Equals(receivedServiceIdentity3.OrDefault())); Assert.Empty(removedIdentities); Assert.Empty(updatedIdentities); }
public async Task RefreshCacheTest() { // Arrange var store = GetEntityStore("cache"); var serviceAuthentication = new ServiceAuthentication(ServiceAuthenticationType.None); Func <ServiceIdentity> si1 = () => new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled); Func <ServiceIdentity> si2 = () => new ServiceIdentity("d2", "m1", "2345", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled); Func <ServiceIdentity> si3 = () => new ServiceIdentity("d3", "5678", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled); Func <ServiceIdentity> si4 = () => new ServiceIdentity("d2", "m4", "9898", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled); var iterator1 = new Mock <IServiceIdentitiesIterator>(); iterator1.SetupSequence(i => i.HasNext) .Returns(true) .Returns(true) .Returns(false); iterator1.SetupSequence(i => i.GetNext()) .ReturnsAsync( new List <ServiceIdentity> { si1(), si2() }) .ReturnsAsync( new List <ServiceIdentity> { si3(), si4() }); var iterator2 = new Mock <IServiceIdentitiesIterator>(); iterator2.SetupSequence(i => i.HasNext) .Returns(true) .Returns(false); iterator2.SetupSequence(i => i.GetNext()) .ReturnsAsync( new List <ServiceIdentity> { si1(), si2(), si3() }); var serviceProxy = new Mock <IServiceProxy>(); serviceProxy.SetupSequence(s => s.GetServiceIdentitiesIterator()) .Returns(iterator1.Object) .Returns(iterator2.Object); var updatedIdentities = new List <ServiceIdentity>(); var removedIdentities = new List <string>(); // Act IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromSeconds(8)); deviceScopeIdentitiesCache.ServiceIdentityUpdated += (sender, identity) => updatedIdentities.Add(identity); deviceScopeIdentitiesCache.ServiceIdentityRemoved += (sender, s) => removedIdentities.Add(s); // Wait for refresh to complete await Task.Delay(TimeSpan.FromSeconds(3)); Option <ServiceIdentity> receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1"); Option <ServiceIdentity> receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1"); Option <ServiceIdentity> receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3"); Option <ServiceIdentity> receivedServiceIdentity4 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m4"); // Assert Assert.True(si1().Equals(receivedServiceIdentity1.OrDefault())); Assert.True(si2().Equals(receivedServiceIdentity2.OrDefault())); Assert.True(si3().Equals(receivedServiceIdentity3.OrDefault())); Assert.True(si4().Equals(receivedServiceIdentity4.OrDefault())); Assert.Empty(updatedIdentities); Assert.Empty(removedIdentities); // Wait for another refresh cycle to complete await Task.Delay(TimeSpan.FromSeconds(8)); receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1"); receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1"); receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3"); receivedServiceIdentity4 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m4"); // Assert Assert.True(si1().Equals(receivedServiceIdentity1.OrDefault())); Assert.True(si2().Equals(receivedServiceIdentity2.OrDefault())); Assert.True(si3().Equals(receivedServiceIdentity3.OrDefault())); Assert.False(receivedServiceIdentity4.HasValue); Assert.Empty(updatedIdentities); Assert.Single(removedIdentities); Assert.Contains("d2/m4", removedIdentities); }
public async Task RefreshCacheWithRefreshRequestTest() { // Arrange var store = new EntityStore <string, string>(new InMemoryDbStore(), "cache"); var serviceAuthentication = new ServiceAuthentication(ServiceAuthenticationType.None); Func <ServiceIdentity> si1 = () => new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled); Func <ServiceIdentity> si2 = () => new ServiceIdentity("d2", "m1", "2345", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled); Func <ServiceIdentity> si3 = () => new ServiceIdentity("d3", "5678", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled); Func <ServiceIdentity> si4 = () => new ServiceIdentity("d2", "m4", "9898", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled); var iterator1 = new Mock <IServiceIdentitiesIterator>(); iterator1.SetupSequence(i => i.HasNext) .Returns(true) .Returns(true) .Returns(false); iterator1.SetupSequence(i => i.GetNext()) .ReturnsAsync( new List <ServiceIdentity> { si1(), si2() }) .ReturnsAsync( new List <ServiceIdentity> { si3(), si4() }); var iterator2 = new Mock <IServiceIdentitiesIterator>(); iterator2.SetupSequence(i => i.HasNext) .Returns(true) .Returns(false); iterator2.SetupSequence(i => i.GetNext()) .ReturnsAsync( new List <ServiceIdentity> { si1(), si2(), si3() }); var iterator3 = new Mock <IServiceIdentitiesIterator>(); iterator3.SetupSequence(i => i.HasNext) .Returns(true) .Returns(false); iterator3.SetupSequence(i => i.GetNext()) .ReturnsAsync( new List <ServiceIdentity> { si1(), si2() }); var iterator4 = new Mock <IServiceIdentitiesIterator>(); iterator4.SetupSequence(i => i.HasNext) .Returns(true) .Returns(false); iterator4.SetupSequence(i => i.GetNext()) .ReturnsAsync( new List <ServiceIdentity> { si3(), si4() }); var serviceProxy = new Mock <IServiceProxy>(); serviceProxy.SetupSequence(s => s.GetServiceIdentitiesIterator()) .Returns(iterator1.Object) .Returns(iterator2.Object) .Returns(iterator3.Object) .Returns(iterator4.Object); var updatedIdentities = new List <ServiceIdentity>(); var removedIdentities = new List <string>(); // Act IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromSeconds(7)); deviceScopeIdentitiesCache.ServiceIdentityUpdated += (sender, identity) => updatedIdentities.Add(identity); deviceScopeIdentitiesCache.ServiceIdentityRemoved += (sender, s) => removedIdentities.Add(s); // Wait for refresh to complete await Task.Delay(TimeSpan.FromSeconds(3)); Option <ServiceIdentity> receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1"); Option <ServiceIdentity> receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1"); Option <ServiceIdentity> receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3"); Option <ServiceIdentity> receivedServiceIdentity4 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m4"); // Assert Assert.True(si1().Equals(receivedServiceIdentity1.OrDefault())); Assert.True(si2().Equals(receivedServiceIdentity2.OrDefault())); Assert.True(si3().Equals(receivedServiceIdentity3.OrDefault())); Assert.True(si4().Equals(receivedServiceIdentity4.OrDefault())); Assert.Equal(0, updatedIdentities.Count); Assert.Equal(0, removedIdentities.Count); // Act - Signal refresh cache multiple times. It should get picked up twice. deviceScopeIdentitiesCache.InitiateCacheRefresh(); deviceScopeIdentitiesCache.InitiateCacheRefresh(); deviceScopeIdentitiesCache.InitiateCacheRefresh(); deviceScopeIdentitiesCache.InitiateCacheRefresh(); // Wait for the 2 refresh cycles to complete, this time because of the refresh request await Task.Delay(TimeSpan.FromSeconds(5)); receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1"); receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1"); receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3"); receivedServiceIdentity4 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m4"); // Assert Assert.True(si1().Equals(receivedServiceIdentity1.OrDefault())); Assert.True(si2().Equals(receivedServiceIdentity2.OrDefault())); Assert.False(receivedServiceIdentity3.HasValue); Assert.False(receivedServiceIdentity4.HasValue); Assert.Equal(0, updatedIdentities.Count); Assert.Equal(2, removedIdentities.Count); Assert.True(removedIdentities.Contains("d2/m4")); Assert.True(removedIdentities.Contains("d3")); // Wait for another refresh cycle to complete, this time because timeout await Task.Delay(TimeSpan.FromSeconds(8)); receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1"); receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1"); receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3"); receivedServiceIdentity4 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m4"); // Assert Assert.True(si3().Equals(receivedServiceIdentity3.OrDefault())); Assert.True(si4().Equals(receivedServiceIdentity4.OrDefault())); Assert.False(receivedServiceIdentity1.HasValue); Assert.False(receivedServiceIdentity2.HasValue); Assert.Equal(0, updatedIdentities.Count); Assert.Equal(4, removedIdentities.Count); Assert.True(removedIdentities.Contains("d2/m1")); Assert.True(removedIdentities.Contains("d1")); }
public async Task RefreshServiceIdentityTest_List() { // Arrange var store = new EntityStore <string, string>(new InMemoryDbStore(), "cache"); var serviceAuthenticationNone = new ServiceAuthentication(ServiceAuthenticationType.None); var serviceAuthenticationSas = new ServiceAuthentication(new SymmetricKeyAuthentication(GetKey(), GetKey())); var si1_initial = new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthenticationNone, ServiceIdentityStatus.Enabled); var si1_updated = new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Enabled); var si2 = new ServiceIdentity("d2", "5678", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Enabled); var iterator1 = new Mock <IServiceIdentitiesIterator>(); iterator1.SetupSequence(i => i.HasNext) .Returns(true) .Returns(false); iterator1.SetupSequence(i => i.GetNext()) .ReturnsAsync( new List <ServiceIdentity> { si1_initial, si2 }); var serviceProxy = new Mock <IServiceProxy>(); serviceProxy.Setup(s => s.GetServiceIdentitiesIterator()) .Returns(iterator1.Object); serviceProxy.Setup(s => s.GetServiceIdentity(It.Is <string>(id => id == "d1"))).ReturnsAsync(Option.Some(si1_updated)); serviceProxy.Setup(s => s.GetServiceIdentity(It.Is <string>(id => id == "d2"))).ReturnsAsync(Option.None <ServiceIdentity>()); var updatedIdentities = new List <ServiceIdentity>(); var removedIdentities = new List <string>(); // Act IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromHours(1)); deviceScopeIdentitiesCache.ServiceIdentityUpdated += (sender, identity) => updatedIdentities.Add(identity); deviceScopeIdentitiesCache.ServiceIdentityRemoved += (sender, s) => removedIdentities.Add(s); // Wait for refresh to complete await Task.Delay(TimeSpan.FromSeconds(3)); Option <ServiceIdentity> receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1"); Option <ServiceIdentity> receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2"); // Assert Assert.True(si1_initial.Equals(receivedServiceIdentity1.OrDefault())); Assert.True(si2.Equals(receivedServiceIdentity2.OrDefault())); // Update the identities await deviceScopeIdentitiesCache.RefreshServiceIdentities(new[] { "d1", "d2" }); receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1"); receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2"); // Assert Assert.True(si1_updated.Equals(receivedServiceIdentity1.OrDefault())); Assert.False(receivedServiceIdentity2.HasValue); Assert.Equal(1, removedIdentities.Count); Assert.Equal("d2", removedIdentities[0]); Assert.Equal(1, updatedIdentities.Count); Assert.Equal("d1", updatedIdentities[0].Id); }
async Task <EdgeHubScopeResult> HandleGetDeviceAndModuleOnBehalfOfAsync(string actorDeviceId, string actorModuleId, IdentityOnBehalfOfRequest request) { Events.ReceivedIdentityOnBehalfOfRequest(actorDeviceId, actorModuleId, request); Preconditions.CheckNonWhiteSpace(request.TargetDeviceId, nameof(request.TargetDeviceId)); bool isModule = false; string targetId = request.TargetDeviceId; if (!request.TargetModuleId.IsNullOrWhiteSpace()) { isModule = true; targetId += "/" + request.TargetModuleId; } IEdgeHub edgeHub = await this.edgeHubGetter; // Check if the actor has provided the originating EdgeHub ID, // if not, then we must be by definition by the origin. string originatingEdge = edgeHub.GetEdgeDeviceId(); if (this.Request.Headers.TryGetValue(Constants.OriginEdgeHeaderKey, out StringValues originHeader) && originHeader.Count > 0) { originatingEdge = originHeader.First(); } // We must always forward the call further upstream first, // as this is invoked for refreshing an identity on-demand, // and we don't know whether our cache is out-of-date. IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache(); await identitiesCache.RefreshServiceIdentityOnBehalfOf(targetId, originatingEdge); Option <ServiceIdentity> targetIdentity = await identitiesCache.GetServiceIdentity(targetId); if (!targetIdentity.HasValue) { // Identity still doesn't exist, this can happen if the identity // is newly added and we couldn't refresh the individual identity // because we don't know where it resides in the nested hierarchy. // In this case our only recourse is to refresh the whole cache // and hope the identity shows up. identitiesCache.InitiateCacheRefresh(); await identitiesCache.WaitForCacheRefresh(TimeSpan.FromSeconds(100)); targetIdentity = await identitiesCache.GetServiceIdentity(targetId); } // Add the identity to the result var identityList = new List <ServiceIdentity>(); targetIdentity.ForEach(i => identityList.Add(i)); // If the target is a module, we also need to // include the parent device as well to match // IoT Hub API behavior if (isModule) { Option <ServiceIdentity> device = await identitiesCache.GetServiceIdentity(request.TargetDeviceId); device.ForEach(i => identityList.Add(i)); } Events.SendingScopeResult(targetId, identityList); return(MakeResultFromIdentities(identityList)); }