Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Amazon Lambda in C# - JsonReaderException

I am attempting to write an AWS Lambda function in C#. I have the AWS Toolkit for Visual Studio 2015. I created a project with the AWS Lambda Project (.Net Core) and then selected the Empty Function option. Which gave me the following code:

UPDATE & ANSWER 02/24/17 - The comment marked as the Answer was useful knowledge but was not the actual answer for me. It was @PavelSafronov's comment in that answer that did the trick. I was either passing nothing in (and getting the error) or I assumed it wanted ME to give the information in JSON format so I would enter { "input": "Some string" } and still get the error. Now that I just passed in "Some string" it worked. However, as far as I am concerned, this seems like a bug. A string is by default nullable and the code written by Amazon even assumes it could be by virtual of the input?.ToUpper() where the ?. is checking for null.

Note: I added the LambdaLogger.Log lines and the Constructor to see where I was getting:

using Amazon.Lambda.Core;
using Amazon.Lambda.Serialization.Json;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(JsonSerializer))]

namespace AWSLambdaTest1 {

  public class Function {

    public Function() {
      LambdaLogger.Log("Within the Constructor");
    }

    public string KevinsTestFunction(string input, ILambdaContext context) {
      LambdaLogger.Log("Within the KTF");
      return input?.ToUpper();
    }

  }
}

The output screen and Solution Explorer were saying:

Errors in C:\Test Projects\AWSLambda1\AWSLambda1\AWSLambda1.xproj
  Unable to resolve 'Amazon.Lambda.Core (>= 1.0.0)' for '.NETCoreApp,Version=v1.0'.

However, this will build and publish to AWS without fail. I can even Invoke it which returns the following - And is my main question:

{
  "errorType" : "JsonReaderException",
  "errorMessage" : "Unexpected character encountered while parsing value: {. Path '', line 1, position 1.",
  "stackTrace"   : [
    "at Newtonsoft.Json.JsonTextReader.ReadStringValue(ReadType readType)",
    "at Newtonsoft.Json.JsonTextReader.ReadAsString()",
    "at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter)",
    "at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)",
    "at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)",
    "at Newtonsoft.Json.JsonSerializer.Deserialize[T](JsonReader reader)",
    "at lambda_method(Closure , Stream , Stream , ContextInfo )"
  ]
}

The Log file showed that the Constructors log message got there but NOT the actual KevingsTestFunction log message.

On a side note, I am able to get the Unable to resolve 'Amazon.Lambda.Core (>= 1.0.0)' for '.NETCoreApp,Version=v1.0' error to go away by adding the following to my project.json file:

"runtimes": {
  "win10-x64": {},
  "win81-x64": {},
  "win8-x64": {},
  "win7-x64": {}
}

Which makes sense on a Windows machine, not so much here on Amazon. Do I need some different runtime(s)?

That change did not change the JsonReaderException exception.

I tried adding "Linux": {} but that made no change either.

I even tried to update the NuGet package Microsoft.NETCore.App from 1.0.0 to 1.1.0 and that did nothing as well and even back to 1.0.1.

I would figure the default example they give you would work, but I am wrong there. It seems like there are issues with the Amazon.Lambda.Serialization.Json.JsonSerializer attribute. Is it possible to just use NewtonSoft?

like image 954
Grandizer Avatar asked Feb 23 '17 17:02

Grandizer


3 Answers

Update the code:

public string KevinsTestFunction(string input, ILambdaContext context) {
  LambdaLogger.Log("Within the KTF");
  return input?.ToUpper();
}

to:

public string KevinsTestFunction(IDictionary input, ILambdaContext context) {
  LambdaLogger.Log("Within the KTF");
  return input["input"]?.ToUpper();
}

Do not forget to

using System.Collections;
like image 165
Marcel Bezerra Avatar answered Nov 05 '22 15:11

Marcel Bezerra


My experience with AWS Lambda in C# in a little limited, but this is the kind of error I get when the input ("test" data if you are triggering the function from the console) is not in a actual JSON format. The best bet might be to create a dummy input class for your testing purposes and then give the lambda function the equivalent JSON data to get it to serialize properly.

As for your project.json, I have not needed to add the runtimes section for AWS Lambda before. If you do then you will need to select the relevant runtimes from this list: https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog

Also here is a example project.json file if you find that useful: https://gist.github.com/TAGray/8cc812065c3b6abcd732b7f6a3bda92a

Hope that helps.

like image 29
Tim Gray Avatar answered Nov 05 '22 15:11

Tim Gray


Per Pavel Safronov -

Yes you should be entering a string not a json object if your Lambda Function entry point is:

public string KevinsTestFunction(string input, ILambdaContext context) {

Then the string you could enter is:

"{ \"input\": \"Something\" }"

You could also change the Lambda Functions entry point to:

public string KevinsTestFunction(JObject input, ILambdaContext context) {

Then you can enter a json object like so:

{ "input": "Something" }

If you're not expecting any input and merely polling a SQS queue or DynamoDb table then you could change the Lambda Function's entry point to:

public string KevinsTestFunction(ILambdaContext context) {

Many variations to play around with.


Now per the update in the original question, by default the AWS web console TEST area will set you up with default test data to send to your Lambda Function. That default test data is a JSON object. As noted it is at odds with the default templates for the C# Lambdas (which accept the string input) made available thru Visual Studio via the AWS SDK. Perhaps this is a built in stumbling block (feature) to force us to run into this issue, pull our hair out over it, then realize how versatile the function handler can be...

like image 24
Zaxxon Avatar answered Nov 05 '22 14:11

Zaxxon