public void CanManuallyConfigureActionLinkFactory()
        {
            // Arrange
            string            uriTemplate = "http://server/service/Customers({0})/Reward";
            Uri               expectedUri = new Uri(string.Format(uriTemplate, 1));
            ODataModelBuilder builder     = new ODataModelBuilder();
            EntityTypeConfiguration <Customer> customer = builder.EntitySet <Customer>("Customers").EntityType;

            customer.HasKey(c => c.CustomerId);
            customer.Property(c => c.Name);

            // Act
            ActionConfiguration reward = customer.Action("Reward");

            reward.HasActionLink(ctx => new Uri(string.Format(uriTemplate, ctx.GetPropertyValue("CustomerId"))),
                                 followsConventions: false);
            IEdmModel              model             = builder.GetEdmModel();
            IEdmEntityType         customerType      = model.SchemaElements.OfType <IEdmEntityType>().SingleOrDefault();
            ODataSerializerContext serializerContext = new ODataSerializerContext {
                Model = model
            };

            ResourceContext context = new ResourceContext(serializerContext, customerType.AsReference(), new Customer {
                CustomerId = 1
            });
            IEdmAction           rewardAction      = Assert.Single(model.SchemaElements.OfType <IEdmAction>()); // Guard
            OperationLinkBuilder actionLinkBuilder = model.GetAnnotationValue <OperationLinkBuilder>(rewardAction);

            //Assert
            Assert.Equal(expectedUri, reward.GetActionLink()(context));
            Assert.NotNull(actionLinkBuilder);
            Assert.Equal(expectedUri, actionLinkBuilder.BuildLink(context));
        }
Beispiel #2
0
        private static void SetupExtendSupportDateActionLink(ActionConfiguration extendSupportDateAction)
        {
            extendSupportDateAction.HasActionLink(eic =>
            {
                Product pd = (Product)eic.EntityInstance;

                return(new Uri(eic.UrlHelper.Link(ODataRouteNames.InvokeBoundAction, new
                {
                    controller = eic.EntitySet.Name,
                    boundId = pd.ID,
                    odataAction = "ExtendSupportDate"
                })));
            });

            //extendSupportDateAction.HasActionLink(ActionLinkBuilder.CreateActionLinkFactory(
            //baseFactory: eic =>
            //{
            //    Product pd = (Product)eic.EntityInstance;

            //    return new Uri(eic.UrlHelper.Link(ODataRouteNames.InvokeBoundAction, new
            //    {
            //        controller = eic.EntitySet.Name,
            //        boundId = pd.ID,
            //        odataAction = "ExtendSupportDate"
            //    }));
            //},
            //expensiveAvailabilityCheck: eic =>
            //{
            //    //do some check here and return true or false
            //    return true;
            //}));
        }
        public void ActionLink_PreservesFollowsConventions(bool value)
        {
            // Arrange
            ODataModelBuilder            builder                  = ODataModelBuilderMocks.GetModelBuilderMock <ODataModelBuilder>();
            ActionConfiguration          configuration            = new ActionConfiguration(builder, "IgnoreAction");
            Mock <IEdmTypeConfiguration> bindingParameterTypeMock = new Mock <IEdmTypeConfiguration>();

            bindingParameterTypeMock.Setup(o => o.Kind).Returns(EdmTypeKind.Entity);
            Type entityType = typeof(object);

            bindingParameterTypeMock.Setup(o => o.ClrType).Returns(entityType);
            configuration.SetBindingParameter("IgnoreParameter", bindingParameterTypeMock.Object);
            configuration.HasActionLink((a) => { throw new NotImplementedException(); }, followsConventions: value);
            builder.AddOperation(configuration);
            builder.AddEntityType(entityType);

            // Act
            IEdmModel model = builder.GetEdmModel();

            // Assert
            var action = Assert.Single(model.SchemaElements.OfType <IEdmAction>());
            OperationLinkBuilder actionLinkBuilder = model.GetOperationLinkBuilder(action);

            Assert.NotNull(actionLinkBuilder);
            Assert.Equal(value, actionLinkBuilder.FollowsConventions);
        }
        public void Apply(ProcedureConfiguration configuration, ODataModelBuilder model)
        {
            ActionConfiguration action = configuration as ActionConfiguration;

            // You only need to create links for bindable actions that bind to a single entity.
            if (action != null && action.IsBindable && action.BindingParameter.TypeConfiguration.Kind == EdmTypeKind.Entity && action.GetActionLink() == null)
            {
                action.HasActionLink(entityContext => GenerateActionLink(entityContext, action));
            }
        }
