public void SetODataContentIdMapping_SetsTheContentIdMappingOnTheRequest()
        {
            // Arrange
            HttpRequest request = new DefaultHttpContext().Request;
            IDictionary <string, string> mapping = new Dictionary <string, string>();

            // Act
            request.SetODataContentIdMapping(mapping);

            // Assert
            Assert.Equal(mapping, ODataBatchHttpRequestExtensions.GetODataContentIdMapping(request));
        }
        /// <summary>
        /// If the request has OData v3 headers in it, then process using V3 deserializer provider.
        /// Otherwise, process as base class.
        /// </summary>
        /// <param name="context">InputFormatter context</param>
        /// <param name="encoding">Encoding of request body</param>
        /// <returns>InputFormatterResult</returns>
        public override Task <InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            Type type = context.ModelType;

            if (type == null)
            {
                throw new ArgumentException("Model type for this request body is null", nameof(type));
            }

            HttpRequest request = context.HttpContext.Request;

            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            // Migration extension need AllowSynchronousIO to be true. (The value is false by default for .Net Core 3.0+, refer to https://github.com/dotnet/docs/issues/14835)
            var syncIOFeature = context.HttpContext.Features.Get <IHttpBodyControlFeature>();

            if (syncIOFeature != null)
            {
                syncIOFeature.AllowSynchronousIO = true;
            }

            // If content length is 0 then return default value for this type
            RequestHeaders contentHeaders = request.GetTypedHeaders();
            object         defaultValue   = GetDefaultValueForType(type);

            if (contentHeaders == null || contentHeaders.ContentLength == 0)
            {
                return(Task.FromResult(InputFormatterResult.Success(defaultValue)));
            }

            try
            {
                Func <ODataDeserializerContext> getODataDeserializerContext = () =>
                {
                    return(new ODataDeserializerContext
                    {
                        Request = request,
                    });
                };

                Action <Exception> logErrorAction = (ex) =>
                {
                    ILogger logger = context.HttpContext.RequestServices.GetService <ILogger>();
                    if (logger == null)
                    {
                        throw ex;
                    }

                    logger.LogError(ex, String.Empty);
                };


                List <IDisposable> disposeList = new List <IDisposable>();

                IServiceProvider          fakeProvider         = (new ServiceCollection()).BuildServiceProvider();
                ODataDeserializerProvider deserializerProvider = new ODataMigrationDeserializerProvider(fakeProvider);

                object result = ReadFromStream(
                    type,
                    defaultValue,
                    request.GetModel(),
                    GetBaseAddressInternal(request),
                    request,
                    // Use GetODataContentIdMapping() from the namespace Microsoft.AspNet.OData.Batch. Reference: https://github.com/OData/WebApi/pull/2012
                    () => ODataMigrationMessageWrapper.Create(request.Body, request.Headers, ODataBatchHttpRequestExtensions.GetODataContentIdMapping(request), request.GetRequestContainer()),
                    (objectType) => deserializerProvider.GetEdmTypeDeserializer(objectType),
                    (objectType) => deserializerProvider.GetODataDeserializer(objectType, request),
                    getODataDeserializerContext,
                    (disposable) => disposeList.Add(disposable),
                    logErrorAction);

                foreach (IDisposable obj in disposeList)
                {
                    obj.Dispose();
                }

                return(Task.FromResult(InputFormatterResult.Success(result)));
            }
            catch (Exception ex)
            {
                context.ModelState.AddModelError(context.ModelName, ex, context.Metadata);
                return(Task.FromResult(InputFormatterResult.Failure()));
            }
        }
 public void GetODataContentIdMapping_NullRequest_Throws()
 {
     // Arrange & Act & Assert
     ExceptionAssert.ThrowsArgumentNull(() => ODataBatchHttpRequestExtensions.GetODataContentIdMapping(null), "request");
 }