New Posts New Posts RSS Feed: Attempting to mock data at *design* time
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Attempting to mock data at *design* time

 Post Reply Post Reply Page  12>
Author
jsobell View Drop Down
Groupie
Groupie
Avatar

Joined: 02-Apr-2009
Location: Australia
Posts: 80
Post Options Post Options   Quote jsobell Quote  Post ReplyReply Direct Link To This Post Topic: Attempting to mock data at *design* time
    Posted: 18-Aug-2010 at 9:53pm
I've just been experimenting to see if I can use saved CacheState data to provide mocking in Blend and VS2010, but have hit an error in the EntityManager constructor.
It fails in Blend when it tries to resolve IdeaBlade.EntityModel.DataSourceResolver.

Has anyone ever managed to get this to work? I've attached the data as a resource, and that is found fine within Blend, but is there any way to fool or force the internal resolver so we can use a 'snapshot' of our live data for Blend development?

Using DF to avoid creating dozens of mock repositories on a large project? Now that would be a coup!
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 19-Aug-2010 at 9:20am
Are you using SL? I found this problem with SL but I believe they were/are addressing it. It's supposed to work under WPF.
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 20-Aug-2010 at 1:21am

We are well on our way to making DevForce play well with Blend. Actually, we probably are THERE. But we haven't documented it well and I don't feel that I'm particularly close to anything worthy of calling a "Best Practice." Let's say I have some "ok" practices :-/

Here's visual evidence of an existence proof: yes, you truly can use a DevForce EntityManager and entities at design time:
 
ComboBox Sample in Blend
 
This example comes from my slight re-design of the "Simple ComboBox in Silverlight" sample code.
 
[Aside: the existing sample is on our web site now. The revised one will be released with our forthcoming "DevForce Cookbook." Look for the Cookbook to arrive within a matter of weeks.]
 
The original point of the sample was to demonstrate how to wire up a ComboBox to DevForce entities AND bind that ComboBox to other DevForce entities.
 
The previous version looked bloody awful; this one just looks bad.
 
However, it's beautiful for the purpose of this forum post!  You can plainly see employee, "Ima", in on the Blend art board. "Ima" does not exist in the Northwind tutorial database. She's a fake Employee, ginned up in a MainPageDesignViewModel that derives from the production MainPageViewModel. The view doesn't know; it's just binding to a ViewModel (VM).
 
All of the fakery happens in the design VM's constructor, shown here:
    public MainPageDesignViewModel() {

      EntityManager = new NorthwindManager(false);
      EntityManager.DefaultQueryStrategy = QueryStrategy.CacheOnly;
      var designEmp = new Employee {
        EmployeeID = 1, FirstName = "Ima", LastName = "Blast", ReportsToEmployeeID = 2,
      };
      var designManagerEmp = new Employee {
        EmployeeID = 2, FirstName = "Slim", LastName = "Ornun", ReportsToEmployeeID = null,
      };
      EntityManager.AttachEntity(designEmp);
      EntityManager.AttachEntity(designManagerEmp);
      PotentialManagers = new List<Employee> { designManagerEmp };
      CurrentEmployee = designEmp;
      Messages.Add("We're in DesignTime now !!!");
    }
The design version of the VM (a) creates two fake employess (Ima and her boss, Slim), (b) creates a disconnected, cache-only EntityManager (EM) - to ensure there is no attempt to talk to the database, and (c) adds the two employees to that EM. Because both fakes are in cache, DevForce can implement the navigation between Ima and Slim via the "Manager" property. I neglected to show this in the ComboBox but you can see it in the message which reads "Ima Blase whose manager is Slim Ornun".
 
It is only a few short hops from here to doing the cache-to-file trick that Jason wants. In fact, I've done what Jason wants on a different project and we'll provide a similar, smaller example in one of the Cookbook recipes .... although perhaps not in the first Cookbook edition. Trust me, it works great.
 
To be precise, it worked great for test runs of your application that you wanted to be fast and free of the need to talk to a database. It didn't work in Blend (although for different reasons than Jason cites).
 
Until DF 2010 v. 6.0.5, it simply wasn't viable to use DF entities in Cider (Visual Studio visual designer) or Blend because we required that the Desktop (aka Web aka "Full DotNet") model carry the same assembly name as the Silverlight model. No problem for the CLR but most tools, including design tools, just choked.
 
Using the same assembly name is no longer required. In fact, is heavily discouraged.
 
Now this ComboBox sample dates from 6.0.2 (I think) ... certainly before we got rid of the assembly name restriction. It did not Blend.
 
