Isolated Storage Application Settings Not Persisting after Application exit - silverlight

I'm having a big problem using WP7 isolated storage and applicationsettings.
I have been using code from Adam Nathan's 101 Windows Phone 7 apps volume 1 as a basis.
I have a settings page where values can be altered and whilst the application is still running these remain active and it all works perfectly. However, as soon as the app exits on my developer phone these are lost and the app restarts with the default settings.
I have no idea why these values are not persisting. Any help would be much appreciated.
Here is the code i've got, its from adam nathan's new book. I sent him a message on twitter and he said its to do with a data type that isn't serializable. I looked into this but i'm only using double and bool values.
public class Setting<T>
{
string name;
T value;
T defaultValue;
bool hasValue;
public Setting(string name, T defaultValue)
{
this.name = name;
this.defaultValue = defaultValue;
}
public T Value
{
get
{
//checked for cached value
if (!this.hasValue)
{
//try to get value from isolated storage
if (IsolatedStorageSettings.ApplicationSettings.TryGetValue(this.name, out this.value))
{
//not set yet
this.value = this.defaultValue;
IsolatedStorageSettings.ApplicationSettings[this.name] = this.value;
}
this.hasValue = true;
}
return this.value;
}
set
{
//save value to isolated storage
IsolatedStorageSettings.ApplicationSettings[this.name] = value;
this.value = value;
this.hasValue = true;
}
}
public T DefaultValue
{
get { return this.defaultValue; }
}
//clear cached value;
public void ForceRefresh()
{
this.hasValue = false;
}
}
Further development:
I receive this error on exiting the application:
A first chance exception of type 'System.IO.IsolatedStorage.IsolatedStorageException' occurred in mscorlib.dll
ERROR FOUND: I'm an idiot and left out one exclamation mark! from the trygetvalue part.

Could you please post your storage code so we could see exactly what's going on? In absense of that code, here's the code I use to save setting to local storage:
IsolatedStorageSettings isoStoreSettings = IsolatedStorageSettings.ApplicationSettings;
if (isoStoreSettings.Contains(key))
{
isoStoreSettings[key] = value;
}
else
{
isoStoreSettings.Add(key, value);
}
isoStoreSettings.Save();
My guess is that you're missing that last line that commits the changes to isolated storage settings to the materialized isolated store instead of just leaving them in memory. If that's not the case, please edit your post with the code so that we can help.

Related

MVC5 DisplayModeProvider registration problems

