Access full page source in WatiN - watin

I am looking for a way to pass my webpages through a DTD validator as part of my WatiN tests, but I haven't found a clean way to access the raw HTML yet. Is there a built-in way to do it?
I think I could access the property IE.InternetExplorer and QueryInterface for the IPersistStreamInit interface and serialize the document to an IStream, but it seems like a lot of work for what I guess must be a fairly common task.
Am I missing something obvious in WatiN? Or can someone think of a better solution than the one I outlined above? That solution is very IE specific after all.

Here is how you access the source code:
browser.ActiveElement.Parent.OuterHtml

string html = browser.Body.Parent.OuterHtml;

There doesn't appear to be a better way. I filed a feature request and submitted a patch at WatiN's sourceforge tracker instead.

Thought to drop some lines to help anyone struggling out there to get the pristine HTML source of a web page via WatiN without, however, patching WatiN - just as a matter of taste.
So capitalizing on Johan Levin's patch I bolted together the following. Be safe and hope you find it useful.
private static TextVariant GetWebPageSource(IE browser)
{
IHTMLDocument2 htmlDocument = ((IEDocument)(browser.DomContainer.NativeDocument)).HtmlDocument;
Encoding encoding = Encoding.GetEncoding(htmlDocument.charset);
IPersistStreamInit persistStream = (IPersistStreamInit)htmlDocument;
MinimalIStream stream = new MinimalIStream();
persistStream.Save(stream, false);
return new TextVariant(encoding.GetString(stream.ToArray()));
}
[Guid("7FD52380-4E07-101B-AE2D-08002B2EC713")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPersistStreamInit
{
void GetClassID(out Guid pClassID);
int IsDirty();
void Load(IStream pStm);
void Save(IStream pStm, bool fClearDirty);
void GetSizeMax(out long pcbSize);
void InitNew();
}
// http://stackoverflow.com/questions/6601355/passing-an-fstream-or-equivalent-from-c-to-c-through-cli
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class MinimalIStream : MemoryStream, IStream
{
public MinimalIStream() { }
public MinimalIStream(byte[] data) : base(data) { }
#region IStream Members
public void Write(byte[] pv, int cb, IntPtr pcbWritten)
{
base.Write(pv, 0, cb);
if (pcbWritten != IntPtr.Zero)
Marshal.WriteInt64(pcbWritten, (long)cb);
}
public void Stat(out STATSTG pstatstg, int grfStatFlag)
{
pstatstg = new STATSTG();
pstatstg.cbSize = base.Length;
}
public void Read(byte[] pv, int cb, IntPtr pcbRead)
{
long bytes_read = base.Read(pv, 0, cb);
if (pcbRead != IntPtr.Zero) Marshal.WriteInt64(pcbRead, bytes_read);
}
public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
{
long pos = base.Seek(dlibMove, (SeekOrigin)dwOrigin);
if (plibNewPosition != IntPtr.Zero) Marshal.WriteInt64(plibNewPosition, pos);
}
public void Clone(out IStream ppstm)
{
ppstm = null;
}
public void Commit(int grfCommitFlags)
{
}
public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
{
}
public void LockRegion(long libOffset, long cb, int dwLockType)
{
}
public void SetSize(long libNewSize)
{
}
public void Revert()
{
}
public void UnlockRegion(long libOffset, long cb, int dwLockType)
{
}
#endregion
}

I found:
browser.ActiveElement.Parent.OuterHtml
will not always get everything, as is dependant on your 'ActiveElement', Therefore:
browser.Body.Parent.OuterHtml
seems to work better. (browser being your instance of IE)
Though I believe Johan Levin is correct in saying the DOM is serialised back to text format.
Therefore would it not be easier to just fetch the document by it's URL (without using WatiN) to validate it.

Related

Problems hooking olesetclipboard

Goal:
While running inside another process (... Say a plugin inside an Office application like Word), intercept the calls to OleSetClipboard/OleGetClipboard and proxy the iDataObject interface by replacing the object originally set/get by the application with one we control, passing on calls to the original object as needed.
Essentially, I would like to control access to the clipboard for a given application.
Progress:
I have successfully hooked the OleSet/GetClipboard functions (as well as others) and can replace the objects with my "proxy" objects. My proxy objects use a .Net definition of IDataObject (System.Runtime.InteropServices.ComTypes.IDataObject).
Note, in this case, I'm using C#, but a similar breakdown happened when I reimplemented in c++.
Problem:
Surprise ... Surprise, the application doesn't function completely normally when I proxy the OleSetClipboard function. Its does just fine when I hook only the OleGetClipboard function side.
I can see my proxied objects on the getter and setter sides calling each other. The breakdown seems to be that when the proxy object on the olegetclipboard side needs to pass thru a getdata call, the olesetclipboard side proxy will throw an exception while trying to execute getdata on the original object that is being proxied on the setter side.
Sudo Example:
Note, this example is not specific to this format. Most/All non text formats fails this way.
I see that the set side calls GetData on the object it is proxying from the original OleSetClipboard call from Word:
Proxy Object (OLESETCLIPBOARD): GetData Called for 15
The structure seems correct:
FORMATETC Structure Info: cfFormat (15) dwAspect (DVASPECT_CONTENT) lindex (-1) ptd (0) tymed (TYMED_HGLOBAL)
But I get an exception:
System.Runtime.InteropServices.COMException:GetData: Message:Invalid
FORMATETC structure (Exception from HRESULT: 0x80040064
(DV_E_FORMATETC))
What may be wrong? What have I not considered? Other thoughts?
Thanks!
Update:
Example class used to proxy ...
public enum DataObjectSource { OLESETCLIPBOARD = 0, OLEGETCLIPBOARD = 1};
public class DataObjectProxy System.Runtime.InteropServices.ComTypes.IDataObject
{
private System.Runtime.InteropServices.ComTypes.IDataObject OriginalClipboardObject;
private DataObjectSource eSource;
public DataObjectProxy(object OriginalObjectToWrap, DataObjectSource eType)
{
this.OriginalClipboardObject = (System.Runtime.InteropServices.ComTypes.IDataObject)OriginalObjectToWrap;
this.eSource = eType;
}
#region Utility Methods
public string GetSingleLineLoggableOutput(FORMATETC FormatToPrint)
{
return $"FORMATETC Structure Info: cfFormat ({(ushort)FormatToPrint.cfFormat} - {GetClipboardFormatName((uint)FormatToPrint.cfFormat)}) dwAspect ({FormatToPrint.dwAspect}) lindex ({FormatToPrint.lindex}) ptd ({FormatToPrint.ptd}) tymed ({FormatToPrint.tymed})";
}
private String GetClipboardFormatName(uint ClipboardFormat)
{
StringBuilder sb = new StringBuilder(1000);
GetClipboardFormatName(ClipboardFormat, sb, sb.Capacity);
return sb.ToString();
}
#endregion Utility Methods
#region pInvokes
[DllImport("user32.dll")]
static extern int GetClipboardFormatName(uint format, [Out] StringBuilder lpszFormatName, int cchMaxCount);
#endregion pInvokes
#region System.Runtime.InteropServices.ComTypes.IDataObject Interface Implemenation
public int DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection)
{
HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): DAdvise Called");
return OriginalClipboardObject.DAdvise(ref pFormatetc, advf, adviseSink, out connection);
}
public void DUnadvise(int connection)
{
HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): DUnadvise Called");
OriginalClipboardObject.DUnadvise(connection);
}
public int EnumDAdvise(out IEnumSTATDATA enumAdvise)
{
HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): EnumDAdvise Called");
return OriginalClipboardObject.EnumDAdvise(out enumAdvise);
}
public IEnumFORMATETC EnumFormatEtc(DATADIR direction)
{
HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): EnumFormatEtc Called");
return OriginalClipboardObject.EnumFormatEtc(direction);
}
public int GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut)
{
HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): GetCanonicalFormatEtc Called");
return OriginalClipboardObject.GetCanonicalFormatEtc(ref formatIn, out formatOut);
}
public void GetData(ref FORMATETC format, out STGMEDIUM medium)
{
try
{
HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): GetData Called for {(ushort)format.cfFormat}");
HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, GetSingleLineLoggableOutput(format));
STGMEDIUM medTemp;
FORMATETC formatTemp = format;
OriginalClipboardObject.GetData(ref formatTemp, out medTemp);
medium = medTemp;
}
catch(Exception getException)
{
HookLogger.LogException(HookLogger.HOOK_CHANNEL, "GetData", getException);
throw;
}
}
public void GetDataHere(ref FORMATETC format, ref STGMEDIUM medium)
{
HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): GetDataHere Called");
OriginalClipboardObject.GetDataHere(ref format, ref medium);
}
public int QueryGetData(ref FORMATETC format)
{
HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): QueryGetData Called");
return OriginalClipboardObject.QueryGetData(ref format);
}
public void SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release)
{
HookLogger.LogDebug(HookLogger.HOOK_CHANNEL, $"Proxy Object ({eSource}): SetData Called");
OriginalClipboardObject.SetData(ref formatIn, ref medium, release);
}
#endregion System.Runtime.InteropServices.ComTypes.IDataObject Interface Implemenation
}