All I had to do was some assembly renaming plus clean and re-build. The view popped right up in Cider and Blend.
 
There was no data visualization though. Just a bunch of weird boxes. The XAML looked ok ... obviously it ran ok ... but it made no sense rendered in Cider or Blend.
 
A little dragging around was helpful but I still wanted to see sample data.
 
So I refactored the ViewModel to facilitate a derived, design-time version of that ViewModel and, presto, that's how I was able to get the layout you see in the image above.
 
[While I was at it, I replaced the button click wiring with Blend Behaviors ... and deleted the entire custom code-behind]
 
You can do the same things to your application, or wait for the Cookbook if you want to see the details.
 
As I mentioned, the cache-to-file variation is not far off. That will take some explanation, however, as there are a few places you can stumble on the way ... as Jason discovered.   Please hang in there.
Back to Top
jsobell View Drop Down
Groupie
Groupie
Avatar

Joined: 02-Apr-2009
Location: Australia
Posts: 80
Post Options Post Options   Quote jsobell Quote  Post ReplyReply Direct Link To This Post Posted: 24-Aug-2010 at 12:42am
Hi Ward,
We've been using mocked entities in Blend without any problems, and it's really only the loading of cached data that we're missing. It's a pain creating mock objects, particularly when they involve tree structures :)
I'm looking forward to seeing what's in this cookbook though.
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 24-Aug-2010 at 10:04am
Glad to hear it's working for you. 6.0.4 made a big difference in this regard.
 
Not sure how quickly I can get to the example you want so let me give you some hints.
 
You have to create the cache file from within a Silverlight Client. You'll be working with SILVERLIGHT types in your SL app so you have to populate your cache with the entities defined as the Silverlight types.
 
Here is an  extract from actually working, code-behind of a tiny SL app called KioskTestingDataMaker:
using System;
using System.Windows;
using System.Windows.Controls;
using System.IO;

namespace Kiosk.Testing.DataMaker {
  public partial class MainPage : UserControl {
    public MainPage() {
      InitializeComponent();
    }

    private void HandlePageLoaded(object sender, RoutedEventArgs e) {
      DataMaker = new TestDataMaker();
      DataMaker.ReadyToWrite += EnableSaveButton;
      DataMaker.Build();
    }

    private void EnableSaveButton(object sender, EventArgs args) {
      saveButton.IsEnabled = true;
      statusTB.Text = "Cache data is ready; click SAVE button to save to local file system.";
    }

    private void HandleSaveButtonClick(object sender, RoutedEventArgs e) {
      statusTB.Text = "Save to the file named "+ DataMaker.CacheFileName +
        " in the directory 'Kiosk.Model.Testing.SL'." ;
      OpenSaveFileDialog();
    }

    private bool OpenSaveFileDialog() {

      SaveFileDialog sfd = new SaveFileDialog() {
        DefaultExt = "dat",
        Filter = "Data files (*.dat)|*.dat|All files (*.*)|*.*",
        FilterIndex = 1
      };

      if (sfd.ShowDialog() == true) {
        statusTB.Text = "Saving cache data to " + sfd.SafeFileName +
          " ... please wait for next message ...";
 
        using (Stream stream = sfd.OpenFile()) {
          DataMaker.WriteCacheToStream(stream);
          stream.Close();
        }

        statusTB.Text = "Saved test data to " + sfd.SafeFileName +
          " ... You're done ... close the application.";
        return true;
      }
      statusTB.Text = "You cancelled ... cache data was not saved; you may close the app now." ;
      return false;

    }

