The name 'Json' does not exist in the current context

I am receiving this error in my custom code function: System.Drawing.Bitmap CS0103 The name ‘Json’ does not exist in the current context.

I have a function that I’ve been working on. The purpose of the function is to pull some UD information based on a given order number. I have been unsuccessful in getting the function to return to a view on the application studio side, so after a never-ending discussion with Epicor on the subject I have decided to rewrite the function so that instead of a flat response, it will now return a response via the API that is three levels deep.

I am pretty positive from my discussion with Epicare that I will be able to use the function in application studio if I can get it working in this way, but my final issue is this error. Has anyone ran into the error and know how I can use Json() in the current context? I’ve attempted adding various namespaces to the using statements, but haven’t had any luck. Appreciate any ideas you all can offer up. Here’s the code currently:

try
{
    var orderHeader = this.Db.OrderHed
        .FirstOrDefault(ohr => ohr.Company == Session.CompanyID && ohr.OrderNum == this.OrderNum);

    if (orderHeader != null)
    {
        var endUser1 = this.Db.UD03
            .FirstOrDefault(udr => udr.Key1 == "EU1" && udr.Key2 == orderHeader.End_User1_c);

        string finalDestinationCountry = string.Empty;
        if (int.TryParse(orderHeader.Final_Dest_Country_c, out int finalDestCountryNum))
        {
            var finalDestCountry = this.Db.Country
                .FirstOrDefault(fdcr => fdcr.CountryNum == finalDestCountryNum);
            finalDestinationCountry = finalDestCountry?.Description ?? string.Empty;
        }

        var result = new
        {
            Order = new
            {
                OrderInfo = new
                {
                    EndUser1 = endUser1?.Character01 ?? string.Empty,
                    EndUser2 = orderHeader.End_User2_c,
                    FinalDestinationCountry = finalDestinationCountry,
                    myExtraOutput = string.Empty
                }
            }
        };

        return Json(result);
    }
    else
    {
        return Json(new { Error = "Order not found" });
    }
}
catch (Exception ex)
{
    return Json(new 
    {
        Order = new
        {
            OrderInfo = new
            {
                EndUser1 = string.Empty,
                EndUser2 = string.Empty,
                FinalDestinationCountry = string.Empty,
                myExtraOutput = ex.ToString()
            }
        }
    });
}

What is this supposed to be? It’s not from Newtonsoft or the canned dotnet Json classes. Is there more code?

Also, nesting multiple new object declarations is some heinous stuff.

1 Like

As usual, that depends lol.

But @jott , where did you get this code example? That’s nothing we normally use.

1 Like

I’m wondering, is Json the name of his output variable?

If so, @jott , some education may be in order.

An Epicor function is not a traditional function.

An Epicor function is a class, with fields.
You are inside a void method in an Epicor function.

If you want to return something, you just set the field.

Json = "myvalue";

You can still exit early with return, but it’s just return;, as there is no return type.
You can work around this by setting your output variables, and then return;

2 Likes

You are correct, sorry. I tried using Newtonsoft and JsonSerializer without any luck.

I had a flat response originally and it was great, but apparently nobody knows how to get that put into a view in application studio. I was given a demonstration where the response was nested three levels and it appears that that will work, so I am trying to run with it.

This was my original code:

try
{
var orderHeader = this.Db.OrderHed
    .FirstOrDefault(ohr => ohr.Company == Session.CompanyID && ohr.OrderNum == this.OrderNum);

if (orderHeader != null)
{
    this.EndUser2 = orderHeader.End_User2_c;

    var endUser1 = this.Db.UD03
        .FirstOrDefault(udr => udr.Key1 == "EU1" && udr.Key2 == orderHeader.End_User1_c);

    if (endUser1 != null)
    {
        this.EndUser1 = endUser1.Character01;
    }

    if (int.TryParse(orderHeader.Final_Dest_Country_c, out int finalDestCountryNum))
    {
        var finalDestCountry = this.Db.Country
            .FirstOrDefault(fdcr => fdcr.CountryNum == finalDestCountryNum);

        if (finalDestCountry != null)
        {
            this.FinalDestinationCountry = finalDestCountry.Description;
        }
    }
}
}
catch (Exception ex)
{
  myExtraOutput = ex.ToString();
}

Which successfully returns this:

{
  "EndUser1": "string",
  "EndUser2": "string",
  "FinalDestinationCountry": "string",
  "myExtraOutput": "string"
}

Which I have found no way to put into a view using the ‘erp-function’ component in application studio.

What you’ll want to do is return a DataSet from your function.

Set your output variable to be a DataSet,

var ds = new DataSet();
var dt = new DataTable("myTable");
dt.Columns.Add("EndUser1", typeof(string));
dt.Columns.Add("EndUser2", typeof(string));
dt.Columns.Add("FinalDestinationCountry", typeof(string));
dt.Columns.Add("myExtraOutput", typeof(string));
ds.Tables.Add(dt);