so I have an mvc 5 application with 3 display modes, desktop (default), mobile, and tablet. I'm using WURFL to figure out devices. Here's the code called from global.cs to register:
public static void RegisterDisplayModes(IList<IDisplayMode> displayModes){
var datafile = HttpContext.Current.Server.MapPath(WurflDataFilePath);
var configurer = new InMemoryConfigurer().MainFile(datafile);
var manager = WURFLManagerBuilder.Build(configurer);
HttpContext.Current.Cache[WURFLMANAGER_CACHE_KEY] = manager;
bool mobileEnabled = ConfigurationManager.AppSettings["EnableMobileSite"] == "true";
bool tabletEnabled = ConfigurationManager.AppSettings["EnableTabletSite"] == "true";
var modeDesktop = new DefaultDisplayMode("") {
ContextCondition = (c => c.Request.IsDesktop())
};
var modeMobile = new DefaultDisplayMode("mobile"){
ContextCondition = (c => c.Request.IsMobile())
};
var modeTablet = new DefaultDisplayMode("tablet"){
ContextCondition = (c => c.Request.IsTablet())
};
displayModes.Clear();
if (mobileEnabled) displayModes.Add(modeMobile);
if (tabletEnabled) displayModes.Add(modeTablet);
displayModes.Add(modeDesktop);
}
I'm using some extension methods to HttpRequestBase, as discussed in http://msdn.microsoft.com/en-us/magazine/dn296507.aspx:
public static bool IsDesktop(this HttpRequestBase request){
return true;
}
public static bool IsMobile(this HttpRequestBase request) {
return IsMobileInternal(request.UserAgent) && !IsForcedDesktop(request);
}
public static bool IsTablet(this HttpRequestBase request) {
return IsTabletInternal(request.UserAgent) && !IsForcedDesktop(request);
}
public static void OverrideBrowser(this HttpRequestBase request, bool forceDesktop){
request.RequestContext.HttpContext.Cache[OVERRIDE_BROWSER_CACHE_KEY] = forceDesktop;
}
public static bool IsForcedDesktop(this HttpRequestBase request){
var isForced = request.RequestContext.HttpContext.Cache[OVERRIDE_BROWSER_CACHE_KEY];
return isForced != null ? isForced.ToString().ToBool() : false;
}
private static bool IsMobileInternal(string userAgent) {
var device = WURFLManagerBuilder.Instance.GetDeviceForRequest(userAgent);
if (device.IsTablet() == true) {
return false;
} else {
return device.IsMobile();
}
}
private static bool IsTabletInternal(string userAgent) {
var device = WURFLManagerBuilder.Instance.GetDeviceForRequest(userAgent);
return device.IsTablet();
}
It all works fine for a while, but then after an hour or so, mobile and tablet devices start displaying the desktop views, and the desktop view starts showing the ViewSwitcher shared view (I assume most people are familiar with it, it just allows you to show the desktop view from a mobile device). It's almost like that caching bug in mvc4. I have tried removing my code to register the display modes, and just went with the default mvc mobile support, and it works fine it has the same issue! So clearly there's a problem in here somewhere... can anyone see anything obvious? Almost impossible to debug cause problems only start coming up after a long time, and even then only on the live system really! Any ideas?
Thanks heaps... been on this issue for way too long now...
Cheers
Andy
EDIT: even stripping it right back to the default implementations creates the issue. I added some debugging code to make sure I'm actually running mvc5, but it appears I am. I've also tried the initially recommended workaround for the issue on mvc4 by disabling the cache, still no joy. Is there really no one with info on this?
So I finally figured it out. Very simple as usual. For some reason I used RequestContext.HttpContext.Cache to save the status when someone wants the full view as opposed to the mobile view. I've never used HttpContext.Cache, I'm pretty sure I would have taken that from a blog somewhere - can't find it anymore though. So all that happened was that it would switch the view for everyone, not just the one person. Can't believe it took weeks to figure that out. Hope it helps someone else at some point.

VB.NET Webbrowser System.UnauthorizedAccessException in Loop

