YES ITS A BUG! -- Bug Caching Non-DataSet objects in ServerDocument???

Is there a bug with caching objects that are not DataSets in Office 2k3 docs

Although the examples state that anything xml-serializable can be cached using the "Cached()" attribute, I have had no luck trying to cache a simple string in a Word doc. My code in ThisDocument.cs is something like:

public partial class ThisDocument
{
    string id = string.Empty;

    [Microsoft.VisualStudio.Tools.Applications.Runtime.Cached()]
    public string ID
    {
        get { return id; }
        set { id = value; }
    }

 


I used to just have a public string that I left null but when I did that the cacheddataitem (see below) was null. So I set to string.Empty.

On the server side I create a new Doc based on my VSTO Word template and do something like:

using ( ServerDocument serverDoc = new ServerDocument( filename, false ) )
{
    CachedDataHostItem host = serverDoc.CachedData.HostItems["TopicTemplate.ThisDocument"];

    CachedDataItem idItem = host.CachedData["ID"];
    idItem.SerializeDataInstance( id.ToString() );

    serverDoc.Save();
}

 


The server side code is successfully adding these strings to the cache. If I inspect the doc with ServerDocument it shows ID with a value.

However... when I open the doc in word, the ID is null. Also, if I check this.DataHost.IsCacheInitialized it returns false. If I check this.IsCached( "ID" ) I get true!!!

What's going on here Why is my cached string not getting initialized properly on Document Startup

Could it be related to my process of creating the doc on the server using my VSTO Word Template (.dot). I'm currently doing it by instantiating Word and adding a new doc based on my template file:

object objTemplate = strTemplate;
Word.Application app = ...
Word.Document doc = app.Documents.Add(
                ref objTemplate,    //Template
                ref objMissing,        //NewTemplate
                ref objMissing,        //DocumentType
                ref objMissing        //Visible
            );

 





Answer this question

YES ITS A BUG! -- Bug Caching Non-DataSet objects in ServerDocument???

  • Michael Palladino

    I should mention that I can retrieve values from the cache using similar code but with a DataSet...

  • Jens Egil Evensen

    I just wasted most of my day on this bug and I'm just as unimpressed with Microsoft as you were over this one.

    Unfortunately I didn't find your post until I'd already diagnosed the same cause. As soon as one or more of the values in the cache contains a null value, the whole cache is gone.

    I did find a simple workaround in the end, you just need to remove any CachedDataItems from the CachedData collection that you want to take the value null.

    Example below using your sample code:

    [Microsoft.VisualStudio.Tools.Applications.Runtime.Cached()]
    public string Test1;

    [Microsoft.VisualStudio.Tools.Applications.Runtime.Cached()]
    public string Test2;

    using ( ServerDocument serverDoc = new ServerDocument( bytes, "doc.doc" ) ) // fileName, false ) )
    {
    CachedDataHostItem host = serverDoc.CachedData.HostItems["TheSpace.ThisDocument"];

    if (testString1 != null)
    {
    CachedDataItem stringItem = host.CachedData["Test1"];
    stringItem.SerializeDataInstance( testString1 );
    }
    else
    {
    host.CachedData.Remove("Test1");
    }

    if (testString2 != null)
    {
    CachedDataItem stringItem = host.CachedData["Test2"];
    stringItem.SerializeDataInstance( testString2 );
    }
    else
    {
    host.CachedData.Remove("Test2");
    }

    // Save modifications
    serverDoc.Save();
    serverDoc.Close();
    }

    You'll then need to start caching programatically rather than using the Cached attribute, at least on any of the cache items that you may potentially be removing.