    private TestDataMaker DataMaker { getset; }

  }
The XAML that goes with it has a Save button and a TextBlock to show the instructions. Dumb and ugly as it comes.
 
I leave as an exercise for you the implementation of the class called TestDataMaker. It's primary job is to query for the entities you want for your test into its EntityManager.
 
The TestDataMaker app asks the user to identify where the file should be saved. That is because this app is a browser-based and must ask for permission. Were it out-of-browser with elevated permissions, it might do this without asking; I wrote this for SL 3 before elevated trust existed.
 
The next challenge is to find and read the cache to load your test- or design-time EntityManager. I imagine there are many ways to do this. What I did was save the file to one of my Silverlight Testing projects. Everytime I run the DataMaker it replaces that file. Meanwhile, that file has a build action of 'Resource" in the test project. Resources are easy to read in Silverlight so my TestRepository has no trouble streaming in the Resource and loading the test EntityManager.
 
You see the "write" side of this equation in the code above where I ask the user to save the file to a file with the name give by the DataMaker.CacheFileName property (e.g., "TestDataCache.dat"), located in the local file system folder, "Kiosk.Model.Testing.SL".
 
Finally, you have to remember to rebuild the Kiosk.Model.Testing.SL test project so that it incorporates the revised resource file.
 
The whole process is more baroque and manual than I would like. Fortunately, I don't have to re-make the test data very often. I can live with it.
 
Btw, note that the resource file is checked in with the project ... so I've got my test data under source control :-/
 
HTH
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 24-Aug-2010 at 10:10am
@jsobell I invite you to improve this approach and share with the rest of us!
Back to Top
jsobell View Drop Down
Groupie
Groupie
Avatar

Joined: 02-Apr-2009
Location: Australia
Posts: 80
Post Options Post Options   Quote jsobell Quote  Post ReplyReply Direct Link To This Post Posted: 24-Aug-2010 at 6:14pm
Hi Ward,
The generation and inclusion of the mock data in my test follows the same approach as yours, and I also include the mock data as a resource. I don't have any issue with this approach.

The code for restoring the cache is where my experiment fails:
            var xx = new RiskStructureDB();
            xx.DefaultQueryStrategy = QueryStrategy.CacheOnly;
            Stream stream = Application.GetResourceStream(new Uri(@"RiskStructureEditor;component/MockData/mock.bin", UriKind.Relative)).Stream;
            xx.CacheStateManager.RestoreCacheState(stream, RestoreStrategy.Normal, true);


This fails in 6.0.5 with the following exception:

   at IdeaBlade.EntityModel.DataSourceResolver.FindKey(String keyName, String keyExtension)
   at IdeaBlade.EntityModel.DataSourceResolver.BuildRelatedInfo(String dataSourceKeyName, IIdGenerator idGenerator)
   at IdeaBlade.EntityModel.DataSourceResolver.set_DataSourceInfoMap(Dictionary`2 value)
   at ReadDataSourceResolverFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )
   at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
   at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)
   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, DataContract& dataContract)
   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 id, RuntimeTypeHandle declaredTypeHandle, String name, String ns)
   at ReadEntityCacheStateFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )
   at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
   at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)
   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, DataContract& dataContract)
   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)
   at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName)
   at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName)
   at System.Runtime.Serialization.XmlObjectSerializer.ReadObject(XmlDictionaryReader reader)
   at IdeaBlade.EntityModel.SerializationFns.RestoreDCS(Type instanceType, Stream stream, Boolean closeOnExit, IEnumerable`1 knownTypes)
   at IdeaBlade.EntityModel.EntityCacheState.Restore(Stream stream, Boolean closeOnExit)
   at IdeaBlade.EntityModel.CacheStateManager.RestoreCacheState(Stream stream, RestoreStrategy strategy, Boolean closeOnExit)
   at RiskStructureEditor.MainPageModel.LoadCacheState() in C:\Dev\RiskStructure\Silverlight\RiskStructureEditor\RiskStructureEditor\MainPage.model.cs:line 350


This appears to be related to the old issues of the DataSourceResolver serialization etc.
Any suggestions?
Once I get the cache retrieval working I'll happily join you in finding an elegant application of this approach :)
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 25-Aug-2010 at 9:11am
Hmmm .... we will look into this ASAP. The code snippet I gave you USED to work (6.0.3) but I haven't tried it recently. Maybe something happened. Will follow up. Didn't want you to feel lonely meanwhile.
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 25-Aug-2010 at 11:17am

Perhaps you may take some comfort in this: I just ran the code and application from which I took that extract (above). Ran it on the nearly latests 6.0.5 bits ... after deleting old test data file and reconstructing ... and it all works ... on my machine :-)

That doesn't make it work on yours of course. At best it indicates that the process works SOMEWHERE on SOME VERSION of DevForce.
 
Please check again that you are constructing the cache file with a Silverlight application.
 
In early days, I tried to create the cache file with a Desktop client. I got the similar serialization failures. You have to build the cache file in an SL "DataMaker" app referencing the same Silverlight model  that you will consume in your SL production app.
 
You probably are doing exactly what I just said ... but I think it worth emphasizing because it is so easy to miss this distinction and sink into the morass (as I first did months ago).
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 25-Aug-2010 at 11:33am
So ... if you still think you're following the recipe and it still isn't working for you ... even with fresh DF 6.0.5 bits ... maybe you can code a little Northwindexample of what you are doing? That's something we could sink our teeth into. Thx. 
Back to Top
jsobell View Drop Down
Groupie
Groupie
Avatar

