Having trouble with getting data to show up on my HoloLens - json

Lately I've been trying to get some data from an external source in the form of JSON.
The library I'm using is the unity fork of Newtonsoft.Json. When i run the project on my computer, it pulls data from the external source, and converts it to an object. The UI/text elements I've made should show the data pulled from my external source, when I run the project on my main computer it has no problems and the data shows up no problem, but when i send the project to my Hololens, my debugger gets data and i can literally see data is being pulled from the external source, but the data won't show up on the hololens. Can anyone enlighten me how i can fix this?
My code is as following:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//using SimpleJSON;
using Newtonsoft.Json;
[System.Serializable]
public class TimeProperties
{
public string Year { get; set; }
public string Month { get; set; }
public string Day { get; set; }
public string Hour { get; set; }
public string Minutes { get; set; }
public string Seconds { get; set; }
}
[System.Serializable]
public class TimeClass
{
public TimeProperties Time { get; set; }
}
public class test : MonoBehaviour
{
string url = "http://172.16.24.135:8080";
public Text year;
public Text month;
public Text day;
public Text hour;
public Text minutes;
public Text seconds;
private void Start()
{
StartCoroutine(UpdateValues());
}
IEnumerator PullJsonData()
{
Debug.Log("entered");
WWW www = new WWW(url);
yield return www;
if(www.error != null)
{
print("There was an error getting the data: " + www.error);
yield break;
}
string jsonstring = www.text;
var data = JsonConvert.DeserializeObject<TimeClass>(jsonstring);
Debug.Log(data.Time.Seconds);
var jaren = data.Time.Year; //data["Year"].AsInt;
var maanden = data.Time.Month;//data["Month"].AsInt;
var dagen = data.Time.Day;//data["Day"].AsInt;
var uren = data.Time.Hour;//data["Hour"].AsInt;
var minuten = data.Time.Minutes;//data["Minutes"].AsInt;
var seconden = data.Time.Seconds;//data["Seconds"].AsInt;
year.text = "Year: " + jaren;
month.text = "Month: " + maanden;
day.text = "Days: " + dagen;
hour.text = "Hours: " + uren;
minutes.text = "Minutes: " + minuten;
seconds.text = "Seconds: " + seconden;
}
IEnumerator UpdateValues()
{
while (true)
{
StartCoroutine(PullJsonData());
yield return new WaitForSeconds(1);
}
}
}
I send it to my hololens via Visual studio code 2017 using "Release x86". I also get the following error:
(Filename: 'C:\buildslave\unity\build\artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)
Display is Transparent
(Filename: C:\buildslave\unity\build\artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)
There was an error getting the data:
(Filename: C:\buildslave\unity\build\artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)
Failed to get spatial stage statics - can't retrieve or interact with boundaries! Error code: '0x80040154'.
(Filename: C:\buildslave\unity\build\Runtime/VR/HoloLens/StageRoot.cpp Line: 20)
entered
(Filename: C:\buildslave\unity\build\artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)'
I pull my JSON data from my external source every second, so every second after runtime, this shows up in my debug:
entered(this is a debug.log inside the class pulljsondata()).
There was an error getting the data:
(Filename: C:\buildslave\unity\build\artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)

I managed to get everything working. The reason nothing showed up on my UI was because i had Unity 2017.3f1 installed with Hololens toolkit with the MixedRealityToolkit v2017.2.1.2 from github(https://github.com/Microsoft/MixedRealityToolkit-Unity).
How I managed to get it working?
I removed Unity 2017.3f1 and installed Unity 2017.2.1f1 and installed the latest version of the MixedRealityToolkit, v2017.2.1.3.
After reinstalling, I tried getting a canvas with some elements up and running, and it pulled json data from an external URL correctly.

Related

How to get error line number when using IExceptionHandlerPathFeature

I am testing a custom error page with IExceptionHandlerPathFeature (see test code in "CODE SEGMENT" section). In the stack trace, I can see the code line number where the exception was triggered.
I would like to know how to extract the line number from the stack trace without having to parse the large block of text. What methods I could use to get the line number?
TEST ENVIRONMENT
App Type: ASP .NET 6 with Razor pages
IDE: VS 2022
Dev Machine: Windows 11
CODE SEGMENT
public class ErrorHandlerModel : PageModel
{
private string _envName;
public ExceptionDetailsModel ExceptionInfo { get; set; }
public ErrorHandlerModel(IWebHostEnvironment webEnv)
{
_envName = webEnv.EnvironmentName;
}
public IActionResult OnGet()
{
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionFeature != null)
{
string reqId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
ExceptionInfo = new ExceptionDetailsModel(reqId);
if (HttpContext.Response.StatusCode != 0)
ExceptionInfo.HttpStatus = HttpContext.Response.StatusCode.ToString();
ExceptionInfo.ErrorMessage = exceptionFeature.Error.Message;
ExceptionInfo.StackTrace = exceptionFeature.Error.StackTrace.ToString();
ExceptionInfo.Route = exceptionFeature.Path;
}
if (_envName.ToLower().IndexOf("develop") >= 0)
{
TempData["show_error_details"] = "yes";
}
else
{
TempData["show_error_details"] = "no";
}
return Page();
}
}

How to load this large json file into objects or dataset using c#?

I'm relatively new to working with JSON and would like to deserialize content I downloaded from https://5e.tools/. I could try to anticipate all the tags/fields in a class, but the dataset example (https://www.newtonsoft.com/json/help/html/DeserializeDataSet.htm) looked more convenient so I tried that first:
using Newtonsoft.Json;
using System;
using System.Data;
using System.IO;
namespace _5EToolsConvertor
{
class Program
{
static void Main(string[] args)
{
string json = File.ReadAllText(#"D:\Downloads\5eTools.1.116.8\data\spells\spells-phb.json");
DataSet dataSet = JsonConvert.DeserializeObject<DataSet>(json);
DataTable dataTable = dataSet.Tables["spell"];
Console.WriteLine(dataTable.Rows.Count);
foreach (DataRow row in dataTable.Rows)
{
Console.WriteLine(row["name"] + " - " + row["level"]); // just to check
}
}
}
}
Here is part of the first item from the JSON file:
{"spell":[{"name":"Acid Splash","source":"PHB","page":211,"srd":true,"level":0,"school":"C","time":[{"number":1,"unit":"action"}],"range":{"type":"point","distance":{"type":"feet","amount":60}},"components":{"v":true,"s":true},"duration":[{"type":"instant"}], ...
I get the error:
An unhandled exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
Unexpected JSON token when reading DataTable: StartObject. Path 'spell[0].range', line 1, position 139.
EDIT 11/30/2020
Advice in the comments suggested moving from a dataset model (spreadsheet) because some of my JSON fields are hierarchical. I've created a class with List<Jobject> for the hierarchical fields like "Time". But, I'd rather end up with all data in vanilla c# objects like Dictionary<string, object>. I'm having trouble converting. What is the best way? This code runs on the full JSON file but prints System.Collections.Generic.List1[Newtonsoft.Json.Linq.JObject]` for every "Time" object.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
namespace _5EToolsConvertor
{
public class Spell
{
public string Name { get; set; }
public string Source { get; set; }
public string Page { get; set; }
public string SRD { get; set; }
public List<JObject> Time { get; set; }
}
class Program
{
static void Main(string[] args)
{
string jsontext = File.ReadAllText(#"D:\Downloads\5eTools.1.116.8\data\spells\spells-phb.json");
JObject json = JObject.Parse(jsontext);
// get JSON result objects into a list
IList<JToken> results = json["spell"].Children().ToList();
// serialize JSON results into .NET objects
IList<Spell> spells = new List<Spell>();
foreach (JToken item in results)
{
// JToken.ToObject is a helper method that uses JsonSerializer internally
Spell spell = item.ToObject<Spell>();
spells.Add(spell);
}
foreach (Spell spell in spells)
{
Console.WriteLine($"Name:{spell.Name} Source:{spell.Source} Page:{spell.Page} SRD:{spell.SRD} Time:{spell.Time}");
}
-david

Unity JSON with mixed media binary objects like audioStream buffers

Which JSON library would you use to parse JSON that contains beyond the usual text data, such as audioStream and binary objects buffers?
You may want to provide more information specific to your case.
The solution depends on whether you are:
Going to serialize that data yourself and then deserialize them.
You could use scriptable objects to store audio, sprite, prefab and in general visual-centric data. Then create an editor extension for that particular scriptable object type to expose and edit the JSON data and store them in a .json file in project's assets.
You already have everything serialized in JSON and just need a way to deserialize them.
In this case, you should probably create the Data class to hold those data, with the serializable types in mind. Then create those data and try to import the stream byte array to either an audio file in the file system or an audio clip in memory.
Here is an example that caches the file in a directory:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using Newtonsoft.Json; // JSON .NET For Unity
using Newtonsoft.Json.Serialization;
[Serializable]
public class MovieModel
{
[Serializable]
public class SlotsData
{
public string Celebrity { get; set; }
public string Genre { get; set; }
}
[Serializable]
public class AudioStreamData
{
public string Type { get; set; }
public byte[] Data { get; set; }
}
public string UserId { get; set; }
public string ContentType { get; set; }
public string IntentName { get; set; }
public SlotsData Slots { get; set; }
public string Message { get; set; }
public string DialogState { get; set; }
public AudioStreamData AudioStream { get; set; }
public override string ToString()
{
return string.Format("[{0}, {1}, {2}, {3}]", UserId, ContentType, IntentName, Message);
}
}
public class MovieWithAudioClip
{
public MovieModel Model { get; set; }
public string CachedFileName { get; set; }
public AudioClip Clip { get; set; }
}
public class AudioClipJSONImporter : MonoBehaviour
{
private static readonly JsonSerializerSettings SERIALIZATION_SETTINGS = new JsonSerializerSettings()
{
// Read the docs to configure the settings based on your data classes and the JSON file itself.
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
private static readonly Dictionary<string, AudioType> WHITELISTED_CONTENT_TYPE_TO_UNITY_AUDIO_TYPE = new Dictionary<string, AudioType>()
{
// Append all the supported content types here with their corresponding type, so that Unity can read them.
{ "audio/mpeg", AudioType.MPEG}
};
private static readonly Dictionary<string, string> CONTENT_TYPE_TO_FILE_EXTENSION = new Dictionary<string, string>()
{
{ "audio/mpeg", ".mp3"}
};
[Header("Drag and drop a JSON movie entry here")]
[SerializeField]
private TextAsset m_MovieEntryJson;
[SerializeField]
private string m_ClipCacheDirectory = "Clips";
[Header("Drag and drop an Audio source here, to preview the current movie entry")]
[SerializeField] AudioSource m_AudioPreviewer;
// Click on the top right of the script when in edit mode to call this procedure.
[ContextMenu("Import JSON entry")]
private void ImportJsonEntry()
{
if (m_MovieEntryJson == null || string.IsNullOrEmpty(m_MovieEntryJson.text))
{
Debug.LogError("Drag and drop a JSON movie entry in the inspector.");
return;
}
MovieModel movieModel = JsonConvert.DeserializeObject<MovieModel>(m_MovieEntryJson.text, SERIALIZATION_SETTINGS);
Debug.LogFormat("Movie entry {0} imported.", movieModel);
Debug.Assert(movieModel != null, "Failed to load movie entry.");
Debug.AssertFormat(movieModel.AudioStream != null, "Failed to load audio stream for movie entry {0}", movieModel);
Debug.AssertFormat(movieModel.AudioStream.Data != null, "Failed to load audio stream byte array for movie entry {0}", movieModel);
if (movieModel == null || movieModel.AudioStream == null || movieModel.AudioStream.Data == null)
{
return;
}
string clipCacheDirName = Application.isPlaying ? Application.persistentDataPath : Application.streamingAssetsPath;
if (!string.IsNullOrEmpty(m_ClipCacheDirectory))
{
clipCacheDirName = Path.Combine(clipCacheDirName, m_ClipCacheDirectory);
}
AudioType supportedAudioType;
string fileExtension = null;
if (!WHITELISTED_CONTENT_TYPE_TO_UNITY_AUDIO_TYPE.TryGetValue(movieModel.ContentType, out supportedAudioType))
{
Debug.LogErrorFormat(
"Failed to load movie {0} with mime type: {1} as it is not in the mime type to extension whitelist.",
movieModel, movieModel.ContentType
);
return;
}
CONTENT_TYPE_TO_FILE_EXTENSION.TryGetValue(movieModel.ContentType, out fileExtension);
StartCoroutine(
GenerateAudioMovie(clipCacheDirName, fileExtension, supportedAudioType, movieModel, (MovieWithAudioClip movie) =>
{
if (m_AudioPreviewer != null)
{
m_AudioPreviewer.clip = movie.Clip;
m_AudioPreviewer.Play();
}
})
);
}
private IEnumerator GenerateAudioMovie(
string rootDirName,
string fileExtension,
AudioType audioType,
MovieModel movieModel,
Action<MovieWithAudioClip> onDone,
Action<string> onError = null
)
{
// Remove this is you can be sure the directory exists.
Directory.CreateDirectory(rootDirName);
// If you can create a non random ID based on the JSON data, that is better.
//
// Mainly, because you can check the file system in case it has already been downloaded and load the clip directly.
// Although, that makes sense only if you have a 'light' route to receive the movie data without the audio stream (which is now cached).
string cachedFileId = Guid.NewGuid().ToString();
string cachedFileName = Path.Combine(rootDirName, cachedFileId + fileExtension);
MovieWithAudioClip audioMovie = new MovieWithAudioClip()
{
Model = movieModel,
CachedFileName = cachedFileName
};
// Source: https://answers.unity.com/questions/686240/audioclip-oggmp3-loaded-from-byte-array.html
//
File.WriteAllBytes(cachedFileName, movieModel.AudioStream.Data);
Debug.LogFormat("Movie audio file exported at: {0}", cachedFileName);
WWW loader = new WWW(string.Format("file://{0}", cachedFileName));
yield return loader;
if (!System.String.IsNullOrEmpty(loader.error))
{
Debug.LogErrorFormat("Failed to load movie {0} at file {1} with error {2}.", movieModel, cachedFileName, loader.error);
if (onError != null)
onError(loader.error);
}
else
{
audioMovie.Clip = loader.GetAudioClip(false, false, audioType);
Debug.AssertFormat(audioMovie.Clip != null, "Failed to generate audio clip for movie entry {0}", movieModel);
if (audioMovie.Clip != null)
{
if (onDone != null)
onDone(audioMovie);
}
else
{
if (onError != null)
onError(loader.error);
}
}
}
}
The code above does not do any processing, it just tries to retrieve an audio clip out of the stream in the JSON and it fails for mp3. However, an audio file will be created in your file system and you can play it and make sure that the JSON parser works.
From there, you need to process the data based on what types you are going to support. Here is a relevant post. Check out the three steps of Kurt-Dekker's answer.
Now, it's up to you to handle the different audio types you want to support, platform compatibility .etc.
Good luck!
I know very little about JSON, and my searches have yielded nothing. Could you tell me a little more on what sort of data you are dealing with?
Try parsing the parts of the file you can with JSON and then for the parts you can't, try building your own parser.
Best of luck.

Web API - Converting JSON to Complex Object Type (DTO) with inheritance

I have the following scenario:
public class WidgetBaseDTO
{
public int WidgetID
{
get;
set;
}
}
public class WidgetTypeA : WidgetBaseDTO
{
public string SomeProperty1
{
get;
set;
}
}
public class WidgetTypeB : WidgetBaseDTO
{
public int SomeProperty2
{
get;
set;
}
}
and my web service returns the following dashboard object whereas the Widgets collection could be of either type A or B:
public class DashboardDTO
{
public List<WidgetBaseDTO> Widgets
{
get;
set;
}
}
my problem is that although the client receives correct JSON content, which is dependent on the Widget type, when reading the response content, they are all being translated to WidgetBaseDTO. what is the correct way to convert these objects to the relevant types?
this is how the response is being read:
string relativeRequestUri = string.Format("api/dashboards/GetDashboard?dashboardID={0}", dashboardID);
using (var client = new HttpClient())
{
// set client options
client.BaseAddress = this.BaseUri;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// make request
HttpResponseMessage response = client.GetAsync(relativeRequestUri).Result;
if (response.IsSuccessStatusCode)
{
DashboardDTO dashboard = response.Content.ReadAsAsync<DashboardDTO>().Result;
}
I believe after receiving the response you are probably trying to cast WidgetBaseDTO to either WidgetTypeA or WidgetTypeB and you are seeing null? if yes, then you can try after making the following setting to the Json formatter on the server...make sure to make this setting on the client side's json formatter too.
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects;
The above setting will cause the type information of WidgetTypeA or WidgetTypeB to be put over the wire which gives a hint to the client as to the actual type of the object being deserialized...you can try looking at the wire format of the response to get an idea...
Client side:
JsonMediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects;
WidgetBaseDTO baseDTO = resp.Content.ReadAsAsync<WidgetBaseDTO>(new MediaTypeFormatter[] { jsonFormatter }).Result;

SSIS/C#: Script Task, C# script to look at directory and store the name of 1 file in a variable

Basically I've written a C# script for a Script task in SSIS that looks in a User::Directory for 1 csv, if & only if there is one file, it stores that in the instance variable which then maps to the package variables of SSIS.
When I exicute, it gives me the red filled in box of the Script task. I think it's related to how I'm looking at the directory, but I'm not sure.
Please help!
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.IO;
namespace ST_e8b4bbbddb4b4806b79f30644240db19.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
private String fileName = "";
private String RootDirictory;
private String FilePath;
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
public ScriptMain()
{
RootDirictory = Dts.Variables["RootDir"].Value.ToString();
FilePath = RootDirictory + "\\" + "SourceData" + "\\";
}
public void setFileName()
{
DirectoryInfo YDGetDir = new DirectoryInfo(FilePath);
FileInfo[] numberOfFiles = YDGetDir.GetFiles(".csv");
if (numberOfFiles.Length < 2)
{
fileName = numberOfFiles[0].ToString();
}
int fileNameLen = fileName.Length;
String temp = fileName.Substring(0, fileNameLen - 5);
fileName = temp;
}
public void mapStateToPackage()
{
if((fileName!=null)||(fileName!=""))
{
Dts.Variables["ExDFileName"].Value = fileName;
}
}
public void Main()
{
setFileName();
mapStateToPackage();
Dts.TaskResult = (int)ScriptResults.Success;
}
}
}
This could simply be done using Foreach loop container as explained in this Stack Overflow question, which was asked by you. :-)
Anyway, to answer your question with respect to Script Task code that you have provided. Below mentioned reasons could be cause of the issues:
You are looking for .csv. This won't return any results because you are looking for a file with no name but extension .csv. The criteria should be *.csv
If you are looking for exactly one file, then the condition if (numberOfFiles.Length < 2) should be changed to if (numberOfFiles.Length == 1)
The section of code after the if section which extracts the file name should be within the above mentioned if condition and not out side of it. This has to be done to prevent applying substring functionality on an empty string.
Modified code can be found under the Script Task Code section.
Sorry, I took the liberty to simplify the code a little. I am not suggesting this is the best way to do this functionality but this is merely an answer to the question.
Hope that helps.
Script Task Code:
C# code that can be used only in SSIS 2008 and above.
/*
Microsoft SQL Server Integration Services Script Task
Write scripts using Microsoft Visual C# 2008.
The ScriptMain is the entry point class of the script.
*/
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.IO;
namespace ST_3effcc4e812041c7a0fea69251bedc25.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
Variables varCollection = null;
String fileName = string.Empty;
String fileNameNoExtension = string.Empty;
String rootDirectory = string.Empty;
String filePath = string.Empty;
#region VSTA generated code
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
public void Main()
{
Dts.VariableDispenser.LockForRead("User::RootDir");
Dts.VariableDispenser.LockForWrite("User::ExDFileName");
Dts.VariableDispenser.GetVariables(ref varCollection);
rootDirectory = varCollection["User::RootDir"].Value.ToString();
filePath = rootDirectory + #"\SourceData\";
DirectoryInfo YDGetDir = new DirectoryInfo(filePath);
FileInfo[] numberOfFiles = YDGetDir.GetFiles("*.csv");
if (numberOfFiles.Length == 1)
{
fileName = numberOfFiles[0].ToString();
fileNameNoExtension = fileName.Substring(0, fileName.LastIndexOf("."));
}
if (!String.IsNullOrEmpty(fileNameNoExtension))
{
varCollection["User::ExDFileName"].Value = fileNameNoExtension;
}
Dts.TaskResult = (int)ScriptResults.Success;
}
}
}