/// <summary> /// Asynchronously serialise data to an output stream. /// </summary> /// <param name="context"> /// Contextual information about the data being deserialised. /// </param> /// <param name="stream"> /// The output stream to which the serialised data will be written. /// </param> /// <returns> /// A <see cref="Task"/> representing the asynchronous operation. /// </returns> public Task WriteAsync(OutputFormatterContext context, Stream stream) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (!SupportedMediaTypes.Contains(context.MediaType)) { throw new NotSupportedException($"The {nameof(JsonFormatter)} cannot write content of type '{context.MediaType}'."); } using (TextWriter writer = context.CreateWriter(stream)) { JsonSerializer serializer = JsonSerializer.Create(SerializerSettings); serializer.Serialize(writer, context.Data, context.DataType); } return(Task.CompletedTask); }
public override bool CanWriteResult([NotNull] OutputFormatterContext context, MediaTypeHeaderValue contentType) { var type = context.Object.GetType(); var request = context.ActionContext.HttpContext.Request; if (request != null) { IEdmModel model = request.ODataProperties().Model; if (model != null) { ODataPayloadKind?payloadKind = null; Type elementType; if (typeof(IEdmObject).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()) || (type.IsCollection(out elementType) && typeof(IEdmObject).GetTypeInfo().IsAssignableFrom(elementType.GetTypeInfo()))) { payloadKind = GetEdmObjectPayloadKind(type, request); } else { payloadKind = GetClrObjectResponsePayloadKind(type, model, request); } return(payloadKind == null ? false : _payloadKinds.Contains(payloadKind.Value)); } } return(false); }
public async Task WriteToStreamAsync_UsesCorrectCharacterEncoding( string content, string encodingAsString, bool isDefaultEncoding) { // Arrange var formatter = new JsonOutputFormatter(); var formattedContent = "\"" + content + "\""; var mediaType = string.Format("application/json; charset={0}", encodingAsString); var encoding = CreateOrGetSupportedEncoding(formatter, encodingAsString, isDefaultEncoding); var expectedData = encoding.GetBytes(formattedContent); var body = new MemoryStream(); var actionContext = GetActionContext(MediaTypeHeaderValue.Parse(mediaType), body); var outputFormatterContext = new OutputFormatterContext { Object = content, DeclaredType = typeof(string), HttpContext = actionContext.HttpContext, SelectedEncoding = encoding }; // Act await formatter.WriteResponseBodyAsync(outputFormatterContext); // Assert var actualData = body.ToArray(); Assert.Equal(expectedData, actualData); }
public override Task WriteResponseBodyAsync(OutputFormatterContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); var response = context.HttpContext.Response; var encoding = context.SelectedEncoding; StandardResponse standard; var o = context.Object as StandardResponse; if (o != null) standard = o; else standard = new StandardResponse { Code = 200 }; return Task.Run(() => { using (var stream = new HttpResponseStreamWriter(response.Body, encoding)) { WriteObject(stream, standard); } }); }
public void SelectResponseCharacterEncoding_SelectsEncoding(string acceptCharsetHeaders, string requestEncoding, string[] supportedEncodings, string expectedEncoding) { // Arrange var mockHttpContext = new Mock<HttpContext>(); var httpRequest = new DefaultHttpContext().Request; httpRequest.Headers["Accept-Charset"] = acceptCharsetHeaders; httpRequest.ContentType = "application/acceptCharset;charset=" + requestEncoding; mockHttpContext.SetupGet(o => o.Request).Returns(httpRequest); var formatter = new TestOutputFormatter(); foreach (string supportedEncoding in supportedEncodings) { formatter.SupportedEncodings.Add(Encoding.GetEncoding(supportedEncoding)); } var formatterContext = new OutputFormatterContext() { Object = "someValue", HttpContext = mockHttpContext.Object, DeclaredType = typeof(string) }; // Act var actualEncoding = formatter.SelectCharacterEncoding(formatterContext); // Assert Assert.Equal(Encoding.GetEncoding(expectedEncoding), actualEncoding); }
/// <summary> /// Asynchronously serialise data to an output stream. /// </summary> /// <param name="context"> /// Contextual information about the data being deserialised. /// </param> /// <param name="stream"> /// The output stream to which the serialised data will be written. /// </param> /// <returns> /// A <see cref="Task"/> representing the asynchronous operation. /// </returns> public Task WriteAsync(OutputFormatterContext context, Stream stream) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (!SupportedMediaTypes.Contains(context.MediaType)) { throw new NotSupportedException($"The {nameof(XmlFormatter)} cannot write content of type '{context.MediaType}'."); } using (XmlWriter writer = XmlWriter.Create(stream)) { DataContractSerializer serializer = new DataContractSerializer(context.DataType); serializer.WriteObject(writer, context.Data); return(Task.CompletedTask); } }
public void SelectResponseCharacterEncoding_SelectsEncoding(string acceptCharsetHeaders, string requestEncoding, string[] supportedEncodings, string expectedEncoding) { // Arrange var mockHttpContext = new Mock<HttpContext>(); mockHttpContext.SetupGet(o => o.Request.AcceptCharset) .Returns(acceptCharsetHeaders); mockHttpContext.SetupGet(o => o.Request.ContentType) .Returns("application/acceptCharset;charset=" + requestEncoding); var actionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor()); var formatter = new TestOutputFormatter(); foreach (string supportedEncoding in supportedEncodings) { formatter.SupportedEncodings.Add(Encoding.GetEncoding(supportedEncoding)); } var formatterContext = new OutputFormatterContext() { Object = "someValue", ActionContext = actionContext, DeclaredType = typeof(string) }; // Act var actualEncoding = formatter.SelectCharacterEncoding(formatterContext); // Assert Assert.Equal(Encoding.GetEncoding(expectedEncoding), actualEncoding); }
public void SelectFormatter_WithNoMatchingAcceptHeadersAndRequestContentType_PicksFormatterBasedOnObjectType (string acceptHeader) { // For no accept headers, // can write is called twice once for the request Content-Type and once for the type match pass. // For each additional accept header, it is called once. // Arrange var acceptHeaderCollection = string.IsNullOrEmpty(acceptHeader) ? null : MediaTypeHeaderValue.ParseList(new[] { acceptHeader }).ToArray(); var stream = new MemoryStream(); var httpResponse = new Mock <HttpResponse>(); httpResponse.SetupProperty <string>(o => o.ContentType); httpResponse.SetupGet(r => r.Body).Returns(stream); var actionContext = CreateMockActionContext(httpResponse.Object, requestAcceptHeader: acceptHeader, requestContentType: "application/xml"); var input = "testInput"; var result = new ObjectResult(input); var mockCountingFormatter = new Mock <IOutputFormatter>(); var context = new OutputFormatterContext() { HttpContext = actionContext.HttpContext, Object = input, DeclaredType = typeof(string) }; var mockCountingSupportedContentType = MediaTypeHeaderValue.Parse("application/text"); mockCountingFormatter.Setup(o => o.CanWriteResult(context, It.Is <MediaTypeHeaderValue>(mth => mth == null))) .Returns(true); mockCountingFormatter.Setup(o => o.CanWriteResult(context, mockCountingSupportedContentType)) .Returns(true); // Set more than one formatters. The test output formatter throws on write. result.Formatters = new List <IOutputFormatter> { new CannotWriteFormatter(), mockCountingFormatter.Object, }; // Act var formatter = result.SelectFormatter(context, result.Formatters); // Assert Assert.Equal(mockCountingFormatter.Object, formatter); mockCountingFormatter.Verify(v => v.CanWriteResult(context, null), Times.Once()); // CanWriteResult is invoked for the following cases: // 1. For each accept header present // 2. Request Content-Type // 3. Type based match var callCount = (acceptHeaderCollection == null ? 0 : acceptHeaderCollection.Count()) + 2; mockCountingFormatter.Verify(v => v.CanWriteResult(context, It.IsNotIn <MediaTypeHeaderValue>(mockCountingSupportedContentType)), Times.Exactly(callCount)); }
/// <summary> /// Build an HTTP request message, selecting an appropriate content formatter to serialise its body content. /// </summary> /// <param name="request"> /// The <see cref="HttpRequest"/>. /// </param> /// <param name="httpMethod"> /// The HTTP request method. /// </param> /// <param name="bodyContent"> /// The request body content. /// </param> /// <param name="mediaType"> /// The request body media type to use. /// </param> /// <param name="encoding"> /// The request body encoding to use. /// </param> /// <param name="baseUri"> /// An optional base URI to use if the request does not already have an absolute request URI. /// </param> /// <returns> /// The configured <see cref="HttpRequestMessage"/>. /// </returns> public static HttpRequestMessage BuildRequestMessage(this HttpRequest request, HttpMethod httpMethod, object bodyContent, string mediaType, Encoding encoding, Uri baseUri = null) { if (request == null) { throw new ArgumentNullException(nameof(request)); } HttpContent httpContent = bodyContent as HttpContent; if (httpContent == null && bodyContent != null) { IFormatterCollection formatters = request.CreateFormatterCollection(); OutputFormatterContext writeContext = new OutputFormatterContext(bodyContent, bodyContent.GetType(), mediaType, encoding); IOutputFormatter writeFormatter = formatters.FindOutputFormatter(writeContext); if (writeFormatter == null) { throw new HttpRequestException($"None of the supplied formatters can write data of type '{writeContext.DataType.FullName}' to media type '{writeContext.MediaType}'."); } httpContent = new FormattedObjectContent(writeFormatter, writeContext); } return(request.BuildRequestMessage(httpMethod, httpContent, baseUri)); }
public void SelectResponseCharacterEncoding_SelectsEncoding(string acceptCharsetHeaders, string requestEncoding, string[] supportedEncodings, string expectedEncoding) { // Arrange var mockHttpContext = new Mock <HttpContext>(); var httpRequest = new DefaultHttpContext().Request; httpRequest.Headers["Accept-Charset"] = acceptCharsetHeaders; httpRequest.ContentType = "application/acceptCharset;charset=" + requestEncoding; mockHttpContext.SetupGet(o => o.Request).Returns(httpRequest); var actionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor()); var formatter = new TestOutputFormatter(); foreach (string supportedEncoding in supportedEncodings) { formatter.SupportedEncodings.Add(Encoding.GetEncoding(supportedEncoding)); } var formatterContext = new OutputFormatterContext() { Object = "someValue", ActionContext = actionContext, DeclaredType = typeof(string) }; // Act var actualEncoding = formatter.SelectCharacterEncoding(formatterContext); // Assert Assert.Equal(Encoding.GetEncoding(expectedEncoding), actualEncoding); }
public async Task WriteToStreamAsync_UsesCorrectCharacterEncoding( string content, string encodingAsString, bool isDefaultEncoding) { // Arrange var formatter = new JsonOutputFormatter(); var formattedContent = "\"" + content + "\""; var mediaType = string.Format("application/json; charset={0}", encodingAsString); var encoding = CreateOrGetSupportedEncoding(formatter, encodingAsString, isDefaultEncoding); var preamble = encoding.GetPreamble(); var data = encoding.GetBytes(formattedContent); var expectedData = new byte[preamble.Length + data.Length]; Buffer.BlockCopy(preamble, 0, expectedData, 0, preamble.Length); Buffer.BlockCopy(data, 0, expectedData, preamble.Length, data.Length); var memStream = new MemoryStream(); var outputFormatterContext = new OutputFormatterContext { Object = content, DeclaredType = typeof(string), ActionContext = GetActionContext(MediaTypeHeaderValue.Parse(mediaType), memStream), SelectedEncoding = encoding }; // Act await formatter.WriteResponseBodyAsync(outputFormatterContext); // Assert var actualData = memStream.ToArray(); Assert.Equal(expectedData, actualData); }
public override async Task WriteResponseBodyAsync(OutputFormatterContext context) { var response = context.ActionContext.HttpContext.Response; response.ContentType = "text/plain;charset=utf-8"; await response.WriteAsync(context.Object as string); }
public override async Task WriteResponseBodyAsync(OutputFormatterContext context) { var response = context.HttpContext.Response; response.ContentType = ContentType + ";charset=utf-8"; await response.WriteAsync(context.Object.ToString()); }
public override async Task WriteResponseBodyAsync(OutputFormatterContext context) { var reqServices = context.HttpContext.RequestServices; var multiContext = (MultiObjectResultContext)reqServices.GetService(typeof(MultiObjectResultContext)); var jsonHelper = (IJsonHelper)reqServices.GetService(typeof(IJsonHelper)); var content = new MultipartContent("json"); var resultObject = context.Object; var resultObjectWasAdded = false; foreach (var entry in multiContext.AdditionalObjects) { object additional = resultObject; if (additional.GetType() != entry.Value.Item1) { additional = reqServices.GetService(entry.Value.Item1); } else { resultObjectWasAdded = true; } content.Add(ContentPart(jsonHelper, entry.Key, additional, entry.Value.Item2)); } if (!resultObjectWasAdded) { content.Add(ContentPart(jsonHelper, resultObject.GetType().Name, resultObject, false)); } var response = context.HttpContext.Response; response.ContentType = content.Headers.ContentType.ToString(); await content.CopyToAsync(response.Body); }
/// <inheritdoc /> public override Task WriteResponseBodyAsync([NotNull] OutputFormatterContext context) { var tempWriterSettings = WriterSettings.Clone(); tempWriterSettings.Encoding = context.SelectedEncoding; using (var xmlWriter = CreateXmlWriter(context.HttpContext.Response.Body, tempWriterSettings)) { var obj = context.Object; var runtimeType = obj?.GetType(); var resolvedType = ResolveType(context.DeclaredType, runtimeType); var wrappingType = GetSerializableType(resolvedType); // Wrap the object only if there is a wrapping type. if (wrappingType != null && wrappingType != resolvedType) { var wrapperProvider = WrapperProviderFactories.GetWrapperProvider( new WrapperProviderContext( declaredType: resolvedType, isSerialization: true)); obj = wrapperProvider.Wrap(obj); } var dataContractSerializer = GetCachedSerializer(wrappingType); dataContractSerializer.WriteObject(xmlWriter, obj); } return(Task.FromResult(true)); }
public void WriteResponseContentHeaders_NoSupportedEncodings_NoEncodingIsSet() { // Arrange var formatter = new TestOutputFormatter(); var testContentType = MediaTypeHeaderValue.Parse("text/json"); formatter.SupportedEncodings.Clear(); formatter.SupportedMediaTypes.Clear(); formatter.SupportedMediaTypes.Add(testContentType); var formatterContext = new OutputFormatterContext() { HttpContext = new DefaultHttpContext(), }; // Act formatter.WriteResponseHeaders(formatterContext); // Assert Assert.Null(formatterContext.SelectedEncoding); Assert.Equal(testContentType, formatterContext.SelectedContentType); // If we had set an encoding, it would be part of the content type header Assert.Equal(testContentType, formatterContext.HttpContext.Response.GetTypedHeaders().ContentType); }
public async Task WriteAsync(OutputFormatterContext context) { var response = context.ActionContext.HttpContext.Response; var responseMessage = context.Object as HttpResponseMessage; if (responseMessage == null) { var message = Resources.FormatHttpResponseMessageFormatter_UnsupportedType( nameof(HttpResponseMessageOutputFormatter), nameof(HttpResponseMessage)); throw new InvalidOperationException(message); } using (responseMessage) { response.StatusCode = (int)responseMessage.StatusCode; var responseFeature = context.ActionContext.HttpContext.GetFeature <IHttpResponseFeature>(); if (responseFeature != null) { responseFeature.ReasonPhrase = responseMessage.ReasonPhrase; } var responseHeaders = responseMessage.Headers; // Ignore the Transfer-Encoding header if it is just "chunked". // We let the host decide about whether the response should be chunked or not. if (responseHeaders.TransferEncodingChunked == true && responseHeaders.TransferEncoding.Count == 1) { responseHeaders.TransferEncoding.Clear(); } foreach (var header in responseHeaders) { response.Headers.AppendValues(header.Key, header.Value.ToArray()); } if (responseMessage.Content != null) { var contentHeaders = responseMessage.Content.Headers; // Copy the response content headers only after ensuring they are complete. // We ask for Content-Length first because HttpContent lazily computes this // and only afterwards writes the value into the content headers. var unused = contentHeaders.ContentLength; foreach (var header in contentHeaders) { response.Headers.AppendValues(header.Key, header.Value.ToArray()); } await responseMessage.Content.CopyToAsync(response.Body); } } }
/// <summary> /// Determine whether the formatter can serialise the specified data. /// </summary> /// <param name="context"> /// Contextual information about the data being serialised. /// </param> /// <returns> /// <c>true</c>, if the formatter can serialise the data; otherwise, <c>false</c>. /// </returns> public bool CanWrite(OutputFormatterContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } return(SupportedMediaTypes.Contains(context.MediaType)); }
public async Task WriteAsync(OutputFormatterContext context) { var response = context.HttpContext.Response; var responseMessage = context.Object as HttpResponseMessage; if (responseMessage == null) { var message = Resources.FormatHttpResponseMessageFormatter_UnsupportedType( nameof(HttpResponseMessageOutputFormatter), nameof(HttpResponseMessage)); throw new InvalidOperationException(message); } using (responseMessage) { response.StatusCode = (int)responseMessage.StatusCode; var responseFeature = context.HttpContext.GetFeature<IHttpResponseFeature>(); if (responseFeature != null) { responseFeature.ReasonPhrase = responseMessage.ReasonPhrase; } var responseHeaders = responseMessage.Headers; // Ignore the Transfer-Encoding header if it is just "chunked". // We let the host decide about whether the response should be chunked or not. if (responseHeaders.TransferEncodingChunked == true && responseHeaders.TransferEncoding.Count == 1) { responseHeaders.TransferEncoding.Clear(); } foreach (var header in responseHeaders) { response.Headers.AppendValues(header.Key, header.Value.ToArray()); } if (responseMessage.Content != null) { var contentHeaders = responseMessage.Content.Headers; // Copy the response content headers only after ensuring they are complete. // We ask for Content-Length first because HttpContent lazily computes this // and only afterwards writes the value into the content headers. var unused = contentHeaders.ContentLength; foreach (var header in contentHeaders) { response.Headers.AppendValues(header.Key, header.Value.ToArray()); } await responseMessage.Content.CopyToAsync(response.Body); } } }
public override void WriteResponseHeaders(OutputFormatterContext context) { if (context.Object is IEdmModel) { context.SelectedContentType = SupportedMediaTypes[2]; } context.ActionContext.HttpContext.Response.Headers.Add("OData-Version", new[] { "4.0" }); base.WriteResponseHeaders(context); }
public override bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType) { if (base.CanWriteResult(context, contentType)) { var actionReturnString = context.Object as string; if (actionReturnString != null) { return(true); } } return(false); }
public override async Task WriteResponseBodyAsync(OutputFormatterContext context) { var contact = (Contact)context.Object; var builder = new StringBuilder(); builder.AppendLine("BEGIN:VCARD"); builder.AppendFormat("FN:{0}", contact.Name); builder.AppendLine(); builder.AppendLine("END:VCARD"); await context.HttpContext.Response.WriteAsync(builder.ToString(), context.SelectedEncoding); }
public override Task WriteResponseBodyAsync(OutputFormatterContext context) { var response = context.ActionContext.HttpContext.Response; var selectedEncoding = context.SelectedEncoding; using (var delegatingStream = new NonDisposableStream(response.Body)) using (var writer = new StreamWriter(delegatingStream, selectedEncoding, 1024, leaveOpen: true)) { WriteObject(writer, context.Object); } return(Task.FromResult(true)); }
public void CanWriteResult_ForNullContentType_UsesFirstEntryInSupportedContentTypes() { // Arrange var context = new OutputFormatterContext(); var formatter = new TestOutputFormatter(); // Act var result = formatter.CanWriteResult(context, null); // Assert Assert.True(result); Assert.Equal(formatter.SupportedMediaTypes[0].ToString(), context.SelectedContentType.ToString()); }
public override Task WriteResponseBodyAsync(OutputFormatterContext context) { var liveShowDetails = context.Object as LiveShowDetails; Debug.Assert(context.Object == null || liveShowDetails != null, $"Object to be formatted should be of type {nameof(LiveShowDetails)}"); if (_noNextShow) { return(_done); } return(WriteLiveShowDetailsToResponseBody(liveShowDetails.NextShowDateUtc, context.HttpContext.Response)); }
public override bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType) { if (base.CanWriteResult(context, contentType)) { var actionReturn = context.Object as Product; if (actionReturn != null) { var response = context.HttpContext.Response; context.SelectedContentType = contentType; return true; } } return false; }
public override bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType) { if (base.CanWriteResult(context, contentType)) { var actionReturn = context.Object as Product; if (actionReturn != null) { var response = context.ActionContext.HttpContext.Response; context.SelectedContentType = contentType; return(true); } } return(false); }
public override Task WriteResponseBodyAsync(OutputFormatterContext context) { var response = context.ActionContext.HttpContext.Response; var book = context.Object as Book; if (book != null) { var path = Path.Combine(_folder, book.ImageName); var buffer = File.ReadAllBytes(path); response.Body.Write(buffer, 0, buffer.Length); } return(Task.FromResult(true)); }
public override void WriteResponseHeaders(OutputFormatterContext context) { var liveShowDetails = context.Object as LiveShowDetails; Debug.Assert(context.Object == null || liveShowDetails != null, $"Object to be formatted should be of type {nameof(LiveShowDetails)}"); if (liveShowDetails == null || liveShowDetails.NextShowDateUtc == null) { _noNextShow = true; context.HttpContext.Response.StatusCode = StatusCodes.Status204NoContent; } else { base.WriteResponseHeaders(context); } }
public override Task WriteResponseBodyAsync(OutputFormatterContext context) { HttpResponse response = context.HttpContext.Response; HttpRequest request = context.HttpContext.Request; StringValues casingValues; bool camelCase = request.Headers.TryGetValue("X-Casing", out casingValues) && casingValues.Contains("camelCase", StringComparer.OrdinalIgnoreCase); using (HttpResponseStreamWriter httpResponseStreamWriter = new HttpResponseStreamWriter(response.Body, context.SelectedEncoding)) { WriteObject(camelCase, httpResponseStreamWriter, context.Object); } return(Task.FromResult(true)); }
public override void WriteResponseHeaders(OutputFormatterContext context) { HttpRequest request = context.ActionContext.HttpContext.Request; HttpResponse response = context.ActionContext.HttpContext.Response; //// When the user asks for application/json we really need to set the content type to //// application/json; odata.metadata=minimal. If the user provides the media type and is //// application/json we are going to add automatically odata.metadata=minimal. Otherwise we are //// going to fallback to the default implementation. //// When calling this formatter as part of content negotiation the content negotiator will always //// pick a non null media type. In case the user creates a new ObjectContent<T> and doesn't pass in a //// media type, we delegate to the base class to rely on the default behavior. It's the user's //// responsibility to pass in the right media type. //var mediaType = context.SelectedContentType; //if (mediaType != null) //{ // if (mediaType.MediaType.Equals("application/json", StringComparison.OrdinalIgnoreCase) && // !mediaType.Parameters.Any(p => p.Name.Equals("odata.metadata", StringComparison.OrdinalIgnoreCase))) // { // mediaType.Parameters.Add(new NameValueHeaderValue("odata.metadata", "minimal")); // } //} //else //{ // // This is the case when a user creates a new ObjectContent<T> passing in a null mediaType // base.WriteResponseHeaders(context); //} //// In general, in Web API we pick a default charset based on the supported character sets //// of the formatter. However, according to the OData spec, the service shouldn't be sending //// a character set unless explicitly specified, so if the client didn't send the charset we chose //// we just clean it. //if (headers.ContentType != null && // !Request.Headers.AcceptCharset // .Any(cs => cs.Value.Equals(headers.ContentType.CharSet, StringComparison.OrdinalIgnoreCase))) //{ // headers.ContentType.CharSet = String.Empty; //} response.Headers.Append( ODataProperties.ODataServiceVersionHeader, ODataUtils.ODataVersionToString(ODataProperties.DefaultODataVersion)); base.WriteResponseHeaders(context); }
public void CanWriteResult_ReturnsTrue_IfReturnTypeIsVoidOrTask(Type declaredType) { // Arrange var formatterContext = new OutputFormatterContext() { Object = "Something non null.", DeclaredType = declaredType, ActionContext = null, }; var contetType = MediaTypeHeaderValue.Parse("text/plain"); var formatter = new HttpNoContentOutputFormatter(); // Act var actualCanWriteResult = formatter.CanWriteResult(formatterContext, contetType); // Assert Assert.True(actualCanWriteResult); }
public async Task WriteAsync_WritesTheStatusCode204() { // Arrange var defaultHttpContext = new DefaultHttpContext(); var formatterContext = new OutputFormatterContext() { Object = null, HttpContext = defaultHttpContext, }; var formatter = new HttpNoContentOutputFormatter(); // Act await formatter.WriteAsync(formatterContext); // Assert Assert.Equal(StatusCodes.Status204NoContent, defaultHttpContext.Response.StatusCode); }
public override async Task WriteResponseBodyAsync(OutputFormatterContext context) { var contact = (Contact)context.Object; var builder = new StringBuilder(); builder.AppendLine("BEGIN:VCARD"); builder.AppendFormat("FN:{0}", contact.Name); builder.AppendLine(); builder.AppendLine("END:VCARD"); var responseStream = new DelegatingStream(context.ActionContext.HttpContext.Response.Body); using (var writer = new StreamWriter(responseStream, context.SelectedEncoding, bufferSize: 1024)) { await writer.WriteAsync(builder.ToString()); } }
public async Task WriteAsync_WritesTheStatusCode204() { // Arrange var defaultHttpContext = new DefaultHttpContext(); var formatterContext = new OutputFormatterContext() { Object = null, ActionContext = new ActionContext(defaultHttpContext, new RouteData(), new ActionDescriptor()) }; var formatter = new HttpNoContentOutputFormatter(); // Act await formatter.WriteAsync(formatterContext); // Assert Assert.Equal(204, defaultHttpContext.Response.StatusCode); }
public async Task WriteAsync(OutputFormatterContext context) { var response = context.ActionContext.HttpContext.Response; var responseMessage = context.Object as HttpResponseMessage; if (responseMessage == null) { var message = Resources.FormatHttpResponseMessageFormatter_UnsupportedType( nameof(HttpResponseMessageOutputFormatter), nameof(HttpResponseMessage)); throw new InvalidOperationException(message); } using (responseMessage) { response.StatusCode = (int)responseMessage.StatusCode; var responseFeature = context.ActionContext.HttpContext.GetFeature <IHttpResponseFeature>(); if (responseFeature != null) { responseFeature.ReasonPhrase = responseMessage.ReasonPhrase; } var responseHeaders = responseMessage.Headers; foreach (var header in responseHeaders) { response.Headers.AppendValues(header.Key, header.Value.ToArray()); } if (responseMessage.Content != null) { var contentHeaders = responseMessage.Content.Headers; foreach (var header in contentHeaders) { response.Headers.AppendValues(header.Key, header.Value.ToArray()); } await responseMessage.Content.CopyToAsync(response.Body); } } }
public override Task WriteResponseBodyAsync(OutputFormatterContext context) { var services = context.HttpContext.RequestServices; var httpContextAccessor = services.GetRequiredService<IHttpContextAccessor>(); var actionContext = services.GetRequiredService<IActionContextAccessor>().ActionContext; var metadataProvider = services.GetRequiredService<IModelMetadataProvider>(); var tempdataProvider = services.GetRequiredService<ITempDataProvider>(); var viewResult = new ViewResult { ViewData = new ViewDataDictionary(metadataProvider, actionContext.ModelState) { Model = context.Object }, TempData = new TempDataDictionary(httpContextAccessor, tempdataProvider) }; return viewResult.ExecuteResultAsync(actionContext); }
public void WriteResponseContentHeaders_FormatterWithNoEncoding_Throws() { // Arrange var testFormatter = new TestOutputFormatter(); var testContentType = MediaTypeHeaderValue.Parse("text/invalid"); var formatterContext = new OutputFormatterContext(); var mockHttpContext = new Mock<HttpContext>(); var httpRequest = new DefaultHttpContext().Request; mockHttpContext.SetupGet(o => o.Request).Returns(httpRequest); formatterContext.HttpContext = mockHttpContext.Object; // Act & Assert var ex = Assert.Throws<InvalidOperationException>( () => testFormatter.WriteResponseHeaders(formatterContext)); Assert.Equal("No encoding found for output formatter " + "'Microsoft.AspNet.Mvc.Test.OutputFormatterTests+TestOutputFormatter'." + " There must be at least one supported encoding registered in order for the" + " output formatter to write content.", ex.Message); }
public override Task ExecuteResultAsync(ActionContext context) { var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<ObjectResult>>(); // See if the list of content types added to this object result is valid. ThrowIfUnsupportedContentType(); var formatters = GetDefaultFormatters(context); var formatterContext = new OutputFormatterContext() { DeclaredType = DeclaredType, HttpContext = context.HttpContext, Object = Value, StatusCode = StatusCode }; var selectedFormatter = SelectFormatter(formatterContext, formatters); if (selectedFormatter == null) { // No formatter supports this. logger.LogWarning("No output formatter was found to write the response."); context.HttpContext.Response.StatusCode = StatusCodes.Status406NotAcceptable; return TaskCache.CompletedTask; } logger.LogVerbose( "Selected output formatter '{OutputFormatter}' and content type " + "'{ContentType}' to write the response.", selectedFormatter.GetType().FullName, formatterContext.SelectedContentType); if (StatusCode.HasValue) { context.HttpContext.Response.StatusCode = StatusCode.Value; } OnFormatting(context); return selectedFormatter.WriteAsync(formatterContext); }
public void CanWriteResult_ByDefault_ReturnsTrue_IfTheValueIsNull(object value, bool declaredTypeAsString, bool expectedCanwriteResult, bool useNonNullContentType) { // Arrange var typeToUse = declaredTypeAsString ? typeof(string) : typeof(object); var formatterContext = new OutputFormatterContext() { Object = value, DeclaredType = typeToUse, ActionContext = null, }; var contetType = useNonNullContentType ? MediaTypeHeaderValue.Parse("text/plain") : null; var formatter = new HttpNoContentOutputFormatter(); // Act var actualCanWriteResult = formatter.CanWriteResult(formatterContext, contetType); // Assert Assert.Equal(expectedCanwriteResult, actualCanWriteResult); }
public virtual bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType) { return false; }
public override Task WriteResponseBodyAsync(OutputFormatterContext context) { return Task.FromResult(true); }
public override bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType) { // Do not set the selected media Type. // The WriteResponseHeaders should do it for you. return true; }
public override Task WriteResponseBodyAsync(OutputFormatterContext context) { throw new NotImplementedException(); }
public void CanWrite_ReturnsFalse_ForUnsupportedType() { // Arrange var context = new OutputFormatterContext(); context.DeclaredType = typeof(string); context.Object = "Hello, world!"; var formatter = new TypeSpecificFormatter(); formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json")); formatter.SupportedTypes.Add(typeof(int)); // Act var result = formatter.CanWriteResult(context, formatter.SupportedMediaTypes[0]); // Assert Assert.False(result); }
public void SelectFormatter_WithNoMatchingAcceptHeadersAndRequestContentType_PicksFormatterBasedOnObjectType (string acceptHeader) { // For no accept headers, // can write is called twice once for the request Content-Type and once for the type match pass. // For each additional accept header, it is called once. // Arrange var acceptHeaderCollection = string.IsNullOrEmpty(acceptHeader) ? null : MediaTypeHeaderValue.ParseList(new[] { acceptHeader }).ToArray(); var stream = new MemoryStream(); var httpResponse = new Mock<HttpResponse>(); httpResponse.SetupProperty<string>(o => o.ContentType); httpResponse.SetupGet(r => r.Body).Returns(stream); var actionContext = CreateMockActionContext(httpResponse.Object, requestAcceptHeader: acceptHeader, requestContentType: "application/xml"); var input = "testInput"; var result = new ObjectResult(input); var mockCountingFormatter = new Mock<IOutputFormatter>(); var context = new OutputFormatterContext() { HttpContext = actionContext.HttpContext, Object = input, DeclaredType = typeof(string) }; var mockCountingSupportedContentType = MediaTypeHeaderValue.Parse("application/text"); mockCountingFormatter.Setup(o => o.CanWriteResult(context, It.Is<MediaTypeHeaderValue>(mth => mth == null))) .Returns(true); mockCountingFormatter.Setup(o => o.CanWriteResult(context, mockCountingSupportedContentType)) .Returns(true); // Set more than one formatters. The test output formatter throws on write. result.Formatters = new List<IOutputFormatter> { new CannotWriteFormatter(), mockCountingFormatter.Object, }; // Act var formatter = result.SelectFormatter(context, result.Formatters); // Assert Assert.Equal(mockCountingFormatter.Object, formatter); mockCountingFormatter.Verify(v => v.CanWriteResult(context, null), Times.Once()); // CanWriteResult is invoked for the following cases: // 1. For each accept header present // 2. Request Content-Type // 3. Type based match var callCount = (acceptHeaderCollection == null ? 0 : acceptHeaderCollection.Count()) + 2; mockCountingFormatter.Verify(v => v.CanWriteResult(context, It.IsNotIn<MediaTypeHeaderValue>(mockCountingSupportedContentType)), Times.Exactly(callCount)); }
public virtual IOutputFormatter SelectFormatterUsingSortedAcceptHeaders( OutputFormatterContext formatterContext, IEnumerable<IOutputFormatter> formatters, IEnumerable<MediaTypeHeaderValue> sortedAcceptHeaders) { IOutputFormatter selectedFormatter = null; foreach (var contentType in sortedAcceptHeaders) { // Loop through each of the formatters and see if any one will support this // mediaType Value. selectedFormatter = formatters.FirstOrDefault( formatter => formatter.CanWriteResult(formatterContext, contentType)); if (selectedFormatter != null) { // we found our match. break; } } return selectedFormatter; }
public virtual IOutputFormatter SelectFormatter( OutputFormatterContext formatterContext, IEnumerable<IOutputFormatter> formatters) { var logger = formatterContext.HttpContext.RequestServices.GetRequiredService<ILogger<ObjectResult>>(); // Check if any content-type was explicitly set (for example, via ProducesAttribute // or Url path extension mapping). If yes, then ignore content-negotiation and use this content-type. if (ContentTypes.Count == 1) { logger.LogVerbose( "Skipped content negotiation as content type '{ContentType}' is explicitly set for the response.", ContentTypes[0]); return SelectFormatterUsingAnyAcceptableContentType(formatterContext, formatters, ContentTypes); } var sortedAcceptHeaderMediaTypes = GetSortedAcceptHeaderMediaTypes(formatterContext); IOutputFormatter selectedFormatter = null; if (ContentTypes == null || ContentTypes.Count == 0) { // Check if we have enough information to do content-negotiation, otherwise get the first formatter // which can write the type. MediaTypeHeaderValue requestContentType = null; MediaTypeHeaderValue.TryParse( formatterContext.HttpContext.Request.ContentType, out requestContentType); if (!sortedAcceptHeaderMediaTypes.Any() && requestContentType == null) { logger.LogVerbose("No information found on request to perform content negotiation."); return SelectFormatterBasedOnTypeMatch(formatterContext, formatters); } // // Content-Negotiation starts from this point on. // // 1. Select based on sorted accept headers. if (sortedAcceptHeaderMediaTypes.Any()) { selectedFormatter = SelectFormatterUsingSortedAcceptHeaders( formatterContext, formatters, sortedAcceptHeaderMediaTypes); } // 2. No formatter was found based on accept headers, fall back on request Content-Type header. if (selectedFormatter == null && requestContentType != null) { selectedFormatter = SelectFormatterUsingAnyAcceptableContentType( formatterContext, formatters, new[] { requestContentType }); } // 3. No formatter was found based on Accept and request Content-Type headers, so // fallback on type based match. if (selectedFormatter == null) { logger.LogVerbose("Could not find an output formatter based on content negotiation."); // Set this flag to indicate that content-negotiation has failed to let formatters decide // if they want to write the response or not. formatterContext.FailedContentNegotiation = true; return SelectFormatterBasedOnTypeMatch(formatterContext, formatters); } } else { if (sortedAcceptHeaderMediaTypes.Any()) { // Filter and remove accept headers which cannot support any of the user specified content types. var filteredAndSortedAcceptHeaders = sortedAcceptHeaderMediaTypes .Where(acceptHeader => ContentTypes.Any(contentType => contentType.IsSubsetOf(acceptHeader))); selectedFormatter = SelectFormatterUsingSortedAcceptHeaders( formatterContext, formatters, filteredAndSortedAcceptHeaders); } if (selectedFormatter == null) { // Either there were no acceptHeaders that were present OR // There were no accept headers which matched OR // There were acceptHeaders which matched but there was no formatter // which supported any of them. // In any of these cases, if the user has specified content types, // do a last effort to find a formatter which can write any of the user specified content type. selectedFormatter = SelectFormatterUsingAnyAcceptableContentType( formatterContext, formatters, ContentTypes); } } return selectedFormatter; }
public override bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType) { return base.CanWriteResult(context, contentType) && !(context.Object is ViewResult); }
public void WriteResponseContentHeaders_NoSelectedContentType_SetsOutputFormatterContext() { // Arrange var testFormatter = new DoesNotSetContext(); var testContentType = MediaTypeHeaderValue.Parse("application/doesNotSetContext"); var formatterContext = new OutputFormatterContext(); var mockHttpContext = new Mock<HttpContext>(); var httpRequest = new DefaultHttpContext().Request; mockHttpContext.SetupGet(o => o.Request).Returns(httpRequest); mockHttpContext.SetupProperty(o => o.Response.ContentType); formatterContext.HttpContext = mockHttpContext.Object; // Act testFormatter.WriteResponseHeaders(formatterContext); // Assert Assert.Equal(Encodings.UTF16EncodingLittleEndian.WebName, formatterContext.SelectedEncoding.WebName); Assert.Equal(Encodings.UTF16EncodingLittleEndian, formatterContext.SelectedEncoding); Assert.Equal("application/doesNotSetContext; charset=" + Encodings.UTF16EncodingLittleEndian.WebName, formatterContext.SelectedContentType.ToString()); }
public virtual IOutputFormatter SelectFormatterUsingAnyAcceptableContentType( OutputFormatterContext formatterContext, IEnumerable<IOutputFormatter> formatters, IEnumerable<MediaTypeHeaderValue> acceptableContentTypes) { var selectedFormatter = formatters.FirstOrDefault( formatter => acceptableContentTypes .Any(contentType => formatter.CanWriteResult(formatterContext, contentType))); return selectedFormatter; }
public async Task WriteResponseHeaders_ClonesMediaType() { // Arrange var formatter = new PngImageFormatter(); formatter.SupportedMediaTypes.Clear(); var mediaType = new MediaTypeHeaderValue("image/png"); formatter.SupportedMediaTypes.Add(mediaType); var formatterContext = new OutputFormatterContext(); formatterContext.HttpContext = new DefaultHttpContext(); // Act await formatter.WriteAsync(formatterContext); // Assert Assert.NotSame(mediaType, formatterContext.SelectedContentType); Assert.Null(mediaType.Charset); Assert.Equal("image/png; charset=utf-8", formatterContext.SelectedContentType.ToString()); }
public async Task ObjectResult_Execute_CallsJsonResult_SetsContent() { // Arrange var expectedContentType = "application/json; charset=utf-8"; var nonStringValue = new { x1 = 10, y1 = "Hello" }; var httpResponse = Mock.Of<HttpResponse>(); httpResponse.Body = new MemoryStream(); var actionContext = CreateMockActionContext(httpResponse); var tempStream = new MemoryStream(); var tempHttpContext = new Mock<HttpContext>(); var tempHttpResponse = new Mock<HttpResponse>(); tempHttpResponse.SetupGet(o => o.Body).Returns(tempStream); tempHttpResponse.SetupProperty<string>(o => o.ContentType); tempHttpContext.SetupGet(o => o.Request).Returns(new DefaultHttpContext().Request); tempHttpContext.SetupGet(o => o.Response).Returns(tempHttpResponse.Object); var tempActionContext = new ActionContext(tempHttpContext.Object, new RouteData(), new ActionDescriptor()); var formatterContext = new OutputFormatterContext() { HttpContext = tempActionContext.HttpContext, Object = nonStringValue, DeclaredType = nonStringValue.GetType() }; var formatter = new JsonOutputFormatter(); formatter.WriteResponseHeaders(formatterContext); await formatter.WriteAsync(formatterContext); // Act var result = new ObjectResult(nonStringValue); await result.ExecuteResultAsync(actionContext); // Assert Assert.Equal(expectedContentType, httpResponse.ContentType); Assert.Equal(tempStream.ToArray(), ((MemoryStream)actionContext.HttpContext.Response.Body).ToArray()); }
private IEnumerable<MediaTypeHeaderValue> GetSortedAcceptHeaderMediaTypes( OutputFormatterContext formatterContext) { var request = formatterContext.HttpContext.Request; var incomingAcceptHeaderMediaTypes = request.GetTypedHeaders().Accept ?? new MediaTypeHeaderValue[] { }; // By default we want to ignore considering accept headers for content negotiation when // they have a media type like */* in them. Browsers typically have these media types. // In these cases we would want the first formatter in the list of output formatters to // write the response. This default behavior can be changed through options, so checking here. var options = formatterContext .HttpContext .RequestServices .GetRequiredService<IOptions<MvcOptions>>() .Value; var respectAcceptHeader = true; if (options.RespectBrowserAcceptHeader == false && incomingAcceptHeaderMediaTypes.Any(mediaType => mediaType.MatchesAllTypes)) { respectAcceptHeader = false; } var sortedAcceptHeaderMediaTypes = Enumerable.Empty<MediaTypeHeaderValue>(); if (respectAcceptHeader) { sortedAcceptHeaderMediaTypes = SortMediaTypeHeaderValues(incomingAcceptHeaderMediaTypes) .Where(header => header.Quality != HeaderQuality.NoMatch); } return sortedAcceptHeaderMediaTypes; }
public virtual Task WriteAsync(OutputFormatterContext context) { throw new NotImplementedException(); }
public bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType) { return context.Object is HttpResponseMessage; }