I'm developing an app for WP8 using HTML5/JavaScript.
I gather user settings in array variable in JavaScript, and would very much like to save these for future use. And save them in roaming settings to be more precise.
After some research, it seems that this is impossible straight from js. The API calls I found to perform this task in Windows 8 does not work under WP8. So only work-around I can come up is structure:
1) When I want to save data, from js I make
window.external.notify("LaunchSaveProcess");
to send notification to browser.
2) In XAML file
<phone:WebBrowser ScriptNotify="Catch_Script_Notification" />
to deliver notifications from browser to c#
3) In c# catch the notification
private void Catch_Script_Notification(object sender, NotifyEventArgs e)
{ if (e.Value.StartsWith("LaunchSaveProcess")) {
//"important function"
} }
4) The "important function" calls a method in JavaScript, which returns the array of user settings, then proceeds to save the data using
var userSettings = Browser.InvokeScript("getSettings()");
var roamingSettings = Windows.Storage.ApplicationData.Current.RoamingSettings;
roamingSettings.Values["settings"] = userSettings;
Now few questions.
Is this model right, or is there a easier way to do it? Can you pass parameters straight from JavaScript to c# somehow while making notification event?
Can I save array straight into roamingSettings, or do I need to chop it down and save everything separate?
For clarification the usersettings array is 1-dimensional array, where I push objects with "key" and "value" pairs. So I can easily access content within loop using
userSettings[i].key and .value syntax.
Another alternative to calling back into JavaScript from C# is to pass all the data in your notification string in one go.
From your JavaScript side, it is very easy to generate a JSON representation of your data. From the C# side however you would have to declare the DataContract that DataContractJsonSerializer would need to interpret this data, which is a bit more work.
JavaScript helper function which takes in your 1D array of key/value pairs:
function saveUserSettings(valuesToSave) {
var notifyObject = { command: "saveUserSettings", values: valuesToSave };
var notifyObjectString = JSON.stringify(notifyObject);
window.external.notify(notifyObjectString);
}
// call it like this...
saveUserSettings([{ key: "key1", value: "value1" },
{ key: "key2", value: "value2" }]);
C# contracts:
using System.Runtime.Serialization;
[DataContract]
public class JsonScriptData
{
[DataMember(Name = "command")]
public string Command { get; set; }
[DataMember(Name = "values")]
public JsonUserSetting[] Values { get; set; }
}
[DataContract]
public class JsonUserSetting
{
[DataMember(Name = "key")]
public string Key{ get; set; }
[DataMember(Name = "value")]
public object Value { get; set; }
}
and your browser script notify becomes:
private void BrowserOnScriptNotify(object sender, NotifyEventArgs notifyEventArgs)
{
var str = notifyEventArgs.Value;
var serializer = new DataContractJsonSerializer(typeof(JsonScriptData));
var bytes = Encoding.UTF8.GetBytes(str);
JsonScriptData commandData;
using (var memoryStream = new MemoryStream(bytes))
{
commandData = (JsonScriptData)serializer.ReadObject(memoryStream);
}
// save out to application settings dictionary
var applicationSettings = IsolatedStorageSettings.ApplicationSettings;
foreach (var value in commandData.Values)
{
applicationSettings[value.Key] = value.Value;
}
applicationSettings.Save();
}
Of course you could save the whole user settings JSON string from JS as a single value into IsolatedStorageSettings which then means C# wouldn't even need to parse it.
Windows.Storage.ApplicationData.Current.RoamingSettings is not supported on Windows Phone 8, but is supported in Windows Phone 8.1. Instead, you can just use the Isolated Storage.
You can use the Coding4Fun.Toolkit.Storage package from NuGet and simply call Serialize.Save("PATH", objectToSave) to save an item and var result = Serialize.Open<TypeOfObject>("PATH") to get the data back.
NOTE: Starting with the next release of the toolkit, Serialize will be Serializer. Just an FYI.
Related
For development purposes I want to display the database it is connected to since I have 1 for development and 1 for production use. How do I do that using either Javascript, html or c#?
Right now I am connected via c#
protected MysqlDbContext db = new MysqlDbContext();
public class MysqlDbContext: DbContext
{
public MysqlDbContext() : base("MysqlDbContext")
{
}
}
var a = db.Database.Connection.Database.ToString(); //returns me the database name
So how can I access the a from my cshtml file?
This looks like you are using Entity Framework. So I will answer that.
In EF core you can get the connection string like this:
var dbName = MysqlDbContext.Database.GetDbConnection().Database;
in EF for .net framework:
public class MysqlDbContext: DbContext
{
public MysqlDbContext() : base("MysqlDbContext")
{
}
public string GetDatabaseName()
{
return MysqlDbContext.Database.Connection.Database;
}
}
And in your controller you get your context as you normally do and then just access this method.
#{
MysqlDbContext db = new MysqlDbContext();
var dbName = db.Database.Connection.Database.ToString();
}
I figured out that using razor syntax to declare my db context and get the name I was able to display it with <a>#dbName</a>.
I'm using CefSharp to have a webbrowser run angularjs code inside a winforms application.
I am able to send c# objects to the js side and then use them if they only contain strings, ints, and so on. But when I try to send an object containing a list of values in it, CefSharp crashes when it trys to parse it on the js side.
An example of the c# code:
public class TestClass
{
public string name { get; set; }
public string other { get; set; }
public List<int> ints { get; set; }
}
Working obj:
TestClass tc = new TestClass()
{
name = "Bobby Test",
other = "Hello"
};
Obj causing crashes:
TestClass tc = new TestClass()
{
name = "Bobby Test",
other = "Hello",
ints = new List<int>(){0,1}
};
How I pass to the js code:
browser.RegisterJsObject("testObj", tc);
My angular code setting it up for use:
$scope.$watch(function ()
{ return window.testObj },
function () {
$scope.someField = window.testObj;
});
I tried doing a JsonConvert.SerializeObject on the object before passing it but it ended up just being an empty object on the js side.
EDIT - Solution
C# to JS:
Changed TestClass to:
TestClass tc = new TestClass()
{
name = "Bobby Test",
other = "Hello",
ints = new int[] {0,1}
};
And it works correctly with the code above without having to call any serializing or deserializing methods directly.
JS to C#:
Although it wasn't in my question:
I am passing an object to the js side with a callback function to c#, the callback function accepts a serialized string from the js side which I then deserialize on the c# side.
Chromium can only handle javascript simple types (Arrays, Numbers, Strings, etc)
What I normally do on the server side with any complex data is return a JSON string:
JavaScriptSerializer().Serialize(myObject);
And then on the client side reconstitute it using
JSON.parse(myObjectAsString);
Works for me
I've been trying for the past hour and can't get it. At this point my controller looks like
public ActionResult GenerateMasterLink (string assetsJSON)
{
...
}
and I've confirmed that it is being passed a string like
[["Microsoft","Azure","roman_column.png"],["Microsoft","Azure","runphp.cmd"],["Microsoft","Azure","runphp.cmd"],["Microsoft","Azure","Picture1.png"],["Microsoft","Azure","vertical-align-scrnsht.png"],["Microsoft","Azure","vertical-align-scrnsht.png"]]
The only question I have is how I get the damned stuff out of it!
I've tried creating a class
public class ThreePartKey
{
public string organizationName { get; set; }
public string categoryName { get; set; }
public string fileName { get; set; }
}
and then done
ThreePartKey [] assetList = new JavaScriptSerializer().Deserialize<ThreePartKey []>(assetsJSON);
which gives me
Failed to load resource: the server responded with a status of 500
(Internal Server Error)
in my browser's console some of the time, and other times gives me
Additional information: Type
'AllyPortal.Controllers.SurfaceAssetsController+ThreePartKey' is not
supported for deserialization of an array.
as a Visual Studio error.
I've experimented with a million things and can't get this right. All I want is to have the JSON in some C# data structure where I can actually use it in my controller. Any suggestions?
You are trying to deserialize to incompatible model. You string input can be deserialized into string[][] variable but in order to allow deserializations into an ThreePartKey you need to name those values per property:
[[organizationName: "Microsoft",...]]
This will copy right value to your model
The problem is that your target datatype doesn't match the source datatype.
If you are converting an array of array of strings, you must deserialize into another array of array of strings, only them, you'll be able to convert it into whatever you want:
In short, replace
ThreePartKey [] assetList = new JavaScriptSerializer().Deserialize<ThreePartKey []>(assetsJSON);
for
ThreePartKey[] assetList = new JavaScriptSerializer().Deserialize<string[][]>(assetsJSON)
.Select(el => new ThreePartKey() {organizationName = el[0], categoryName = el[1], fileName = el[2]})
.ToArray();
I have created a Web API that will receive Input from Jquery and will use this input to dynamically alter a string that's stored in a resource file.
This String happens to be an almost complete piece of vbscript code that I plan on passing back down to my website.
My problem is that the resource automatically "stringifies" the Code and the output is flooded with escape characters which renders it completly unusable as actual code.
Is there a way to store the code in a way that makes escape strings unneccesary while still enabling me to alter it similiar to "if it were a string" and pass it down to my Website?
The goal is to then use Jquery/Javascript to make this code into an actual vbscript file and let the user download it.
As per request here some Code.
public string GetDeployment(Deployment deployment)
{
string vbs = Resource1.vbs;
vbs = vbs.Replace("%environment%", deployment.SystemKind);
vbs = vbs.Replace("%platform%", deployment.PlatformKind);
vbs = vbs.Replace("%application%", deployment.ApplicationName);
vbs = vbs.Replace("%config", deployment.ConfigInfix ?? "Null");
vbs = vbs.Replace("%subFolder%", deployment.subFolder ?? "Null");
return vbs;
}
This method alters the vbscript depending on the Input. The API itself receives a JSON with Data for all the properties of deployment.
public class DeploymentController : ApiController
{
private DeploymentRepository DeploymentRepository;
public DeploymentController()
{
DeploymentRepository = new DeploymentRepository();
}
[HttpPost]
public string Post([FromBody]Deployment deployment)
{
return DeploymentRepository.GetDeployment(deployment);
}
}
I have the following class on my server:
public class JsonDialog
{
public IEnumerable<string> Errors { set; get; }
public string Modified { set; get; }
public string ModifiedBy { get; set; }
public string PartitionKey { set; get; }
public string PartitionKeyNew { set; get; }
public string RowKey { get; set; }
public string RowKeyNew { get; set; }
public bool Success { set; get; }
}
In my MVC action method I return a JsonResult:
return Json(new JsonDialog
{
Success = false,
Errors = errors
});
In my client code I have the following:
$.ajax({
url: href,
dataType: 'json',
type: 'POST',
data: $form.serializeArray()
})
.done(onDone)
.fail(onFail);
var onDone = function (json, textStatus, XMLHttpRequest) {
json = json || {};
if (json.Success) {
Because I am using a class on the server the compiler checks to ensure I don't make any spelling mistakes and for example it will not allow me to enter "success = false". However on the client there's no checking and I could code json.sUccEss and it would still be okay with that but it would not give me the desired result.
Is there any way in Javascript that I can have some error checking like I have on the server? Anything like getting data into a class and having the IDE check that class fields are correct?
I solve this (partially) by creating a matching object in JS with, what I refer to as a 'factory' method (but that's a misnomer if you're using the term 'factory' as is referred to here. It's really more analogous to 'casting', but since JS doesn't have strong typing, that's not exactly right either.
Obviously, this code pattern is also pretty verbose if all you're doing is trying to get intellisense working, but if you have methods on your JS-side object... we'll fictionally say: JsonResult.prototype.markErrorsReviewed...then this pattern where you get an instance of a given 'class' is helpful.
For the sake of brevity, I'm going to just use your C# class on which to base my JS:
var JsonResult = function () {
this.Errors = [];
this.Modified = null;
this.ModifiedBy = null;
//...rest of your properties, defaulted as necessary
}
JsonResult.factory = function (o) {
var j = new JsonResult();
$.extend(j, o);
//do other processing here if needed (for example, ASP.NET serializes DateTime retardedly)
return j;
}
AJAX:
$.ajax({
success: function(json, status, xhr) {
var myobj = JsonResult.factory(json);
//VS2010 will now give you intellisense w/ proper property names on myobj
//Note: it's still buggy and sometimes won't detect things properly, but it usually works
}
});
May be there could be tools but if you can achieve that following ways:
In the controller you render the partially view instead of json result and pass the class object on that then on that view you have to write the objcetName.PropertyName and it would you check it.
Maybe there are good Text Editors that would help you, but there is no such thing for Javascript.
Editors like TextSublime can fake the code introspection and give an in file search to give help typing the same names.
IDE like Eclipse or Netbeans do a better job but are still really far away from what you want.
Javascript is not a language strongly typed like Java or C# (if we can say that they are...) so you won't find all those candy features you have with VS and C#.
This is what NetBeans does and this is not as advanced as you wish.