Beispiel #5
0
        public void Apply(ProcedureConfiguration configuration, ODataModelBuilder model)
        {
            ActionConfiguration action = configuration as ActionConfiguration;

            // You only need to create links for bindable actions that bind to a single entity.
            if (action != null && action.IsBindable && action.BindingParameter.TypeConfiguration.Kind == EdmTypeKind.Entity && action.GetActionLink() == null)
            {
                string bindingParamterType = action.BindingParameter.TypeConfiguration.FullName;
                action.HasActionLink(entityContext => entityContext.GenerateActionLink(bindingParamterType, action.Name), followsConventions: true);
            }
        }
        public void HasActionLink_ThrowsException_OnNonBindableActions()
        {
            // Arrange
            ODataModelBuilder   builder = new ODataModelBuilder();
            ActionConfiguration action  = builder.Action("NoBindableAction");

            // Act & Assert
            ExceptionAssert.Throws <InvalidOperationException>(
                () => action.HasActionLink(ctx => new Uri("http://any"), followsConventions: false),
                "To register an action link factory, actions must be bindable to a single entity. " +
                "Action 'NoBindableAction' does not meet this requirement.");
        }
        public void HasActionLink_SetsFollowsConventions(bool value)
        {
            // Arrange
            ODataModelBuilder            builder = new ODataModelBuilder();
            ActionConfiguration          action  = new ActionConfiguration(builder, "IgnoreAction");
            Mock <IEdmTypeConfiguration> bindingParameterTypeMock = new Mock <IEdmTypeConfiguration>();

            bindingParameterTypeMock.Setup(o => o.Kind).Returns(EdmTypeKind.Entity);
            bindingParameterTypeMock.Setup(o => o.ClrType).Returns(typeof(int));
            IEdmTypeConfiguration bindingParameterType = bindingParameterTypeMock.Object;

            action.SetBindingParameter("IgnoreParameter", bindingParameterType);

            // Act
            action.HasActionLink((a) => { throw new NotImplementedException(); }, followsConventions: value);

            // Assert
            Assert.Equal(value, action.FollowsConventions);
        }
