July, 2006

  • Cloudy in Seattle

    Licensing in Cider

    • 5 Comments

    We're just finishing up the implementation of licensing in Cider, I'll let you know when it will be visible in a CTP. 

    What we did was implement the System.ComponentModel Licensing that was also used in Windows Forms.  Our feedback was that this is a sufficient model -- yeah it isn't great but it works and circumventing that licensing is sufficient to show intent.

    So how does licensing work in a nutshell?  In essence, it's as simple as follows:

    1. A control developer creates a licensed control. A control, a LicenseProvider and a license file. (potentially creates a derived License)
    2. An application developer instantiates this licensed control at design time by drag dropping the control from the toolbox onto the design surface.
    3. The LicenseProvider reads the license file and parses it to ensure the contents are valid.  Note that different features/capabilities can be encoded into the license file.
    4. If the license file is valid, the control will be created and a licx file added to the project.  If it isn't, control cannot be instantiated on the design surface -- this happen every time the control is drag dropped onto the design surface. 
    5. At compile time, the LC.exe tool will run and based on the licx file, add licensing data into the assembly using the licensed control.
    6. At runtime, the LicenseProvider gets the licensing data that was embedded into the assembly using the control and performs a runtime license check.
    7. If the runtime license check fails an exception will be thrown from the constructor of the licensed control.

    We provide a default implementation of the LicenseProvider called the LicFileLicenseProvider.  It is very simple, the license file is a file with a string that corresponds to:  "<type.FullName> is a licensed component.".  That is the license key.

    When a control that uses the LicFileLicenseProvider is instantiated at design time, a lic file with the aforementioned license key is checked.  At build time, that license key is embedded in the assembly (this is determined by the call to LicenseContext.SetSavedLicenseKey that the LicenseProvider makes) and at runtime when the control is instantiated, the license key is extracted from the calling assembly and verfiied by the LicFileLicenseProvider.

    There are a couple of good resources out there to fill in the gaps if you want to add licensing to your control.  Check out:

    http://windowsforms.net/articles/licensing.aspx

    http://www.myagent.dk/2005/02/net_licensing.html

    License Initialization and Cleanup in Cider
    In WPF, there isn't a concept of IDisposable so cleaning up the License in Dispose() won't work.  Additionally, there are situations where a control can be unloaded and reloaded multiple times.  So for licensing in WPF, the following pattern is recommended for calling LicenseManager.Validate() and License.Dispose():

    [LicenseProvider(typeof(JimsLicenseProvider))]
    public class CustomLicensedButton : Button
    {
       
    private License license = null;
       
    public CustomLicensedButton()
        {
            ValidateLicense();
           
    this.Loaded += new System.Windows.RoutedEventHandler(CustomLicensedButton_Loaded);
           
    this.Unloaded += new System.Windows.RoutedEventHandler(CustomLicensedButton_Unloaded);
       
    }

        void CustomLicensedButton_Unloaded(object sender, System.Windows.RoutedEventArgs e)
       
    {
           
    CleanupLicense();
       
    }

        void CustomLicensedButton_Loaded(object sender, System.Windows.RoutedEventArgs e)
       
    {
           
    ValidateLicense();
       
    }

        private void ValidateLicense()
       
    {
           
    if (license == null)
           
    {
                
    license = LicenseManager.Validate(typeof(CustomLicensedButton), this);
           
    }
       
    }

        private void CleanupLicense()
       
    {
           
    if (license != null)
           
    {
                
    license.Dispose();
                
    license = null;
           
    }
       
    }
    }

    Adding Licensed Controls Through XAML
    In this case, if the control is licensed but does not have a valid license file, the designer will not show the UI (Window, Page, UserControl etc) where it is being used, instead it will show a message indicating that the control could not be instantiated.

    If the license file is valid, the control will work but the licx file will not be added/updated based on the addition of a licensed control.  If the licx file does not contain the type for your control, the license key will not be embedded into the assembly using that control and the runtime license check will fail.

    The workaround is to drag drop a control from the toolbox onto any Windows, Page, UserControl etc. as the licx file is created/updated per project.  Alternatively, you can create the licx file by hand.

    Writing the Licx File
    The other difference between Windows Forms and Cider is that in Cider we don't re-write the licx file if has been modified by hand.  In VS 2005, you could delete a type key from the licx file and when the designer reloaded the UI it would ensure all of the keys for the licensed control used on that UI were in the licx.  This is no longer the case, the licx file is only created/updated when a control is drag dropped from the toolbox onto the designer surface.

    Partial Trust
    There is a bug in the current implementation that our Control Developer customers lamented at the last dev lab.  The bug is that licensing doesn't work in partial trust.  To give you an update, a bug has been filed on this and the initial prognosis is good although this is not something that is handled by the Cider team.

  • Cloudy in Seattle

    Shared Bytes, Private Bytes and Fixups

    • 0 Comments

    This post is actually a re-post of a post I did a little under year ago during PDC '05 after attending a talk by Rico Mariani and chatting with him afterwards.  The original post is here.

    The reason I thought to re-post this is I was talking to a couple of fellow Cider-tonions about some perf analysis work that was being done and I figured it would be a useful thing to share.  Here it is:

    Shared Bytes vs Private Bytes
    A shared byte is one that can be shared across multiple processes. A private byte cannot. So what bytes qualify as shareable? Unaltered pages of a dll where the backing file for that dll is not the page file but the dll itself.

    Anytime a page of code or data from a dll needs to change for a particular process, it is marked dirty and becomes private. This can occur on pages that have references to objects on the heap, pages that have code offsets that get modified after load time, or on pages in the data segment that change.

    A quick way to have almost all of your dll marked private is to have it rebased during load time.

    This concept mainly applies to NGEN'd images as non-NGEN'd images mainly consist of IL that will be JIT compiled on the loader heap and therefore will all be private. The IL is shared, but it is discarded after JIT anyhow. [addition: if a non-NGEN'd assembly gets rebased, the whole assembly will still be loaded and checked for fixups which can be a performance hit]

    It's important to realize that the benefit of shared bytes are just that: that they can be shared across multiple processes and their cost can be amortized across the number of processes using those bytes. For assemblies like the .Net Framework assemblies, having shared bytes is a clear benefit. That said, in non-sharing cases, optimizing for shared bytes may sub-optimize your code so caveat emptor.

    Fixups
    The term "fixups" refers to "fixing up" an address in the code to a new address. Since this modifies a page for a given process, any page that has a fixup, also becomes private.

    Reducing Private Bytes
    The following are some ways you can reduce the number of private bytes:

    • put code that will be private together such that the number of pages that need to be marked private is decreased
    • prevent rebasing
    • fix addresses so that they don't become a fixup

    String Freezing and Hard Binding
    String Freezing and Hard Binding are both great examples of how the concepts above are being applied.

    In .Net 2.0, you can mark an assembly such that it will freeze its string literals. What that means is that all of the strings in that assembly will be put in a separate segment (during NGEN) so that all of the references to string literals will not require a fixup.

    The reason strings need fixups is because the literals need to be wrapped in a string instance and the code then points to those instances.

    With string freezing, there is a benefit in that the string isn't duplicated in the literal and the string instance as well as the reduction in private pages. Note as well that those string instances are interned (with opt in/opt out in whibey see the article here) to avoid duplication.

    The downside of string freezing is that such an assembly cannot be unloaded -- because the reference to that string now resides in a segment of that dll instead of on the heap and code in other assemblies may be depending on that reference.

    Hard binding refers to another new NGEN feature where NGEN assumes that a reference from one assembly to another is always going to be there. That allows NGEN to hard code offsets from one assembly to another reducing the need for load time fixups.

    The downside is that any assemblies that are hard bound will be loaded at the same time as the referencing assembly. This is in order to guarantee that the desired load addresses are gotten.

  • Cloudy in Seattle

    The Results Are In

    • 2 Comments

    For those of you who attended the dev lab last week at Microsoft, you'll recall I handed out a questionnaire asking you how you would spend $100 across our extensibility feature set. 

    Well, the results are in!  Here is how you, our customer, decided how you would spend that money.  Note that some of the surveys went over budget (>$100) and some came in under budget (<$100) -- I normalized the results to $100 (hence the floats).

    Licensing 190.4353
    Access to other controls/components on the design surface 131.384
    Access to resources, style, data sources etc. 115.0248
    Adorners 111.3557
    Actions/Verbs 107.2425
    Custom Property Editors 103.9696
    Sub-properties 94.22967
    API for determining when a control is in design mode 91.37385
    Specify a toolbox icon 84.61041
    Custom Object Editor 76.09384
    Custom Collection Editors 75.26635
    Reusing Designer Components (editors, data binding picker and Property Grid) 73.42868
    Customizing Control Creation 67.02088
    Launch wizard on object creation 64.11646
    Specify additional assembly references to add to the project when a control is added to the design surface 61.77895
    Shadow a property at design time 57.33183
    Support for Cider/Sparkle Metadata 57.19479
    Default value initialization 48.14241

Page 1 of 1 (3 items)