Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;

namespace Microsoft.Azure.Functions.Worker.Sdk

@kshyju kshyju Aug 20, 2021

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved 2 existing extension method classes under the new "Extensions" directory. They were in the root of the project earlier.

Expand Down
52 changes: 52 additions & 0 deletions sdk/Sdk/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

namespace Microsoft.Azure.Functions.Worker.Sdk
{
internal static class StringExtensions
{
/// <summary>
/// Returns a copy of the string in camelCase.
/// </summary>
public static string ToCamelCase(this string value)
Comment thread
kshyju marked this conversation as resolved.
Outdated
{
// Using the same logic as in JsonCamelCaseNamingPolicy(System.Text.Json)

if (string.IsNullOrEmpty(value) || !char.IsUpper(value[0]))
{
return value;
}

char[] chars = value.ToCharArray();

for (int i = 0; i < chars.Length; i++)
{
if (i == 1)
{
if (!char.IsUpper(chars[i]))
{
break;
}
}

bool hasNext = (i + 1 < chars.Length);

// Stop when next char is already lowercase.
if (i > 0 && hasNext && !char.IsUpper(chars[i + 1]))
{
// If the next char is a space, lowercase current char before exiting.
if (chars[i + 1] == ' ')
{
chars[i] = char.ToLowerInvariant(chars[i]);
}

break;
}

chars[i] = char.ToLowerInvariant(chars[i]);
}

return new string(chars);
}
}
}
5 changes: 3 additions & 2 deletions sdk/Sdk/FunctionMetadataGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ private void AddOutputBindingsFromReturnType(IList<ExpandoObject> bindingMetadat
private static bool IsHttpTrigger(ExpandoObject bindingMetadata)
{
return bindingMetadata.Any(kvp => string.Equals(kvp.Key, "Type", StringComparison.Ordinal)
&& string.Equals(kvp.Value?.ToString(), Constants.HttpTriggerBindingType, StringComparison.Ordinal));
&& string.Equals(kvp.Value?.ToString(), Constants.HttpTriggerBindingType.ToCamelCase(), StringComparison.Ordinal));
}

private bool TryAddOutputBindingsFromProperties(IList<ExpandoObject> bindingMetadata, TypeDefinition typeDefinition)
Expand Down Expand Up @@ -381,7 +381,8 @@ private static ExpandoObject BuildBindingMetadataFromAttribute(CustomAttribute a
bindingDict["Name"] = parameterName!;
}

bindingDict["Type"] = bindingType;
// The "Type" property value must be camelCase for the scaling infrastructure to work correctly
bindingDict["Type"] = bindingType.ToCamelCase();
bindingDict["Direction"] = GetBindingDirection(attribute);

