public static Stream WriteToStream <TBody>(TBody value, string contentType, Encoding encoding)
        {
            // formatters do not support non HTTP context processing
            var httpContext = new HttpContextMock();

            httpContext.Response.Body = new MemoryStream();

            var outputFormatterCanWriteContext = new OutputFormatterWriteContext(
                httpContext,
                (str, enc) => new StreamWriter(httpContext.Response.Body, encoding),
                value?.GetType(),
                value)
            {
                ContentType = new StringSegment(contentType)
            };

            var outputFormatter = outputFormatters.GetOrAdd(contentType, _ =>
            {
                var mvcOptions = TestServiceProvider.GetRequiredService <IOptions <MvcOptions> >();

                var formatter = mvcOptions.Value?.OutputFormatters?.FirstOrDefault(f => f.CanWriteResult(outputFormatterCanWriteContext));
                ServiceValidator.ValidateFormatterExists(formatter, contentType);

                return(formatter);
            });

            AsyncHelper.RunSync(() => outputFormatter.WriteAsync(outputFormatterCanWriteContext));

            // copy memory stream because formatters close the original one
            return(new MemoryStream(((MemoryStream)httpContext.Response.Body).ToArray()));
        }
        public static TModel ReadFromStream <TModel>(Stream stream, string contentType, Encoding encoding)
        {
            stream.Restart();

            // formatters do not support non HTTP context processing
            var httpContext = new HttpContextMock();

            httpContext.Request.Body        = stream;
            httpContext.Request.ContentType = contentType;

            var typeOfModel           = typeof(TModel);
            var modelMetadataProvider = TestServiceProvider.GetRequiredService <IModelMetadataProvider>();
            var modelMetadata         = modelMetadataProvider.GetMetadataForType(typeOfModel);

            var inputFormatterContext = new InputFormatterContext(
                httpContext,
                string.Empty,
                new ModelStateDictionary(),
                modelMetadata,
                (str, enc) => new StreamReader(httpContext.Request.Body, encoding));

            var inputFormatter = inputFormatters.GetOrAdd(contentType, _ =>
            {
                var mvcOptions = TestServiceProvider.GetRequiredService <IOptions <MvcOptions> >();
                var formatter  = mvcOptions.Value?.InputFormatters?.FirstOrDefault(f => f.CanRead(inputFormatterContext));
                ServiceValidator.ValidateFormatterExists(formatter, contentType);

                return(formatter);
            });

            var result = AsyncHelper.RunSync(() => inputFormatter.ReadAsync(inputFormatterContext)).Model;

            try
            {
                return((TModel)result);
            }
            catch (Exception)
            {
                throw new InvalidDataException($"Expected stream content to be formatted to {typeOfModel.ToFriendlyTypeName()} when using '{contentType}', but instead received {result.GetName()}.");
            }
        }