Exemplo n.º 1
0
        public void ServiceActionParameterInvalidCasesTest()
        {
            ResourceType complexType           = new ResourceType(typeof(object), ResourceTypeKind.ComplexType, null, "foo", "Address", false);
            ResourceType entityType            = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "foo", "Order", false);
            ResourceSet  entitySet             = new ResourceSet("Set", entityType);
            ResourceType collectionOfPrimitive = ResourceType.GetCollectionResourceType(ResourceType.GetPrimitiveResourceType(typeof(int)));
            ResourceType collectionOfComplex   = ResourceType.GetCollectionResourceType(complexType);
            ResourceType collectionType        = ResourceType.GetEntityCollectionResourceType(entityType);

            var parameterTypes = ResourceTypeUtils.GetPrimitiveResourceTypes()
                                 .Concat(new ResourceType[] {
                complexType,
                entityType,
                collectionOfPrimitive,
                collectionOfComplex,
                collectionType
            });

            AstoriaTestNS.TestUtil.RunCombinations(parameterTypes, (parameterType) =>
            {
                Exception e = AstoriaTestNS.TestUtil.RunCatching(() => new ServiceActionParameter("p", parameterType));
                if (parameterType != ResourceType.GetPrimitiveResourceType(typeof(System.IO.Stream)))
                {
                    Assert.IsNull(e, "Service op parameter should have succeeded.");
                }
                else
                {
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, "The service operation parameter 'p' of type 'Edm.Stream' is not supported.\r\nParameter name: parameterType");
                }
            });
        }
