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)); }
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)); } }
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); }
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); }
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; //})); }