(ZipPackage)myWordDocument

Fun fact: MSOffice 2013+ documents are compressed archives, a.k.a. zip files. They’re built and manipulated using the same System.IO.Packaging namespace that’s used by SQL Server Data Tools to make dacpacs.

Advertisements

Copy an Open Word/Excel File

I had a requirement to disallow saving a file over a certain size. Simple! Wait…how do I find out what size it is without saving it?

Make a copy of the file and check the size of the copy. Wait…I want to check the size of the in-memory edits. Curses! Foiled again.

Luckily, the Excel object model has the answer: Workbook.SaveAsCopy. This method does exactly what I want. So:

  1. Get a temporary file path.
  2. .SaveAsCopy.
  3. Check the size of the copy.
  4. Delete the copy.

And now we copy & paste for Word…which doesn’t have that method.

!

But a Word Document does implement the IPersistFile interface, which implements the Save method, which is the same thing. So cast your Document to IPersistFile and save away.

So now I’ve got all the pieces.

  1. Intercept the save.
  2. Copy the in-memory document.
  3. Check the size.
  4. Delete the copy.
  5. Warn the user that the document is too large.
  6. Don’t save.
  7. Happy dance.

.NET Assembly Binding

99.999% of the time the framework loads assemblies seamlessly and transparently.  The other 0.001% of the time is so painful that it more than makes up for the rest.  One of the more common troublemakers is the Newtonsoft.Json.dll.  There are still Microsoft assemblies (System.Net.Http.Formatting!  Yup, I called you out!) that reference years-old versions of the Newtonsoft assembly.  Any other time you can’t get msbuild to perform indirect reference chaining to save your life, but it does love to look several references back and grab an older version of Newtonsoft.  How does that work?  Why does it do that?

This topic has been covered ad nauseum on many other forums, so I’ll just present a list of references I’ve used.

How the Runtime Locates Assemblies on MSDN.

Redirecting Assembly Versions on MSDN.

Assembly Binding Log Viewer on MSDN.  Also known as the Fusion Log Viewer.  This is your best reference for learning exactly what happened when the framework tried to load your assembly.  The viewer is already installed on your machine if you have Visual Studio installed.  Open the developer command prompt with Admin permissions and type “fuslogvw”.  A lot of the older blogs talk about making changes directly to your registry.  Don’t do that.  Use the utility.

If everything is working properly, including a configured binding redirect, you’ll see something like the image below.

The framework wanted version 6.0, but found a redirect in the config file that told it to use 9.0 instead.

fusionlog

Recently I had an issue that turned out to be malformed XML in the config file.  This manifested as the fusion log showing me that the framework was apparently ignoring the configured redirect.  It can’t do that, so I dug into the XML and discovered the malformation.  The fusion log was invaluable for troubleshooting that issue.

Scott Hanselman has some good tips here.

Some good tips on stackoverflow here and here.

The MSBuild output is always a wealth of information if you dig through it.  In Visual Studio, type “verb” in your Quick Launch to bring up the Build and Run section in the Options dialog.  Change “MSBuild project build output verbosity” to Detailed.  Rebuild your solution and you’ll get plenty of information that will (hopefully) provide some clues as to the path being followed to get to the assembly.


Things to watch out for:

  • Assembly binding redirect configurations.
  • Use the log viewer to be sure the framework is using the config file you think it should be using.

Things to remember:

  • It’s not magic.  It’s not random.  The framework follows a very specific set of steps to determine which assembly to load.  Understanding that process will make you seem like a dark wizard to the muggles.

Handy C# Shortcuts

Rather than walking down an object model validating that each level is not null, like this:

if ((this.MyThing != null) && (this.MyThing.MySubThing != null))
{
    // do stuff
}

You can shortcut with a Null-conditional Operator:

if (this.MyThing?.MySubThing != null)
{
    // do stuff
}

Rather than explicitly checking and initializing a backing variable, like this:

public Thing MyThing
{
    get
    {
        if (_myThing == null)
        {
            _myThing = new Thing();
        }
        return _myThing;
    }
    set { _myThing = value; }
}

You can use a Null-coalescing Operator and make use of the fact that assigning a value to a variable also returns the value:

public Thing MyThing
{
    get { return _myThing ?? (_myThing = new Thing()); }
    set { _myThing = value; }
}

Rather than creating a read-only property without a setter, like this:

public Thing MyOtherThing
{
    get
    {
        return _myOtherThing;
    }
}

You can just use a Lambda Operator to return the backing variable:

public Thing MyOtherThing => _myOtherThing;

Suppressing XAML Debugging Tools

So you know the little black box in your XAML form with links to the debugging tools?  Looks like this:

xaml1

It has links to the Live Visual Tree and the Live Property Explorer, among other things.  They’re useful tools, to be sure, but if I’m not using them, I don’t want to see the little toolbox.  You can minimize it, like this:

xaml2

Now it’s smaller, but it’s still there.  I like a minimalist view of things.  That little black bar annoys me.  It draws the eye.  How to get rid of it?  I asked my friend the internet a few minutes at a time for many days to no avail.  Maybe I wasn’t using the correct search terms.  So I started poking around Visual Studio and I found it here:

xaml3

In retrospect, it seems obvious that it’s in the “Live Visual Tree” tool window (Debug > Windows > Live Visual Tree).  And voila!

xaml4

Aaaaahhhh.  No more little black boxes or bars.  All is right with the world again.

 

Organizing Bookmarks

If your “Bookmarks” window just says Bookmark1, Bookmark2, etc., you’re not getting the full potential out of your bookmarks.

  • You can right-click and change the name of a bookmark.
  • You can create folders to group bookmarks together.
  • You can drag & drop to reorder bookmarks.

Put all these features together, and your bookmarks window is capable of conveying so much more information.  For example, the image below shows me the list of bookmarks, in order, associate with Pasting an A.

bookmarks