Exemplo n.º 2
0
        /// <summary>
        /// Get the resource type for the given clr type.
        /// </summary>
        /// <param name="metadataProvider">An instance of the IDataServiceMetadataProvider.</param>
        /// <param name="type">Clr type in question.</param>
        /// <param name="elementTypeName">Name of the element type if <paramref name="type"/> is a
        /// <see cref="DSPResource"/> type or a collection type of <see cref="DSPResource"/>.</param>
        /// <returns>The resource type for the given clr type.</returns>
        private static ResourceType GetResourceTypeFromType(IDataServiceMetadataProvider metadataProvider, Type type, string elementTypeName)
        {
            Debug.Assert(metadataProvider != null, "metadataProvider != null");
            if (type == typeof(void))
            {
                return(null);
            }

            ResourceType resourceType;
            Type         elementType = type;

            if (!type.IsPrimitive && type.IsGenericType && typeof(IEnumerable).IsAssignableFrom(type))
            {
                elementType = type.GetGenericArguments()[0];
            }

            if (elementType == typeof(DSPResource))
            {
                metadataProvider.TryResolveResourceType(elementTypeName, out resourceType);
            }
            else
            {
                resourceType = ResourceType.GetPrimitiveResourceType(elementType);
                if (resourceType == null && !metadataProvider.TryResolveResourceType(elementType.FullName, out resourceType))
                {
                    throw new DataServiceException(string.Format("The type '{0}' is unknown to the metadata provider.", elementType.FullName));
                }
            }

            if (type != elementType)
            {
                if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                {
                    resourceType = ResourceType.GetEntityCollectionResourceType(resourceType);
                }
                else
                {
                    resourceType = ResourceType.GetCollectionResourceType(resourceType);
                }
            }

            return(resourceType);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Gets the return type of the operation.
        /// </summary>
        /// <param name="resultType">Type of element of the method result. This is the item type of the return type if the return type is a collection type.</param>
        /// <param name="resultKind">Kind of result expected from this operation.</param>
        /// <returns>Returns the return type of the operation.</returns>
        private static ResourceType GetReturnTypeFromResultType(ResourceType resultType, ServiceOperationResultKind resultKind)
        {
            if ((resultKind == ServiceOperationResultKind.Void && resultType != null) ||
                (resultKind != ServiceOperationResultKind.Void && resultType == null))
            {
                throw new ArgumentException(Strings.ServiceOperation_ResultTypeAndKindMustMatch("resultKind", "resultType", ServiceOperationResultKind.Void));
            }

            if (resultType != null && resultType.ResourceTypeKind == ResourceTypeKind.Collection)
            {
                throw new ArgumentException(Strings.ServiceOperation_InvalidResultType(resultType.FullName));
            }

            if (resultType != null && resultType.ResourceTypeKind == ResourceTypeKind.EntityCollection)
            {
                throw new ArgumentException(Strings.ServiceOperation_InvalidResultType(resultType.FullName));
            }

            ResourceType returnType;

            if (resultType == null)
            {
                Debug.Assert(resultKind == ServiceOperationResultKind.Void, "resultKind == ServiceOperationResultKind.Void");
                returnType = null;
            }
            else if ((resultType.ResourceTypeKind == ResourceTypeKind.Primitive || resultType.ResourceTypeKind == ResourceTypeKind.ComplexType) && (resultKind == ServiceOperationResultKind.Enumeration || resultKind == ServiceOperationResultKind.QueryWithMultipleResults))
            {
                returnType = ResourceType.GetCollectionResourceType(resultType);
            }
            else if (resultType.ResourceTypeKind == ResourceTypeKind.EntityType && (resultKind == ServiceOperationResultKind.Enumeration || resultKind == ServiceOperationResultKind.QueryWithMultipleResults))
            {
                returnType = ResourceType.GetEntityCollectionResourceType(resultType);
            }
            else
            {
                Debug.Assert(
                    resultKind == ServiceOperationResultKind.DirectValue || resultKind == ServiceOperationResultKind.QueryWithSingleResult,
                    "resultKind == ServiceOperationResultKind.DirectValue || resultKind == ServiceOperationResultKind.QueryWithSingleResult");
                returnType = resultType;
            }

            return(returnType);
        }
Exemplo n.º 4
0
    // Allow all types: Primitive/Complex/Entity and IQueryable<> and IEnumerable<>
    private ResourceType GetResourceType(Type type)
    {
        if (type.IsGenericType)
        {
            var typeDef = type.GetGenericTypeDefinition();
            if (typeDef.GetGenericArguments().Count() == 1)
            {
                if (typeDef == typeof(IEnumerable <>) || typeDef == typeof(IQueryable <>))
                {
                    var elementResource = GetResourceType(type.GetGenericArguments().Single());
                    if ((elementResource.ResourceTypeKind | ResourceTypeKind.EntityType) == ResourceTypeKind.EntityType)
                    {
                        return(ResourceType.GetEntityCollectionResourceType(elementResource));
                    }
                    else
                    {
                        return(ResourceType.GetCollectionResourceType(elementResource));
                    }
                }
            }

            throw new Exception($"Generic action parameter type {type} not supported");
        }

        if (ActionFactory.__primitives.Contains(type))
        {
            return(ResourceType.GetPrimitiveResourceType(type));
        }

        var resourceType = _metadata.Types.SingleOrDefault(s => s.Name == type.Name);

        if (resourceType == null)
        {
            throw new Exception($"Generic action parameter type {type} not supported");
        }

        return(resourceType);
    }
Exemplo n.º 5
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);
                    }
                }
            }
        }
