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); }
public CallDetails(ActionQueue actionQueue, IServiceActorWrapper target, object wrappedObject, string typeOfObjectToWrap, Action action) { ActionQueue = actionQueue; Target = target; WrappedObject = wrappedObject; TypeOfObjectToWrap = typeOfObjectToWrap; Action = action; }
public void Pop(ActionQueue actionQueue) { _callStack = _callStack.Pop(out ActionQueue removeActionQueue); if (removeActionQueue != actionQueue) { throw new InvalidOperationException(); } }
/// <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); }
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); }
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); }
/// <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); }
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)); }
public void Push(ActionQueue actionQueue) { _callStack = _callStack.Push(actionQueue); }