                if (!this.IsCached("
    Test1"))
                {
                    StartCaching("
    Test1");
                }
                if (!this.IsCached("
    Test2"))
                {
                    StartCaching("
    Test2");
                }


  • 2232

    I think we are facing a problem related to your post:

    I am trying to cache string data in the document while on the server (ASP.NET page) before sending the document to client through the browser. Here is the code in the document class:

    public partial class ThisDocument

    {

    [Microsoft.VisualStudio.Tools.Applications.Runtime.Cached()]

    public string StringData = string.Empty;

    private void ThisDocument_Startup(object sender, System.EventArgs e)

    {

    //some code goes here

    }

    }

    On the ASPNET page the code opens a word document and tries to inject the string variable:

    protected void Page_Load(object sender, EventArgs e)

    {

    FileStream fs = null;

    ServerDocument sd= null;

    try

    {

    fs = new FileStream(Server.MapPath("OutgoingLetter.doc"), FileMode.Open);

    sd = new ServerDocument(fs, "*.doc");

    CachedDataHostItem dataHostItem = null;

    if (sd.CachedData.HostItems["OutgoingLetter.ThisDocument"] == null) // Added this check cuz without it it was always returning null!!

    {

    dataHostItem = sd.CachedData.HostItems.Add("OutgoingLetter.ThisDocument");

    }

    else

    {

    dataHostItem = sd.CachedData.HostItems["OutgoingLetter.ThisDocument"];

    }

    CachedDataItem cachedItem = null;

    if (dataHostItem.CachedData["StringData"] == null) // Added this check cuz without it it was always returning null!!

    {

    cachedItem = dataHostItem.CachedData.Add("StringData","System.String");

    }

    else

    {

    cachedItem = dataHostItem.CachedData["StringData"];

    }

    string temp = "some secrete to store";

    cachedItem.SerializeDataInstance(temp);

    sd.Save();

    Response.ContentType = "application/msword";

    Response.BinaryWrite(sd.Document);

    }

    catch

    {

    throw;

    }

    finally

    {

    fs.Close();

    }

    When I run the asp page, the server code runs with not errors, till loaded in the browser and VSTO kicks in, the following error occurs:

    Cannot find any public instance member with ID StringData in object OutgoingLetter.ThisDocument.


    ************** Exception Text **************
    Microsoft.VisualStudio.Tools.Applications.Runtime.CannotFindObjectToFillException: Cannot find any public instance member with ID StringData in object OutgoingLetter.ThisDocument.
       at Microsoft.VisualStudio.Tools.Applications.Runtime.AppDomainManagerInternal.AddFromCache(Object viewObject, String dataType, String id, Object value)
       at Microsoft.VisualStudio.Tools.Applications.Runtime.AppDomainManagerInternal.Microsoft.VisualStudio.Tools.Applications.Runtime.ICachedDataProvider.FillCachedData(Object viewObject)
       at OutgoingLetter.ThisDocument.InitializeCachedData()
       at OutgoingLetter.ThisDocument.Initialize()
       at Microsoft.VisualStudio.Tools.Applications.Runtime.AppDomainManagerInternal.CreateStartupObject(EntryPoint entryPoint, Dependency dependency, Assembly objectAssembly)
       at Microsoft.VisualStudio.Tools.Applications.Runtime.AppDomainManagerInternal.ConfigureAppDomain()
       at Microsoft.VisualStudio.Tools.Applications.Runtime.AppDomainManagerInternal.LoadAssembliesAndConfigureAppDomain(IHostServiceProvider serviceProvider)
       at Microsoft.VisualStudio.Tools.Applications.Runtime.AppDomainManagerInternal.ExecuteCustomization(IHostServiceProvider serviceProvider)
    ----------------------------------------


    Apparently the problem starts at InitializeCachedData method and VSTO is unable to locate the string public field!! although it's declared as Public and initialized to emtpy string.

    In your post I've realized that you were able to cache strings as long as you fill them with non-null value, Iand  wish I could reach this point. Am I missing something in the code

    I appreciate any help.



  • JordanS

    Data caching only works with a public field--not with a public property.

    So you have to have a class like this:

    public partial class ThisDocument
    {
      public string id;
    }



  • DCODER

    Shawn,

    Here's code (below) for a sample document that caches successfully:

    1) Create a VSTO Word project and replace the ThisDocument class with the code below.
    2) Build and run the project.
    3) See the "No cached data..." dialog.
    4) Save the document and close it.
    5) Reopen the document (make sure you don't recompile it as this will destroy what you just saved.
    6) See the "Cached data is..." dialog.

    Just to be clear you can cache public read/write non-parameterised properties and public fields. To quote the documentation:

    To be cacheable, a data object must:

    • Be a read/write public field or property, not read-only or write-only.

    • Not be an indexer or other parameterized property.
      Here's all the documentation on data caching.

    Here's the page with all the info: http://msdn2.microsoft.com/library/75akte27(en-US,VS.80).aspx

    Let me know if this helps... Apologies for now getting to this sooner. I suspect your problems are to do with how your document is being created on the server.

    Is caching the only thing that's not working in your sample. For caching to work code has to run on the server. If you put a "Hello World" messagebox in your startup event does this display

    Ade Miller
    Developer, VSTO.


     
        public partial class ThisDocument
        {
            private string _myData;

            [Cached]
            public string myData
            {
                get { return _myData; }
                set { _myData = value; }
            }

            private void ThisDocument_Startup(object sender, System.EventArgs e)
            {
                if (String.IsNullOrEmpty(myData))
                {
                    myData = "Some information";
                    MessageBox.Show("No cached data present");
                }
                else
                {
                    MessageBox.Show(String.Format("Cached data is: \"{0}\"", myData));
                }
            }

            private void ThisDocument_Shutdown(object sender, System.EventArgs e)
            {
            }

            #region VSTO Designer generated code

            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InternalStartup()
            {
                this.Startup += new System.EventHandler(ThisDocument_Startup);
                this.Shutdown += new System.EventHandler(ThisDocument_Shutdown);
            }

            #endregion
        }


     



  • Saurabh11

    Well after coming back to my code almost a month later I FINALLY have the answer. I'm not sure how nobody else has noticed, or commented about this, but I feel it's a pretty nasty bug.

    Situation: I want to write to a Word document's cache so that the FIRST time it's opened in word, the cache is set up and its items are avaiable in ThisDocument.

    Assume you have a string declared in your doc:

            [Microsoft.VisualStudio.Tools.Applications.Runtime.Cached()]
            public string Test;

    Before sending opening in the Word client, I'll add values to the cache like:

                string testString = "Hello World!";

                using ( ServerDocument serverDoc = new ServerDocument( bytes, "doc.doc" ) ) // fileName, false ) )
                {
                    CachedDataHostItem host = serverDoc.CachedData.HostItems["TheSpace.ThisDocument"];

                    CachedDataItem stringItem = host.CachedData["Test"];
                    stringItem.SerializeDataInstance( testString );

                    // Save modifications
                    serverDoc.Save();
                    serverDoc.Close();
                }

    Everything works fine if the string is non-null. BUT, if the string IS NULL, your cache will never work!! Imagine you don't have 1 string, but 10 strings labeled as "cached". If ONE of those strings is null, then the cache is corrupt (or something... ) and you lose all the info you wrote using ServerDocument.

    Another (what I see as a bug) is that if you open a doc using ServerDocument as above, and don't serialize ALL the "cached" members, the same thing will happen... no cache for you!
    For example, if you have the following in your "ThisDocument":

            [Microsoft.VisualStudio.Tools.Applications.Runtime.Cached()]
            public string Test1;

            [Microsoft.VisualStudio.Tools.Applications.Runtime.Cached()]
            public string Test2;

    You need to serialize BOTH data instances (with non-null values) or you're SOL.
    ie.
                using ( ServerDocument serverDoc = new ServerDocument( bytes, "doc.doc" ) ) // fileName, false ) )
                {
                    CachedDataHostItem host = serverDoc.CachedData.HostItems["TheSpace.ThisDocument"];

                    CachedDataItem stringItem = host.CachedData["Test1"];
                    stringItem.SerializeDataInstance( testString1 );

                    CachedDataItem stringItem2 = host.CachedData["Test2"];
                    stringItem2.SerializeDataInstance( testString2 );

                    // Save modifications
                    serverDoc.Save();
                    serverDoc.Close();
                }

    I hope this helps someone, because I really spent A LOT of time trying to track this down.

    Cheers!
    Shawn


  • KMahon

    Hi Shawn.

    I've taken a look at this bug and want to understand your need to store nulls in the cached data. Would it meet your needs to simply store an empty string in this case If not, what's the reason that you'd like to store null values

    Also, are null strings all that you're concerned with Or do you have a scenario where you need to store null for different data types as well

    And thank you for providing exceptional detail on what you had to do to repro the bug. The behavior that is occurring is definitely not something that is easily understood.


  • Allan_Hansen

    No, I don't think storing a null as an empty string is acceptable because in many cases a null should be treated very differently from an empty string. A null means the data is not there, and an empty string means the data is there but happens to be empty.

    Also, strings are not the only thing that I want to store in the docs. If any data type can be serialized, then I'd want null be a valid value for any data type.

    Thanks,
    Shawn

  • Ron Dombrowski

    Thanks for your great feedback. Can you please post this as a bug in the MSDN Product Feedback Center We can then track it and investigate it further. Here is the link:

    < xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />MSDN Product Feedback Center< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

    http://lab.msdn.microsoft.com/productfeedback/

    Thanks so much!

    Mike Hernandez
    Community Program Manager
    VSTO Team


  • DavidATaylor

    Thanks for your reply. Do you happen to have a working version using a public non-DataSet field

    Although my post had properties, I had tried fields too - and have since re-tried, but am afraid it didn't work again. Any thoughts

    Thanks,
    Shawn

  • yestee

    I got the source of the problem. It's in the following line:

    finally

    {

    fs.Close();

    sd.Close(); // Missing :-)

    }

    Now it's caching correctly. Thanks anyway :-)



  • O.Tacke

    Thanks so much for your help. I too suspect my problems arise from the way I'm creating these docs. But I don't know how else to do it. My situation is the following:

    - Create a VSTO Word Template project that has public fields/properties whatever of types Guid, string, and DataSet

    - On a server I need to create a new doc based on the template. So I use App.Documents.Add passing in the path to my VSTO template. (Is there a better way of doing this Preferrably without using word on the server...)

    - Serialize data using ServerDocument. Save it then pass to the client.

    At this point all the data is there on the client!! I wrote a cache inspector and see everything I cached on the server side. Guids, Strings, DataSets all there.

    - Open the document. Break at "ThisDocument_Startup" (or even at InternalStartup) and all the strings are empty (not null), the Guid == Guid.Empty, but the DataSet is a-ok!

    Thanks for your help on this... it's making me go crazy!

    Shawn

  • KTI

    So does anyone on the VSTO dev team care to comment

    This is the "great office server-side feature" we've all been waiting for, but I can't seem to get it to work... and none of the examples on the web use anything but DataSet even though all of them mention that "anything serializable" can be used.

  • YES ITS A BUG! -- Bug Caching Non-DataSet objects in ServerDocument???