Joined: 02-Apr-2009
Location: Australia
Posts: 80
Post Options Post Options   Quote jsobell Quote  Post ReplyReply Direct Link To This Post Posted: 01-Sep-2010 at 12:28am
Sorry, been moving house over the weekend so haven't been coding for a few days...

Not quite sure about this comment:

Hmmm .... we will look into this ASAP. The code snippet I gave you USED to work (6.0.3) but I haven't tried it recently. Maybe something happened. Will follow up. Didn't want you to feel lonely meanwhile.

Which code snippet are you referring to? The snippet you posted only saves the mock data, and there's no problem there; it's recreating the cache in design mode that breaks with internal null reference errors in all the tests I've done.

I'll check out the proper 6.05 when it's online, and see if anything has been magically fixed.

Cheers,
 Jason
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 01-Sep-2010 at 1:31am
Hi Jason - I did look into it ASAP. The kiosk app I demonstrated at DevConnections in April only works because I can save to cache and restore from cache.
 
Now that app did not work in design mode at the time because there were gremlins in VS and Blend and in DevForce that worked against it. I must have missed the "design mode" component of your post. It would help if you said "Blend" a few hundred more times so I wouldn't miss it :-)
 
I haven't had time to see if there are challenges going the next step and working with cached data in a design time VM consumed in Blend (or Cider).
 
I've been living in 6.0.5 for what seems like forever (6 or 7 weeks is "forever" around here) so I'm not sure if the version upgrade will relieve your troubles.
 
If you have something that fails, I'd be happy to check it out. Can you send me a small Northwind example? I'd be much obliged. Otherwise, I'll have to put this off for at least two weeks.
 
p.s.: trust the move went well and you haven't locked yourself out of the house yet.
 
 
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 02-Sep-2010 at 7:54pm
Update: We reproduced your case, found the obstacle to deserializing the cache while in Blend or Cider, and we have a fix. Unfortunately, the obstacle remains in 6.0.5.
 
I'm hoping myself to get an early 6.0.6 to try out the fix. Perhaps you can wait another 6 or 7 weeks for the official 6.0.6 ... although I'll be happy to send you an EAP of 6.0.6 as soon as we feel even slighly comfortable with it.
 
Thanks for driving hard on this issue.  That just makes the product better.
Back to Top
mikedfox View Drop Down
Newbie
Newbie


Joined: 29-Apr-2010
Posts: 21
Post Options Post Options   Quote mikedfox Quote  Post ReplyReply Direct Link To This Post Posted: 02-Dec-2010 at 12:50pm
Ward, this still seems to be broken. I'm adapting your recent clientui example and when I try to add items to my design time data manager using load cache, I get an error in serialization. It says that there are unknown types. At runtime, the same load from cache works.
 
As an alternate, I tried manually creating some sample data, but get an error trying to add entities with an identity key. Its looking for an idgenerator, even though at runtime it works.
 
I have 6.0.6.1
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 02-Dec-2010 at 1:50pm
Mike - I am at Firestarter today so can't look at it this second. I take it you are not creating and attaching entities in code but, rather, trying to import them into the Design Entity Manager cache. I will look at this when I get back.
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 05-Dec-2010 at 10:15am
@Mike - I posted an update to our BookShelf sample application so that it now uses an EntityCacheState for design time data. The zip includes a long document with a chapter on this subject. Find it at http://www.ideablade.com/BookShelfDF/BookShelfDF.zip. I just posted that chapter in my blog.
 
You get that serialization error because DevForce can't find your entity model while in the designers. I don't know yet why we can't find it and I'm going to get to the bottom of that question. Meanwhile, the workaround is simple: tell DevForce where to find your model assembly ... which you do with a line such as follows. You must execute it BEFORE creating any EntityManager:
 
    // Register the model's assembly name among probed assemblies
    // Must be called BEFORE the first EM creation else
    // fails w/ deserialization exception
    IdeaBlade.Core.IdeaBladeConfig.Instance.ProbeAssemblyNames
        .Add(typeof(BookClubEntities).Assembly.FullName);
 
The "BookClubEntities" class happens to be the specialized EntityManager defined in the application model; any class from that model would do for finding the model assembly.


Edited by WardBell - 05-Dec-2010 at 11:25am
Back to Top
 Post Reply Post Reply Page  12>

Forum Jump Forum Permissions View Drop Down