예제 #1
0
        public static void RegisterPendingOperation(object objectWrapped, IPendingOperation pendingOperation)
        {
            if (objectWrapped == null)
            {
                throw new ArgumentNullException(nameof(objectWrapped));
            }

            if (pendingOperation == null)
            {
                throw new ArgumentNullException(nameof(pendingOperation));
            }

            ActionQueue actionQueue = null;

            if (_wrappersCache.TryGetValue(objectWrapped, out var wrapperTypes))
            {
                var firstWrapper = wrapperTypes.First().Value;

                actionQueue = ((IServiceActorWrapper)firstWrapper).ActionQueue;
            }

            if (actionQueue == null)
            {
                throw new InvalidOperationException($"Object {objectWrapped} of type '{objectWrapped.GetType()}' is not managed by ServiceActor: call ServiceRef.Create<> to create a service actor for it");
            }

            actionQueue.RegisterPendingOperation(pendingOperation);
        }
예제 #2
0
 public CallDetails(ActionQueue actionQueue, IServiceActorWrapper target, object wrappedObject, string typeOfObjectToWrap, Action action)
 {
     ActionQueue        = actionQueue;
     Target             = target;
     WrappedObject      = wrappedObject;
     TypeOfObjectToWrap = typeOfObjectToWrap;
     Action             = action;
 }
예제 #3
0
        public void Pop(ActionQueue actionQueue)
        {
            _callStack = _callStack.Pop(out ActionQueue removeActionQueue);

            if (removeActionQueue != actionQueue)
            {
                throw new InvalidOperationException();
            }
        }
예제 #4
0
        /// <summary>
        /// Get or create a synchronization wrapper around <paramref name="objectToWrap"/>
        /// </summary>
        /// <typeparam name="T">Type of the interface describing the service to wrap</typeparam>
        /// <param name="objectToWrap">Actual implementation type of the service</param>
        /// <param name="aggregateKey">Optional aggregation key to use in place of the <see cref="ServiceDomainAttribute"/> attribute</param>
        /// <returns>Synchronization wrapper object that implements <typeparamref name="T"/></returns>
        public static T CreateFor <T>(object objectToWrap, object aggregateKey = null) where T : class
        {
            if (objectToWrap == null)
            {
                throw new ArgumentNullException(nameof(objectToWrap));
            }

            var serviceType = typeof(T);

            if (objectToWrap is IServiceActorWrapper)
            {
                //objectToWrap is already a wrapper
                //test if it's the right interface
                if (objectToWrap is T)
                {
                    return((T)objectToWrap);
                }

                objectToWrap = ((IServiceActorWrapper)objectToWrap).WrappedObject;
                //throw new ArgumentException($"Parameter is already a wrapper but not for interface '{serviceType}'", nameof(objectToWrap));
            }

            //NOTE: Do not use AddOrUpdate() to avoid _wrapperCache lock while generating wrapper

            ActionQueue actionQueue = null;
            object      wrapper;

            if (_wrappersCache.TryGetValue(objectToWrap, out var wrapperTypes))
            {
                if (wrapperTypes.TryGetValue(serviceType, out wrapper))
                {
                    return((T)wrapper);
                }

                var firstWrapper = wrapperTypes.First().Value;

                actionQueue = ((IServiceActorWrapper)firstWrapper).ActionQueue;
            }

            actionQueue = actionQueue ?? GetActionQueueFor(serviceType, aggregateKey);

            wrapper = GetOrCreateWrapper(serviceType, objectToWrap, actionQueue);

            wrapperTypes = _wrappersCache.GetOrAdd(objectToWrap, new ConcurrentDictionary <Type, object>());

            wrapperTypes.TryAdd(serviceType, wrapper);

            return((T)wrapper);
        }
예제 #5
0
        public bool CanPush(ActionQueue actionQueue, bool allowReentrantCalls)
        {
            var actionQueueInStack = _callStack.Any(_ => _ == actionQueue);// &&

            //_callStack.Peek() != actionQueue;
            if (!allowReentrantCalls && actionQueueInStack)
            {
                throw new InvalidOperationException("Reentrant call detected");
            }

            if (actionQueueInStack)
            {
                return(false);
            }

            return(true);
        }
