Big JSON stream on Azure - azure

I'm working on a big data export API, but I'm having isssues when it needs to transport big data as JSON. An example of such is a transfer of over 4 milion records. When saved as a textfile, the data is suposed to be about 380MB, but for some reason the stream is cut short to about 250-280MB (always dfferent) and when I check the file in notepad, it did just cut off the data in the middle of a record.
This behaviour is only happening on the Azure server, I can download the full file through my local IIS. Also weird is that when I export the data as XML, which results in an even bigger file of +600MB did not have this issue.
Our Azure app service plan is S3 (4 cores, 7GB memory) which I believe should be enough, the code that actually transfers the data is the following function:
public IActionResult ResponseConvert(IList data)
{
return new Microsoft.AspNetCore.Mvc.JsonResult(data);
}
The data parameter is a List<dynamic> object, containing the +4 milion records.
At first glance it seems like Azure terminates the stream prematurely, any idea why and how this can be prevented?

In the end I've writen my own JsonResult class, that would use a JsonTextWriter to transfer the data. This seems to work fine with larger objects, even on Azure.
Here's the full class:
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Text;
namespace MyProject.OutputFormat
{
public class JsonResult : ActionResult
{
private readonly IList _data;
public Formatting Formatting { get; set; }
public string MimeType { get; set; }
public JsonResult(IList data)
{
_data = data;
// Default values
MimeType = "application/json";
Formatting = Formatting.None;
}
public override void ExecuteResult(ActionContext context)
{
context.HttpContext.Response.ContentType = MimeType;
using (var sw = new StreamWriter(context.HttpContext.Response.Body, Encoding.UTF8))
{
using (var writer = new JsonTextWriter(sw) { Formatting = Formatting })
{
writer.WriteStartArray();
if (_data != null)
{
foreach (var item in _data)
{
writer.WriteStartObject();
if (item is ExpandoObject)
{
foreach (KeyValuePair<string, object> prop in item as ExpandoObject)
{
writer.WritePropertyName(prop.Key);
writer.WriteValue(prop.Value != null ? prop.Value.GetType().Name != "Byte[]" ? prop.Value.ToString() : ((byte[])prop.Value).BinaryToString() : null);
}
}
else
{
var props = item.GetType().GetProperties().Where(i => i.Name != "Item");
foreach (var prop in props)
{
var val = prop.GetValue(item);
writer.WritePropertyName(prop.Name);
writer.WriteValue(val != null ? val.GetType().Name != "Byte[]" ? val.ToString() : ((byte[])val).BinaryToString() : null);
}
}
writer.WriteEndObject();
}
}
writer.WriteEndArray();
}
}
}
}
}
The BinaryToString() method you see is a self written extension on byte[] to convert a byte array to a base64 string.
Small note, though this works for bigger data, the JsonResult in Microsoft.AspNetCore.Mvc downloads faster. Getting the response to the client is as fast, but since this method only converts during download, it takes a bit longer until the stream is fully downloaded. If you do not have any issues in your environment, I'd advise using the one in Microsoft.AspNetCore.Mvc.

Related

UWP apps accessing files from random location on system