dt.Rows.Add("A", "B", "C", "D");

output = ds;
{
  "myTable": [
    {
      "EndUser1": "A",
      "EndUser2": "B",
      "FinalDestinationCountry": "C",
      "myExtraOutput": "D"
    }
  ]
}
1 Like

the full response will look like:

{
    "returnObj": {
        "myTable": [
            {
                "EndUser1": "A",
                "EndUser2": "B",
                "FinalDestinationCountry": "C",
                "myExtraOutput": "D"
            }
        ]
    }
}
1 Like

This is what I was looking for. I am now realizing why this isn’t working thanks to your earlier response. Back to the drawing board. Thank you sir.

1 Like

If it’s just these four values that you’re looking for, you don’t have to stick it into a view - you can read it directly from the actionResult set and store it somewhere (like TransView) to be used. Use a row-update widget to set TransView.EndUser1 to {actionResult.EndUser1}, for example, and set up four columns in the row-update to take care of all your values.

If it’s more than one row, then for sure it’s best to use a table.

1 Like

It’s antipattern to basically all C# I’ve ever seen. If it’s SOP in another language, okay, when in Rome do as the Romans do. I see no Romans here, Caesar.

Ave atque vale

1 Like

Basically the only time I use it, is to build up complex objects or template objects for serialization/ deserialization with Epicor, since we are limited to running inside a method, and can’t create classes. Many times you can get by with the built in structures, but sometimes you can’t.

I myself try not to, but you can’t always control what you are parsing from somewhere else.

1 Like

Final code:

try
{
    // Create a DataSet to hold the result
    DataSet ds = new DataSet();
    DataTable table = new DataTable("OrderData");

    // Add columns for the values
    table.Columns.Add("EndUser1", typeof(string));
    table.Columns.Add("EndUser2", typeof(string));
    table.Columns.Add("FinalDestinationCountry", typeof(string));
    table.Columns.Add("ErrorOutput", typeof(string));  // Column for error message

    // Create a new DataRow to store the values
    DataRow row = table.NewRow();

    var orderHeader = this.Db.OrderHed
        .FirstOrDefault(ohr => ohr.Company == Session.CompanyID && ohr.OrderNum == this.OrderNum);

    if (orderHeader != null)
    {
        // Set EndUser2 value
        row["EndUser2"] = orderHeader.End_User2_c;

        // Get EndUser1 value
        var endUser1 = this.Db.UD03
            .FirstOrDefault(udr => udr.Key1 == "EU1" && udr.Key2 == orderHeader.End_User1_c);

        if (endUser1 != null)
        {
            row["EndUser1"] = endUser1.Character01;
        }

        // Get FinalDestinationCountry value
        if (int.TryParse(orderHeader.Final_Dest_Country_c, out int finalDestCountryNum))
        {
            var finalDestCountry = this.Db.Country
                .FirstOrDefault(fdcr => fdcr.CountryNum == finalDestCountryNum);

            if (finalDestCountry != null)
            {
                row["FinalDestinationCountry"] = finalDestCountry.Description;
            }
        }
    }

    // Set error output as empty since no exception occurred
    row["ErrorOutput"] = string.Empty;

    // Add the populated row to the table
    table.Rows.Add(row);

    // Add the table to the DataSet
    ds.Tables.Add(table);
    
    //set output ds
    this.ds = ds;
}
catch (Exception ex)
{
    // Create a DataSet to hold the error
    DataSet ds = new DataSet();
    DataTable table = new DataTable("OrderData");

    // Add columns for values and error
    table.Columns.Add("EndUser1", typeof(string));
    table.Columns.Add("EndUser2", typeof(string));
    table.Columns.Add("FinalDestinationCountry", typeof(string));
    table.Columns.Add("ErrorOutput", typeof(string));  // Column for error message

    // Create a new DataRow for the error case
    DataRow row = table.NewRow();

    // Leave the value fields empty, but fill in the error message
    row["EndUser1"] = string.Empty;
    row["EndUser2"] = string.Empty;
    row["FinalDestinationCountry"] = string.Empty;
    row["ErrorOutput"] = ex.ToString();  // Store the exception message

    // Add the row to the table
    table.Rows.Add(row);

    // Add the table to the DataSet
    ds.Tables.Add(table);
    
    //set output ds
    this.ds = ds;
}

Response Body:

{
  "ds": {
    "OrderData": [
      {
        "EndUser1": "",
        "EndUser2": "",
        "FinalDestinationCountry": "",
        "ErrorOutput": ""
      }
    ]
  }
}

Setting it up in application studio:

I do want to try this in the future, but need to look into it more:

3 Likes