Exemplo n.º 6
0
        protected override IEnumerable <ServiceAction> LoadServiceActions(IDataServiceMetadataProvider dataServiceMetadataProvider)
        {
            ResourceType productType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Product", out productType);

            ResourceType orderLineType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.OrderLine", out orderLineType);

            ResourceType personType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Person", out personType);

            ResourceType employeeType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Employee", out employeeType);

            ResourceType specialEmployeeType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.SpecialEmployee", out specialEmployeeType);

            ResourceType contractorType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Contractor", out contractorType);

            //
            // actions with the same name and non-related binding types
            //
            var RetrieveProductActionProduct = new ServiceAction(
                "RetrieveProduct",
                ResourceType.GetPrimitiveResourceType(typeof(int)),
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
            {
                new ServiceActionParameter("product", productType),
            });

            RetrieveProductActionProduct.SetReadOnly();
            yield return(RetrieveProductActionProduct);

            var RetrieveProductActionOrderLine = new ServiceAction(
                "RetrieveProduct",
                ResourceType.GetPrimitiveResourceType(typeof(int)),
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
            {
                new ServiceActionParameter("orderLine", orderLineType),
            });

            RetrieveProductActionOrderLine.SetReadOnly();
            yield return(RetrieveProductActionOrderLine);

            //
            // Collection bound actions with the same name
            //
            var increaseSalariesActionEmployee = new ServiceAction(
                "IncreaseSalaries",
                null,
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
            {
                new ServiceActionParameter("employees", ResourceType.GetEntityCollectionResourceType(employeeType)),
                new ServiceActionParameter("n", ResourceType.GetPrimitiveResourceType(typeof(int))),
            });

            increaseSalariesActionEmployee.SetReadOnly();
            yield return(increaseSalariesActionEmployee);

            var increaseSalariesActionSpecialEmployee = new ServiceAction(
                "IncreaseSalaries",
                null,
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
            {
                new ServiceActionParameter("specialEmployees", ResourceType.GetEntityCollectionResourceType(specialEmployeeType)),
                new ServiceActionParameter("n", ResourceType.GetPrimitiveResourceType(typeof(int))),
            });

            increaseSalariesActionSpecialEmployee.SetReadOnly();
            yield return(increaseSalariesActionSpecialEmployee);

            //
            // Actions with the same name and base/derived type binding parameters
            //
            var updatePersonInfoAction = new ServiceAction(
                "UpdatePersonInfo",
                null,
                null,
                OperationParameterBindingKind.Never,
                null);

            updatePersonInfoAction.SetReadOnly();
            yield return(updatePersonInfoAction);

            var updatePersonInfoActionPerson = new ServiceAction(
                "UpdatePersonInfo",
                null,
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
            {
                new ServiceActionParameter("person", personType),
            });

            updatePersonInfoActionPerson.SetReadOnly();
            yield return(updatePersonInfoActionPerson);

            var updatePersonInfoActionEmployee = new ServiceAction(
                "UpdatePersonInfo",
                null,
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
            {
                new ServiceActionParameter("employee", employeeType),
            });

            updatePersonInfoActionEmployee.SetReadOnly();
            yield return(updatePersonInfoActionEmployee);

            var updatePersonInfoActionSpecialEmployee = new ServiceAction(
                "UpdatePersonInfo",
                null,
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
            {
                new ServiceActionParameter("specialEmployee", specialEmployeeType),
            });

            updatePersonInfoActionSpecialEmployee.SetReadOnly();
            yield return(updatePersonInfoActionSpecialEmployee);

            var updatePersonInfoActionContractor = new ServiceAction(
                "UpdatePersonInfo",
                null,
                null,
                OperationParameterBindingKind.Always,
                new[]
            {
                new ServiceActionParameter("contractor", contractorType),
            });

            updatePersonInfoActionContractor.SetReadOnly();
            yield return(updatePersonInfoActionContractor);

            //
            // Actions with the same name, base/derived type binding parameters, different non-binding parameters
            //
            var increaseEmployeeSalaryActionEmployee = new ServiceAction(
                "IncreaseEmployeeSalary",
                ResourceType.GetPrimitiveResourceType(typeof(bool)),
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
            {
                new ServiceActionParameter("employee", employeeType),
                new ServiceActionParameter("n", ResourceType.GetPrimitiveResourceType(typeof(int))),
            });

            increaseEmployeeSalaryActionEmployee.SetReadOnly();
            yield return(increaseEmployeeSalaryActionEmployee);

            var increaseEmployeeSalaryActionSpecialEmployee = new ServiceAction(
                "IncreaseEmployeeSalary",
                ResourceType.GetPrimitiveResourceType(typeof(int)),
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
            {
                new ServiceActionParameter("specialEmployee", specialEmployeeType),
            });

            increaseEmployeeSalaryActionSpecialEmployee.SetReadOnly();
            yield return(increaseEmployeeSalaryActionSpecialEmployee);
        }
        protected override IEnumerable <ServiceAction> LoadServiceActions(IDataServiceMetadataProvider dataServiceMetadataProvider)
        {
            ResourceType employeeType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Employee", out employeeType);
            ResourceType computerDetailType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.ComputerDetail", out computerDetailType);
            ResourceType computerType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Computer", out computerType);
            ResourceType customerType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Customer", out customerType);
            ResourceType auditInfoType;

            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.AuditInfo", out auditInfoType);
            ResourceSet computerSet;

            dataServiceMetadataProvider.TryResolveResourceSet("Computer", out computerSet);
            var increaseSalaryAction = new ServiceAction(
                "IncreaseSalaries",
                null,
                null,
                OperationParameterBindingKind.Always,
                new[]
            {
                new ServiceActionParameter("employees", ResourceType.GetEntityCollectionResourceType(employeeType)),
                new ServiceActionParameter("n", ResourceType.GetPrimitiveResourceType(typeof(int))),
            });

            increaseSalaryAction.SetReadOnly();

            yield return(increaseSalaryAction);

            var sackEmployeeAction = new ServiceAction(
                "Sack",
                null,
                null,
                OperationParameterBindingKind.Always,
                new[]
            {
                new ServiceActionParameter("employee", employeeType),
            });

            sackEmployeeAction.SetReadOnly();

            yield return(sackEmployeeAction);

            var getComputerAction = new ServiceAction(
                "GetComputer",
                computerType,
                OperationParameterBindingKind.Always,
                new[]
            {
                new ServiceActionParameter("computer", computerType)
            },
                new ResourceSetPathExpression("computer"));

            getComputerAction.SetReadOnly();

            yield return(getComputerAction);

            var changeCustomerAuditInfoAction = new ServiceAction(
                "ChangeCustomerAuditInfo",
                null,
                null,
                OperationParameterBindingKind.Always,
                new[]
            {
                new ServiceActionParameter("customer", customerType),
                new ServiceActionParameter("auditInfo", auditInfoType),
            });

            changeCustomerAuditInfoAction.SetReadOnly();

            yield return(changeCustomerAuditInfoAction);

            var resetComputerDetailsSpecificationsAction = new ServiceAction(
                "ResetComputerDetailsSpecifications",
                null,
                null,
                OperationParameterBindingKind.Always,
                new[]
            {
                new ServiceActionParameter("computerDetail", computerDetailType),
                new ServiceActionParameter("specifications", ResourceType.GetCollectionResourceType(ResourceType.GetPrimitiveResourceType(typeof(string)))),
                new ServiceActionParameter("purchaseTime", ResourceType.GetPrimitiveResourceType(typeof(DateTimeOffset)))
            });

            resetComputerDetailsSpecificationsAction.SetReadOnly();

            yield return(resetComputerDetailsSpecificationsAction);
        }