in UWP there are files and permissions restrictions, so we can only acces files directly from few folders or we can use filepicker to access from anywhere on system.
how can I use the files picked from filepicker and use them anytime again when the app runs ? tried to use them again by path but it gives permission error. I know about the "futureacceslist" but its limit is 1000 and also it will make the app slow if I am not wrong? .
Is there a better way to do this ? or can we store storage files link somehow in local sqlite database?
If you need to access lots of files, asking the user to select the parent folder and then storing that is probably a better solution (unless you want to store 1,000 individually-picked files from different locations). You can store StorageFolders in the access list as well.
I'm not sure why you think it will make your app slow, but the only real way to know if this will affect your performance is to try it and measure against your goals.
Considering this method..
public async static Task<byte[]> ToByteArray(this StorageFile file)
{
byte[] fileBytes = null;
using (IRandomAccessStreamWithContentType stream = await file.OpenReadAsync())
{
fileBytes = new byte[stream.Size];
using (DataReader reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
reader.ReadBytes(fileBytes);
}
}
return fileBytes;
}
This class..
public class AppFile
{
public string FileName { get; set; }
public byte[] ByteArray { get; set; }
}
And this variable
List<AppFile> _appFiles = new List<AppFile>();
Just..
var fileOpenPicker = new FileOpenPicker();
IReadOnlyList<StorageFile> files = await fileOpenPicker.PickMultipleFilesAsync();
foreach (var file in files)
{
var byteArray = await file.ToByteArray();
_appFiles.Add(new AppFile { FileName = file.DisplayName, ByteArray = byteArray });
}
UPDATE
using Newtonsoft.Json;
using System.Linq;
using Windows.Security.Credentials;
using Windows.Storage;
namespace Your.Namespace
{
public class StateService
{
public void SaveState<T>(string key, T value)
{
var localSettings = ApplicationData.Current.LocalSettings;
localSettings.Values[key] = JsonConvert.SerializeObject(value);
}
public T LoadState<T>(string key)
{
var localSettings = ApplicationData.Current.LocalSettings;
if (localSettings.Values.ContainsKey(key))
return JsonConvert.DeserializeObject<T>(((string) localSettings.Values[key]));
return default(T);
}
public void RemoveState(string key)
{
var localSettings = ApplicationData.Current.LocalSettings;
if (localSettings.Values.ContainsKey(key))
localSettings.Values.Remove((key));
}
public void Clear()
{
ApplicationData.Current.LocalSettings.Values.Clear();
}
}
}
A bit late, but, yes the future access list will slow down your app in that it returns storagfile, storagefolder, or storeageitem objects. These run via the runtime broker which hits a huge performance barrier at about 400 objects regardless of the host capability

Creating a local database in windows phone app 8 using vs2012