예제 #6
0
        public bool CanPush(ActionQueue actionQueue, bool allowReentrantCalls)
        {
            var actionQueueInStack = _callStack.Any(_ => _ == actionQueue);// &&

            //_callStack.Peek() != actionQueue;
            if (!allowReentrantCalls && actionQueueInStack)
            {
                throw new InvalidOperationException($"Reentrant call detected {string.Join(">>", _callStack.Select(_ => _.ExecutingInvocationItem))}");
            }

            if (actionQueueInStack)
            {
                return(false);
            }

            return(true);
        }
예제 #7
0
        /// <summary>
        /// Execute <paramref name="actionToExecute"/> in the same queue of <paramref name="serviceObject"/>
        /// </summary>
        /// <param name="serviceObject">Service implementation or wrapper</param>
        /// <param name="actionToExecute">Action to execute in the queue of <paramref name="serviceObject"/></param>
        /// <param name="createWrapperIfNotExists">Generate a wrapper for the object on the fly if it doesn't exist</param>
        public static void Call(object serviceObject, Action actionToExecute, bool createWrapperIfNotExists = false)
        {
            if (serviceObject == null)
            {
                throw new ArgumentNullException(nameof(serviceObject));
            }

            if (actionToExecute == null)
            {
                throw new ArgumentNullException(nameof(actionToExecute));
            }

            ActionQueue actionQueue = null;

            if (serviceObject is IServiceActorWrapper)
            {
                actionQueue = ((IServiceActorWrapper)serviceObject).ActionQueue;
            }

            if (actionQueue == null)
            {
                if (_wrappersCache.TryGetValue(serviceObject, out var wrapperTypes))
                {
                    var firstWrapper = wrapperTypes.First().Value;

                    actionQueue = ((IServiceActorWrapper)firstWrapper).ActionQueue;
                }
            }

            if (actionQueue == null)
            {
                throw new InvalidOperationException("Unable to get the action queue for the object: create a wrapper for the object with ServiceRef.Create<> first");
            }

            actionQueue.Enqueue(actionToExecute);
        }
예제 #8
0
        private static object GetOrCreateWrapper(Type interfaceType, object objectToWrap, ActionQueue actionQueue)
        {
            var implType       = objectToWrap.GetType();
            var sourceTemplate = new ServiceActorWrapperTemplate(interfaceType, implType);

            var wrapperAssembly = _wrapperAssemblyCache.GetOrAdd(new AssemblyTypeKey(interfaceType, implType), (key) =>
            {
                var source = sourceTemplate.TransformText();

                string assemblyFilePath = null;
                if (EnableCache)
                {
                    var assemblyCacheFolder = CachePath ?? Path.Combine(Path.GetTempPath(), "ServiceActor");
                    Directory.CreateDirectory(assemblyCacheFolder);

                    assemblyFilePath = Path.Combine(assemblyCacheFolder, MD5Hash(source) + ".dll");

                    if (File.Exists(assemblyFilePath))
                    {
                        return(Assembly.LoadFile(assemblyFilePath));
                    }
                }

                var script = CSharpScript.Create(
                    source,
                    options: ScriptOptions.Default.AddReferences(
                        Assembly.GetExecutingAssembly(),
                        interfaceType.Assembly,
                        implType.Assembly,
                        typeof(Nito.AsyncEx.AsyncAutoResetEvent).Assembly)
                    );

                var diagnostics = script.Compile();
                if (diagnostics.Any())
                {
                    throw new InvalidOperationException();
                }

                var compilation = script.GetCompilation();

                //var tempFile = Path.GetTempFileName();
                using (var dllStream = new MemoryStream())
                {
                    var emitResult = compilation.Emit(dllStream);
                    if (!emitResult.Success)
                    {
                        // emitResult.Diagnostics
                        throw new InvalidOperationException();
                    }

                    if (assemblyFilePath != null)
                    {
                        File.WriteAllBytes(assemblyFilePath, dllStream.ToArray());
                    }

                    return(Assembly.Load(dllStream.ToArray()));
                }
            });

            //return new <#= TypeToWrapName #>AsyncActorWrapper((<#= TypeToWrapFullName #>)ObjectToWrap, "<#= TypeToWrapFullName #>", ActionQueueToShare);
            var wrapperImplType = wrapperAssembly.GetTypes().First(_ => _.GetInterface("IServiceActorWrapper") != null);

            return(Activator.CreateInstance(
                       wrapperImplType, objectToWrap, sourceTemplate.TypeToWrapFullName, actionQueue));
        }
예제 #9
0
 public void Push(ActionQueue actionQueue)
 {
     _callStack = _callStack.Push(actionQueue);
 }