Exemplo n.º 1
0
 public ChangeSetEntry(object entity, DomainOperation operation,
                       bool returnEntity = true,
                       EntityUpdateFiledsInfo entityUpdateFiledsInfo = null) :
     this(0, entity, null, operation, returnEntity,
          entityUpdateFiledsInfo)
 {
 }
        /// <summary>
        /// Invokes an operation according to the specified <paramref name="operationType"/> and entity
        /// </summary>
        /// <typeparam name="TEntity">The entity type</typeparam>
        /// <param name="operationType">The type of operation to invoke</param>
        /// <param name="submitOperation">
        /// The <see cref="Expression"/> identifying the operation to invoke. This parameter can be <c>null</c>
        /// as long as <paramref name="entity"/> is not.
        /// </param>
        /// <param name="entity">
        /// The entity to pass to the operation. This parameter can be <c>null</c> as long as
        /// <paramref name="submitOperation"/> is not.
        /// </param>
        /// <param name="original">The original version of the entity. This parameter can be <c>null</c>.</param>
        /// <exception cref="DomainServiceTestHostException">is thrown if there are any <see cref="ChangeSet"/> errors</exception>
        private void SubmitCore <TEntity>(DomainOperation operationType, Expression submitOperation, TEntity entity, TEntity original) where TEntity : class
        {
            OperationContext context = this.CreateOperationContext(DomainOperationType.Submit);

            ChangeSetEntry changeSetEntry;

            if (operationType == DomainOperation.Update)
            {
                if (submitOperation != null)
                {
                    changeSetEntry = Utility.GetCustomUpdateChangeSetEntry(context, submitOperation, original);
                }
                else
                {
                    changeSetEntry = Utility.GetChangeSetEntry(context, entity, original, operationType);
                    changeSetEntry.HasMemberChanges = true;
                }
            }
            else
            {
                changeSetEntry = Utility.GetChangeSetEntry(context, entity, original, operationType);
            }
            ChangeSet changeSet = Utility.CreateChangeSet(changeSetEntry);

            SubmitChangeSetCore(context, changeSet);
        }
        /// <summary>
        /// Invokes an operation according to the specified <paramref name="operationType"/> and entity and returns
        /// the validation errors, the change set, and whether the operation completed successfully
        /// </summary>
        /// <typeparam name="TEntity">The entity type</typeparam>
        /// <param name="operationType">The type of operation to invoke</param>
        /// <param name="submitOperation">
        /// The <see cref="Expression"/> identifying the operation to invoke. This parameter can be <c>null</c>
        /// as long as <paramref name="entity"/> is not.
        /// </param>
        /// <param name="entity">
        /// The entity to pass to the operation. This parameter can be <c>null</c> as long as
        /// <paramref name="submitOperation"/> is not.
        /// </param>
        /// <param name="original">The original version of the entity. This parameter can be <c>null</c>.</param>
        /// <param name="validationResults">The validation errors that occurred</param>
        /// <param name="changeSet">The change set</param>
        private bool TrySubmitCore <TEntity>(DomainOperation operationType, Expression submitOperation, TEntity entity, TEntity original, out IList <ValidationResult> validationResults, out ChangeSet changeSet) where TEntity : class
        {
            OperationContext context = this.CreateOperationContext(DomainOperationType.Submit);

            ChangeSetEntry changeSetEntry;

            if (operationType == DomainOperation.Update)
            {
                if (submitOperation != null)
                {
                    changeSetEntry = Utility.GetCustomUpdateChangeSetEntry(context, submitOperation, original);
                }
                else
                {
                    changeSetEntry = Utility.GetChangeSetEntry(context, entity, original, operationType);
                    changeSetEntry.HasMemberChanges = true;
                }
            }
            else
            {
                changeSetEntry = Utility.GetChangeSetEntry(context, entity, original, operationType);
            }
            changeSet = Utility.CreateChangeSet(changeSetEntry);

            return(TrySubmitChangeSetCore(context, changeSet, out validationResults));
        }
 /// <summary>
 /// Initializes a new <see cref="DomainDataServiceOperation"/> instance.
 /// </summary>
 /// <param name="name">name of the service operation.</param>
 /// <param name="resultKind">Kind of result expected from this operation.</param>
 /// <param name="resultType">Type of element of the method result.</param>
 /// <param name="resultSet">EntitySet of the result expected from this operation.</param>
 /// <param name="method">Protocol (for example HTTP) method the service operation responds to.</param>
 /// <param name="parameters">In-order parameters for this operation.</param>
 /// <param name="operationKind">Kind of domain service operation.</param>
 internal DomainDataServiceOperation(
     string name,
     ServiceOperationResultKind resultKind,
     ResourceType resultType,
     ResourceSet resultSet,
     string method,
     IEnumerable <ServiceOperationParameter> parameters,
     DomainOperation operationKind) : base(name, resultKind, resultType, resultSet, method, parameters)
 {
     this.OperationKind = operationKind;
 }
