Showing posts with label windows phone. Show all posts
Showing posts with label windows phone. Show all posts

Sunday, February 22, 2015

Project is not a WPF project.


For the last year, I've mostly just been maintaining my PAX app by adding the new schedule data and maps for each new PAX event. The last few times I opened it up to do that, I noticed that the design window always showed "Invalid Markup" for my xaml files, and sometimes when I built the project I got a strange avalanche of build errors, including
Error 50 Application is not supported in a Windows Presentation Foundation (WPF) project.
Error 47 Cannot add content to an object of type "ApplicationBar". 
Error 5 Cannot add content to an object of type "PhoneApplicationPage".
....

 
I had no idea how to fix it, or why it was occurring - obviously, my project was not and never had been a WPF project. I made some notes for myself like 'closed Visual Studio, deleted bin and obj files, re-opened, and it was fixed' - then when it happened again, following the same process wouldn't fix it! 

Finally this time, I managed to work it out. These errors occur if I have a *.xaml file open in the editing pane when I run a build. Wow. 100% reproducible, too. At least it's easy to fix...

Thursday, March 27, 2014

app download statistics

Currently, I write my app targeted at windows phone 7.1, which means it runs on all windows phones out there. There are some nice new features in the windows phone 8 sdk, and it seems like a lot of effort to run multiple versions, so I have been thinking about just ditching wp7 and building only for wp8. Before doing that, however, I thought it would be nice to have some actual numbers on what phones are running my app.

I thought I'd have to add this in my own analytics call, but it turns out the Dev Center offers an excel export of your download stats that includes the phone OS Version for each purchaser (along with other info like manufacturer, mobile operator, phone language, and somehow even user gender and age group). So I downloaded that report for the last year and found 

- 140 users with wp7
- 225 users with wp8
- 78 users with unspecified OS versions (not sure how that works)

looks like over a third of my users are still on 7, so I should definitely make sure the app still works for them!

Sunday, January 5, 2014

SQLite woes, cont.


At the end of my last post, I could launch the app and view events, but then got a Null Reference Exception while saving the events into the db. Oddly enough, debugging through the code showed that I was getting a SQLite error code 11 on *every second event*, and then getting a Null Reference Exception after a set of events.The call stack showed:

{System.NullReferenceException: NullReferenceException
   at Community.CsharpSqlite.Sqlite3.sqlite3BtreeClose(Btree& p)
   at Community.CsharpSqlite.Sqlite3.sqlite3_close(sqlite3 db)
   at SQLiteClient.SQLiteConnection.Dispose()
   at PAX7.Utilicode.DBHelper.Close()
   at PAX7.Utilicode.DBHelper.Finalize()}

perhaps I'm calling close twice? I added a breakpoint in the DBHelper.Close() method to check this. I also wrapped the code inside the method in a try-catch-throw to Little Watson block to avoid crashing the app with this exception.

