private async Task RunRoutineAsync( ITransitionCarrier transitionCarrier, TransitionDescriptor transitionDescriptor, CancellationToken ct) { using (_transitionScope.Enter(transitionDescriptor)) { var transitionMonitor = _transitionScope.CurrentMonitor; var serviceId = await transitionCarrier.GetServiceIdAsync(ct); var routineDescriptor = await transitionCarrier.GetRoutineDescriptorAsync(ct); object serviceInstance; IServiceDefinition serviceDefinition; #warning IntrinsicRoutines must be registered in the service registry, but it needs the engine IoC to resolve. if (serviceId.ProxyName == nameof(IntrinsicRoutines)) { serviceInstance = _intrinsicRoutines; serviceDefinition = IntrinsicCommunicationModel.IntrinsicRoutinesServiceDefinition; } else { serviceInstance = _serviceProxyBuilder.Build(serviceId); serviceDefinition = ((ServiceProxyContext)((IProxy)serviceInstance).Context).Definition; } var routineMethod = _routineMethodResolver.Resolve(serviceDefinition, routineDescriptor.MethodId); //var serviceStateContainer = _serviceStateValueContainerProvider.CreateContainer(serviceInstance); //var isStatefullService = serviceStateContainer.GetCount() > 0; //if (isStatefullService) // await transitionCarrier.ReadServiceStateAsync(serviceStateContainer, ct); Task completionTask; IValueContainer asmValueContainer = null; if (TryCreateAsyncStateMachine(routineMethod, out var asmInstance, out var asmMetadata)) { var isContinuation = transitionDescriptor.Type == TransitionType.ContinueRoutine; asmValueContainer = await LoadRoutineStateAsync(transitionCarrier, asmInstance, asmMetadata, isContinuation, ct); asmMetadata.Owner.FieldInfo?.SetValue(asmInstance, serviceInstance); transitionMonitor.OnRoutineStart( serviceId, routineDescriptor, serviceInstance, routineMethod, asmInstance); try { #warning possibly need to create a proxy? on a sealed ASM class? How to capture Task.Delay if it's not immediate after first MoveNext? asmInstance.MoveNext(); completionTask = GetCompletionTask(asmInstance, asmMetadata); } catch (Exception ex) { // The MoveNext() must not throw, but instead complete the task with an error. // try-catch is added just in case for a non-compiler-generated state machine. var taskResultType = TaskAccessor.GetTaskResultType(routineMethod.ReturnType); completionTask = TaskAccessor.FromException(taskResultType, ex); } }
public async Task <BootstrapResult> BootstrapAsync(CancellationToken ct) { //_serviceRegistry.Register( // new ServiceRegistrationInfo // { // Name = nameof(IntrinsicRoutines), // QualifiedServiceTypeName = typeof(IntrinsicRoutines).AssemblyQualifiedName, // QualifiedImplementationTypeName = typeof(IntrinsicRoutines).AssemblyQualifiedName, // IsSingleton = true // }); //foreach (var serviceType in _appServiceDiscoveryFromCodeMarkup.DiscoverServiceTypes()) //{ // ServiceRegistrationInfo registrationInfo; // try // { // registrationInfo = _appServiceRegistrationInfoExtractor.Extract(serviceType); // } // catch // { // continue; // } // // TODO: fill in 'fabric' config? // _serviceRegistry.Register(registrationInfo); //} //foreach (var registrationInfo in _appServiceDiscoveryFromRuntimeCollection.Services) //{ // // TODO: fill in 'fabric' config? // _serviceRegistry.Register(registrationInfo); //} var appIocContainer = _appIocContainerProviders .Select(p => p.GetAppIocContainer()) .FirstOrDefault(c => c != null); if (appIocContainer != null) { foreach (var bindingInfo in appIocContainer.DiscoverServices()) { var registrationInfo = new ServiceRegistrationInfo { QualifiedServiceTypeName = bindingInfo.ServiceType.AssemblyQualifiedName, QualifiedImplementationTypeName = bindingInfo.ImplementationType?.AssemblyQualifiedName, IsExternal = bindingInfo.IsExternal, IsSingleton = true }; // TODO: fill in 'fabric' config? _serviceRegistry.Register(registrationInfo); } } if (appIocContainer == null) { appIocContainer = new BasicAppServiceIocContainer(); } _appIocContainerHolder.Container = appIocContainer; foreach (var serviceRegistration in _serviceRegistry.AllRegistrations) { if (serviceRegistration.IsSingleton) { var implementationType = serviceRegistration.ImplementationType; if (implementationType == null && appIocContainer.TryGetImplementationType( serviceRegistration.ServiceType, out implementationType) == true) { // TODO: properly update registration ((ServiceRegistration)serviceRegistration).ImplementationType = implementationType; } if (!serviceRegistration.IsExternal && implementationType == null) { throw new InvalidOperationException( $"Could not find implementation type for service '{serviceRegistration.ServiceType}'."); } Func <object> proxyFactory = () => { var serviceId = new ServiceId { ServiceName = serviceRegistration.ServiceName }; var proxy = _serviceProxyBuilder.Build(serviceId); return(proxy); }; appIocContainer.RebindService( serviceRegistration.ServiceType, proxyFactory); if (implementationType != null) { appIocContainer.RebindService( implementationType, proxyFactory); } } } if (_fabric != null) { await _fabric.InitializeAsync(ct); } await _serviceRegistryUpdaterViaDiscovery.UpdateAsync(ct); if (_fabric != null && _servicePublishers.Length > 0) { var servicesToRegister = new List <ServiceRegistrationInfo>(); foreach (var serviceRegistration in _serviceRegistry.AllRegistrations.Where(r => !r.IsExternal)) { var serviceId = new ServiceId { ServiceName = serviceRegistration.ServiceName }; if (_fabric.GetConnector(serviceId) is IFabricConnectorWithConfiguration connectorWithConfiguration) { servicesToRegister.Add(new ServiceRegistrationInfo { Name = serviceRegistration.ServiceName, QualifiedServiceTypeName = serviceRegistration.ServiceType.FullName, IsSingleton = serviceRegistration.IsSingleton, IsExternal = true, ConnectorType = connectorWithConfiguration.ConnectorType, ConnectorConfiguration = connectorWithConfiguration.Configuration }); } } if (servicesToRegister.Count > 0) { foreach (var publisher in _servicePublishers) { await publisher.PublishAsync(servicesToRegister, ct); } } } if (_fabric != null) { await _fabric.StartAsync(ct); } return(new BootstrapResult { Fabric = _fabric, AppIocContainer = _appIocContainerHolder.Container }); }
private async Task RunRoutineAsync( ITransitionCarrier transitionCarrier, ITransitionData transitionData, TransitionDescriptor transitionDescriptor, CancellationToken ct) { using (_transitionScope.Enter(transitionDescriptor)) { var transitionMonitor = _transitionScope.CurrentMonitor; var serviceId = await transitionData.GetServiceIdAsync(ct); var routineDescriptor = await transitionData.GetRoutineDescriptorAsync(ct); var serviceInstance = #warning IntrinsicRoutines must be registered in the service registry, but it needs the engine IoC to resolve. serviceId.ProxyName == nameof(IntrinsicRoutines) ? _intrinsicRoutines : _serviceProxyBuilder.Build(serviceId); #warning check if the serviceInstance proxy is an actual non-abstract class with implementation // Need exact underlying type of the service implementation type to call // the routine method directly without using the virtual method table. var serviceType = (serviceInstance as IProxy)?.ObjectType ?? serviceInstance.GetType(); var routineMethod = _routineMethodResolver.Resolve(serviceType, routineDescriptor.MethodId); var serviceStateContainer = _serviceStateValueContainerProvider.CreateContainer(serviceInstance); var isStatefullService = serviceStateContainer.GetCount() > 0; if (isStatefullService) { await transitionData.ReadServiceStateAsync(serviceStateContainer, ct); } Task completionTask; IValueContainer asmValueContainer = null; if (TryCreateAsyncStateMachine(routineMethod, out var asmInstance, out var asmMetadata, out completionTask)) { var isContinuation = transitionDescriptor.Type == TransitionType.ContinueRoutine; asmValueContainer = await LoadRoutineStateAsync(transitionData, asmInstance, asmMetadata, isContinuation, ct); asmMetadata.Owner.FieldInfo?.SetValue(asmInstance, serviceInstance); transitionMonitor.OnRoutineStart( serviceId, routineDescriptor, serviceInstance, routineMethod, asmInstance); try { #warning possibly need to create a proxy? on a sealed ASM class? How to capture Task.Delay if it's not immediate after first MoveNext? asmInstance.MoveNext(); } catch (Exception ex) { // The MoveNext() must not throw, but instead complete the task with an error. // try-catch is added just in case for a non-compiler-generated state machine. var taskResultType = TaskAccessor.GetTaskResultType(routineMethod.ReturnType); completionTask = TaskAccessor.FromException(taskResultType, ex); } }