I've had this code working for at least a year and today it threw an exception that i haven't been able to figure out why its happening. Its a Forms.WebBrowser that hits a generic site first and then a secondary site.
'first site
wbr.ScriptErrorsSuppressed = False
wbr.Navigate("http://www.bing.com/?rb=0")
Do
Application.DoEvents()
Loop Until wbr.ReadyState = WebBrowserReadyState.Complete
'second site
wbr.ScriptErrorsSuppressed = True
Dim start As DateTime = DateTime.Now
Dim loopTimeout As TimeSpan = TimeSpan.FromSeconds(timeout)
wbr.Navigate("http://www.FlightAware.com")
Do
Application.DoEvents()
'loop timer
If DateTime.Now.Subtract(start) > loopTimeout Then
'stop browser
wbr.Stop()
'throw exception
Dim eExpTme As Exception = New Exception("A loop timeout occurred in the web request.")
Throw eExpTme
End If
Loop Until wbr.ReadyState = WebBrowserReadyState.Complete
The error happens on the second site access and it shows that it errors on the very last line with
System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
at System.Windows.Forms.UnsafeNativeMethods.IHTMLLocation.GetHref()
at System.Windows.Forms.WebBrowser.get_Document()
at System.Windows.Forms.WebBrowser.get_ReadyState()
I just don't get why its errorring on the second site and not the first and what exactly that error message means. I've looked at some help forums but nothing concrete that i can use to troubleshoot.
AGP
The web site has a frame on ad.doubleclick.net, by default cross-domain frame access is disabled for the internet zone, so you get a security exception.
Catch the exception and move on. There isn't much you need to care about in the frame, doubleclick is an ad service.
You can implement IInternetSecurityManager and let IE to believe ad.doubleclick.net and FlightAware.com are the same web site, but this can cause security problem if you extend the trust to arbitrary web sites.
Here is a little hack in C# which you can convert in Vb.net:
public class CrossFrameIE
{
// Returns null in case of failure.
public static IHTMLDocument2 GetDocumentFromWindow(IHTMLWindow2 htmlWindow)
{
if (htmlWindow == null)
{
return null;
}
// First try the usual way to get the document.
try
{
IHTMLDocument2 doc = htmlWindow.document;
return doc;
}
catch (COMException comEx)
{
// I think COMException won't be ever fired but just to be sure ...
if (comEx.ErrorCode != E_ACCESSDENIED)
{
return null;
}
}
catch (System.UnauthorizedAccessException)
{
}
catch
{
// Any other error.
return null;
}
// At this point the error was E_ACCESSDENIED because the frame contains a document from another domain.
// IE tries to prevent a cross frame scripting security issue.
try
{
// Convert IHTMLWindow2 to IWebBrowser2 using IServiceProvider.
IServiceProvider sp = (IServiceProvider)htmlWindow;
// Use IServiceProvider.QueryService to get IWebBrowser2 object.
Object brws = null;
sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out brws);
// Get the document from IWebBrowser2.
IWebBrowser2 browser = (IWebBrowser2)(brws);
return (IHTMLDocument2)browser.Document;
}
catch
{
}
return null;
}
private const int E_ACCESSDENIED = unchecked((int)0x80070005L);
private static Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
private static Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E");
}
// This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface!
[ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
}

System.Printing.PrintQueue QueueStatus not updating