How to use Queue in StackExchange.Redis

I am confused about how to use Queue in StackExchange.Redis.
I have tried download the source code and check the documentation.
I still can not find how to use it.
please give me suggestion.
thanks very much.
Redis supports both queues and stacks through the LPUSH, LPOP, RPUSH and RPOP commands. It is just a matter of calling the right operations on a list. Below are sample implementations of a queue and a stack as a reference. "Connection" in the code below is just an instance of a ConnectionMultiplexer
static class RedisStack
{
public static void Push(RedisKey stackName, RedisValue value)
{
Connection.GetDatabase().ListRightPush(stackName, value);
}
public static RedisValue Pop(RedisKey stackName)
{
return Connection.GetDatabase().ListRightPop(stackName);
}
}
static class RedisQueue
{
public static void Push(RedisKey queueName, RedisValue value)
{
Connection.GetDatabase().ListRightPush(queueName, value);
}
public static RedisValue Pop(RedisKey queueName)
{
return Connection.GetDatabase().ListLeftPop(queueName);
}
}

how do I track metrics in jmeter for 'java requests' with sub results?

I am using jmeter with Java Request samplers. These call java classes I have written which returns a SampleResult object which contains the timing metrics for the use case. SampleResult is a tree and can have child SampleResult objects (SampleResult.addSubResult method). I cant seem to find a good way in jmeter to track the sub results so I can only easily get the results for the parent SampleResult.
Is there a listener in jmeter that allows me to see statistics / graphs for sub results (for instance see the average time across all sub results with the same name).
I have just succeeded in doing this, and wanted to share it. If you follow the instructions I provide here, it will work for you as well. I did this for the summary table listener. And, I did it on Windows. And, I used Eclipse
Steps:
Go to JMeter's web site and download the source code. You can find that here, for version 3.0.
http://jmeter.apache.org/download_jmeter.cgi
One there, I clicked the option to download the Zip file for the Source.
Then, on that same page, download the binary for version 3.0, if you have not already done so. Then, extract that zip file onto your hard drive.
Once you've extracted the zip file to your hard drive, grab the file "SummaryReport.java". It can be found here: "\apache-jmeter-3.0\src\components\org\apache\jmeter\visualizers\SummaryReport.java"
Create a new class in Eclipse, then Copy/Paste all of that code into your new class. Then, rename your class from what it is, "SummaryReport" to a different name. And everywhere in the code, replace "SummaryReport" with the new name of your class.
I am using Java 8. So, there is one line of code that won't compile for me. It's the line below.
private final Map tableRows = new ConcurrentHashMap<>();
You need to remove the <> on that line, as Java 1.8 doesn't support it. Then, it will compile
There was one more line that gave a compile error. It was the one below.
CSVSaveService.saveCSVStats(StatGraphVisualizer.getAllTableData(model, FORMATS),writer,`
saveHeaders.isSelected() ? StatGraphVisualizer.getLabels(COLUMNS) : null);
Firstly, it wasn't finding the source for class StatGraphVisualizer. So, I imported it, as below.
import org.apache.jmeter.visualizers.StatGraphVisualizer;
Secondly, it wasn't finding the method "getLabels" in "StatGraphVisualizer.getLabels." So, here is what this line of code looked like after I fixed it. It is seen below.
CSVSaveService.saveCSVStats(StatGraphVisualizer.getAllTableData(model, FORMATS),writer);
That compiles. That method doesn't need the second argument.
Now, everything should compile.
Find this method below. This is where you will begin adding your customizations.
#Override
public void add(final SampleResult res) {
You need to create an array of all of your sub results, as I did, as seen below. The line in Bold is the new code. (All new code is seen in Bold).
public void add(final SampleResult res) {
final String sampleLabel = res.getSampleLabel(); // useGroupName.isSelected());
**final SampleResult[] theSubResults = res.getSubResults();**
Then, create a String for each label for your sub results objects, as seen below.
**final String writesampleLabel = theSubResults[0].getSampleLabel(); // (useGroupName.isSelected());
final String readsampleLabel = theSubResults[1].getSampleLabel(); // (useGroupName.isSelected());**
Next, go to the method below.
JMeterUtils.runSafe(false, new Runnable() {
#Override
public void run() {
The new code added is below, in Bold.
JMeterUtils.runSafe(false, new Runnable() {
#Override
public void run() {
Calculator row = null;
**Calculator row1 = null;
Calculator row2 = null;**
synchronized (lock) {
row = tableRows.get(sampleLabel);
**row1 = tableRows.get(writesampleLabel);
row2 = tableRows.get(readsampleLabel);**
if (row == null) {
row = new Calculator(sampleLabel);
tableRows.put(row.getLabel(), row);
model.insertRow(row, model.getRowCount() - 1);
}
**if (row1 == null) {
row1 = new Calculator(writesampleLabel);
tableRows.put(row1.getLabel(), row1);
model.insertRow(row1, model.getRowCount() - 1);
}
if (row2 == null) {
row2 = new Calculator(readsampleLabel);
tableRows.put(row2.getLabel(), row2);
model.insertRow(row2, model.getRowCount() - 1);
}**
} // close lock
/*
* Synch is needed because multiple threads can update the counts.
*/
synchronized(row) {
row.addSample(res);
}
**synchronized(row1) {
row1.addSample(theSubResults[0]);
}**
**synchronized(row2) {
row2.addSample(theSubResults[1]);
}**
That is all that needs to be customized.
In Eclipse, export your new class into a Jar file. Then place it inside of the lib/ext folder of your binary of Jmeter that you extracted, from Step 1 above.
Start up Jmeter, as you normally would.
In your Java sampler, add a new Listener. You will now see two "Summary Table" listeners. One of these will be the new one that you have just created. Once you have brought that new one into your Java Sampler, rename it to something unique. Then run your test and look at your new "Summary Table" listener. You will see summary results/stats for all of your sample results.
My next step is to perform these same steps for all of the other Listeners that I would like to customize.
I hope that this post helps.
Here is some of my plugin code which you can use as a starting point in writing your own plugin. I cant really post everything as there are really dozens of classes. Few things to know are:
my plugin like all visualizer plugins extends the jmeter class
AbstractVisualizer
you need the following jars in eclipse to complile:
jfxrt.jar,ApacheJMeter_core.jar
you need java 1.8 for javafx (the jar file comes in the sdk)
if you compile a plugin you need to put that in jmeter/lib/ext.
You also need to put the jars from bullet 2 in jmeter/lib
there is a method called "add(SampleResult)" in my class. This
will get called by the jmeter framework every time a java sample
completes and will pass the SampleResult as a parameter. Assuming you
have your own Java Sample classes that extend
AbstractJavaSamplerClient your class will have a method called
runTest which returns a sampleresult. That same return object will be
passed into your plugins add method.
my plugin puts all the sample results into a buffer and only
updates the screen every 5 results.
Here is the code:
import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.TestStateListener;
import org.apache.jmeter.visualizers.gui.AbstractVisualizer;
public class FxVisualizer extends AbstractVisualizer implements TestStateListener {
int currentId = 0;
/**
*
*/
private static final long serialVersionUID = 1L;
private static final int BUFFER_SIZE = 5;
#Override
public String getName()
{
return super.getName();//"George's sub result viewer.";
}
#Override
public String getStaticLabel()
{
return "Georges FX Visualizer";
}
#Override
public String getComment()
{
return "George wrote this plugin. There are many plugins like it but this one is mine.";
}
static Long initCount = new Long(0);
public FxVisualizer()
{
init();
}
private void init()
{
//LoggingUtil.debug("in FxVisualizer init()");
try
{
FxTestListener.setListener(this);
this.setLayout(new BorderLayout());
Border margin = new EmptyBorder(10, 10, 5, 10);
this.setBorder(margin);
//this.add(makeTitlePanel(), BorderLayout.NORTH);
final JFXPanel fxPanel = new JFXPanel();
add(fxPanel);
//fxPanel.setScene(getScene());
Platform.runLater(new Runnable() {
#Override
public void run() {
initFX(fxPanel);
}
});
}
catch(Exception e)
{
e.printStackTrace();
}
}
static FxVisualizerScene fxScene;
private static void initFX(JFXPanel fxPanel) {
// This method is invoked on the JavaFX thread
fxScene = new FxVisualizerScene();
fxPanel.setScene(fxScene.getScene());
}
final List <Event> bufferedEvents = new ArrayList<Event>();
#Override
public void add(SampleResult result)
{
final List <Event> events = ...;//here you need to take the result.getSubResults() parameter and get all the children events.
final List<Event> eventsToAdd = new ArrayList<Event>();
synchronized(bufferedEvents)
{
for (Event evt : events)
{
bufferedEvents.add(evt);
}
if (bufferedEvents.size() >= BUFFER_SIZE)
{
eventsToAdd.addAll(bufferedEvents);
bufferedEvents.clear();
}
}
if (eventsToAdd.size() > 0)
{
Platform.runLater(new Runnable() {
#Override
public void run() {
updatePanel(eventsToAdd);
}
});
}
}
public void updatePanel(List <Event> events )
{
for (Event evt: events)
{
fxScene.addEvent(evt);
}
}
#Override
public void clearData()
{
synchronized(bufferedEvents)
{
Platform.runLater(new Runnable() {
#Override
public void run() {
bufferedEvents.clear();
fxScene.clearData();
}
});
}
}
#Override
public String getLabelResource() {
return "Georges Java Sub FX Sample Listener";
}
Boolean isRunning = false;
#Override
public void testEnded()
{
final List<Event> eventsToAdd = new ArrayList<Event>();
synchronized(bufferedEvents)
{
eventsToAdd.addAll(bufferedEvents);
bufferedEvents.clear();
}
if (eventsToAdd.size() > 0)
{
Platform.runLater(new Runnable() {
#Override
public void run() {
updatePanel(eventsToAdd);
fxScene.testStopped();
}
});
}
}
Long testCount = new Long(0);
#Override
public void testStarted() {
synchronized(bufferedEvents)
{
Platform.runLater(new Runnable() {
#Override
public void run() {
updatePanel(bufferedEvents);
bufferedEvents.clear();
fxScene.testStarted();
}
});
}
}
#Override
public void testEnded(String arg0)
{
//LoggingUtil.debug("testEnded 2:" + arg0);
testEnded();
}
int registeredCount = 0;
#Override
public void testStarted(String arg0) {
//LoggingUtil.debug("testStarted 2:" + arg0);
testStarted();
}
}
OK so I just decided to write my own jmeter plugin and it is dead simple. Ill share the code for posterity when it is complete. Just write a class that extends AbstractVisualizer, compile it into a jar, then throw it into the jmeter lib/ext directory. That plugin will show up in the listeners section of jmeter when you go to add visualizers.

Moles appears to require moled methods to be hashed

I am trying out Moles on a home project to (hopefully) be able to recommend that it be adopted in projects at work. I am working with VS 10.0.30319 and Moles 1.0.0.0.
I have created the following class:
public class DeveloperTestControlBL
{
public static bool VerifyCurrentDevelopmentStatus(int tpid, int testStatusID)
{
return false; // For this example, always return false,
// so that a return of true means the delegation worked
}
}
In my test class, I have created a test which tests a class which calls the VerifyCurrentDevelopmentStatus method. I would have expected to have a declaration of the form:
[TestMethod]
[HostType("Moles")]
public void TestPreTCIToEditReady_WithMoles()
{
var devTCBL = new SDeveloperTestControlBL();
devTCBL.VerifyCurrentDevelopmentStatus = delegate(int tpid, int testStatusID)
{
return true;
}
// rest of the test here
}
What I have found is that to set the delegate I have to do this:
[TestClass]
public class MyTest
{
[TestMethod]
[HostType("Moles")]
public void TestPreTCIToEditReady_WithMoles()
{
DelegateExample.Moles.MDeveloperTestControlBL.VerifyCurrentDevelopmentStatusInt32Int32 =
VerifyCurrentDevelopmentStatusAlwaysTrue;
// Rest of the test here
}
private bool VerifyCurrentDevelopmentStatusAlwaysTrue(int tpid, int status)
{
return true;
}
Does anyone have any advice as to what I am doing incorrectly? I have the
using Microsoft.Moles.Framework; statement and have a reference to DeveloperTestControlBL.Moles in the test project.
Thanks in advance,
Ron L
Try this
devTCBL.VerifyCurrentDevelopmentStatus (delegate(int tpid, int testStatusID)
{
return true;
});
It worked for me.

Sterling database not persist on Windows phone

I followed sterling database examples from several persons. Neither of them seems to work out for me. When I persist some stuff on my database everything clearly gets persisted using sterling (on my phone, not emulator) when debugging. However when I relaunch my app the database is empty. Is somebody else experiencing the same problem. Or does someone have a complete working example. I know my serializing and saving works... As long as I don't relaunch my app loading my state works...
Code in my app.cs
public static ISterlingDatabaseInstance Database { get; private set; }
private static SterlingEngine _engine;
private static SterlingDefaultLogger _logger;
private void Application_Launching(object sender, LaunchingEventArgs e)
{
ActivateEngine();
}
// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
ActivateEngine();
}
// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
DeactivateEngine();
}
// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
DeactivateEngine();
}
private void ActivateEngine()
{
_engine = new SterlingEngine();
_logger = new SterlingDefaultLogger(SterlingLogLevel.Information);
_engine.Activate();
Database = _engine.SterlingDatabase.RegisterDatabase<SokobanDb>();
}
private void DeactivateEngine()
{
_logger.Detach();
_engine.Dispose();
Database = null;
_engine = null;
}
Code in my viewModel
public void LoadState(int level)
{
var levelState = App.Database.Load<LevelState>(level);
if (levelState != null)
{
//TODO: check if game started, then create board from boardstring property else create new board
//Labyrint = new Labyrint(Factory.CreateBoard());
NewGame(level);
}
else
{
NewGame(level);
}
}
public void SaveState()
{
var levelState = new LevelState { LevelId = _level, Moves = Labyrint.Moves, Board = Labyrint.ToString() };
App.Database.Save(levelState);
App.Database.Flush(); //Required to clean indexes etc.
}
The default Sterling database uses an in-memory driver. To persist, pass it an isolated storage driver. Per the documentation guide quickstart:
https://sites.google.com/site/sterlingdatabase/sterling-user-guide/getting-started
The code looks like this:
_databaseInstance = _engine.SterlingDatabase.RegisterDatabase(new IsolatedStorageDriver());
Note the instance of the isolated storage driver being passed in. That should do it for you.
When in doubt, take a look at the unit tests shipped with the source. Those contain tons of examples of memory, isolated storage, etc. to show various patterns for setting it up.

Resources