private object GetMarshalledParameter(DataServiceOperationContext operationContext, ServiceActionParameter serviceActionParameter, object value)
        {
            var parameterKind = serviceActionParameter.ParameterType.ResourceTypeKind;

            // Need to Marshall MultiValues i.e. Collection(Primitive) & Collection(ComplexType)
            if (parameterKind == ResourceTypeKind.EntityType)
            {
                // This entity is UNATTACHED. But people are likely to want to edit this...
                IDataServiceUpdateProvider2 updateProvider = operationContext.GetService(typeof(IDataServiceUpdateProvider2)) as IDataServiceUpdateProvider2;
                value = updateProvider.GetResource(value as IQueryable, serviceActionParameter.ParameterType.InstanceType.FullName);
                value = updateProvider.ResolveResource(value); // This will attach the entity.
            }
            else if (parameterKind == ResourceTypeKind.EntityCollection)
            {
                // WCF Data Services constructs an IQueryable that is NoTracking...
                // but that means people can't just edit the entities they pull from the Query.
                var query = value as ObjectQuery;
                query.MergeOption = MergeOption.AppendOnly;
            }
            else if (parameterKind == ResourceTypeKind.Collection)
            {
                // need to coerce into a List<> for dispatch
                var enumerable = value as IEnumerable;
                // the <T> in List<T> is the Instance type of the ItemType
                var elementType = (serviceActionParameter.ParameterType as CollectionResourceType).ItemType.InstanceType;
                // call IEnumerable.Cast<T>();
                var    castMethod      = CastMethodGeneric.MakeGenericMethod(elementType);
                object marshalledValue = castMethod.Invoke(null, new[] { enumerable });
                // call IEnumerable<T>.ToList();
                var toListMethod = ToListMethodGeneric.MakeGenericMethod(elementType);
                value = toListMethod.Invoke(null, new[] { marshalledValue });
            }
            return(value);
        }
Пример #2
0
            /// <summary>
            /// Constructs a delegate to invoke the service action with the provided parameters.
            /// </summary>
            /// <param name="operationContext">The data service operation context instance.</param>
            /// <param name="dataService">The data service instance.</param>
            /// <param name="action">The service action to invoke.</param>
            /// <param name="parameters">The parameters required to invoke the service action.</param>
            private void ConstructInvokeDelegateForServiceAction(DataServiceOperationContext operationContext, ServiceAction action, object[] parameters)
            {
                var info = action.CustomState as DSPServiceActionInfo;

                if (info == null)
                {
                    throw new InvalidOperationException("Insufficient information to invoke the service action!");
                }

                IDataServiceUpdateProvider2 updateProvider = (IDataServiceUpdateProvider2)operationContext.GetService(typeof(IDataServiceUpdateProvider2));

                if (updateProvider == null)
                {
                    throw new InvalidOperationException("DataServiceOperationContext.GetService(IDataServiceUpdateProvider2) returned null!");
                }

                this.invokeDelegate = () =>
                {
                    int idx = 0;
                    if (action.BindingParameter != null)
                    {
                        if (action.BindingParameter.ParameterType.ResourceTypeKind == ResourceTypeKind.EntityType)
                        {
                            parameters[idx] = updateProvider.GetResource((IQueryable)parameters[idx], null);
                        }

                        parameters[idx] = updateProvider.ResolveResource(parameters[idx]);
                        idx++;
                    }

                    var methodParameters = info.Method.GetParameters();
                    for (; idx < parameters.Length; idx++)
                    {
                        ServiceActionParameter sap = action.Parameters[idx];
                        if (sap.ParameterType.ResourceTypeKind == ResourceTypeKind.Collection && parameters[idx] != null)
                        {
                            ResourceType itemResourceType = ((CollectionResourceType)sap.ParameterType).ItemType;

                            // Need to call ResolveResource on each complex item in the collection.
                            Type       parameterType = methodParameters[idx].ParameterType;
                            Type       itemType      = parameterType.GetGenericArguments()[0];
                            MethodInfo resolveCollectionMethod;

                            if (parameterType.GetGenericTypeDefinition() == typeof(IQueryable <>))
                            {
                                resolveCollectionMethod = DSPInvokableAction.ResolveCollectionAsQueryableMethodInfo.MakeGenericMethod(itemType);
                            }
                            else
                            {
                                resolveCollectionMethod = DSPInvokableAction.ResolveCollectionMethodInfo.MakeGenericMethod(itemType);
                            }

                            parameters[idx] = resolveCollectionMethod.Invoke(null, new object[] { updateProvider, parameters[idx], itemResourceType.ResourceTypeKind == ResourceTypeKind.Primitive });
                        }
                        else if (sap.ParameterType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                        {
                            parameters[idx] = updateProvider.ResolveResource(parameters[idx]);
                        }
                    }

                    this.result = info.Method.Invoke(info.Instance, parameters);
                };
            }