Is there a way to update the print queue status information contained in the PrintQueue object?
I've tried calling Refresh on the PrintQueue object but that doesn't really do anything. For instance, I've turned off the printer and the Control Panel correctly shows the printer as "Offline", however the QueueStatus property, as well as the IsOffline property don't reflect that - no matter how many times I call Refresh on both the PrintServer and the PrintQueue in question.
I've seen examples of how to get status information using WMI queries but I wonder - since these properties are available on the PrintQueue object - whether there is any way to use those.
After try to print your PrintDocument (System.Drawing.Printing), try to check status of printjobs.
First step:
Initialize your printDocument.
Second step:
Get your printer Name From System.Drawing.Printing.PrinterSettings.InstalledPrinters.Cast<string>();
And copy it into your printerDocument.PrinterSettings.PrinterName
Third step:
Try to print and dispose.
printerDocument.Print();
printerDocument.Dispose();
Last step: Run the check in a Task (do NOT block UI thread).
Task.Run(()=>{
if (!IsPrinterOk(printerDocument.PrinterSettings.PrinterName,checkTimeInMillisec))
{
// failed printing, do something...
}
});
Here is the implementation:
private bool IsPrinterOk(string name,int checkTimeInMillisec)
{
System.Collections.IList value = null;
do
{
//checkTimeInMillisec should be between 2000 and 5000
System.Threading.Thread.Sleep(checkTimeInMillisec);
using (System.Management.ManagementObjectSearcher searcher = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_PrintJob WHERE Name like '%" + name + "%'"))
{
value = null;
if (searcher.Get().Count == 0) // Number of pending document.
return true; // return because we haven't got any pending document.
else
{
foreach (System.Management.ManagementObject printer in searcher.Get())
{
value = printer.Properties.Cast<System.Management.PropertyData>().Where(p => p.Name.Equals("Status")).Select(p => p.Value).ToList();
break;
}
}
}
}
while (value.Contains("Printing") || value.Contains("UNKNOWN") || value.Contains("OK"));
return value.Contains("Error") ? false : true;
}
Good luck.

'Invalid attempt to read when no data is present' - exception happens "sometimes" in Entity Framework

I get the above error sometimes during the read. The exception originates from ASP.NET SqlDataReader whenever you try to read data before calling the Read() method. Since EF does all these internally, I am wondering what else can cause this error. could it be network (or) db connectivity?
thanks
Additional Bounty Info (GenericTypeTea):
I've got the same error after upgrading to EF Code First RC (4.1):
"Invalid attempt to read when no data
is present"
This is the code in question:
using (var context = GetContext())
{
var query = from item in context.Preferences
where item.UserName == userName
where item.PrefName == "TreeState"
select item;
// Error on this line
Preference entity = query.FirstOrDefault();
return entity == null ? null : entity.Value;
}
The table structure is as follows:
Preference
{
Username [varchar(50)]
PrefName [varchar(50)]
Value [varchar(max)] Nullable
}
The table is standalone and has no relationships. This is the DbModelBuilder code:
private void ConfigurePreference(DbModelBuilder builder)
{
builder.Entity<Preference>().HasKey(x => new { x.UserName, x.PrefName });
builder.Entity<Preference>().ToTable("RP_Preference");
}
Exactly the same code works perfectly in CTP5. I'm guessing this is an RC bug, but any ideas of how to fix it would be appreciated.
This error occurs when there is a large amount of data in the RC release. The difference between the RC and CTP5 is that you need to specify the [MaxLength] property that contains a large amount of data.
Are you re-using contexts? I would guess this is happening as a result of something you are doing within GetContext
If GetContext() provides a stale context, in which the DataReader is closed/corrupted, I could see the above happening.
I cannot reproduce your problem on EF4.1 RC1.
POCO:
public class Preference
{
public string UserName { get; set; }
public string PrefName { get; set; }
public string Value { get; set; }
}
Context:
public class PreferenceContext : DbContext
{
public DbSet<Preference> Preferences {get;set;}
public PreferenceContext()
: base("Data Source=localhost;Initial Catalog=_so_question_ef41_rc;Integrated Security=SSPI;") {
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
ConfigurePreference(modelBuilder);
base.OnModelCreating(modelBuilder);
}
private void ConfigurePreference(DbModelBuilder builder)
{
builder.Entity<Preference>().HasKey(x => new { x.UserName, x.PrefName });
builder.Entity<Preference>().ToTable("RP_Preference");
}
}
My little Console App:
class Program
{
static void Main(string[] args)
{
string userName = "Anon";
for (int i = 0; i < 10000; i++)
{
var p = GetPreference(userName);
}
}
private static string GetPreference(string userName)
{
using (var context = new PreferenceContext())
{
var query = from item in context.Preferences
where item.UserName == userName
where item.PrefName == "TreeState"
select item;
// Error on this line
Preference entity = query.FirstOrDefault();
return entity == null ? null : entity.Value;
}
}
}
I do 10,000 reads, and no error. You will need to post more complete code to continue.
Increase the CommandTimeout on the context.
I had the same issue with EF4 - In my case I was (trying to) return the list of entities within the using{} section. This is the same as you are doing in your question:
return entity == null ? null : entity.Value;
} // end using
I moved the return to after the } and it worked.
I think I had the problem because the code was in a function which had already queried the database in another using block, I suspect the table was locking but not reporting the error, ending the using block before the return released the database lock.
Steve

Best way of designing the flow of code when reading/writing from database

