public async Task Posting_NonDerivedType_To_Action_Expecting_BaseType_Throws() { // Arrange StringContent content = new StringContent("{ '@odata.type' : '#Microsoft.AspNet.OData.Test.Builder.TestModels.Motorcycle' }"); var headers = FormatterTestHelper.GetContentHeaders("application/json"); IODataRequestMessage oDataRequest = ODataMessageWrapperHelper.Create(await content.ReadAsStreamAsync(), headers); ODataMessageReader reader = new ODataMessageReader(oDataRequest, new ODataMessageReaderSettings(), _model); ODataDeserializerProvider deserializerProvider = ODataDeserializerProviderFactory.Create(); ODataDeserializerContext context = new ODataDeserializerContext { Model = _model }; IEdmActionImport action = _model.EntityContainer .OperationImports() .Single(f => f.Name == "PostMotorcycle_When_Expecting_Car") as IEdmActionImport; Assert.NotNull(action); IEdmEntitySetBase actionEntitySet; action.TryGetStaticEntitySet(_model, out actionEntitySet); context.Path = new ODataPath(new OperationImportSegment(new[] { action }, actionEntitySet, null)); // Act & Assert ExceptionAssert.Throws <ODataException>( () => new ODataResourceDeserializer(deserializerProvider).Read(reader, typeof(Car), context), "A resource with type 'Microsoft.AspNet.OData.Test.Builder.TestModels.Motorcycle' was found, " + "but it is not assignable to the expected type 'Microsoft.AspNet.OData.Test.Builder.TestModels.Car'. " + "The type specified in the resource must be equal to either the expected type or a derived type."); }
public void Posting_NonDerivedType_To_Action_Expecting_BaseType_Throws() { // Arrange StringContent content = new StringContent("{ '@odata.type' : '#System.Web.OData.Builder.TestModels.Motorcycle' }"); content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); IODataRequestMessage oDataRequest = new ODataMessageWrapper(content.ReadAsStreamAsync().Result, content.Headers); ODataMessageReader reader = new ODataMessageReader(oDataRequest, new ODataMessageReaderSettings(), _model); ODataDeserializerProvider deserializerProvider = DependencyInjectionHelper.GetDefaultODataDeserializerProvider(); ODataDeserializerContext context = new ODataDeserializerContext { Model = _model }; IEdmActionImport action = _model.EntityContainer .OperationImports() .Single(f => f.Name == "PostMotorcycle_When_Expecting_Car") as IEdmActionImport; Assert.NotNull(action); IEdmEntitySetBase actionEntitySet; action.TryGetStaticEntitySet(_model, out actionEntitySet); context.Path = new ODataPath(new OperationImportSegment(new[] { action }, actionEntitySet, null)); // Act & Assert Assert.Throws <ODataException>( () => new ODataResourceDeserializer(deserializerProvider).Read(reader, typeof(Car), context), "An resource with type 'System.Web.OData.Builder.TestModels.Motorcycle' was found, " + "but it is not assignable to the expected type 'System.Web.OData.Builder.TestModels.Car'. " + "The type specified in the resource must be equal to either the expected type or a derived type."); }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } ActionModel action = context.Action; IEdmModel model = context.Model; // By convention, we use the operation import name as the action name in the controller string actionMethodName = action.ActionName; var edmOperationImports = model.ResolveOperationImports(actionMethodName, enableCaseInsensitive: true); if (!edmOperationImports.Any()) { return(true); } (var actionImports, var functionImports) = edmOperationImports.SplitOperationImports(); // It's not allowed to have an action import and function import with the same name. if (actionImports.Count > 0 && functionImports.Count > 0) { throw new ODataException(Error.Format(SRResources.OperationMustBeUniqueInEntitySetContainer, actionMethodName)); } else if (actionImports.Count > 0 && context.Action.Attributes.Any(a => a is HttpPostAttribute)) { if (actionImports.Count != 1) { throw new ODataException(Error.Format(SRResources.MultipleActionImportFound, actionMethodName)); } IEdmActionImport actionImport = actionImports[0]; IEdmEntitySetBase targetEntitySet; actionImport.TryGetStaticEntitySet(model, out targetEntitySet); // TODO: // 1. shall we check the [HttpPost] attribute, or does the ASP.NET Core have the default? // 2) shall we check the action has "ODataActionParameters" parameter type? ODataPathTemplate template = new ODataPathTemplate(new ActionImportSegmentTemplate(actionImport, targetEntitySet)); action.AddSelector("Post", context.Prefix, context.Model, template, context.Options?.RouteOptions); return(true); } else if (functionImports.Count > 0 && context.Action.Attributes.Any(a => a is HttpGetAttribute)) { IEdmFunctionImport functionImport = FindFunctionImport(functionImports, action); if (functionImport == null) { return(false); } IEdmEntitySetBase targetSet; functionImport.TryGetStaticEntitySet(model, out targetSet); // TODO: // 1) shall we check the [HttpGet] attribute, or does the ASP.NET Core have the default? ODataPathTemplate template = new ODataPathTemplate(new FunctionImportSegmentTemplate(functionImport, targetSet)); action.AddSelector("Get", context.Prefix, context.Model, template, context.Options?.RouteOptions); return(true); } else { // doesn't find an operation, return true means to skip the remaining conventions. return(false); } }