Exemplo n.º 5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ChangeSetEntry"/> class
        /// </summary>
        /// <param name="id">The client Id for the entity.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="originalEntity">The original entity. May be null.</param>
        /// <param name="operation">The operation to be performed</param>
        public ChangeSetEntry(int id, object entity, object originalEntity, DomainOperation operation)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            this._id     = id;
            this._entity = entity;
            // Setting original entity through a property so that _hasMemberChanges is set to correct value
            this.OriginalEntity = originalEntity;
            this.Operation      = operation;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ChangeSetEntry"/> class
        /// </summary>
        /// <param name="id">The client Id for the entity.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="originalEntity">The original entity. May be null.</param>
        /// <param name="operation">The operation to be performed</param>
        public ChangeSetEntry(int id, object entity, object originalEntity, DomainOperation operation)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            this._id = id;
            this._entity = entity;
            // Setting original entity through a property so that _hasMemberChanges is set to correct value
            this.OriginalEntity = originalEntity;
            this.Operation = operation;
        }
Exemplo n.º 7
0
        /// <summary>
        /// Initializes a new instance of the DomainOperationEntry class
        /// </summary>
        /// <param name="domainServiceType">The <see cref="DomainService"/> Type this operation is a member of.</param>
        /// <param name="name">The name of the operation</param>
        /// <param name="operation">The <see cref="DomainOperation"/></param>
        /// <param name="returnType">The return Type of the operation</param>
        /// <param name="parameters">The parameter definitions for the operation</param>
        /// <param name="attributes">The method level attributes for the operation</param>
        protected DomainOperationEntry(Type domainServiceType, string name, DomainOperation operation, Type returnType, IEnumerable <DomainOperationParameter> parameters, AttributeCollection attributes)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (returnType == null)
            {
                throw new ArgumentNullException(nameof(returnType));
            }
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }
            if (attributes == null)
            {
                throw new ArgumentNullException(nameof(attributes));
            }
            if (domainServiceType == null)
            {
                throw new ArgumentNullException(nameof(domainServiceType));
            }

            if (operation == DomainOperation.None)
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resource.InvalidDomainOperationEntryType, Enum.GetName(typeof(DomainOperation), operation)));
            }

            bool isTaskType = TypeUtility.IsTaskType(returnType);

            this._methodName        = isTaskType ? RemoveAsyncFromName(name) : name;
            this._actualReturnType  = returnType;
            this.ReturnType         = isTaskType ? TypeUtility.GetTaskReturnType(returnType) : returnType;
            this._attributes        = attributes;
            this.Operation          = operation;
            this._domainServiceType = domainServiceType;

            List <DomainOperationParameter> effectiveParameters = parameters.ToList();
            int paramCount = effectiveParameters.Count;

            if (paramCount > 0)
            {
                DomainOperationParameter lastParameter = effectiveParameters[paramCount - 1];
                if (lastParameter.IsOut && lastParameter.ParameterType.HasElementType && lastParameter.ParameterType.GetElementType() == typeof(int))
                {
                    this.HasOutCountParameter = true;
                    effectiveParameters       = effectiveParameters.Take(paramCount - 1).ToList();
                }
            }
            this.Parameters = effectiveParameters.AsReadOnly();
        }
Exemplo n.º 8
0
        private DomainOperation insertDomainOperation(DomainOperation type, TreeNode parent)
        {
            DomainOperation n = new DomainOperation(type);

            if (parent == null)
            {
                tree.Nodes.Add(n.TreeNode);
            }
            else
            {
                parent.Nodes.Add(n.TreeNode);
            }
            return(n);
        }