I want to develop an app in windows phone 8.
I am totally new to this. I want to create a database for that app from which I can perform CRUID Operations.
I found some information while browsing and watching videos but I did't understand much of it.
Some Steps I did:
Installed windows phone app 8 sdk for vs2012
Added some Sqlite extension from Manage Nuget Packages.
Developed a basic interface for the app.
Copied and pasted the code with few changes
What I want:
Permanently Insert and Fetch data from database (I had downloaded a code from some website but after running it when I close the emulator and try to view the data previously entered, it won't return it)
Like it should be stored in phone memory or any such place
Display the fetched data in listview or grid
Please send me the link that i can go through or any such resembling question asked here
The MainPage.xaml.cs Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using CustomerPhoneApp.Resources;
using SQLite;
using System.IO;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.UI.Popups;
using System.Data.Linq;
using System.Diagnostics;
namespace CustomerPhoneApp
{
public partial class MainPage : PhoneApplicationPage
{
[Table("Users")]
public class User
{
[PrimaryKey, Unique]
public string Name { get; set; }
public string Age { get; set; }
}
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
try
{
var path = ApplicationData.Current.LocalFolder.Path + #"\users.db";
var db = new SQLiteAsyncConnection(path);
await db.CreateTableAsync<User>();
}
catch (Exception)
{
}
}
// Constructor
public MainPage()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
if (txtName.Text != "" && txtAge.Text != "")
{
var path = ApplicationData.Current.LocalFolder.Path + #"\users.db";
var db = new SQLiteAsyncConnection(path);
var data = new User
{
Name = txtName.Text,
Age = txtAge.Text,
};
int x = await db.InsertAsync(data);
}
else
{
MessageBox.Show("enter the title and Notes");
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
RetriveUserSavedData();
}
private async void RetriveUserSavedData()
{
string Result = "";
var path = ApplicationData.Current.LocalFolder.Path + #"\users.db";
var db = new SQLiteAsyncConnection(path);
List<User> allUsers = await db.QueryAsync<User>("Select * From Users");
var count = allUsers.Any() ? allUsers.Count : 0;
foreach (var item in allUsers)
{
Result += "Name: " + item.Name + "\nAge: " + item.Age.ToString() + "\n\n";
}
if (Result.ToString() == "")
{
MessageBox.Show("No Data");
}
else
{
MessageBox.Show(Result.ToString());
}
}
private void txtName_TextChanged(object sender, TextChangedEventArgs e)
{
}
private void txtName_GotFocus(object sender, RoutedEventArgs e)
{
txtName.Text = "";
}
private void txtAge_GotFocus(object sender, RoutedEventArgs e)
{
txtAge.Text = "";
}
}
}
1.-Permanently Insert and Fetch data from database (I had downloaded a code from some website but after running it when I close the emulator and try to view the data previously entered, it won't return it)
When you close the emulator you lost all apps installet on it, so if you close it, you lost all. If you want test your data save, you can close the application (only de app, not the emulator) and open it from your app list in the WP emulator.
Like it should be stored in phone memory or any such place
With SQL lite you canĀ“t store the data in the SD, it will be stored in your app directory, if you want use the SD to store data, you can use binary files
Display the fetched data in listview or grid
To show your data in the listview or grid, you need create a ViewModel or DataContext and then use Binding to "send" the data to de view.

error : is a field but used as a type

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace WindowsFormsApplication5
{
public class ClientContext
{
private string p;
public ClientContext(string p)
{
// TODO: Complete member initialization
this.p = p;
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//First construct client context, the object which will be responsible for
//communication with SharePoint:
private ClientContext context = new ClientContext("#url");
//then get a hold of the list item you want to download, for example
public List list;
public ClientContext
{
list = context.Web.Lists.GetByTitle("001_CFR_DPV_COST_REV_SHARING");
}
//note that data has not been loaded yet. In order to load the data
//you need to tell SharePoint client what you want to download:
context.Load(result, items=>items.Include(
item => item["Title"],
item => item["FileRef"]
));
//now you get the data
context.ExecuteQuery();
//here you have list items, but not their content (files). To download file
//you'll have to do something like this:
var item = items.First();
//get the URL of the file you want:
var fileRef = item["FileRef"];
//get the file contents:
FileInformation fileInfo = File.OpenBinaryDirect(context, fileRef.ToString());
using (var memory = new MemoryStream())
{
byte[] buffer = new byte[1024 * 64];
int nread = 0;
while ((nread = fileInfo.Stream.Read(buffer, 0, buffer.Length)) > 0)
{
memory.Write(buffer, 0, nread);
}
memory.Seek(0, SeekOrigin.Begin);
// ... here you have the contents of your file in memory,
// do whatever you want
}
}
}
this is the complete code.
I don't know why it is showing error. I searched for the error "is a field but used as a type" and I tried that but it didn't help. Please help with a solution Code to this since I am new to this. Thank you in advance.
What are you trying to achieve by this lines of code?
public partial class Form1 : Form
{
...
public ClientContext
{
list = context.Web.Lists.GetByTitle("001_CFR_DPV_COST_REV_SHARING");
}
}
What is public ClientContext {} inside class Form1 ?
It seems that you intended to create constructor to a class in another class and for compiler it looks more like a property but without accessors (get, set) as if it is a Type or smth like this.
Try to put get; set; accessors inside if you intended to create property:
public List Context
{
get
{
list = context.Web.Lists.GetByTitle("001_CFR_DPV_COST_REV_SHARING");
return list;
}
}
Or change it to method instead :
public void GetClientContext()
{
list = context.Web.Lists.GetByTitle("001_CFR_DPV_COST_REV_SHARING");
}

Using RazorEngine with TextWriter

I want to use RazorEngine to generate some html files. It's easy to generate strings first, then write them to files. But if the generated strings are too large, that will cause memory issues.
So I wonder is there a non-cached way to use RazorEngine, like using StreamWriter as its output rather than a string.
I google this for a while, but with no luck.
I think use a custom base template should be the right way, but the documents are so few(even out of date) on the offcial homepage of RazorEngine.
Any hint will be helpful!
OK. I figured it out.
Create a class that inherits TemplateBase<T>, and take a TextWrite parameter in the constructor.
public class TextWriterTemplate<T> : TemplateBase<T>
{
private readonly TextWriter _tw;
public TextWriterTemplate(TextWriter tw)
{
_tw = tw;
}
// override Write and WriteLiteral methods, write text using the TextWriter.
public override void Write(object value)
{
_tw.Write(value);
}
public override void WriteLiteral(string literal)
{
_tw.Write(literal);
}
}
Then use the template as this:
private static void Main(string[] args)
{
using (var sw = new StreamWriter(#"output.txt"))
{
var config = new FluentTemplateServiceConfiguration(c =>
c.WithBaseTemplateType(typeof(TextWriterTemplate<>))
.ActivateUsing(context => (ITemplate)Activator.CreateInstance(context.TemplateType, sw))
);
using (var service = new TemplateService(config))
{
service.Parse("Hello #Model.Name", new {Name = "Waku"}, null, null);
}
}
}
The content of output.txt should be Hello WAKU.

Does ServiceStack support binary responses?

Is there any mechanism in ServiceStack services to return streaming/large binary data? WCF's MTOM support is awkward but effective in returning large amounts of data without text conversion overhead.
I love service stack, this litle code was enough to return an Excel report from memory stream
public class ExcelFileResult : IHasOptions, IStreamWriter
{
private readonly Stream _responseStream;
public IDictionary<string, string> Options { get; private set; }
public ExcelFileResult(Stream responseStream)
{
_responseStream = responseStream;
Options = new Dictionary<string, string> {
{"Content-Type", "application/octet-stream"},
{"Content-Disposition", "attachment; filename=\"report.xls\";"}
};
}
public void WriteTo(Stream responseStream)
{
if (_responseStream == null)
return;
_responseStream.WriteTo(responseStream);
responseStream.Flush();
}
}
From a birds-eye view ServiceStack can return any of:
Any DTO object -> serialized to Response ContentType
HttpResult, HttpError, CompressedResult (IHttpResult) for Customized HTTP response
The following types are not converted and get written directly to the Response Stream:
String
Stream
IStreamWriter
byte[] - with the application/octet-stream Content Type.
Details
In addition to returning plain C# objects, ServiceStack allows you to return any Stream or IStreamWriter (which is a bit more flexible on how you write to the response stream):
public interface IStreamWriter
{
void WriteTo(Stream stream);
}
Both though allow you to write directly to the Response OutputStream without any additional conversion overhead.
If you want to customize the HTTP headers at the sametime you just need to implement IHasOptions where any Dictionary Entry is written to the Response HttpHeaders.
public interface IHasOptions
{
IDictionary<string, string> Options { get; }
}
Further than that, the IHttpResult allows even finer-grain control of the HTTP output where you can supply a custom Http Response status code. You can refer to the implementation of the HttpResult object for a real-world implementation of these above interfaces.
I had a similar requirement which also required me to track progress of the streaming file download. I did it roughly like this:
server-side:
service:
public object Get(FooRequest request)
{
var stream = ...//some Stream
return new StreamedResult(stream);
}
StreamedResult class:
public class StreamedResult : IHasOptions, IStreamWriter
{
public IDictionary<string, string> Options { get; private set; }
Stream _responseStream;
public StreamedResult(Stream responseStream)
{
_responseStream = responseStream;
long length = -1;
try { length = _responseStream.Length; }
catch (NotSupportedException) { }
Options = new Dictionary<string, string>
{
{"Content-Type", "application/octet-stream"},
{ "X-Api-Length", length.ToString() }
};
}
public void WriteTo(Stream responseStream)
{
if (_responseStream == null)
return;
using (_responseStream)
{
_responseStream.WriteTo(responseStream);
responseStream.Flush();
}
}
}
client-side:
string path = Path.GetTempFileName();//in reality, wrap this in try... so as not to leave hanging tmp files
var response = client.Get<HttpWebResponse>("/foo/bar");
long length;
if (!long.TryParse(response.GetResponseHeader("X-Api-Length"), out length))
length = -1;
using (var fs = System.IO.File.OpenWrite(path))
fs.CopyFrom(response.GetResponseStream(), new CopyFromArguments(new ProgressChange((x, y) => { Console.WriteLine(">> {0} {1}".Fmt(x, y)); }), TimeSpan.FromMilliseconds(100), length));
The "CopyFrom" extension method was borrowed directly from the source code file "StreamHelper.cs" in this project here: Copy a Stream with Progress Reporting (Kudos to Henning Dieterichs)
And kudos to mythz and any contributor to ServiceStack. Great project!

Resources