Exemplo n.º 8
0
        public void InvalidCasesTest()
        {
            ResourceType rt = (ResourceType)ResourceTypeUtils.GetTestInstance(typeof(ResourceType));

            ResourceType complexType = new ResourceType(typeof(object), ResourceTypeKind.ComplexType, null, "Namespace", "Address", false);
            ResourceType entityType  = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "Namespace", "Order", false);
            ResourceType primitiveOrComplexCollectionType = ResourceType.GetCollectionResourceType(complexType);
            ResourceType entityCollectionType             = ResourceType.GetEntityCollectionResourceType(entityType);
            ResourceType namedStreamType = ResourceType.GetPrimitiveResourceType(typeof(System.IO.Stream));

            AstoriaTestNS.TestUtil.RunCombinations(
                GetPropertyKindValues(),
                new ResourceType[] { entityType, complexType, primitiveOrComplexCollectionType, entityCollectionType }.Concat(ResourceTypeUtils.GetPrimitiveResourceTypes()),
                (kind, type) =>
            {
                bool invalidCase = true;

                if (IsValidValue(kind))
                {
                    if ((kind.HasFlag(ResourcePropertyKind.Primitive) && type.ResourceTypeKind == ResourceTypeKind.Primitive && type != namedStreamType) ||
                        (kind.HasFlag(ResourcePropertyKind.ComplexType) && type.ResourceTypeKind == ResourceTypeKind.ComplexType) ||
                        (kind.HasFlag(ResourcePropertyKind.ResourceReference) && type.ResourceTypeKind == ResourceTypeKind.EntityType) ||
                        (kind.HasFlag(ResourcePropertyKind.ResourceSetReference) && type.ResourceTypeKind == ResourceTypeKind.EntityType) ||
                        (kind.HasFlag(ResourcePropertyKind.Collection) && type.ResourceTypeKind == ResourceTypeKind.Collection) ||
                        (kind.HasFlag(ResourcePropertyKind.Stream) && type == namedStreamType))
                    {
                        invalidCase = false;
                    }

                    if ((kind & ResourcePropertyKind.Key) == ResourcePropertyKind.Key &&
                        type.InstanceType.IsGenericType && type.InstanceType.GetGenericTypeDefinition() == typeof(Nullable <>))
                    {
                        invalidCase = true;
                    }
                }

                if (invalidCase)
                {
                    ExceptionUtils.ThrowsException <ArgumentException>(
                        () => new ResourceProperty("TestProperty", kind, type),
                        string.Format("resource property constructor test case. Kind: '{0}', Type: '{1}: {2}'", kind, type.ResourceTypeKind, type.InstanceType));
                }
                else
                {
                    ResourceProperty p = new ResourceProperty("TestProperty", kind, type);
                    Assert.AreEqual("TestProperty", p.Name, "Name was not stored properly");
                    Assert.AreEqual(kind, p.Kind, "Kind was not stored properly");
                    Assert.AreEqual(type, p.ResourceType, "Type was not stored properly");
                    Assert.AreEqual(p.Kind.HasFlag(ResourcePropertyKind.Stream) ? false : true, p.CanReflectOnInstanceTypeProperty, "CanReflectOnInstanceTypeProperty should be true by default on non-NamedStreams, and false on NamedStreams.");
                    Assert.IsNull(p.MimeType, "MimeType should be null by default.");

                    if (p.Kind.HasFlag(ResourcePropertyKind.Stream))
                    {
                        ExceptionUtils.ThrowsException <InvalidOperationException>(
                            () => { p.CanReflectOnInstanceTypeProperty = false; },
                            "CanReflectOnInstanceTypeProperty should be settable on non-namedstreams, and not settable on namedstreams");
                    }
                    else
                    {
                        p.CanReflectOnInstanceTypeProperty = false;
                    }

                    Assert.AreEqual(false, p.CanReflectOnInstanceTypeProperty, "CanReflectOnInstanceTypeProperty should be false.");

                    bool shouldFail = true;
                    if ((kind & ResourcePropertyKind.Primitive) == ResourcePropertyKind.Primitive)
                    {
                        shouldFail = false;
                    }

                    if (shouldFail)
                    {
                        ExceptionUtils.ThrowsException <InvalidOperationException>(
                            () => p.MimeType = "plain/text",
                            string.Format("Setting MimeType on non-primitive property should fail. Kind: '{0}', Type: '{1}: {2}'", kind, type.ResourceTypeKind, type.InstanceType));
                    }
                    else
                    {
                        p.MimeType = "plain/text";
                    }
                }
            });
        }