{System.NullReferenceException: NullReferenceException
   at Community.CsharpSqlite.Sqlite3.sqlite3FindIndex(sqlite3 db, String zName, String zDb)
   at Community.CsharpSqlite.Sqlite3.sqlite3StartTable(Parse pParse, Token pName1, Token pName2, Int32 isTemp, Int32 isView, Int32 isVirtual, Int32 noErr)
   at Community.CsharpSqlite.Sqlite3.yy_reduce(yyParser yypParser, Int32 yyruleno)
   at Community.CsharpSqlite.Sqlite3.sqlite3Parser(yyParser yyp, Int32 yymajor, Token yyminor, Parse pParse)
   at Community.CsharpSqlite.Sqlite3.sqlite3RunParser(Parse pParse, String zSql, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3Prepare(sqlite3 db, String zSql, Int32 nBytes, Int32 saveSqlFlag, Vdbe pReprepare, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3LockAndPrepare(sqlite3 db, String zSql, Int32 nBytes, Int32 saveSqlFlag, Vdbe pOld, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3_prepare(sqlite3 db, String zSql, Int32 nBytes, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3_exec(sqlite3 db, String zSql, dxCallback xCallback, Object pArg, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3InitCallback(Object pInit, Int64 argc, Object p2, Object NotUsed)
   at Community.CsharpSqlite.Sqlite3.sqlite3InitOne(sqlite3 db, Int32 iDb, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3Init(sqlite3 db, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3ReadSchema(Parse pParse)
   at Community.CsharpSqlite.Sqlite3.sqlite3LocateTable(Parse pParse, Int32 isView, String zName, String zDbase)
   at Community.CsharpSqlite.Sqlite3.sqlite3SrcListLookup(Parse pParse, SrcList pSrc)
   at Community.CsharpSqlite.Sqlite3.sqlite3Insert(Parse pParse, SrcList pTabList, ExprList pList, Select pSelect, IdList pColumn, Int32 onError)
   at Community.CsharpSqlite.Sqlite3.sqlite3Insert(Parse pParse, SrcList pTabList, ExprList pList, Int32 null_4, IdList pColumn, Int32 onError)
   at Community.CsharpSqlite.Sqlite3.yy_reduce(yyParser yypParser, Int32 yyruleno)
   at Community.CsharpSqlite.Sqlite3.sqlite3Parser(yyParser yyp, Int32 yymajor, Token yyminor, Parse pParse)
   at Community.CsharpSqlite.Sqlite3.sqlite3RunParser(Parse pParse, String zSql, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3Prepare(sqlite3 db, String zSql, Int32 nBytes, Int32 saveSqlFlag, Vdbe pReprepare, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3LockAndPrepare(sqlite3 db, String zSql, Int32 nBytes, Int32 saveSqlFlag, Vdbe pOld, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3_prepare_v2(sqlite3 db, String zSql, Int32 nBytes, Vdbe& ppStmt, Int32 dummy)
   at SQLiteClient.SQLiteCommand.ExecuteNonQuery[T](T toInsert)
   at PAX7.Utilicode.DBHelper.Insert[T](T obj, String statement)
   at PAX7.Model.Schedule.sqlInsertEvent(Event newEvent)}


this one
{System.NullReferenceException: NullReferenceException
   at Community.CsharpSqlite.Sqlite3.DbHasProperty(sqlite3 D, Int32 I, UInt16 P)
   at Community.CsharpSqlite.Sqlite3.sqlite3Init(sqlite3 db, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3ReadSchema(Parse pParse)
   at Community.CsharpSqlite.Sqlite3.sqlite3LocateTable(Parse pParse, Int32 isView, String zName, String zDbase)
   at Community.CsharpSqlite.Sqlite3.sqlite3SrcListLookup(Parse pParse, SrcList pSrc)
   at Community.CsharpSqlite.Sqlite3.sqlite3Insert(Parse pParse, SrcList pTabList, ExprList pList, Select pSelect, IdList pColumn, Int32 onError)
   at Community.CsharpSqlite.Sqlite3.sqlite3Insert(Parse pParse, SrcList pTabList, ExprList pList, Int32 null_4, IdList pColumn, Int32 onError)
   at Community.CsharpSqlite.Sqlite3.yy_reduce(yyParser yypParser, Int32 yyruleno)
   at Community.CsharpSqlite.Sqlite3.sqlite3Parser(yyParser yyp, Int32 yymajor, Token yyminor, Parse pParse)
   at Community.CsharpSqlite.Sqlite3.sqlite3RunParser(Parse pParse, String zSql, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3Prepare(sqlite3 db, String zSql, Int32 nBytes, Int32 saveSqlFlag, Vdbe pReprepare, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3LockAndPrepare(sqlite3 db, String zSql, Int32 nBytes, Int32 saveSqlFlag, Vdbe pOld, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3_prepare_v2(sqlite3 db, String zSql, Int32 nBytes, Vdbe& ppStmt, Int32 dummy)
   at SQLiteClient.SQLiteCommand.ExecuteNonQuery[T](T toInsert)
   at PAX7.Utilicode.DBHelper.Insert[T](T obj, String statement)
   at PAX7.Model.Schedule.sqlInsertEvent(Event newEvent)}


{SQLiteClient.SQLiteException: Unknown error
   at SQLiteClient.SQLiteCommand.ExecuteNonQuery[T](T toInsert)
   at PAX7.Utilicode.DBHelper.Insert[T](T obj, String statement)}

{System.NullReferenceException: NullReferenceException
   at Community.CsharpSqlite.Sqlite3.ENC(sqlite3 db)
   at Community.CsharpSqlite.Sqlite3.sqlite3VdbeExec(Vdbe p)
   at Community.CsharpSqlite.Sqlite3.sqlite3Step(Vdbe p)
   at Community.CsharpSqlite.Sqlite3.sqlite3_step(Vdbe pStmt)
   at Community.CsharpSqlite.Sqlite3.sqlite3_exec(sqlite3 db, String zSql, dxCallback xCallback, Object pArg, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3InitCallback(Object pInit, Int64 argc, Object p2, Object NotUsed)
   at Community.CsharpSqlite.Sqlite3.sqlite3InitOne(sqlite3 db, Int32 iDb, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3Init(sqlite3 db, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3ReadSchema(Parse pParse)
   at Community.CsharpSqlite.Sqlite3.sqlite3LocateTable(Parse pParse, Int32 isView, String zName, String zDbase)
   at Community.CsharpSqlite.Sqlite3.sqlite3SrcListLookup(Parse pParse, SrcList pSrc)
   at Community.CsharpSqlite.Sqlite3.sqlite3Insert(Parse pParse, SrcList pTabList, ExprList pList, Select pSelect, IdList pColumn, Int32 onError)
   at Community.CsharpSqlite.Sqlite3.sqlite3Insert(Parse pParse, SrcList pTabList, ExprList pList, Int32 null_4, IdList pColumn, Int32 onError)
   at Community.CsharpSqlite.Sqlite3.yy_reduce(yyParser yypParser, Int32 yyruleno)
   at Community.CsharpSqlite.Sqlite3.sqlite3Parser(yyParser yyp, Int32 yymajor, Token yyminor, Parse pParse)
   at Community.CsharpSqlite.Sqlite3.sqlite3RunParser(Parse pParse, String zSql, String& pzErrMsg)
   at Community.CsharpSqlite.Sqlite3.sqlite3Prepare(sqlite3 db, String zSql, Int32 nBytes, Int32 saveSqlFlag, Vdbe pReprepare, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3LockAndPrepare(sqlite3 db, String zSql, Int32 nBytes, Int32 saveSqlFlag, Vdbe pOld, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3_prepare_v2(sqlite3 db, String zSql, Int32 nBytes, Vdbe& ppStmt, Int32 dummy)
   at SQLiteClient.SQLiteCommand.ExecuteNonQuery[T](T toInsert)
   at PAX7.Utilicode.DBHelper.Insert[T](T obj, String statement)
   at PAX7.Model.Schedule.sqlInsertEvent(Event newEvent)}



and this, seriously?

{SQLiteClient.SQLiteException: SQL logic error or missing database
   at SQLiteClient.SQLiteCommand.ExecuteNonQuery[T](T toInsert)
   at PAX7.Utilicode.DBHelper.Insert[T](T obj, String statement)}

+        ex    {SQLiteClient.SQLiteException: no such table: events
   at SQLiteClient.SQLiteCommand.ExecuteNonQuery[T](T toInsert)
   at PAX7.Utilicode.DBHelper.Insert[T](T obj, String statement)}    System.Exception {SQLiteClient.SQLiteException}

+        $exception    {System.ObjectDisposedException: Cannot access a closed file.
   at System.IO.__Error.FileNotOpen()
   at System.IO.FileStream.get_Length()
   at System.IO.IsolatedStorage.IsolatedStorageFileStream.get_Length()
   at Community.CsharpSqlite.Sqlite3.sqlite3_fileSize(sqlite3_file id, Int32& pSize)
   at Community.CsharpSqlite.Sqlite3.sqlite3OsFileSize(sqlite3_file id, Int32& pSize)
   at Community.CsharpSqlite.Sqlite3.sqlite3PagerPagecount(Pager pPager, Int32& pnPage)
   at Community.CsharpSqlite.Sqlite3.hasHotJournal(Pager pPager, Int32& pExists)
   at Community.CsharpSqlite.Sqlite3.sqlite3PagerSharedLock(Pager pPager)
   at Community.CsharpSqlite.Sqlite3.lockBtree(BtShared pBt)
   at Community.CsharpSqlite.Sqlite3.sqlite3BtreeBeginTrans(Btree p, Int32 wrflag)
   at Community.CsharpSqlite.Sqlite3.schemaIsValid(Parse pParse)
   at Community.CsharpSqlite.Sqlite3.sqlite3Prepare(sqlite3 db, String zSql, Int32 nBytes, Int32 saveSqlFlag, Vdbe pReprepare, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3LockAndPrepare(sqlite3 db, String zSql, Int32 nBytes, Int32 saveSqlFlag, Vdbe pOld, Vdbe& ppStmt, String& pzTail)
   at Community.CsharpSqlite.Sqlite3.sqlite3_prepare_v2(sqlite3 db, String zSql, Int32 nBytes, Vdbe& ppStmt, Int32 dummy)
   at SQLiteClient.SQLiteCommand.ExecuteNonQuery[T](T toInsert)
   at PAX7.Utilicode.DBHelper.Insert[T](T obj, String statement)
   at PAX7.Model.Schedule.sqlInsertEvent(Event newEvent)}    System.Exception {System.ObjectDisposedException}


while events from all four days are visible on first load, only events on friday are saved back to the database (inspected with isolated storage explorer). It has correctly saved the star and reminder for the event I added to my schedule, however.

Tuesday, December 17, 2013

sharing app data for the live tile


So, the recommended way to share data between the app and the periodic task is by files in the isolated storage - perfect, that was my plan!

BUT, my periodic task project doesn't by default have access to the classes defined in the app - which will make it tricky to read and parse the schedule xml :/ And I can't make it reference that project, because it 'is not supported by a Background Agent'.

Clearly, I need to extract shared functionality to a library of some supported type, and reference it from both projects. I'll need
 - event object definition
 - schedule parser

Basically this is all the bits contained in my Model definition, which makes me feel like I must have structured it in a reasonable way :) Unfortunately, once I moved them, I found that I had a lot of View-related code in there, calling App.Resources, etc, which wouldn't work in a shared library :/ Well, I guess the cleanup required here will make the code better altogether, so it's worth doing!

I used this post as an example to get me started: 
http://www.31a2ba2a-b718-11dc-8314-0800200c9a66.com/2011/11/this-is-continuation-of-this-post.html

Specifically, I have an SQLite db which is instantiated in the App.xaml.cs class, which I can't refer to from my library - and is probably the wrong place anyway. But, the DB seems to use the Assembly name to access it: and isn't the assembly name going to be different between the main app and the background task? There's not much reference on the web, but a couple of people say that it isn't possible to use sqlite in a background task. I was worried that I would have to update my model to use the db for the full list, and back to the flat file for the individual schedule, which would be a shame - but I decided to go ahead with the refactoring and try it - and everything ran! It didn't work, quite - it always said 0 events found - but it managed to instantiate the db connection and run through all the code without panicking, so must be most of the way there.

Unfortunately, I found that the database had starting renaming all events to "1.0" when they were stored. I figured out that this was because I had added a new field to the Event object, which was messing up the Insert statement. Once that was solved, I started hitting exceptions when the scheduled task tried to read the db - I figured that was because the db file was locked, because it was never being closed by the main process. I cleaned up the DBHelper file a little, turning it into a singleton and making sure that every operation which called Open() also called Close(). At this point, I decided should probably create an Interface for the DBHelper, which would make testing easier and also make migration easier if I switch away from SQLite at some point.  I recently started actually trying to use some of Visual Studio's refactoring abilities, so here I did right-click on the class name -> Refactor -> Extract Interface. Then select which of the public methods I wanted in the Interface, and Done! Pretty nice.

Unfortunately, when I ran the app again, the database locking was even worse - even the original app process could never open it, always getting the same error. I decided that I did need a real mutex. I found the outlines in another stack overflow answer and added a check/hold/release mutext everywhere I had the open/close db work. Running with this made it clear that actually, it wasn't a deadlock - even when I turned off the background agent, I was getting 'unable to open database' errors every time. Clearly, the actual problem had been introduced when I updated the DB schema. I could validate with the Isolated Storage Explorer that it was being copied into storage correctly. I stepped through the code and verified that the db was being opened successfully on first contact - but then when it attempted to execute a query, the code tried to open a dbname of "Events.sqlite-journal", which threw a storage exception because it didn't exist.

I followed advice (from Stack Overflow, obvs) to create the journal file back at the start with the actual db file - but still got an error when trying to open it. To narrow down the problem, I tried opening the file straight after creating it - and still got the error. I think I should have been able to figure this out from there, but instead I went and searched to get a list of basic causes for this error - and the very first answer was 'you haven't closed the stream that was returned when you created the file'. Duh, I mean, really. Added a file.Close(), ran the app, everything works! Well, except a Null Reference Exception when I tried to add an event to my schedule, but lots of things worked. Some, at least. More than earlier today.

(this post was written as-it-happened, between december 17 and 26. Very useful for tracking what I had done when I was only doing random half-hours of work!)

Tuesday, October 15, 2013

Phone devs love this one weird trick.


Just came across a really sweet fiddler trick to make life a little simpler for windows phone development: set up an autoresponder rule that serves the FiddlerRoot certificate from a nice short url, to save a little effort in the process of re-installing it every time you restart the emulator.

http://rikk.it/2013/07/capture-windows-phone-8-network-traffic-with-fiddler/