Exemplo n.º 9
0
        public bool Load(string nodesXMLFilename)
        {
            try
            {
                XElement x = XElement.Load(nodesXMLFilename, LoadOptions.None);

                XElement settings = x.Element("settings");
                foreach (XElement n in x.Elements("node"))
                {
                    switch (n.Attribute("type").Value)
                    {
                    case "do":
                        DistancePrimitive dp = new DistancePrimitive(n.Attribute("name").Value, n.Attribute("caption").Value, n.Attribute("code").Value);
                        foreach (XElement p in n.Elements("prop"))
                        {
                            dp.Properties.Add(createInputProperty(p.Attribute("type").Value, p.Attribute("name").Value, p.Attribute("default").Value));
                        }
                        DistanceFieldTypes.Add(dp);
                        break;

                    case "distop":
                        DistanceOperation distop = new DistanceOperation(n.Attribute("name").Value, n.Attribute("caption").Value, n.Attribute("code").Value);
                        foreach (XElement p in n.Elements("prop"))
                        {
                            distop.Properties.Add(createInputProperty(p.Attribute("type").Value, p.Attribute("name").Value, p.Attribute("default").Value));
                        }
                        DistanceOperations.Add(distop);
                        break;

                    case "domop":
                        DomainOperation dop = new DomainOperation(n.Attribute("name").Value, n.Attribute("caption").Value, n.Attribute("code").Value);
                        foreach (XElement p in n.Elements("prop"))
                        {
                            dop.Properties.Add(createInputProperty(p.Attribute("type").Value, p.Attribute("name").Value, p.Attribute("default").Value));
                        }
                        DomainOperations.Add(dop);
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                errors.Add("Failed to load nodes.xml (" + e.Message + ")");
                return(false);
            }

            return(true);
        }
Exemplo n.º 10
0
 public ChangeSetEntry(int id, object entity,
                       object originalEntity,
                       DomainOperation operation,
                       bool returnEntity = true,
                       EntityUpdateFiledsInfo entityUpdateFiledsInfo = null)
 {
     if (entity == null)
     {
         throw new ArgumentNullException("entity");
     }
     this._id               = id;
     this._entity           = entity;
     this.OriginalEntity    = originalEntity;
     this.Operation         = operation;
     ReturnEntity           = returnEntity;
     EntityUpdateFiledsInfo = entityUpdateFiledsInfo;
 }
        /// <summary>
        /// Classifies a domain operation based on naming convention.
        /// </summary>
        /// <param name="operation">The domain operation to inspect.</param>
        /// <returns>True if the operation matches a convention; false otherwise.</returns>
        private bool TryClassifyImplicitDomainOperation(ReflectionDomainOperationEntry operation)
        {
            DomainOperation operationType = (DomainOperation)(-1);

            if (operation.ReturnType == typeof(void))
            {
                // Check if this looks like an insert, update or delete method.
                if (insertPrefixes.Any(p => operation.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
                {
                    operationType = DomainOperation.Insert;
                }
                else if (updatePrefixes.Any(p => operation.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
                {
                    operationType = DomainOperation.Update;
                }
                else if (deletePrefixes.Any(p => operation.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
                {
                    operationType = DomainOperation.Delete;
                }
                else if (this.IsCustomMethod(operation))
                {
                    operationType = DomainOperation.Custom;
                }
            }
            else if (this.IsQueryMethod(operation))
            {
                operationType = DomainOperation.Query;
            }

            if ((int)operationType == -1 && IsInvokeOperation(operation))
            {
                operationType = DomainOperation.Invoke;
            }

            if ((int)operationType != -1)
            {
                operation.Operation  = operationType;
                operation.IsInferred = true;
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Helper method performs a submit operation against a given proxy instance.
        /// </summary>
        /// <param name="domainService">The type of <see cref="DomainService"/> to perform this query operation against.</param>
        /// <param name="context">The current context.</param>
        /// <param name="domainServiceInstances">The list of tracked <see cref="DomainService"/> instances that any newly created
        /// <see cref="DomainServices"/> will be added to.</param>
        /// <param name="currentOriginalEntityMap">The mapping of current and original entities used with the utility <see cref="DomainServiceProxy.AssociateOriginal"/> method.</param>
        /// <param name="entity">The entity being submitted.</param>
        /// <param name="operationName">The name of the submit operation. For CUD operations, this can be null.</param>
        /// <param name="parameters">The submit operation parameters.</param>
        /// <param name="domainOperation">The type of submit operation.</param>
        /// <exception cref="ArgumentNullException">if <paramref name="context"/> is null.</exception>
        /// <exception cref="ArgumentNullException">if <paramref name="entity"/> is null.</exception>
        /// <exception cref="OperationException">if operation errors are thrown during execution of the submit operation.</exception>
        public static void Submit(Type domainService, DomainServiceContext context, IList<DomainService> domainServiceInstances, IDictionary<object, object> currentOriginalEntityMap, object entity, string operationName, object[] parameters, DomainOperation domainOperation)
        {
            context = new DomainServiceContext(context, DomainOperationType.Submit);
            DomainService service = CreateDomainServiceInstance(domainService, context, domainServiceInstances);

            object originalEntity = null;
            currentOriginalEntityMap.TryGetValue(entity, out originalEntity);

            // if this is an update operation, regardless of whether original
            // values have been specified, we need to mark the operation as
            // modified
            bool hasMemberChanges = domainOperation == DomainOperation.Update;

            // when custom methods are invoked, the operation type
            // is Update
            if (domainOperation == DomainOperation.Custom)
            {
                domainOperation = DomainOperation.Update;
            }

            ChangeSetEntry changeSetEntry = new ChangeSetEntry(1, entity, originalEntity, domainOperation);
            changeSetEntry.HasMemberChanges = hasMemberChanges;
            if (!string.IsNullOrEmpty(operationName))
            {
                changeSetEntry.EntityActions = new List<Serialization.KeyValue<string, object[]>>(); 
                changeSetEntry.EntityActions.Add(new Serialization.KeyValue<string, object[]>(operationName, parameters));
            }

            ChangeSet changeSet = new ChangeSet(new[] { changeSetEntry });

            service.Submit(changeSet);

            if (changeSetEntry.HasError)
            {
                throw new OperationException(Resource.DomainServiceProxy_OperationError, changeSetEntry.ValidationErrors);
            }
        }
Exemplo n.º 13
0
        /// <summary>
        /// Helper method performs a submit operation against a given proxy instance.
        /// </summary>
        /// <param name="domainService">The type of <see cref="DomainService"/> to perform this query operation against.</param>
        /// <param name="context">The current context.</param>
        /// <param name="domainServiceInstances">The list of tracked <see cref="DomainService"/> instances that any newly created
        /// <see cref="DomainServices"/> will be added to.</param>
        /// <param name="currentOriginalEntityMap">The mapping of current and original entities used with the utility <see cref="DomainServiceProxy.AssociateOriginal"/> method.</param>
        /// <param name="entity">The entity being submitted.</param>
        /// <param name="operationName">The name of the submit operation. For CUD operations, this can be null.</param>
        /// <param name="parameters">The submit operation parameters.</param>
        /// <param name="domainOperation">The type of submit operation.</param>
        /// <exception cref="ArgumentNullException">if <paramref name="context"/> is null.</exception>
        /// <exception cref="ArgumentNullException">if <paramref name="entity"/> is null.</exception>
        /// <exception cref="OperationException">if operation errors are thrown during execution of the submit operation.</exception>
        public static void Submit(Type domainService, DomainServiceContext context, IList <DomainService> domainServiceInstances, IDictionary <object, object> currentOriginalEntityMap, object entity, string operationName, object[] parameters, DomainOperation domainOperation)
        {
            context = new DomainServiceContext(context, DomainOperationType.Submit);
            DomainService service = CreateDomainServiceInstance(domainService, context, domainServiceInstances);

            object originalEntity = null;

            currentOriginalEntityMap.TryGetValue(entity, out originalEntity);

            // if this is an update operation, regardless of whether original
            // values have been specified, we need to mark the operation as
            // modified
            bool hasMemberChanges = domainOperation == DomainOperation.Update;

            // when custom methods are invoked, the operation type
            // is Update
            if (domainOperation == DomainOperation.Custom)
            {
                domainOperation = DomainOperation.Update;
            }

            ChangeSetEntry changeSetEntry = new ChangeSetEntry(1, entity, originalEntity, domainOperation);

            changeSetEntry.HasMemberChanges = hasMemberChanges;
            if (!string.IsNullOrEmpty(operationName))
            {
                changeSetEntry.EntityActions = new List <Serialization.KeyValue <string, object[]> >();
                changeSetEntry.EntityActions.Add(new Serialization.KeyValue <string, object[]>(operationName, parameters));
            }

            ChangeSet changeSet = new ChangeSet(new[] { changeSetEntry });

            service.SubmitAsync(changeSet, CancellationToken.None)
            .GetAwaiter().GetResult();

            if (changeSetEntry.HasError)
            {
                throw new OperationException(Resource.DomainServiceProxy_OperationError, changeSetEntry.ValidationErrors);
            }
        }
Exemplo n.º 14
0
 public static ChangeSetEntry GetChangeSetEntry(OperationContext context, object entity, object original, DomainOperation operationType)
 {
     Utility.EnsureOperationSupported(context, entity.GetType(), operationType);
     context.OperationName = context.DomainServiceDescription.GetSubmitMethod(entity.GetType(), operationType).Name;
     return new ChangeSetEntry(Utility.DefaultChangeSetEntryId, entity, original, operationType);
 }
            /// <summary>
            /// Creates an instance of a <see cref="ReflectionDomainOperationEntry"/>.
            /// </summary>
            /// <param name="domainServiceType">The DomainService Type the method belongs to.</param>
            /// <param name="methodInfo">The MethodInfo of the method.</param>
            /// <param name="operation">The operation.</param>         
            public ReflectionDomainOperationEntry(Type domainServiceType, MethodInfo methodInfo, DomainOperation operation)
                : base(domainServiceType, methodInfo.Name, operation, methodInfo.ReturnType, GetMethodParameters(methodInfo), GetAttributeCollection(methodInfo))
            {
                if (methodInfo == null)
                {
                    throw new ArgumentNullException("methodInfo");
                }

                // Generic methods aren’t supported, and will be caught during DomainServiceDescription validation.
                if (!methodInfo.IsGenericMethodDefinition)
                {
                    this._method = DynamicMethodUtility.GetDelegateForMethod(methodInfo);
                }
            }
        /// <summary>
        /// Gets the submit method for the specified entity type and <see cref="DomainOperation"/>
        /// </summary>
        /// <param name="entityType">The entity type</param>
        /// <param name="operation">The <see cref="DomainOperation"/> type to get the method for. Must be
        /// an Insert, Update or Delete operation.</param>
        /// <returns>The method if it exists, otherwise null</returns>
        public DomainOperationEntry GetSubmitMethod(Type entityType, DomainOperation operation)
        {
            this.EnsureInitialized();

            if (entityType == null)
            {
                throw new ArgumentNullException("entityType");
            }
            if ((operation != DomainOperation.Insert) &&
                (operation != DomainOperation.Update) &&
                (operation != DomainOperation.Delete))
            {
                throw new ArgumentOutOfRangeException("operation");
            }

            for (Type baseType = entityType; baseType != typeof(object) && baseType != null; baseType = baseType.BaseType)
            {
                Dictionary<DomainOperation, DomainOperationEntry> entitySubmitMethods = null;
                if (this._submitMethods.TryGetValue(baseType, out entitySubmitMethods))
                {
                    DomainOperationEntry submitMethod = null;
                    if (entitySubmitMethods.TryGetValue(operation, out submitMethod))
                    {
                        return submitMethod;
                    }
                }
            }

            return null;
        }
        /// <summary>
        /// Recursive helper for <see cref="IsOperationSupported"/>. This method checks support
        /// for the type directly, then checks composing parents as well.
        /// </summary>
        /// <param name="entityType">The entity Type to check.</param>
        /// <param name="operationType">The operation Type to check.</param>
        /// <param name="isParent">True if the check should use compositional parent rules.</param>
        /// <param name="visited">Visited map used during recursion.</param>
        /// <returns><c>True</c> if the operation is supported, <c>false</c> otherwise.</returns>
        private bool IsOperationSupportedInternal(Type entityType, DomainOperation operationType, bool isParent, HashSet<Type> visited)
        {
            if (this.GetSubmitMethod(entityType, operationType) != null)
            {
                // an explicit operation exists
                return true;
            }

            if (operationType == DomainOperation.Update || isParent)
            {
                // when checking operation support for a composed child,
                // if the parent supports Update, all operations are supported
                // for the child
                bool canUpdate = this.GetSubmitMethod(entityType, DomainOperation.Update) != null
                                 || this.GetCustomMethods(entityType).Any();
                if (canUpdate)
                {
                    return true;
                }
            }

            // Avoid infinite recursion in the case of composition cycles
            if (visited.Contains(entityType))
            {
                return false;
            }
            visited.Add(entityType);

            // for compositional children, if the parent supports the operation (or supports
            // Update) the operation is supported.
            foreach (PropertyDescriptor parentAssociation in this.GetParentAssociations(entityType))
            {
                if (this.IsOperationSupportedInternal(parentAssociation.ComponentType, operationType, true, visited))
                {
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Determines whether the specified change operation is supported for the specified Type.
        /// If the Type is the child of one or more composition relationships, operation support
        /// takes parent support into account.
        /// </summary>
        /// <param name="entityType">The entity Type to check.</param>
        /// <param name="operationType">The operation Type to check. Must be one of the
        /// change operation types Insert, Update or Delete.</param>
        /// <returns><c>True</c> if the operation is supported, <c>false</c> otherwise.</returns>
        public bool IsOperationSupported(Type entityType, DomainOperation operationType)
        {
            if (entityType == null)
            {
                throw new ArgumentNullException("entityType");
            }

            if (operationType != DomainOperation.Insert &&
                operationType != DomainOperation.Update &&
                operationType != DomainOperation.Delete)
            {
                throw new ArgumentOutOfRangeException("operationType");
            }

            HashSet<Type> visited = new HashSet<Type>();
            return this.IsOperationSupportedInternal(entityType, operationType, false, visited);
        }
        /// <summary>
        /// Validates that every CUD method (aka domain operation) exposed on a derived
        /// entity is also exposed on that entity's root.
        /// </summary>
        /// <exception cref="InvalidOperationException">if any derived entity exposes a domain operation not also on the root.</exception>
        private void ValidateDerivedDomainOperations()
        {
            HashSet<Type> rootEntityTypes = new HashSet<Type>(this.RootEntityTypes);
            IEnumerable<Type> derivedEntityTypes = this.EntityTypes.Where(t => !rootEntityTypes.Contains(t));
            DomainOperation[] allDomainOperations = new DomainOperation[] { DomainOperation.Insert, DomainOperation.Update, DomainOperation.Delete };

            foreach (Type derivedType in derivedEntityTypes)
            {
                Type rootType = this.GetRootEntityType(derivedType);

                // Loop over Insert, Update, Delete for each entity
                foreach (DomainOperation domainOperation in allDomainOperations)
                {
                    DomainOperationEntry derivedOperation = this.GetSubmitMethod(derivedType, domainOperation);
                    if (derivedOperation != null)
                    {
                        DomainOperationEntry rootOperation = this.GetSubmitMethod(rootType, domainOperation);
                        if (rootOperation == null)
                        {
                            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.DomainOperation_Required_On_Root, derivedOperation.Name, derivedType.Name, rootType.Name));
                        }
                    }
                }
            }
        }
        private static bool IsValidMethodSignature(DomainServiceDescription description, DomainOperationEntry operationEntry, DomainOperation operation, out Exception error)
        {
            string methodName = operationEntry.Name;
            ReadOnlyCollection<DomainOperationParameter> parameters = operationEntry.Parameters;
            Type returnType = operationEntry.ReturnType;

            switch (operation)
            {
                case DomainOperation.Delete:
                case DomainOperation.Insert:
                case DomainOperation.Update:
                    {
                        // insert signature check: parameter length must be 1
                        if (parameters.Count != 1)
                        {
                            error = new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.InvalidInsertUpdateDeleteMethod_IncorrectParameterLength, methodName));
                            return false;
                        }

                        // parameter must be by-value
                        if (!IsByVal(parameters[0]))
                        {
                            error = new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.InvalidDomainOperationEntry_ParamMustBeByVal, methodName, parameters[0].Name));
                            return false;
                        }

                        if (!description._entityTypes.Contains(parameters[0].ParameterType))
                        {
                            error = new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.InvalidDomainMethod_ParamMustBeEntity, parameters[0].Name, methodName));
                            return false;
                        }

                        break;
                    }
                case DomainOperation.Query:
                    {
                        // Ignore the optional "out count" parameter.
                        IEnumerable<DomainOperationParameter> queryParameters = parameters;
                        DomainOperationParameter lastParameter = queryParameters.LastOrDefault();
                        if (lastParameter != null && lastParameter.IsOut)
                        {
                            queryParameters = queryParameters.Take(queryParameters.Count() - 1).ToArray();
                        }

                        foreach (DomainOperationParameter param in queryParameters)
                        {
                            if (!TypeUtility.IsPredefinedType(param.ParameterType))
                            {
                                error = new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.InvalidDomainOperationEntry_ParamMustBeSimple, methodName, param.Name));
                                return false;
                            }
                        }

                        // Determine the entity Type and validate the return type
                        // (must return IEnumerable<T> or a singleton)
                        bool isSingleton = false;
                        Type entityType = DomainServiceDescription.GetQueryEntityReturnType(operationEntry, out isSingleton, out error);
                        if (error != null)
                        {
                            return false;
                        }

                        // validate the entity Type
                        if (entityType == null || !description._entityTypes.Contains(entityType))
                        {
                            string errorMessage;
                            if (!IsValidEntityType(entityType, out errorMessage))
                            {
                                error = new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.Invalid_Entity_Type, entityType.Name, errorMessage));
                                return false;
                            }
                        }

                        // Only IEnumerable<T> returning query methods can be marked composable
                        if (isSingleton && ((QueryAttribute)operationEntry.OperationAttribute).IsComposable)
                        {
                            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.DomainServiceDescription_SingletonQueryMethodCannotCompose, methodName, returnType));
                        }

                        break;
                    }
                case DomainOperation.Custom:
                    {
                        // check that the method signature is conforming to our expectations (Entity, one or more of pre-defined types)
                        if (parameters.Count == 0)
                        {
                            error = new InvalidOperationException(Resource.InvalidCustomMethod_MethodCannotBeParameterless);
                            return false;
                        }
                        bool first = true;
                        foreach (DomainOperationParameter param in parameters)
                        {
                            if (first)
                            {
                                // if first parameter, ensure that its type is one of the Entity types associated with CRUD.
                                if (!description._entityTypes.Contains(param.ParameterType))
                                {
                                    error = new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.InvalidDomainMethod_ParamMustBeEntity, param.Name, methodName));
                                    return false;
                                }
                                first = false;
                            }
                            else if (!TypeUtility.IsPredefinedType(param.ParameterType) && !TypeUtility.IsSupportedComplexType(param.ParameterType))
                            {
                                error = new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.InvalidDomainOperationEntry_ParamMustBeSimple, methodName, param.Name));
                                return false;
                            }
                        }
                        break;
                    }
                case DomainOperation.Invoke:
                    {
                        foreach (DomainOperationParameter param in parameters)
                        {
                            // parameter Type must be one of the predefined types, a supported complex type, an entity or collection of entities
                            if (!description._entityTypes.Contains(param.ParameterType) && !TypeUtility.IsPredefinedType(param.ParameterType) && !TypeUtility.IsSupportedComplexType(param.ParameterType))
                            {
                                // see if the parameter type is a supported collection of entities
                                Type elementType = TypeUtility.GetElementType(param.ParameterType);
                                bool isEntityCollection = description._entityTypes.Contains(elementType) && TypeUtility.IsSupportedCollectionType(param.ParameterType);
                                if (!isEntityCollection)
                                {
                                    error = new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.InvalidInvokeOperation_ParameterType, methodName));
                                    return false;
                                }
                            }
                        }

                        // return Type must be one of the predefined types, an entity or collection of entities
                        if (returnType != typeof(void) && !description._entityTypes.Contains(returnType) && !TypeUtility.IsPredefinedType(returnType) && !TypeUtility.IsSupportedComplexType(returnType))
                        {
                            // see if the return is a supported collection of entities
                            Type elementType = TypeUtility.GetElementType(returnType);
                            bool isEntityCollection = description._entityTypes.Contains(elementType) && TypeUtility.IsSupportedCollectionType(returnType);
                            if (!isEntityCollection)
                            {
                                error = new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.InvalidInvokeOperation_ReturnType, methodName));
                                return false;
                            }
                        }
                        break;
                    }
            }

            if (operation != DomainOperation.Invoke && operation != DomainOperation.Query)
            {
                // return type should be void for other domain operations except invoke operations
                if (returnType != typeof(void) || operationEntry.IsTaskAsync)
                {
                    error = new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.InvalidDomainOperationEntry_NonQueryMustReturnVoid, methodName));
                    return false;
                }
            }

            error = null;
            return true;
        }
        /// <summary>
        /// Defines a proxy Submit operation.
        /// </summary>
        /// <param name="context">The generation context.</param>
        /// <param name="method">The contract method.</param>
        /// <param name="domainOperation">The type of <see cref="DomainOperation"/>.</param>
        private static void GenerateSubmitMethod(GenerationContext context, MethodInfo method, DomainOperation domainOperation)
        {
            /* Here's the C# equivalent of what we want to generate:
            * 
            *     public void $(MethodName)($(EntityParameter), (... [$(ParameterAttributes)] $(Parameters)))
            *     {
            *         DomainServiceProxyHelpers.Submit(this, entity, operationName, parameters, domainOperation)
            *     }
            * 
            */

            ParameterInfo[] parameters = method.GetParameters();
            Type[] parameterTypes = parameters.Select(p => p.IsOut || p.ParameterType.IsByRef ? p.ParameterType.GetElementType() : p.ParameterType).ToArray();
            MethodBuilder queryMethod =
                context.TypeBuilder.DefineMethod(
                    method.Name,
                    MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual,
                    method.ReturnType,
                    parameters.Select(pi => pi.ParameterType).ToArray());

            InitializeMethod(queryMethod, method);

            ILGenerator methodBody = queryMethod.GetILGenerator();

            // Emit:
            //
            //     object[] parameterValues;
            LocalBuilder paramValuesLocal = methodBody.DeclareLocal(typeof(object[]));

            // Emit:
            //
            //     // For all 'out' parameters
            //     <parameter> = default();
            for (int i = 0; i < parameters.Length; ++i)
            {
                ParameterInfo parameter = parameters[i];

                if (parameter.IsOut && !parameter.IsIn)
                {
                    methodBody.Emit(OpCodes.Ldarg_S, i + 1); // <parameter>
                    methodBody.Emit(OpCodes.Initobj, parameterTypes[i]); // <parameter> = default();
                }
            }

            // Do we need to pass parameters along?  For a submit method, we can 
            // assume the first parameter is the entity so we check to see if
            // additional parameters exist beyond that.
            if ((parameters.Length - 1) < 1)
            {
                // Emit:
                //
                //     parameterValues = null;
                methodBody.Emit(OpCodes.Ldnull);
                methodBody.Emit(OpCodes.Stloc, paramValuesLocal);
            }
            else
            {
                // Emit:
                //
                //     parameterValues = new object[ $(Parameters).Length ];
                methodBody.Emit(OpCodes.Ldc_I4_S, parameters.Length - 1);
                methodBody.Emit(OpCodes.Newarr, typeof(object));
                methodBody.Emit(OpCodes.Stloc, paramValuesLocal);

                // Emit:
                //
                //     // Repeat for all parameter values...
                //     parameterValues[n] = $(Parameters)[n];
                for (int i = 1; i < parameters.Length; i++)
                {
                    ParameterInfo param = parameters[i];

                    methodBody.Emit(OpCodes.Ldloc, paramValuesLocal); // parameterValues
                    methodBody.Emit(OpCodes.Ldc_I4_S, i - 1);
                    methodBody.Emit(OpCodes.Ldarg_S, i + 1); // parameterValues[n]

                    // out/ref types?  push on stack
                    if (param.IsOut || param.ParameterType.IsByRef)
                    {
                        methodBody.Emit(OpCodes.Ldobj, parameterTypes[i]);
                    }

                    // value or generics?  box it up
                    if (parameterTypes[i].IsValueType || parameterTypes[i].IsGenericParameter)
                    {
                        methodBody.Emit(OpCodes.Box, parameterTypes[i]);
                    }

                    methodBody.Emit(OpCodes.Stelem_Ref); // parameterValues[n] = arg[n]
                }
            }

            // Emit:
            // 
            //     object[] objectParams = new object[8];
            LocalBuilder objectParams = methodBody.DeclareLocal(typeof(object[]));
            methodBody.Emit(OpCodes.Ldc_I4_8);
            methodBody.Emit(OpCodes.Newarr, typeof(object));
            methodBody.Emit(OpCodes.Stloc_S, objectParams);

            // Emit:
            // 
            //     objectParams[0] = this._domainServiceType;
            methodBody.Emit(OpCodes.Ldloc_S, objectParams);
            methodBody.Emit(OpCodes.Ldc_I4_S, 0);
            methodBody.Emit(OpCodes.Ldarg_0);
            methodBody.Emit(OpCodes.Ldfld, context.DomainServiceTypeField);
            methodBody.Emit(OpCodes.Stelem_Ref);

            // Emit:
            // 
            //     objectParams[1] = this._domainServiceContext;
            methodBody.Emit(OpCodes.Ldloc_S, objectParams);
            methodBody.Emit(OpCodes.Ldc_I4_S, 1);
            methodBody.Emit(OpCodes.Ldarg_0);
            methodBody.Emit(OpCodes.Ldfld, context.DomainServiceContextField);
            methodBody.Emit(OpCodes.Stelem_Ref);

            // Emit:
            // 
            //     objectParams[2] = this.DomainServiceInstances;
            methodBody.Emit(OpCodes.Ldloc_S, objectParams);
            methodBody.Emit(OpCodes.Ldc_I4_S, 2);
            methodBody.Emit(OpCodes.Ldarg_0);
            methodBody.Emit(OpCodes.Callvirt, context.DomainServiceInstancesGetter);
            methodBody.Emit(OpCodes.Stelem_Ref);

            // Emit:
            // 
            //     objectParams[3] = this.CurrentOriginalEntityMap;
            methodBody.Emit(OpCodes.Ldloc_S, objectParams);
            methodBody.Emit(OpCodes.Ldc_I4_S, 3);
            methodBody.Emit(OpCodes.Ldarg_0);
            methodBody.Emit(OpCodes.Callvirt, context.DomainServiceCurrentOriginalGetter);
            methodBody.Emit(OpCodes.Stelem_Ref);

            // Emit:
            // 
            //     objectParams[4] = entity;
            methodBody.Emit(OpCodes.Ldloc_S, objectParams);
            methodBody.Emit(OpCodes.Ldc_I4_S, 4);
            methodBody.Emit(OpCodes.Ldarg_1);
            methodBody.Emit(OpCodes.Stelem_Ref);

            // Emit:
            // 
            //     objectParams[5] = operationName; // if a custom operation
            methodBody.Emit(OpCodes.Ldloc_S, objectParams);
            methodBody.Emit(OpCodes.Ldc_I4_S, 5);
            if (domainOperation == DomainOperation.Custom)
            {
                methodBody.Emit(OpCodes.Ldstr, method.Name);
            }
            else
            {
                methodBody.Emit(OpCodes.Ldnull);
            }
            methodBody.Emit(OpCodes.Stelem_Ref);

            // Emit:
            // 
            //     objectParams[6] = parameters;
            methodBody.Emit(OpCodes.Ldloc_S, objectParams);
            methodBody.Emit(OpCodes.Ldc_I4_S, 6);
            methodBody.Emit(OpCodes.Ldloc_S, paramValuesLocal);
            methodBody.Emit(OpCodes.Stelem_Ref);

            // Emit:
            // 
            //     objectParams[7] = (int)domainOperation;
            methodBody.Emit(OpCodes.Ldloc_S, objectParams);
            methodBody.Emit(OpCodes.Ldc_I4_S, 7);
            methodBody.Emit(OpCodes.Ldc_I4_S, (int)domainOperation);
            methodBody.Emit(OpCodes.Box, typeof(int));
            methodBody.Emit(OpCodes.Stelem_Ref);

            // Emit:
            // 
            //     submitDelegate.DynamicInvoke(objectParams);  // leaving result on stack
            EmitDelegateInvoke(methodBody, objectParams, context.SubmitDelegateField);

            methodBody.Emit(OpCodes.Pop); // ignore result, its a void returning method
            methodBody.Emit(OpCodes.Ret);
        }
