Пример #1
0
        public void GetTargetSetTestsSetBindingTypeShouldPerformCorrectValidation()
        {
            ResourceType actorEntityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "foo", "Actor", false)
            {
                CanReflectOnInstanceType = false
            };
            ResourceProperty idProperty = new ResourceProperty("ID", ResourcePropertyKind.Primitive | ResourcePropertyKind.Key, ResourceType.GetPrimitiveResourceType(typeof(int)))
            {
                CanReflectOnInstanceTypeProperty = false
            };

            actorEntityType.AddProperty(idProperty);

            ResourceType addressComplexType = new ResourceType(typeof(object), ResourceTypeKind.ComplexType, null, "foo", "Address", false)
            {
                CanReflectOnInstanceType = false
            };

            addressComplexType.AddProperty(new ResourceProperty("StreetAddress", ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(string)))
            {
                CanReflectOnInstanceTypeProperty = false
            });
            addressComplexType.AddProperty(new ResourceProperty("ZipCode", ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(int)))
            {
                CanReflectOnInstanceTypeProperty = false
            });

            actorEntityType.AddProperty(new ResourceProperty("PrimaryAddress", ResourcePropertyKind.ComplexType, addressComplexType)
            {
                CanReflectOnInstanceTypeProperty = false
            });
            actorEntityType.AddProperty(new ResourceProperty("OtherAddresses", ResourcePropertyKind.Collection, ResourceType.GetCollectionResourceType(addressComplexType))
            {
                CanReflectOnInstanceTypeProperty = false
            });

            ResourceType movieEntityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "foo", "Movie", false)
            {
                CanReflectOnInstanceType = false
            };

            movieEntityType.AddProperty(idProperty);

            ResourceProperty moviesNavProp = new ResourceProperty("Movies", ResourcePropertyKind.ResourceSetReference, movieEntityType)
            {
                CanReflectOnInstanceTypeProperty = false
            };

            actorEntityType.AddProperty(moviesNavProp);
            ResourceProperty actorsNavProp = new ResourceProperty("Actors", ResourcePropertyKind.ResourceSetReference, actorEntityType)
            {
                CanReflectOnInstanceTypeProperty = false
            };

            movieEntityType.AddProperty(actorsNavProp);

            ResourceType derivedActorEntityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, actorEntityType, "foo", "DerivedActor", false)
            {
                CanReflectOnInstanceType = false
            };
            ResourceType derivedMovieEntityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, movieEntityType, "foo", "DerivedMovie", false)
            {
                CanReflectOnInstanceType = false
            };

            actorEntityType.SetReadOnly();
            derivedActorEntityType.SetReadOnly();
            movieEntityType.SetReadOnly();
            derivedMovieEntityType.SetReadOnly();
            addressComplexType.SetReadOnly();
            DataServiceProviderSimulator providerSimulator = new DataServiceProviderSimulator();

            providerSimulator.AddResourceType(actorEntityType);
            providerSimulator.AddResourceType(derivedActorEntityType);
            providerSimulator.AddResourceType(movieEntityType);
            providerSimulator.AddResourceType(derivedMovieEntityType);
            providerSimulator.AddResourceType(addressComplexType);

            ResourceSet actorSet = new ResourceSet("Actors", actorEntityType);
            ResourceSet movieSet = new ResourceSet("Movies", movieEntityType);

            actorSet.SetReadOnly();
            movieSet.SetReadOnly();
            providerSimulator.AddResourceSet(actorSet);
            providerSimulator.AddResourceSet(movieSet);

            providerSimulator.AddResourceAssociationSet(new ResourceAssociationSet("Actors_Movies", new ResourceAssociationSetEnd(actorSet, actorEntityType, moviesNavProp), new ResourceAssociationSetEnd(movieSet, movieEntityType, actorsNavProp)));

            DataServiceConfiguration config = new DataServiceConfiguration(providerSimulator);

            config.SetEntitySetAccessRule("*", EntitySetRights.All);
            config.DataServiceBehavior.MaxProtocolVersion = ODataProtocolVersion.V4;

            var dataService = new DataServiceSimulator()
            {
                OperationContext = new DataServiceOperationContext(new DataServiceHostSimulator())
            };

            dataService.ProcessingPipeline = new DataServiceProcessingPipeline();
            DataServiceStaticConfiguration staticConfiguration = new DataServiceStaticConfiguration(dataService.Instance.GetType(), providerSimulator);
            IDataServiceProviderBehavior   providerBehavior    = DataServiceProviderBehavior.CustomDataServiceProviderBehavior;

            DataServiceProviderWrapper provider = new DataServiceProviderWrapper(
                new DataServiceCacheItem(
                    config,
                    staticConfiguration),
                providerSimulator,
                providerSimulator,
                dataService,
                false);

            dataService.Provider      = provider;
            provider.ProviderBehavior = providerBehavior;

            var testCases = new[]
            {
                new
                {
                    AppendParameterName = true,
                    Path         = "",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    ErrorMessage = default(string)
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/Movies",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = ResourceSetWrapper.CreateResourceSetWrapper(movieSet, provider, set => set),
                    ErrorMessage = default(string)
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/Movies/Actors/Movies",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = ResourceSetWrapper.CreateResourceSetWrapper(movieSet, provider, set => set),
                    ErrorMessage = default(string)
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/foo.DerivedActor/Movies/foo.DerivedMovie/Actors/foo.DerivedActor/Movies",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = ResourceSetWrapper.CreateResourceSetWrapper(movieSet, provider, set => set),
                    ErrorMessage = default(string)
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression '{0}/' is not a valid expression because it contains an empty segment or it ends with '/'."
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/Movies/",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression '{0}/Movies/' is not a valid expression because it contains an empty segment or it ends with '/'."
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/Movies//Actors",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = ResourceSetWrapper.CreateResourceSetWrapper(movieSet, provider, set => set),
                    ErrorMessage = "The path expression '{0}/Movies//Actors' is not a valid expression because it contains an empty segment or it ends with '/'."
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/foo.DerivedActor",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression '{0}/foo.DerivedActor' is not a valid expression because it ends with the type identifier 'foo.DerivedActor'. A valid path expression must not end in a type identifier."
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/Movies/foo.DerivedMovie",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression '{0}/Movies/foo.DerivedMovie' is not a valid expression because it ends with the type identifier 'foo.DerivedMovie'. A valid path expression must not end in a type identifier."
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/Foo",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression '{0}/Foo' is not a valid expression because the segment 'Foo' is not a type identifier or a property on the resource type 'foo.Actor'."
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/ID",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression '{0}/ID' is not a valid expression because the segment 'ID' is a property of type 'Edm.Int32'. A valid path expression must only contain properties of entity type."
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/OtherAddresses",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression '{0}/OtherAddresses' is not a valid expression because the segment 'OtherAddresses' is a property of type 'Collection(foo.Address)'. A valid path expression must only contain properties of entity type."
                },
                new
                {
                    AppendParameterName = true,
                    Path         = "/Movies/Actors/PrimaryAddress",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression '{0}/Movies/Actors/PrimaryAddress' is not a valid expression because the segment 'PrimaryAddress' is a property of type 'foo.Address'. A valid path expression must only contain properties of entity type."
                },
                new
                {
                    AppendParameterName = false,
                    Path         = "foo",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression 'foo' is not a valid path expression. A valid path expression must start with the binding parameter name '{0}'."
                },
                new
                {
                    AppendParameterName = false,
                    Path         = "abc/pqr",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression 'abc/pqr' is not a valid path expression. A valid path expression must start with the binding parameter name '{0}'."
                },
                new
                {
                    AppendParameterName = false,
                    Path         = "actorParameter",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression 'actorParameter' is not a valid path expression. A valid path expression must start with the binding parameter name '{0}'."
                },
                new
                {
                    AppendParameterName = false,
                    Path         = "actorsParameter",
                    BindingSet   = ResourceSetWrapper.CreateResourceSetWrapper(actorSet, provider, set => set),
                    TargetSet    = default(ResourceSetWrapper),
                    ErrorMessage = "The path expression 'actorsParameter' is not a valid path expression. A valid path expression must start with the binding parameter name '{0}'."
                },
            };

            ServiceActionParameter actorParameter  = new ServiceActionParameter("actor", actorEntityType);
            ServiceActionParameter actorsParameter = new ServiceActionParameter("actors", ResourceType.GetEntityCollectionResourceType(actorEntityType));
            var parameters = new ServiceActionParameter[] { actorParameter, actorsParameter };

            foreach (var parameter in parameters)
            {
                foreach (var testCase in testCases)
                {
                    string pathString = testCase.AppendParameterName ? parameter.Name + testCase.Path : testCase.Path;
                    var    path       = new ResourceSetPathExpression(pathString);
                    Assert.AreEqual(pathString, path.PathExpression);
                    string expectedErrorMessage = testCase.ErrorMessage == null ? null : string.Format(testCase.ErrorMessage, parameter.Name);
                    try
                    {
                        path.SetBindingParameter(parameter);
                        path.InitializePathSegments(provider);
                        var targetSet = path.GetTargetSet(provider, testCase.BindingSet);
                        Assert.IsNull(expectedErrorMessage, "Expecting exception but received none.");
                        Assert.AreEqual(targetSet.Name, testCase.TargetSet.Name);
                    }
                    catch (InvalidOperationException e)
                    {
                        Assert.AreEqual(expectedErrorMessage, e.Message);
                    }
                }
            }
        }
        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);
        }
Пример #3
0
        private MethodInfo RetrieveOverloadedServiceAction(IEnumerable <MethodInfo> overloadedServiceActionMethods, ServiceActionParameter bindingParameterToSearch)
        {
            foreach (MethodInfo mi in overloadedServiceActionMethods)
            {
                ParameterInfo bindingParameter = mi.GetParameters().FirstOrDefault();

                // handle unbound actions
                if (bindingParameter == null && bindingParameterToSearch == null)
                {
                    return(mi);
                }

                // find the MethodInfo for the action based on the binding parameter type
                if (bindingParameter != null &&
                    bindingParameterToSearch != null &&
                    bindingParameter.ParameterType == bindingParameterToSearch.ParameterType.InstanceType)
                {
                    return(mi);
                }
            }

            return(null);
        }
Пример #4
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);
                };
            }