// Is string parameter type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void ValidateTrigger(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "myReq" },
{ "Type", "HttpTrigger" },
{ "Type", "httpTrigger" },
{ "Direction", "In" },
{ "authLevel", "Admin" },
{ "methods", new[] { "get", "Post" } },
Expand Down Expand Up @@ -86,7 +86,7 @@ void ValidateTrigger(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "myReq" },
{ "Type", "HttpTrigger" },
{ "Type", "httpTrigger" },
{ "Direction", "In" },
{ "authLevel", "Admin" },
{ "methods", new[] { "get", "Post" } },
Expand Down Expand Up @@ -119,7 +119,7 @@ void ValidateTrigger(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "myReq" },
{ "Type", "HttpTrigger" },
{ "Type", "httpTrigger" },
{ "Direction", "In" },
{ "authLevel", "Admin" },
{ "methods", new[] { "get", "Post" } },
Expand Down Expand Up @@ -169,7 +169,7 @@ void ValidateQueueTrigger(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "queuePayload" },
{ "Type", "QueueTrigger" },
{ "Type", "queueTrigger" },
{ "Direction", "In" },
{ "Connection", "MyConnection" },
{ "queueName", "queueName" },
Expand All @@ -182,7 +182,7 @@ void ValidateBlobOutput(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "$return" },
{ "Type", "Blob" },
{ "Type", "blob" },
{ "Direction", "Out" },
{ "blobPath", "container1/hello.txt" },
{ "Connection", "MyOtherConnection" }
Expand All @@ -198,7 +198,7 @@ void ValidateBlobTrigger(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "blob" },
{ "Type", "BlobTrigger" },
{ "Type", "blobTrigger" },
{ "Direction", "In" },
{ "blobPath", "container2/%file%" },
{ "DataType", "String" }
Expand All @@ -210,7 +210,7 @@ void ValidateQueueOutput(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "$return" },
{ "Type", "Queue" },
{ "Type", "queue" },
{ "Direction", "Out" },
{ "queueName", "queue2" },
});
Expand All @@ -236,7 +236,7 @@ void ValidateTrigger(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "timer" },
{ "Type", "TimerTrigger" },
{ "Type", "timerTrigger" },
{ "Direction", "In" },
{ "schedule", "0 0 0 * * *" },
{ "RunOnStartup", false }
Expand Down Expand Up @@ -273,7 +273,7 @@ void ValidateQueueTrigger(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "queuePayload" },
{ "Type", "QueueTrigger" },
{ "Type", "queueTrigger" },
{ "Direction", "In" },
{ "Connection", "MyConnection" },
{ "queueName", "queueName" },
Expand All @@ -286,7 +286,7 @@ void ValidateBlobOutput(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "blobOutput" },
{ "Type", "Blob" },
{ "Type", "blob" },
{ "Direction", "Out" },
{ "blobPath", "container1/hello.txt" },
{ "Connection", "MyOtherConnection" },
Expand All @@ -299,7 +299,7 @@ void ValidateQueueOutput(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "queueOutput" },
{ "Type", "Queue" },
{ "Type", "queue" },
{ "Direction", "Out" },
{ "queueName", "queue2" },
{ "DataType", "String" }
Expand Down Expand Up @@ -335,7 +335,7 @@ void ValidateHttpTrigger(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "req" },
{ "Type", "HttpTrigger" },
{ "Type", "httpTrigger" },
{ "Direction", "In" },
{ "methods", new[] { "get" } },
{ "DataType", "String" }
Expand All @@ -357,7 +357,7 @@ void ValidateQueueOutput(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "queueOutput" },
{ "Type", "Queue" },
{ "Type", "queue" },
{ "Direction", "Out" },
{ "queueName", "queue2" },
{ "DataType", "String" }
Expand Down Expand Up @@ -389,7 +389,7 @@ void ValidateHttpTrigger(ExpandoObject b)
AssertExpandoObject(b, new Dictionary<string, object>
{
{ "Name", "req" },
{ "Type", "HttpTrigger" },
{ "Type", "httpTrigger" },
{ "Direction", "In" },
{ "methods", new[] { "get" } },
{ "DataType", "String" }
Expand Down Expand Up @@ -468,7 +468,7 @@ void ValidateTrigger(ExpandoObject b, bool many)
var expected = new Dictionary<string, object>()
{
{ "Name", "input" },
{ "Type", "EventHubTrigger" },
{ "Type", "eventHubTrigger" },
{ "Direction", "In" },
{ "eventHubName", "test" },
{ "Connection", "EventHubConnectionAppSetting" }
Expand Down
24 changes: 24 additions & 0 deletions test/FunctionMetadataGeneratorTests/StringExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using Microsoft.Azure.Functions.Worker.Sdk;
using Xunit;

namespace Microsoft.Azure.Functions.SdkTests
{
public class StringExtensionsTests
{
[Theory]
[InlineData("QueueTrigger", "queueTrigger")]
[InlineData("HTTPTrigger", "httpTrigger")]
[InlineData("Blob", "blob")]
[InlineData("", "")]
[InlineData(null, null)]
public void ToCamelCaseWorks(string input, string expectedOutput)
{
var actual = input.ToCamelCase();

Assert.Equal(expectedOutput, actual);
}
}
}