Exemplo n.º 9
0
        public void ServiceOperationConstructorInvalidTests()
        {
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "The 'resultType' parameter must be null when the 'resultKind' parameter value is 'Void', however the 'resultType' parameter cannot be null when the 'resultKind' parameter is of any value other than 'Void'. Please make sure that the 'resultKind' parameter value is set according to the 'resultType' parameter value.",
                "op", ServiceOperationResultKind.Void, ResourceType.GetPrimitiveResourceType(typeof(int)), null, "GET", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "The 'resultType' parameter must be null when the 'resultKind' parameter value is 'Void', however the 'resultType' parameter cannot be null when the 'resultKind' parameter is of any value other than 'Void'. Please make sure that the 'resultKind' parameter value is set according to the 'resultType' parameter value.",
                "op", ServiceOperationResultKind.DirectValue, null, null, "GET", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "A parameter with the name 'p1' already exists. Please make sure that every parameter has a unique name.",
                "op", ServiceOperationResultKind.Void, null, null, "GET",
                new ServiceOperationParameter[] {
                new ServiceOperationParameter("p1", ResourceType.GetPrimitiveResourceType(typeof(int))),
                new ServiceOperationParameter("p1", ResourceType.GetPrimitiveResourceType(typeof(string)))
            });
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "The resource type 'Collection(foo.Customer)' is not a type that can be returned by a service operation. A service operation can only return values of an entity type, a complex type or any primitive type, other than the stream type.",
                "op", ServiceOperationResultKind.QueryWithMultipleResults, ResourceType.GetEntityCollectionResourceType(new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "foo", "Customer", false)), null, "GET", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "The resource type 'Edm.Stream' is not a type that can be returned by a service operation. A service operation can only return values of an entity type, a complex type or any primitive type, other than the stream type.",
                "op", ServiceOperationResultKind.DirectValue, ResourceType.GetPrimitiveResourceType(typeof(System.IO.Stream)), null, "GET", null);

            ResourceProperty p            = new ResourceProperty("ID", ResourcePropertyKind.Primitive | ResourcePropertyKind.Key, ResourceType.GetPrimitiveResourceType(typeof(int)));
            ResourceType     customerType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "Foo", "NoBaseType", false);

            customerType.AddProperty(p);
            customerType.SetReadOnly();
            ResourceSet  customerSet = new ResourceSet("Customers", customerType);
            ResourceType orderType   = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "Foo", "NoBaseType", false);

            orderType.AddProperty(p);
            orderType.SetReadOnly();

            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "'resultSet' must be null when 'resultType' is null or not an EntityType.",
                "op", ServiceOperationResultKind.Void, null, customerSet, "GET", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "'resultSet' must be null when 'resultType' is null or not an EntityType.",
                "op", ServiceOperationResultKind.DirectValue, ResourceType.GetPrimitiveResourceType(typeof(int)), customerSet, "GET", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "When 'resultType' is an entity type, 'resultSet' cannot be null and the resource type of 'resultSet' must be assignable from 'resultType'.",
                "op", ServiceOperationResultKind.QueryWithMultipleResults, customerType, null, "GET", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "When 'resultType' is an entity type, 'resultSet' cannot be null and the resource type of 'resultSet' must be assignable from 'resultType'.",
                "op", ServiceOperationResultKind.QueryWithMultipleResults, orderType, customerSet, "GET", null);

            ExceptionUtils.ThrowsException <InvalidOperationException>(
                () =>
            {
                ServiceOperation op = new ServiceOperation("op", ServiceOperationResultKind.Void, null, null, "GET", null);
                op.MimeType         = null;
            },
                "MimeType cannot be set to null");

            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "Value cannot be null or empty.\r\nParameter name: method",
                "op", ServiceOperationResultKind.DirectValue, ResourceType.GetPrimitiveResourceType(typeof(int)), null, null, null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "Value cannot be null or empty.\r\nParameter name: method",
                "op", ServiceOperationResultKind.DirectValue, ResourceType.GetPrimitiveResourceType(typeof(int)), null, string.Empty, null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "Value cannot be null or empty.\r\nParameter name: name",
                null, ServiceOperationResultKind.DirectValue, ResourceType.GetPrimitiveResourceType(typeof(int)), null, "GET", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "Value cannot be null or empty.\r\nParameter name: name",
                string.Empty, ServiceOperationResultKind.DirectValue, ResourceType.GetPrimitiveResourceType(typeof(int)), null, "GET", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "An invalid HTTP method 'PUT' was specified for the service operation 'op'. Only the HTTP 'POST' and 'GET' methods are supported for service operations.",
                "op", ServiceOperationResultKind.Void, null, null, "PUT", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "An invalid HTTP method 'PATCH' was specified for the service operation 'op'. Only the HTTP 'POST' and 'GET' methods are supported for service operations.",
                "op", ServiceOperationResultKind.Void, null, null, "PATCH", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "An invalid HTTP method 'DELETE' was specified for the service operation 'op'. Only the HTTP 'POST' and 'GET' methods are supported for service operations.",
                "op", ServiceOperationResultKind.Void, null, null, "DELETE", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "An invalid HTTP method 'HEAD' was specified for the service operation 'op'. Only the HTTP 'POST' and 'GET' methods are supported for service operations.",
                "op", ServiceOperationResultKind.Void, null, null, "HEAD", null);
            ExceptionUtils.CheckInvalidConstructorParameters(
                typeof(ServiceOperation),
                "An invalid HTTP method 'Some Method' was specified for the service operation 'op'. Only the HTTP 'POST' and 'GET' methods are supported for service operations.",
                "op", ServiceOperationResultKind.Void, null, null, "Some Method", null);
        }