Exemplo n.º 22
0
 private static void EnsureOperationSupported(OperationContext context, Type entityType, DomainOperation operationType)
 {
     if (!context.DomainServiceDescription.IsOperationSupported(entityType, operationType))
     {
         throw new DomainServiceTestHostException(string.Format(
             CultureInfo.CurrentCulture,
             Resources.OperationNotSupported,
             operationType,
             entityType,
             context.DomainServiceDescription.DomainServiceType));
     }
 }
Exemplo n.º 23
0
 private static void EnsureOperationSupported(OperationContext context, Type entityType, DomainOperation operationType)
 {
     if (!context.DomainServiceDescription.IsOperationSupported(entityType, operationType))
     {
         throw new DomainServiceTestHostException(string.Format(
                                                      CultureInfo.CurrentCulture,
                                                      Resources.OperationNotSupported,
                                                      operationType,
                                                      entityType,
                                                      context.DomainServiceDescription.DomainServiceType));
     }
 }
            /// <summary>
            /// Creates an instance of a <see cref="ReflectionDomainOperationEntry"/>.
            /// </summary>
            /// <param name="domainServiceType">The DomainService Type the method belongs to.</param>
            /// <param name="methodInfo">The MethodInfo of the method.</param>
            /// <param name="operation">The operation.</param>
            public ReflectionDomainOperationEntry(Type domainServiceType, MethodInfo methodInfo, DomainOperation operation)
                : base(domainServiceType, methodInfo.Name, operation, methodInfo.ReturnType, GetMethodParameters(methodInfo), GetAttributeCollection(methodInfo))
            {
                if (methodInfo == null)
                {
                    throw new ArgumentNullException("methodInfo");
                }

                // Generic methods aren’t supported, and will be caught during DomainServiceDescription validation.
                if (!methodInfo.IsGenericMethodDefinition)
                {
                    this._method = DynamicMethodUtility.GetDelegateForMethod(methodInfo);
                }
            }
