Skip to content

Commit 96abcf5

Browse files
committed
Fixing HTTP content negotiation for .NET
1 parent 9f766c1 commit 96abcf5

File tree

3 files changed

+50
-18
lines changed

3 files changed

+50
-18
lines changed

src/WebJobs.Script/Binding/HttpBinding.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,19 +156,20 @@ private static HttpContent CreateResultContent(object content, string mediaType)
156156

157157
private static HttpResponseMessage CreateNegotiatedResponse(HttpRequestMessage request, HttpStatusCode statusCode, object content)
158158
{
159+
HttpResponseMessage result = request.CreateResponse(statusCode);
160+
159161
if (content == null)
160162
{
161-
return request.CreateResponse(statusCode);
163+
return result;
162164
}
163165

164166
var configuration = request.GetConfiguration();
165167
IContentNegotiator negotiator = configuration.Services.GetContentNegotiator();
166-
var result = negotiator.Negotiate(content.GetType(), request, configuration.Formatters);
168+
var negotiationResult = negotiator.Negotiate(content.GetType(), request, configuration.Formatters);
167169

168-
return new HttpResponseMessage(statusCode)
169-
{
170-
Content = new ObjectContent(content.GetType(), content, result.Formatter, result.MediaType)
171-
};
170+
result.Content = new ObjectContent(content.GetType(), content, negotiationResult.Formatter, negotiationResult.MediaType);
171+
172+
return result;
172173
}
173174

174175
public void ProcessResult(IDictionary<string, object> functionArguments, object[] systemArguments, string triggerInputName, object result)
@@ -184,8 +185,7 @@ public void ProcessResult(IDictionary<string, object> functionArguments, object[
184185
HttpResponseMessage response = result as HttpResponseMessage;
185186
if (response == null)
186187
{
187-
response = request.CreateResponse(HttpStatusCode.OK);
188-
response.Content = new ObjectContent(result.GetType(), result, new JsonMediaTypeFormatter());
188+
response = CreateNegotiatedResponse(request, HttpStatusCode.OK, result);
189189
}
190190

191191
request.Properties[ScriptConstants.AzureFunctionsHttpResponseKey] = response;

test/WebJobs.Script.Tests/CSharpEndToEndTests.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ public async Task HttpTrigger_Post_Dynamic()
266266
Method = HttpMethod.Post,
267267
Content = new StringContent(input.ToString())
268268
};
269-
request.SetConfiguration(new HttpConfiguration());
269+
request.SetConfiguration(Fixture.RequestConfiguration);
270+
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
270271
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
271272

272273
Dictionary<string, object> arguments = new Dictionary<string, object>
@@ -283,6 +284,44 @@ public async Task HttpTrigger_Post_Dynamic()
283284
Assert.Equal("Name: Mathew Charles, Location: Seattle", body);
284285
}
285286

287+
[Theory]
288+
[InlineData("application/json", "\"Name: Fabio Cavalcante, Location: Seattle\"")]
289+
[InlineData("application/xml", "<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">Name: Fabio Cavalcante, Location: Seattle</string>")]
290+
[InlineData("text/plain", "Name: Fabio Cavalcante, Location: Seattle")]
291+
public async Task HttpTrigger_GetWithAccept_NegotiatesContent(string accept, string expectedBody)
292+
{
293+
var input = new JObject
294+
{
295+
{ "name", "Fabio Cavalcante" },
296+
{ "location", "Seattle" }
297+
};
298+
299+
HttpRequestMessage request = new HttpRequestMessage
300+
{
301+
RequestUri = new Uri(string.Format("http://localhost/api/httptrigger-dynamic")),
302+
Method = HttpMethod.Post,
303+
Content = new StringContent(input.ToString())
304+
};
305+
request.SetConfiguration(Fixture.RequestConfiguration);
306+
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(accept));
307+
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
308+
309+
Dictionary<string, object> arguments = new Dictionary<string, object>
310+
{
311+
{ "input", request },
312+
{ ScriptConstants.SystemTriggerParameterName, request }
313+
};
314+
315+
await Fixture.Host.CallAsync("HttpTrigger-Dynamic", arguments);
316+
317+
HttpResponseMessage response = (HttpResponseMessage)request.Properties[ScriptConstants.AzureFunctionsHttpResponseKey];
318+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
319+
Assert.Equal(accept, response.Content.Headers.ContentType.MediaType);
320+
321+
string body = await response.Content.ReadAsStringAsync();
322+
Assert.Equal(expectedBody, body);
323+
}
324+
286325
public class TestFixture : EndToEndTestFixture
287326
{
288327
private const string ScriptRoot = @"TestScripts\CSharp";
Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
using System;
2-
using System.Net;
3-
using System.Net.Http;
4-
5-
public static HttpResponseMessage Run(dynamic input)
1+
public static string Run(dynamic input)
62
{
7-
return new HttpResponseMessage(HttpStatusCode.OK)
8-
{
9-
Content = new StringContent($"Name: {input.name}, Location: {input.location}")
10-
};
3+
return $"Name: {input.name}, Location: {input.location}";
114
}

0 commit comments

Comments
 (0)