So I'm trying out a concept tool of mine where I need to be able to read and write data from a database real easy. I've set up the form as I like and spread around different text boxes and dropdownboxes to read the data from the database. And I've got it all to work and all, but there's a small bug I don't fully understand why's there. Some textboxes don't update the text from the database. But it seems as it only occurs if the data in the database is nothing. So the value from the last row is still hanging in the textbox and thus, clicking "Update" actually updates the value from the field from the last row, into the new row. Messing everything up.
Now, what I'm the most interested in is the shear flow of the code. What's the best way of laying out the code to do all this? So far I've got this:
This is the code when clicking on a cell in the datagridview:
Private Sub DataGridView_CellClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView.CellClick
On Error Resume Next
selectedName = Me.DataGridView.CurrentRow.Cells(0).Value
selectedGenre = Me.DataGridView.CurrentRow.Cells(1).Value
selectedRhytm = Me.DataGridView.CurrentRow.Cells(2).Value
selectedLength = Me.DataGridView.CurrentRow.Cells(3).Value
selectedFinished = Me.DataGridView.CurrentRow.Cells(4).Value
selectedSoundFile = Me.DataGridView.CurrentRow.Cells(5).Value
txtBoxName.Text = selectedName
txtBoxGenre.Text = selectedGenre
txtBoxRhytm.Text = selectedRhytm
txtBoxLength.Text = selectedLength
txtBoxFinished.Text = selectedFinished
txtBoxSoundFile.Text = selectedSoundFile
End Sub
The "selected"-variables are all declared in a GlobalCode.vb I've got where I create all of them for use later. They are defined like this:
Friend Module GlobalVariables
Friend selectedName As String = Nothing
Friend selectedGenre As String = Nothing
Friend selectedRhytm As String = Nothing
Friend selectedLength As String = Nothing
Friend selectedFinished As String = Nothing
Friend selectedSoundFile As String = Nothing
End Module
I haven't really done anything like this before. I'm more of a designer rather than programmer, but I really need to try out a concept so I'm not sure this is the way of doing this at all. I've found that it works, most of the times. But I reckon skilled programmers have a way of designing the layout of the code so it's efficient, clean and easy to read.
So how does this look?
(I can't see anything database related in the question, btw)
Perhaps the best way of laying out this code is... not to. Don't write code for things that the standard data-binding frameworks can handle. For example (sorry it is C#, but it should translate - all of the "good" bits here are provided by the .NET framework, not the language); some UI code - note no code to copy values:
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
// some sample data
BindingList<Track> tracks = new BindingList<Track>();
tracks.Add(new Track { Name = "foo", Genre = "Rock", Rhythm = "insane", Length = 180 });
tracks.Add(new Track { Name = "bar", Genre = "Classic", Rhythm = "sedate", Length = 240 });
// show the data on a form
using (Form form = new Form {
Controls = {
new DataGridView { DataSource = tracks, Dock = DockStyle.Fill },
new TextBox { DataBindings = {{"Text", tracks, "Name"}}, Dock = DockStyle.Bottom},
new TextBox { DataBindings = {{"Text", tracks, "Genre"}}, Dock = DockStyle.Bottom},
new TextBox { DataBindings = {{"Text", tracks, "Rhythm"}}, Dock = DockStyle.Bottom},
new TextBox { DataBindings = {{"Text", tracks, "Length"}}, Dock = DockStyle.Bottom},
}
}) {
Application.Run(form);
}
}
}
With supporting data entity:
class Track : INotifyPropertyChanged {
private string name, genre, rhythm;
private int length;
public event PropertyChangedEventHandler PropertyChanged;
private void SetField<T>(ref T field, T value, string propertyName) {
if (!EqualityComparer<T>.Default.Equals(field, value)) {
field = value;
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public string Name { get { return name; } set { SetField(ref name, value, "Name"); } }
public string Genre { get { return genre; } set { SetField(ref genre, value, "Genre"); } }
public string Rhythm { get { return rhythm; } set { SetField(ref rhythm, value, "Rhythm"); } }
public int Length { get { return length; } set { SetField(ref length, value, "Length"); } }
}
Try commenting out On Error Resume Next for a bit and seeing what happens. I've managed to confuse myself more times than I can count with that statement.
EDIT
I just realized this is VB.Net. You shouldn't ever be using On Error Resume Next in this case. Use Try Catch structures.

Resources