Erro de serializador JSON com BotFramework e LUIS

Comunidade StackOverflow!

Eu tenho um chatbot e integrei o LUIS.ai para torná-lo mais inteligente. Um dos diálogos está prestes a marcar uma consulta com um supervisor (professor). Tudo está funcionando bem, com literalmente o mesmo código. Há algumas horas, estou tendo alguns erros estranhos.

 Exception: Type 'Newtonsoft.Json.Linq.JArray' in Assembly 'Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' is not marked as serializable.

Como reproduzir o erro?

Se a Entidade (Professor e Data) estiver ausente da entrada do usuário, FINE, o bot cria o Formulário, solicitando entradas ausentes e apresenta os horários sugeridos para a reunião.

Se uma das Entidades estiver faltando na entrada, ela criará um Formulário e solicitará a Data ou Entidade do Professor ausente e apresentará os horários de reunião sugeridos.

MAS

Se a entrada do usuário contiver a Entidade: o Professor e a Data também, estou recebendo o erro.

Aqui está minha classe WebApiConfig:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Json settings
            config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
            JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                Formatting = Newtonsoft.Json.Formatting.Indented,
                NullValueHandling = NullValueHandling.Ignore,
            };

            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

Só estou enfrentando esse erro quando estou tentando obter uma Entidade da declaração do usuário, que é um tipo de builtin.dateTimeV2.

Este método assíncrono é chamado:

    //From the LUIS.AI language model the entities
    private const string EntityMeetingDate = "MeetingDate";
    private const string EntityTeacher = "Teacher";

    [LuisIntent("BookSupervision")]
public async Task BookAppointment(IDialogContext context, IAwaitable<IMessageActivity> activity, LuisResult result)
{
    var message = await activity;
    await context.PostAsync($"I am analysing your message: '{message.Text}'...");

    var meetingsQuery = new MeetingsQuery();

    EntityRecommendation teacherEntityRecommendation;
    EntityRecommendation dateEntityRecommendation;

    if (result.TryFindEntity(EntityTeacher, out teacherEntityRecommendation))
    {
        teacherEntityRecommendation.Type = "Name";
    }
    if (result.TryFindEntity(EntityMeetingDate, out dateEntityRecommendation))
    {
        dateEntityRecommendation.Type = "Date";
    }

    var meetingsFormDialog = new FormDialog<MeetingsQuery>(meetingsQuery, this.BuildMeetingsForm, FormOptions.PromptInStart, result.Entities);
    context.Call(meetingsFormDialog, this.ResumeAfterMeetingsFormDialog);

}

Métodos adicionais para criar um formulário:

 private IForm<MeetingsQuery> BuildMeetingsForm()
{
    OnCompletionAsyncDelegate<MeetingsQuery> processMeetingsSearch = async (context, state) =>
    {
        var message = "Searching for supervision slots";
        if (!string.IsNullOrEmpty(state.Date))
        {
            message += $" at {state.Date}...";
        }
        else if (!string.IsNullOrEmpty(state.Name))
        {
            message += $" with professor {state.Name}...";
        }
        await context.PostAsync(message);
    };

    return new FormBuilder<MeetingsQuery>()
        .Field(nameof(MeetingsQuery.Date), (state) => string.IsNullOrEmpty(state.Date))
        .Field(nameof(MeetingsQuery.Name), (state) => string.IsNullOrEmpty(state.Name))
        .OnCompletion(processMeetingsSearch)
        .Build();
}

private async Task ResumeAfterMeetingsFormDialog(IDialogContext context, IAwaitable<MeetingsQuery> result)
{
try
{
    var searchQuery = await result;

    var meetings = await this.GetMeetingsAsync(searchQuery);

    await context.PostAsync($"I found {meetings.Count()} available slots:");

    var resultMessage = context.MakeMessage();
    resultMessage.AttachmentLayout = AttachmentLayoutTypes.Carousel;
    resultMessage.Attachments = new List<Attachment>();

    foreach (var meeting in meetings)
    {
        HeroCard heroCard = new HeroCard()
        {
            Title = meeting.Teacher,
            Subtitle = meeting.Location,
            Text = meeting.DateTime,
            Images = new List<CardImage>()
            {
                new CardImage() {Url = meeting.Image}
            },
            Buttons = new List<CardAction>()
            {
                new CardAction()
                {
                    Title = "Book Appointment",
                    Type = ActionTypes.OpenUrl,
                    Value = $"https://www.bing.com/search?q=easj+roskilde+" + HttpUtility.UrlEncode(meeting.Location)
                }
            }
        };

        resultMessage.Attachments.Add(heroCard.ToAttachment());
    }

    await context.PostAsync(resultMessage);
}
catch (FormCanceledException ex)
{
    string reply;

    if (ex.InnerException == null)
    {
        reply = "You have canceled the operation.";
    }
    else
    {
        reply = $"Oops! Something went wrong :( Technical Details: {ex.InnerException.Message}";
    }

    await context.PostAsync(reply);
}
finally
{
    context.Wait(DeconstructionOfDialog);
}
}


private async Task<IEnumerable<Meeting>> GetMeetingsAsync(MeetingsQuery searchQuery)
{
    var meetings = new List<Meeting>();

    //some random result manually for demo purposes
    for (int i = 1; i <= 5; i++)
    {
        var random = new Random(i);
        Meeting meeting = new Meeting()
        {
            DateTime = $" Available time: {searchQuery.Date} At building {i}",
            Teacher = $" Professor {searchQuery.Name}",
            Location = $" Elisagårdsvej 3, Room {random.Next(1, 300)}",
            Image = $"https://placeholdit.imgix.net/~text?txtsize=35&txt=Supervision+{i}&w=500&h=260"
        };

        meetings.Add(meeting);
    }

    return meetings;
}

A coisa mais estranha que este código funcionou, e meu grito e respeito vão para a comunidade no GitHub, porque acho que essa é uma plataforma incrível, com toneladas de documentação e exemplos.

questionAnswers(1)

yourAnswerToTheQuestion