Skip to content

Commit

Permalink
adding default Json formatters for requests
Browse files Browse the repository at this point in the history
  • Loading branch information
brettsam committed Nov 26, 2019
1 parent c6942f2 commit d4f5e48
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 1 deletion.
25 changes: 24 additions & 1 deletion src/WebJobs.Script.WebHost/WebScriptHostBuilderExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Azure.WebJobs.Host.Config;
using Microsoft.Azure.WebJobs.Host.Executors;
using Microsoft.Azure.WebJobs.Host.Loggers;
Expand Down Expand Up @@ -30,7 +31,7 @@ public static IHostBuilder AddWebScriptHost(this IHostBuilder builder, IServiceP
IDependencyValidator validator = rootServiceProvider.GetService<IDependencyValidator>();
IMetricsLogger metricsLogger = rootServiceProvider.GetService<IMetricsLogger>();

builder.UseServiceProviderFactory(new JobHostScopedServiceProviderFactory(rootServiceProvider, rootScopeFactory, validator))
_ = builder.UseServiceProviderFactory(new JobHostScopedServiceProviderFactory(rootServiceProvider, rootScopeFactory, validator))
.ConfigureServices(services =>
{
// register default configuration
Expand Down Expand Up @@ -75,6 +76,11 @@ public static IHostBuilder AddWebScriptHost(this IHostBuilder builder, IServiceP
services.AddSingleton<IHostedService, FunctionsSyncService>();
}

if (!environment.IsV2CompatibilityMode())
{
new FunctionsMvcBuilder(services).AddNewtonsoftJson();
}

services.AddSingleton<HttpRequestQueue>();
services.AddSingleton<IHostLifetime, JobHostHostLifetime>();
services.AddSingleton<IWebJobsExceptionHandler, WebScriptHostExceptionHandler>();
Expand Down Expand Up @@ -126,5 +132,22 @@ private static void ConfigureRegisteredBuilders<TBuilder>(TBuilder builder, ISer
configureBuilder.Configure(builder);
}
}

/// <summary>
/// Used internally to register Newtonsoft formatters with our ScriptHost.
/// </summary>
private class FunctionsMvcBuilder : IMvcBuilder
{
private readonly IServiceCollection _serviceCollection;

public FunctionsMvcBuilder(IServiceCollection serviceCollection)
{
_serviceCollection = serviceCollection;
}

public ApplicationPartManager PartManager { get; } = new ApplicationPartManager();

public IServiceCollection Services => _serviceCollection;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"bindings": [
{
"type": "httpTrigger",
"name": "payload",
"direction": "in",
"methods": [ "post" ],
"authLevel": "anonymous"
},
{
"type": "http",
"name": "$return",
"direction": "out"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

public static TestPayload Run(TestPayload payload)
{
return payload;
}

public class TestPayload
{
public CustomType Custom { get; set; }

public IEnumerable<CustomType> CustomEnumerable { get; set; }
}

public class CustomType
{
public string CustomProperty { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"bindings": [
{
"type": "httpTrigger",
"name": "payload",
"direction": "in",
"methods": [ "post" ],
"authLevel": "anonymous"
},
{
"type": "http",
"name": "$return",
"direction": "out"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

public static TestPayload Run(TestPayload payload)
{
return payload;
}

public class TestPayload
{
public CustomType Custom { get; set; }

public IEnumerable<CustomType> CustomEnumerable { get; set; }
}

public class CustomType
{
public string CustomProperty { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,72 @@ public async Task HttpTrigger_Post_Dynamic()
Assert.Equal("Name: Mathew Charles, Location: Seattle", body);
}

[Fact]
public async Task HttpTrigger_Model_Binding()
{
(JObject req, JObject res) = await MakeModelRequest(Fixture.Host.HttpClient);
Assert.True(JObject.DeepEquals(req, res), res.ToString());
}

[Fact]
public async Task HttpTrigger_Model_Binding_V2CompatMode()
{
// We need a custom host to set this to v2 compat mode.
using (var host = new TestFunctionHost(@"TestScripts\CSharp", Path.Combine(Path.GetTempPath(), "Functions"),
configureWebHostServices: webHostServices =>
{
var environment = new TestEnvironment();
environment.SetEnvironmentVariable(EnvironmentSettingNames.FunctionsV2CompatibilityModeKey, "true");
webHostServices.AddSingleton<IEnvironment>(_ => environment);
},
configureScriptHostWebJobsBuilder: webJobsBuilder =>
{
webJobsBuilder.Services.Configure<ScriptJobHostOptions>(o =>
{
// Only load the functions we care about
o.Functions = new[]
{
"HttpTrigger-Model-v2",
};
});
}))
{

(JObject req, JObject res) = await MakeModelRequest(host.HttpClient, "-v2");

// in v2, we expect the response to have a null customEnumerable property.
req["customEnumerable"] = null;

Assert.True(JObject.DeepEquals(req, res), res.ToString());
}
}

private static async Task<(JObject requestContent, JObject responseContent)> MakeModelRequest(HttpClient httpClient, string suffix = null)
{
var payload = new
{
custom = new { customProperty = "value" },
customEnumerable = new[] { new { customProperty = "value1" }, new { customProperty = "value2" } }
};

var jObject = JObject.FromObject(payload);
var json = jObject.ToString();

HttpRequestMessage request = new HttpRequestMessage
{
RequestUri = new Uri($"http://localhost/api/httptrigger-model{suffix}"),
Method = HttpMethod.Post,
Content = new StringContent(json, Encoding.UTF8, "application/json")
};

request.Content.Headers.ContentLength = json.Length;

HttpResponseMessage response = await httpClient.SendAsync(request);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

return (jObject, JObject.Parse(await response.Content.ReadAsStringAsync()));
}

[Fact]
public async Task HttpTriggerToBlob()
{
Expand Down Expand Up @@ -448,6 +514,7 @@ public override void ConfigureScriptHost(IWebJobsBuilder webJobsBuilder)
"AssembliesFromSharedLocation",
"HttpTrigger-Dynamic",
"HttpTrigger-Scenarios",
"HttpTrigger-Model",
"HttpTrigger-Redirect",
"HttpTriggerToBlob",
"FunctionExecutionContext",
Expand Down

0 comments on commit d4f5e48

Please sign in to comment.