Beispiel #8
0
        public void Apply(ProcedureConfiguration configuration, ODataModelBuilder model)
        {
            ActionConfiguration action = configuration as ActionConfiguration;

            if (action == null || !action.IsBindable)
            {
                return;
            }

            // You only need to create links for bindable actions that bind to a single entity.
            if (action.BindingParameter.TypeConfiguration.Kind == EdmTypeKind.Entity && action.GetActionLink() == null)
            {
                if (action.BindingParameter.TypeConfiguration.Kind == EdmTypeKind.Entity &&
                    action.GetActionLink() == null)
                {
                    string bindingParameterType = action.BindingParameter.TypeConfiguration.FullName;
                    action.HasActionLink(
                        entityContext =>
                        entityContext.GenerateActionLink(bindingParameterType, action.FullyQualifiedName),
                        followsConventions: true);
                }
            }
            else if (action.BindingParameter.TypeConfiguration.Kind == EdmTypeKind.Collection &&
                     action.GetFeedActionLink() == null)
            {
                if (((CollectionTypeConfiguration)action.BindingParameter.TypeConfiguration).ElementType.Kind ==
                    EdmTypeKind.Entity)
                {
                    string bindingParameterType = action.BindingParameter.TypeConfiguration.FullName;
                    action.HasFeedActionLink(
                        feedContext =>
                        feedContext.GenerateActionLink(bindingParameterType, action.FullyQualifiedName),
                        followsConventions: true);
                }
            }
        }
        // Builds the EDM model for the OData service, including the OData action definitions.
        private static IEdmModel GetModel()
        {
            ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
            var moviesEntitySet            = modelBuilder.EntitySet <Movie>("Movies");

            moviesEntitySet.EntityType.Ignore(m => m.TimeStamp);    // Don't expose timestamp to clients

            // Now add actions to the EDM.

            // CheckOut
            // URI: ~/odata/Movies(1)/CheckOut
            // Transient action. It is not available when the item is already checked out.
            ActionConfiguration checkout = modelBuilder.Entity <Movie>().TransientAction("CheckOut");

            // Provide a function that returns a link to the action, when the action is available, or
            // returns null when the action is not available.
            checkout.HasActionLink(ctx =>
            {
                Movie movie = ctx.EntityInstance as Movie;

                // Note: In some cases, checking whether the action is available may be relatively expensive.
                // For example, it might require a DB lookup.

                // Avoid doing expensive checks inside a loop (i.e., when serializing a feed). Instead, simply
                // mark the action as available, by returning an action link.

                // The SkipExpensiveAvailabilityChecks flag says whether to skip expensive checks. If this flag
                // is true AND your availability check is expensive, skip the check and return a link.

                // In this sample, the check is not really expensive, but we honor the flag to show how it works.
                bool createLink = true;
                if (ctx.SkipExpensiveAvailabilityChecks)
                {
                    // Caller asked us to skip the availability check.
                    createLink = true;
                }
                else if (!movie.IsCheckedOut) // Here is the "expensive" check
                {
                    createLink = true;
                }

                if (createLink)
                {
                    // Return the URI of the action.
                    return(new Uri(ctx.Url.CreateODataLink(
                                       new EntitySetPathSegment(ctx.EntitySet),
                                       new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(movie.ID, ODataVersion.V3)),
                                       new ActionPathSegment(checkout.Name))));
                }
                else
                {
                    return(null);
                }
            }, followsConventions: true);   // "followsConventions" means the action follows OData conventions.
            checkout.ReturnsFromEntitySet <Movie>("Movies");

            // ReturnMovie
            // URI: ~/odata/Movies(1)/Return
            // Always bindable. If the movie is not checked out, the action is a no-op.
            // Binds to a single entity; no parameters.
            var returnAction = modelBuilder.Entity <Movie>().Action("Return");

            returnAction.ReturnsFromEntitySet <Movie>("Movies");

            // SetDueDate action
            // URI: ~/odata/Movies(1)/SetDueDate
            // Binds to a single entity; takes an action parameter.
            var setDueDate = modelBuilder.Entity <Movie>().Action("SetDueDate");

            setDueDate.Parameter <DateTime>("DueDate");
            setDueDate.ReturnsFromEntitySet <Movie>("Movies");

            // CheckOut action
            // URI: ~/odata/Movies/CheckOut
            // Shows how to bind to a collection, instead of a single entity.
            // This action also accepts $filter queries. For example:
            //     ~/odata/Movies/CheckOut?$filter=Year eq 2005
            var checkOutFromCollection = modelBuilder.Entity <Movie>().Collection.Action("CheckOut");

            checkOutFromCollection.ReturnsCollectionFromEntitySet <Movie>("Movies");

            // CheckOutMany action
            // URI: ~/odata/Movies/CheckOutMany
            // Shows an action that takes a collection parameter.
            ActionConfiguration checkoutMany = modelBuilder.Entity <Movie>().Collection.Action("CheckOutMany");

            checkoutMany.CollectionParameter <int>("MovieIDs");
            checkoutMany.ReturnsCollectionFromEntitySet <Movie>("Movies");

            // CreateMovie action
            // URI: ~/odata/CreateMovie
            // Non-bindable action. You invoke it from the service root.
            ActionConfiguration createMovie = modelBuilder.Action("CreateMovie");

            createMovie.Parameter <string>("Title");
            createMovie.ReturnsFromEntitySet <Movie>("Movies");

            return(modelBuilder.GetEdmModel());
        }
        public void HasActionLink_SetsFollowsConventions(bool value)
        {
            // Arrange
            ODataModelBuilder builder = new ODataModelBuilder();
            ActionConfiguration action = new ActionConfiguration(builder, "IgnoreAction");
            Mock<IEdmTypeConfiguration> bindingParameterTypeMock = new Mock<IEdmTypeConfiguration>();
            bindingParameterTypeMock.Setup(o => o.Kind).Returns(EdmTypeKind.Entity);
            IEdmTypeConfiguration bindingParameterType = bindingParameterTypeMock.Object;
            action.SetBindingParameter("IgnoreParameter", bindingParameterType, alwaysBindable: false);

            // Act
            action.HasActionLink((a) => { throw new NotImplementedException(); }, followsConventions: value);

            // Assert
            Assert.Equal(value, action.FollowsConventions);
        }
        public void ActionLink_PreservesFollowsConventions(bool value)
        {
            // Arrange
            ODataModelBuilder builder = ODataModelBuilderMocks.GetModelBuilderMock<ODataModelBuilder>();
            ActionConfiguration configuration = new ActionConfiguration(builder, "IgnoreAction");
            Mock<IEdmTypeConfiguration> bindingParameterTypeMock = new Mock<IEdmTypeConfiguration>();
            bindingParameterTypeMock.Setup(o => o.Kind).Returns(EdmTypeKind.Entity);
            Type entityType = typeof(object);
            bindingParameterTypeMock.Setup(o => o.ClrType).Returns(entityType);
            configuration.SetBindingParameter("IgnoreParameter", bindingParameterTypeMock.Object,
                alwaysBindable: false);
            configuration.HasActionLink((a) => { throw new NotImplementedException(); }, followsConventions: value);
            builder.AddProcedure(configuration);
            builder.AddEntityType(entityType);

            // Act
            IEdmModel model = builder.GetEdmModel();

            // Assert
            var action = Assert.Single(model.SchemaElements.OfType<IEdmAction>());
            ActionLinkBuilder actionLinkBuilder = model.GetActionLinkBuilder(action);
            Assert.NotNull(actionLinkBuilder);
            Assert.Equal(value, actionLinkBuilder.FollowsConventions);
        }
Beispiel #12
0
        private static void SetupExtendSupportDateActionLink(ActionConfiguration extendSupportDateAction)
        {
            extendSupportDateAction.HasActionLink(eic =>
            {
                Product pd = (Product)eic.EntityInstance;

                return new Uri(eic.UrlHelper.Link(ODataRouteNames.InvokeBoundAction, new
                {
                    controller = eic.EntitySet.Name,
                    boundId = pd.ID,
                    odataAction = "ExtendSupportDate"
                }));
            });

            //extendSupportDateAction.HasActionLink(ActionLinkBuilder.CreateActionLinkFactory(
            //baseFactory: eic =>
            //{
            //    Product pd = (Product)eic.EntityInstance;

            //    return new Uri(eic.UrlHelper.Link(ODataRouteNames.InvokeBoundAction, new
            //    {
            //        controller = eic.EntitySet.Name,
            //        boundId = pd.ID,
            //        odataAction = "ExtendSupportDate"
            //    }));
            //},
            //expensiveAvailabilityCheck: eic =>
            //{
            //    //do some check here and return true or false
            //    return true;
            //}));
        }