I have this original code:
public async Task<ActionResult> Chunk_Upload_Save(IEnumerable<IFormFile> files, string metaData)
{
if (metaData == null)
{
return await Save(files);
}
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(metaData));
JsonSerializer serializer = new JsonSerializer();
ChunkMetaData chunkData;
using (StreamReader streamReader = new StreamReader(ms))
{
chunkData = (ChunkMetaData)serializer.Deserialize(streamReader, typeof(ChunkMetaData));
}
string path = String.Empty;
// The Name of the Upload component is "files"
if (files != null)
{
foreach (var file in files)
{
path = Path.Combine(WebHostEnvironment.WebRootPath, "App_Data", chunkData.FileName);
//AppendToFile(path, file);
}
}
FileResult fileBlob = new FileResult();
fileBlob.uploaded = chunkData.TotalChunks - 1<= chunkData.ChunkIndex;
fileBlob.fileUid = chunkData.UploadUid;
return Json(fileBlob);
}
I converted it using only System.Text.Json.* to this:
public async Task<ActionResult> Chunk_Upload_Save(IEnumerable<IFormFile> files, string metaData)
{
if (metaData == null)
{
return await Save(files);
}
var ms = new MemoryStream(Encoding.UTF8.GetBytes(metaData));
ChunkMetaDataModel chunkData;
using (var streamReader = new StreamReader(ms))
{
// Here is the issues
chunkData = (ChunkMetaDataModel) await JsonSerializer.DeserializeAsync(streamReader, typeof(ChunkMetaDataModel));
}
// The Name of the Upload component is "files"
if (files != null)
{
foreach (var file in files)
{
Path.Combine(hostEnvironment.WebRootPath, "App_Data", chunkData!.FileName);
//AppendToFile(path, file);
}
}
var fileBlob = new FileResultModel
{
uploaded = chunkData!.TotalChunks - 1 <= chunkData.ChunkIndex,
fileUid = chunkData.UploadUid
};
return Json(fileBlob);
}
I get the error:
Argument 1: cannot convert from 'System.IO.StreamReader' to 'System.IO.Stream'.
By Argument 1, VS is pointing to the streamReader parameter and it's this line:
chunkData = (ChunkMetaData)serializer.Deserialize(streamReader, typeof(ChunkMetaData));
How do I convert this to the System.Text.Json API?
System.Text.Json is designed to deserialize most efficiently from UTF8 byte sequences rather than UTF16 strings, so there is no overload to deserialize from a StreamReader. Instead deserialize directly from the MemoryStream ms using the following:
chunkData = await JsonSerializer.DeserializeAsync<ChunkMetaDataModel>(ms);
Notes:
There is no reason to use async deserialization when deserializing from a MemoryStream. Instead use synchronous deserialization like so:
chunkData = JsonSerializer.Deserialize<ChunkMetaDataModel>(ms);
And since you already have a string metaData containing the JSON to be deserialized, you can deserialize directly from it using the Deserialize<TValue>(ReadOnlySpan<Char>, JsonSerializerOptions) overload:
chunkData = JsonSerializer.Deserialize<ChunkMetaDataModel>(metaData);
System.Text.Json will do the UTF16 to UTF8 conversion for you internally using memory pooling.
If you really must deserialize from a StreamReader for some reason (e.g. incremental integration of System.Text.Json with legacy code), see Reading string as a stream without copying for suggestions on how to do this.
Related
I need to save the information from an input page into a JSON File and output the information onto another page reading from the JSON File. I've tried many things and what seemed to work for me is using the specialfolder localapplication data.
Now, I don't quite understand how I can output the information and also check if the data is even put in correctly.
I previously used StreamReader to output the information on the JSON file and then put it on a ListView but this doesn't work if I have the file in the specialfolder. It says "stream cant be null". The commented out code is the code I tried in previous attempts.
Code:
ListPageVM (Read Page)
private ObservableCollection<MainModel> data;
public ObservableCollection<MainModel> Data
{
get { return data; }
set { data = value; OnPropertyChanged(); }
}
public ListPageVM()
{
var assembly = typeof(ListPageVM).GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream(Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "eintraege.json"/"SaveUp.Resources.eintraege.json"/));
//var file = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "eintraege.json");
using (var reader = new StreamReader(stream))
{
var json = reader.ReadToEnd();
List<MainModel> dataList = JsonConvert.DeserializeObject<List<MainModel>>(json);
data = new ObservableCollection<MainModel>(dataList);
}
}
MainPageVM (Write Page)
public Command Einfügen
{
get
{
return new Command(() =>
{
// Data ins Json
_mainModels.Add(DModel);
Datum = DateTime.Now.ToString("dd.mm.yyyy");
//var assembly = typeof(ListPageVM).GetTypeInfo().Assembly;
//FileStream stream = new FileStream("SaveUp.Resources.eintraege.json", FileMode.OpenOrCreate, FileAccess.Write);
var file = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "eintraege.json");
//Stream stream = assembly.GetManifestResourceStream("SaveUp.Resources.eintraege.json");
if (!File.Exists(file))
{
File.Create(file);
}
using (var writer = File.AppendText(file))
{
string data = JsonConvert.SerializeObject(_mainModels);
writer.WriteLine(data);
}
});
}
}
you are trying to read and write resources, not files. That won't work. Instead do this
var path = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "eintraege.json");
File.WriteAllText(path, myjson);
to read the data back
var json = File.ReadAllText(path);
In public ScenarioPage() of ScenarioPage.cs I have the following code to read from a json file:
var assembly = typeof(ScenarioPage).GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream("firstSession.json");
using (StreamReader reader = new StreamReader(stream)) // System.ArgumentNullException
{
var json = reader.ReadToEnd();
List<SessionModel> data = JsonConvert.DeserializeObject<List<SessionModel>>(json);
foreach(SessionModel scenario in data)
{
label.Text = scenario.title;
break;
};
}
I am getting an ArgumentNullException for the stream input. firstSession.json is in the same folder as ScenarioPage.cs, and it is set as an embedded resource. It seems like Visual Studio is not recognizing that my json file is there. Is this is a bug? Or is there something wrong with my code?
Where did you put the Json File, I put it in the Json File in the root Of PCL like following screenshot.
Then use following code to read the Json File.
void GetJsonData()
{
string jsonFileName = "firstSession.json";
ContactList ObjContactList = new ContactList();
var assembly = typeof(MainPage).GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{jsonFileName}");
using (var reader = new System.IO.StreamReader(stream))
{
var jsonString = reader.ReadToEnd();
//Converting JSON Array Objects into generic list
ObjContactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
}
EmployeeView.ItemsSource = ObjContactList.contacts;
}
And here is running GIF.
I update my demo to you. you can test it
https://github.com/851265601/Xamarin.Android_ListviewSelect/blob/master/PlayMusicInBack.zip
I have created a Web API service that accepts a POSTed JSON file. With the service, I want to parse the JSON file using JSON.NET. I have seen multiple posts on the subject, however, I don't want to save the file to disk. I want to keep the file in memory, parse the file and dispose of the file in memory.
I'm also using .NET Framework 4.0.
EDIT: I should be more clear. When the file is POSTed, it is a file stream. The part I don't know is how to convert the stream to JSON.
public HttpResponseMessage Post()
{
HttpResponseMessage result = null;
int FileLen;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
string MyString = string.Empty;
var postedFile = httpRequest.Files[0];
FileLen = postedFile.ContentLength;
byte[] input = new byte[FileLen];
System.IO.Stream testStream = postedFile.InputStream;
testStream.Read(input, 0, FileLen);
for (int Loop1 = 0; Loop1 < FileLen; Loop1++)
MyString = MyString + input[Loop1].ToString();
CurrentRate.JSONSerializer(MyString);
}
Since JSON.NET has the ability to deserialize a file (converted to a stream) with the following code:
using (StreamReader file = File.OpenText(#"<pathToFile>"))
{
JsonSerializer serializer = new JsonSerializer();
MyObject myObject = (MyObject)serializer.Deserialize(file, typeof(MyObject));
}
By swapping out the stream from File.OpenText with something similar to the following
using (var stream = new MemoryStream(<FileByteArrayFromMemory>);
using (StreamReader file = new StreamReader(stream))
{
JsonSerializer serializer = new JsonSerializer();
MyObject myObject = (MyObject)serializer.Deserialize(file, typeof(MyObject));
}
we never have to deal with an actual file. There may be a more efficient way to create the MemoryStream or you may already have aStream and could initialize the and could skip that step.
EDIT 2: more explicitly showed swapping the StreamReader
I am using DependencyService in android/ios and windows phone to write and read a XML file in my Xamarin.forms project. I am referring to working with files.
I was able to implement the function given in the example but what I actually want is reading and writing to a XML file.
I followed a usual c# procedure to read and write to xml file but getting errors as the method is async.
I have never used async await methods so not sure how to go about it.
Here is what I tried:
public async Task SaveTextAsync(string filename, string text)
{
ApplicationData data = new ApplicationData();
ApplicationVersion version = new ApplicationVersion();
version.SoftwareVersion = "test";
data.ApplicationVersion = version;
XmlSerializer writer =
new XmlSerializer(typeof(ApplicationData));
System.IO.FileStream file = System.IO.File.Create(path);
writer.Serialize(file, data);
file.Close();
}
public async Task<string> LoadTextAsync(string filename)
{
var path = CreatePathToFile(filename);
ApplicationData cars = null;
XmlSerializer serializer = new XmlSerializer(typeof(ApplicationData));
StreamReader reader = new StreamReader(path);
cars = (ApplicationData)serializer.Deserialize(reader);
reader.Close();
}
string CreatePathToFile(string filename)
{
var docsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
return Path.Combine(docsPath, filename);
}
Edit
Working Read and write to txt file code is here:
public async Task SaveTextAsync (string filename, string text)
{
var path = CreatePathToFile (filename);
using (StreamWriter sw = File.CreateText (path))
await sw.WriteAsync(text);
}
public async Task<string> LoadTextAsync (string filename)
{
var path = CreatePathToFile (filename);
using (StreamReader sr = File.OpenText(path))
return await sr.ReadToEndAsync();
}
I managed to get it work. Here is my code:
public async Task SaveTextAsync(string filename)
{
var path = CreatePathToFile(filename);
ApplicationData data = new ApplicationData();
ApplicationVersion version = new ApplicationVersion();
version.SoftwareVersion = "test version";
data.ApplicationVersion = version;
XmlSerializer writer =
new XmlSerializer(typeof(ApplicationData));
System.IO.FileStream file = System.IO.File.Create(path);
writer.Serialize(file, data);
file.Close();
}
public async Task<ApplicationData> LoadTextAsync(string filename)
{
var path = CreatePathToFile(filename);
ApplicationData records = null;
await Task.Run(() =>
{
// Create an instance of the XmlSerializer specifying type and namespace.
XmlSerializer serializer = new XmlSerializer(typeof(ApplicationData));
// A FileStream is needed to read the XML document.
FileStream fs = new FileStream(path, FileMode.Open);
XmlReader reader = XmlReader.Create(fs);
// Use the Deserialize method to restore the object's state.
records = (ApplicationData)serializer.Deserialize(reader);
fs.Close();
});
return records;
}
I'm trying to receive a file using Web Api from a user and then convert the file into a FileStream without writing the file to a server(Must stay in memory).
I have code that will allow me to write it to the server but all attempts to put it into a FileStream without writing the file to the server have failed.
public class ReceiverController : ApiController
{
public Task<HttpResponseMessage> Upload()
{
HttpRequestMessage request = this.Request;
if (!request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.UnsupportedMediaType));
}
string root = HttpContext.Current.Server.MapPath("~/App_Data/");
var provider = new MultipartFormDataStreamProvider(root);
var task = request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(o =>
{
FileInfo fileInfo = new FileInfo(provider.FileData.First().LocalFileName);
string fileName = provider.FileData.First().Headers.ContentDisposition.FileName.Replace("\"", "");
if (!File.Exists(Path.Combine(root, fileName)))
{
File.Move(fileInfo.FullName, Path.Combine(root, fileName));
}
return new HttpResponseMessage()
{
Content = new StringContent("File uploaded.")
};
});
return task;
}
}
fileName.PostedFile.InputStream --- gives me Stream and I use the following code to convert it to byte array. Then byte array is converted to filestream according to the following code.
BinaryReader br = new BinaryReader(fileName);
bytary= br.ReadBytes((Int32)fileName.Length);
for(int i = 0; i < bytary.Length; i++)
{
fileStream.WriteByte(bytary[i]);
}