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 ); |

YES ITS A BUG! -- Bug Caching Non-DataSet objects in ServerDocument???
Michael Palladino
Jens Egil Evensen
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{
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{
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!!{
"OutgoingLetter.ThisDocument");}
else{
"OutgoingLetter.ThisDocument"];}
CachedDataItem cachedItem = null; if (dataHostItem.CachedData["StringData"] == null) // Added this check cuz without it it was always returning null!!{
"StringData","System.String");}
else{
"StringData"];}
string temp = "some secrete to store";cachedItem.SerializeDataInstance(temp);
sd.Save();
Response.ContentType =
"application/msword";Response.BinaryWrite(sd.Document);
}
catch{
throw;}
finally{
}
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
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
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
{
}
Now it's caching correctly. Thanks anyway :-)
O.Tacke
- 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
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.