Exemplo n.º 10
0
        public void ServiceActionConstructorTests()
        {
            ResourceProperty id           = new ResourceProperty("ID", ResourcePropertyKind.Primitive | ResourcePropertyKind.Key, ResourceType.GetPrimitiveResourceType(typeof(int)));
            ResourceType     customerType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "Foo", "Customer", false);

            customerType.AddProperty(id);
            customerType.SetReadOnly();
            ResourceSet  customerSet = new ResourceSet("Customers", customerType);
            ResourceType orderType   = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "Foo", "Order", false);

            orderType.AddProperty(id);
            orderType.SetReadOnly();

            ResourceType complexType           = new ResourceType(typeof(object), ResourceTypeKind.ComplexType, null, "foo", "Address", false);
            ResourceType collectionOfPrimitive = ResourceType.GetCollectionResourceType(ResourceType.GetPrimitiveResourceType(typeof(int)));
            ResourceType collectionOfComplex   = ResourceType.GetCollectionResourceType(complexType);
            ResourceType collectionOfCustomer  = ResourceType.GetEntityCollectionResourceType(customerType);
            ResourceType collectionOfOrder     = ResourceType.GetEntityCollectionResourceType(orderType);

            var types = ResourceTypeUtils.GetPrimitiveResourceTypes().Concat(new ResourceType[] { null, customerType, orderType, complexType, collectionOfPrimitive, collectionOfComplex, collectionOfCustomer, collectionOfOrder });
            var resultSetsOrPathExpressions = new object[] { null, customerSet, new ResourceSetPathExpression("p1/Foo") };
            var parameters = types.Except(new[] { ResourceType.GetPrimitiveResourceType(typeof(System.IO.Stream)) }).Select(t => t != null ? new ServiceActionParameter[] { new ServiceActionParameter("p1", t) } : new ServiceActionParameter[0]);

            parameters = parameters.Concat(types.Except(new[] { ResourceType.GetPrimitiveResourceType(typeof(System.IO.Stream)), null }).ToList().Combinations(2).Select(tt => new ServiceActionParameter[] { new ServiceActionParameter("p1", tt[0]), new ServiceActionParameter("p2", tt[1]) }));
            var operationParameterBindings = new OperationParameterBindingKind[] { OperationParameterBindingKind.Never, OperationParameterBindingKind.Sometimes, OperationParameterBindingKind.Always };

            AstoriaTestNS.TestUtil.RunCombinations(
                types, resultSetsOrPathExpressions, parameters, operationParameterBindings,
                (returnType, resultSetOrPathExpression, paramList, operationParameterBindingKind) =>
            {
                ServiceAction action    = null;
                ResourceSet resourceSet = resultSetOrPathExpression as ResourceSet;
                ResourceSetPathExpression pathExpression = resultSetOrPathExpression as ResourceSetPathExpression;
                bool bindable = (operationParameterBindingKind == OperationParameterBindingKind.Always || operationParameterBindingKind == OperationParameterBindingKind.Sometimes);
                Exception e   = null;

                try
                {
                    if (pathExpression != null)
                    {
                        bindable = true;
                        action   = new ServiceAction("foo", returnType, OperationParameterBindingKind.Sometimes, paramList, pathExpression);
                    }
                    else
                    {
                        action = new ServiceAction("foo", returnType, resourceSet, operationParameterBindingKind, paramList);
                    }
                }
                catch (Exception ex)
                {
                    e = ex;
                }
                if (resourceSet != null && operationParameterBindingKind != OperationParameterBindingKind.Never)
                {
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, "When 'returnType' is an entity type or an entity collection type, 'resultSetPathExpression' and 'resultSet' cannot be both null and the resource type of the result set must be assignable from 'returnType'.");
                }
                else if (returnType != null && (returnType.ResourceTypeKind == ResourceTypeKind.EntityType || returnType.ResourceTypeKind == ResourceTypeKind.EntityCollection) &&
                         (resourceSet == null && pathExpression == null ||
                          resourceSet != null && returnType.ResourceTypeKind == ResourceTypeKind.EntityType && resourceSet.ResourceType != returnType ||
                          resourceSet != null && returnType.ResourceTypeKind == ResourceTypeKind.EntityCollection && resourceSet.ResourceType != ((EntityCollectionResourceType)returnType).ItemType))
                {
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, "When 'returnType' is an entity type or an entity collection type, 'resultSetPathExpression' and 'resultSet' cannot be both null and the resource type of the result set must be assignable from 'returnType'.");
                }
                else if ((returnType == null || returnType.ResourceTypeKind != ResourceTypeKind.EntityCollection && returnType.ResourceTypeKind != ResourceTypeKind.EntityType) && resourceSet != null)
                {
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, "'resultSet' must be null when 'returnType' is null, not an entity type or not an entity collection type.");
                }
                else if ((returnType == null || returnType.ResourceTypeKind != ResourceTypeKind.EntityCollection && returnType.ResourceTypeKind != ResourceTypeKind.EntityType) && pathExpression != null)
                {
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, "'resultSetPathExpression' must be null when 'returnType' is null, not an entity type or not an entity collection type.");
                }
                else if (returnType == ResourceType.GetPrimitiveResourceType(typeof(System.IO.Stream)))
                {
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, "The resource type 'Edm.Stream' is not a type that can be returned by a function or action. A function or action can only return values of an entity type, an entity collection type, a complex type, a collection type or any primitive type, other than the stream type.\r\nParameter name: returnType");
                }
                else if (paramList.Length > 0 && paramList.Skip(bindable ? 1 : 0).Any(p => p.ParameterType.ResourceTypeKind == ResourceTypeKind.EntityType || p.ParameterType.ResourceTypeKind == ResourceTypeKind.EntityCollection))
                {
                    var param             = paramList.Skip(bindable ? 1 : 0).First(p => p.ParameterType.ResourceTypeKind == ResourceTypeKind.EntityType || p.ParameterType.ResourceTypeKind == ResourceTypeKind.EntityCollection);
                    var parameterTypeKind = param.ParameterType.ResourceTypeKind;
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, string.Format("The '{0}' parameter is of resource type kind '{1}' and it is not the binding parameter. Parameter of type kind '{1}' is only supported for the binding parameter.", param.Name, parameterTypeKind));
                }
                else if (pathExpression != null && !bindable)
                {
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, "The binding parameter type must be an entity type or an entity collection type when 'resultSetPathExpression' is not null.");
                }
                else if (bindable && paramList.Length == 0)
                {
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, "Bindable actions or functions must have at least one parameter, where the first parameter is the binding parameter.\r\nParameter name: operationParameterBindingKind");
                }
                else if (pathExpression != null && bindable && paramList.First().ParameterType.ResourceTypeKind != ResourceTypeKind.EntityType && paramList.First().ParameterType.ResourceTypeKind != ResourceTypeKind.EntityCollection)
                {
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, "The binding parameter type must be an entity type or an entity collection type when 'resultSetPathExpression' is not null.");
                }
                else if (paramList.Length > 0 && bindable && paramList[0].ParameterType.ResourceTypeKind != ResourceTypeKind.EntityType && paramList[0].ParameterType.ResourceTypeKind != ResourceTypeKind.EntityCollection)
                {
                    ExceptionUtils.IsExpectedException <ArgumentException>(e, "An action's binding parameter must be of type Entity or EntityCollection.\r\nParameter name: parameters");
                }
                else
                {
                    Assert.IsNull(e, "Received exception but expected none. Exception message: {0}", e == null ? string.Empty : e.Message);
                    Assert.IsNotNull(action, "Action should be constructed.");

                    Assert.AreEqual("foo", action.Name, "unexpected name");
                    Assert.AreEqual(returnType, action.ReturnType, "unexpected return type");
                    Assert.AreEqual(resourceSet, action.ResourceSet, "unexpected result set");
                    Assert.AreEqual(pathExpression, action.ResultSetPathExpression, "unexpected path expression");
                    Assert.IsTrue(!bindable || action.BindingParameter == action.Parameters.First(), "unexpected binding parameter");
                    Assert.IsTrue(action.Method == "POST", "HttpMethod must be POST for ServiceActions.");
                    Assert.IsTrue(action.ResourceSet == null || action.ResultSetPathExpression == null, "'resultSet' and 'resultSetPathExpression' cannot be both set by the constructor.");
                }
            });
        }