Exemplo n.º 25
0
        public bool Setup(string functionsXMLFilename)
        {
            try
            {
                XElement x = XElement.Load(functionsXMLFilename, LoadOptions.None);

                XElement helpers = x.Element("helpers");
                foreach (XElement h in helpers.Elements("code"))
                {
                    XAttribute comment = h.Attribute("comment");
                    HelperCode helper  = new HelperCode(h.Attribute("name").Value, h.Value, comment == null ? "" : comment.Value);
                    Helpers.Add(helper.Name, helper);
                }

                XElement nodes = x.Element("nodes");

                foreach (XElement n in nodes.Elements("node"))
                {
                    string   code     = "";
                    string[] requires = null;

                    XElement func = n.Element("function");
                    if (func != null)
                    {
                        code = func.Value;
                        XAttribute requ = func.Attribute("requires");
                        if (requ != null)
                        {
                            requires = requ.Value.Split(",".ToCharArray());
                        }
                    }

                    XAttribute com     = n.Attribute("comment");
                    string     comment = "";
                    if (com != null)
                    {
                        comment = com.Value;
                    }

                    SceneNode node = null;

                    switch (n.Attribute("type").Value)
                    {
                    case "dp":
                        node = new DistancePrimitive(n.Attribute("name").Value, n.Attribute("caption").Value, n.Attribute("mask").Value, code, requires, comment);
                        DistanceFieldTypes.Add(node as DistancePrimitive);
                        break;

                    case "distop":
                        node = new DistanceOperation(n.Attribute("name").Value, n.Attribute("caption").Value, n.Attribute("mask").Value, code, requires, comment);
                        DistanceOperations.Add(node as DistanceOperation);
                        break;

                    case "domop":
                        node = new DomainOperation(n.Attribute("name").Value, n.Attribute("caption").Value, n.Attribute("mask").Value, code, requires, comment);
                        DomainOperations.Add(node as DomainOperation);
                        break;
                    }

                    if (node != null && n.Element("properties") != null)
                    {
                        foreach (XElement p in n.Element("properties").Elements("property"))
                        {
                            node.Properties.Add(createInputProperty(p.Attribute("type").Value, p.Attribute("name").Value, p.Attribute("default").Value));
                        }
                    }
                }
            }
            catch (Exception e)
            {
                errors.Add("Failed to load/parse " + functionsXMLFilename + ":\n" + e.Message);
                return(false);
            }

            return(true);
        }
Exemplo n.º 26
0
 public static ChangeSetEntry GetChangeSetEntry(OperationContext context, object entity, object original, DomainOperation operationType)
 {
     Utility.EnsureOperationSupported(context, entity.GetType(), operationType);
     context.OperationName = context.DomainServiceDescription.GetSubmitMethod(entity.GetType(), operationType).Name;
     return(new ChangeSetEntry(Utility.DefaultChangeSetEntryId, entity, original, operationType));
 }