Welcome to MSDN Blogs Sign in | Join | Help

What's New in Globalization in .NET 4 Beta 1 [Melitta Andersen]

In Justin’s recent post outlining What’s New in the BCL in .NET 4 Beta 1, there were only a few lines about the globalization updates.  That’s because Mohamed Elgazzar was working on a more extensive document which provides details about the extent of the changes and additions to that space.  I’m happy to say that the document is now live.  Please check it out here: Microsoft .NET Framework 4 (Beta 1): What is New in Globalization

What's New in the BCL in .NET 4 Beta 1 [Justin Van Patten]

Visual Studio 2010 and .NET Framework 4 Beta 1 are available for download.  .NET 4 Beta 1 contains new functionality and improvements throughout the framework.  In this post I’ll discuss the changes specific to the BCL.

Many of the features listed below were previously announced when we released the .NET Framework 4 CTP back in November of last year.  I’ve included these features again below for completeness.  New functionality in Beta 1 that wasn’t present in the CTP is denoted as such.

  • Code Contracts
    System.Diagnostics.Contracts provides a language-agnostic way to express coding assumptions in .NET programs.  The contracts take the form of pre-conditions, post-conditions, and object invariants.  Contracts act as checked documentation of your external and internal APIs.  The contracts are used to improve testing via runtime checking, enable static contract verification, and could be used in documentation generation.  We partnered with Microsoft Research to deliver this feature in .NET 4.  More information and links to the tools are available on the Code Contracts DevLabs site.
    (new in Beta 1) The latest release of the tools works with Visual Studio 2010 Beta 1.

  • Parallel Extensions
    The Parallel Computing Platform team worked with us to add the Task Parallel Library (TPL), Coordination Data Structures, and Parallel LINQ (PLINQ) to the BCL in .NET 4.  This includes an improved ThreadPool scheduling algorithm for tasks, Task and Task<T>, the static Parallel class, concurrent collections in System.Collections.Concurrent, and other coordination data structures such as Lazy<T>, CountdownEvent, Barrier, SemaphoreSlim, SpinLock, SpinWait, and ManualResetEventSlim.  More information is available over at the PFX team’s blog.

  • BigInteger
    System.Numerics.BigInteger is an arbitrary-precision integer data type.  BigInteger supports all the standard integer operations, including bit manipulation.  It can be used from any .NET language, and some of the new .NET languages—such as F# and IronPython—have support built-in to the language.  We partnered with the Microsoft Solver Foundation team to deliver this in .NET 4. 

  • Variance annotations (new in Beta 1)
    C# and VB now support safe co- and contra-variance for generic interface and delegate types.  Co-variance means that a generic of a type, e.g. an IEnumerable<String>, can be treated as a generic of any supertype, e.g. an IEnumerable<Object>.  Contra-variance means that a generic of a type, e.g. an Action<Object>, can be treated as a generic of a subtype, e.g. an Action<String>.  In C#, co-variance is annotated with the “out” keyword and contra-variance is annotated with the “in” keyword.  VB has similar “In” and “Out” keywords.  We’ve annotated several interfaces and delegates in the BCL for variance, including: IEnumerable<T>, IEnumerator<T>, IComparer<T>, IEqualityComparer<T>, IComparable<T>, the Action and Func delegates, Predicate<T>, Comparison<T>, EventHandler<TEventArgs>, and Converter<TInput, TOutput>.

  • Tuples (new in Beta 1)
    We’ve added common Tuple types in the BCL to facilitate language interoperability and to reduce duplication in the framework.  A tuple is a simple generic data structure that holds an ordered set of items of heterogeneous types.  Tuples are supported natively in languages such as F# and IronPython, but are also easy to use from any .NET language such as C# and VB.

  • SortedSet<T> (new in Beta 1)
    We’ve added a SortedSet<T> collection along with a new ISet<T> interface.  SortedSet<T> uses a self-balancing tree which maintains data in sorted order for performance guarantees with insertion, deletion, and searches.  Both the new SortedSet<T> and the existing HashSet<T> implement ISet<T>.

  • File System Enumeration Improvements (new in Beta 1)
    System.IO.Directory and System.IO.DirectoryInfo have new APIs for enumerating the file system that return IEnumerable<T>s instead of arrays.  These new APIs are more efficient than the array-based APIs because they do not need to allocate a (potentially large) array and you can access the first results immediately instead of waiting for the entire array to be created and returned.  We’ve also added new convenience APIs for efficiently reading, writing, and appending lines from/to a text file using IEnumerable<String>.  These new APIs are useful in LINQ scenarios where you may want to quickly and efficiently query the contents of a text file and write out the results to a log file without allocating any arrays.

  • MemoryMappedFiles
    System.IO.MemoryMappedFiles exposes the memory mapping functionality provided by Windows as first-class managed APIs.  Memory mapped files can be used to efficiently edit very large files and can also be used to create shared memory for inter-process communication.  Along with this feature, we’re introducing System.IO.UnmanagedMemoryAccessor, a new class that enables random access to unmanaged memory similar to how UnmanagedMemoryStream enables sequential access to such memory.

  • Registry Improvements (new in Beta 1)
    We’ve added support to Microsoft.Win32.RegistryKey for accessing alternate registry views (32bit and 64bit views) on 64bit Windows.  We’ve also added the ability to create volatile keys—keys that are stored in memory and are not persisted when the hive unloads (which typically happens on reboot).  In addition, we’ve added new extensibility APIs that take and return a SafeRegistryHandle to make it easier to interoperate with Win32 registry APIs that do not have managed wrappers.

  • Globalization data updated to Unicode 5.1 (new in Beta 1)
    Culture data in .NET 4 has been updated, including updating the character information to Unicode 5.1.  We have also added support for new cultures, including new neutral cultures.

  • ResourceManager Improvements
    The ResourceManager in System.Resources has been improved to respect the user’s preferred UI languages when looking for localized resources, instead of only using the CurrentUICulture’s parent chain.  This means if the user has specified in Windows that she prefers French and Spanish, the ResourceManager will look for French and Spanish resources before falling back to the neutral resources.  This change is present in Silverlight 2 as well as .NET 4.

  • Compression Improvements
    The compression algorithms in System.IO.Compression have been improved in .NET 4.  DeflateStream and GZipStream no longer inflate already compressed data.  This means that in many cases you’ll see better compression ratios when using these streams on .NET 4.  We’ve also removed the 4 GB size limit, so you can now compress streams over 4 GB in length.

You can learn more about what’s new in the BCL in .NET Framework 4 on Channel9: Inside .NET 4: Meet the BCL Team.

We hope you enjoy the new functionality and improvements in Beta 1.  Be sure to let us know if you run into any issues or if you have any further suggestions.  And look out for even more improvements and refinements in the next preview release of .NET Framework 4.

Posted by BCLTeam | 27 Comments
Filed under: ,

Preview of Code Contract Tools Now Available [Melitta Andersen]

In my Introduction to Code Contracts post, I mentioned that the tools to enable runtime checking and static analysis were not included in the .NET Framework 4.0 CTP.

Today we are releasing a preview version of the Code Contracts tools on the DevLabs site.  DevLabs is a site for getting preview releases of innovative new projects for developers out to the community.  You can read more about it on Soma’s introductory blog post.  The specific Code Contracts page on DevLabs can be found here.

The tools include a binary rewriter to enable runtime checking, a static checker, a new project pane for VS projects, and an updated copy of the Code Contract library.  For more details on what these are, you can check out the Code Contracts page, which includes an overview, a video on how to get started, an FAQ, and other useful information.  You can also check out the documentation (PDF), or get an overview in Soma’s recent post on Code Contracts.

This current release is targeted at Visual Studio 2008 Team System and can be used for commercial development.  The academic release that can be used for non-commercial use on any Visual Studio 2008 edition except Express can still be found on the Contracts page on the Microsoft Research site.

This new release also comes with more ways to provide feedback and get answers.  In my last post, I mentioned the Code Contracts thread on the Pex forum.  Now Code Contracts has its own forum.  So please go try out these new tools and tell us what you think.

Posted by BCLTeam | 11 Comments
Filed under:

In-depth: How .NET managed services interact with the ServiceControlManager (SCM) [Kim Hamilton]

.NET managed services are based on NT services, and both need to know how to interact with the ServiceControlManager (SCM) to remain responsive. For managed services, many of the complexities of interacting with the SCM are handled for you by System.ServiceProcess.ServiceBase; however, there are some you still need to be aware of.

I’ll summarize the key interactions between the SCM and any service (managed or native). I’ll describe how these apply to managed services — which interactions you need to perform and which are handled for you. Lastly, I’ll walk through a representative SCM command to show the full sequence.

SCM Interaction 1

General Guidance

When SCM sends a request, acknowledge it by updating the service state (e.g. pending) and spawn a new thread to handle the request so that the SCM can communicate with other services

Background

The SCM only communicates with one service at a time. This guidance allows the SCM to be unblocked so it can communicate with other services. So the suggested behavior for services is: set the status to pending and kick off a new thread to do any necessary work (thereby unblocking the SCM). The SCM can then move on to interacting with other services, while the worker thread updates the SCM with progress and completion status.

Impact for managed services

This is only partially relevant for managed services because ServiceBase handles much of this for you. You only need to worry about this if you expect your service will require more time than the “unresponsive” limit, or to spawn a thread that will last the entire lifetime of the service. Here are the details:

  • You don’t need to start a new thread just to unblock the SCM. ServiceBase calls your OnStart/OnStop (we’ll refer to those as OnX) on a worker thread, so when you’re OnStart/OnStop is called, you’re not blocking the SCM
  • You don’t set the service state. The ServiceBase class sets the service state to X_PENDING before calling your OnX/OnX. Also, when your OnX method returns, ServiceBase performs the final status update, e.g. to STATUS_STOPPED. (In fact, there’s not even a managed API for setting these states.)
  • While your OnX thread isn’t blocking the SCM, you do need ensure it doesn’t exceed its time limit. You can help ensure you have enough time by calling RequestAdditionalTime, discussed in SCM Interaction 2.
  • You do need to spawn a new thread in OnStart for any processing that should happen during the entire lifetime of the service.

SCM Interaction 2

General Guidance

After the SCM issues a command, the SCM gives each service a default amount of time to complete its work. If the service requires more time it must tell the manager that it needs more time, otherwise the manager will assume it’s hung.

Background

As mentioned in the previous interaction, it’s important that a service doesn’t block the SCM, so that the SCM can respond to other services. However, the SCM also expects status updates from the service, to ensure the service is responsive. For example, after issuing a start command, the SCM expects the service to update its state to started within 30 seconds. After issuing a stop command, the SCM expects the service to update its state to stopped within 20 seconds.

Impact for managed services

This is where your managed service needs to pay attention to avoid the SCM flagging your service as unresponsive.

  • You don’t have to explicitly update the state; ServiceBase does this for you when your OnStart or OnStop method completes
  • You do have to call RequestAdditionalTime if you expect the OnX method to exceed the timeout.

SCM Interaction 3

General Guidance

To give SCM impression of progress, update the dwCurrentState or dwCheckPoint

Background

These state and checkpoints are intermediate “in progress” types of notification to let the SCM know your service isn’t hanging.

Impact for managed services

With managed services, these details are abstracted away. All you have to do is call RequestAdditionalTime() and those details are handled for you behind the scenes. ServiceBase will handle the state and checkpoint details in its message to the SCM.

Walkthrough: how ServiceBase handles Stop command

To demonstrate the above, let’s walk through how ServiceBase responds to a STOP command from the SCM. Note that Start is similar.

ServiceBase receives STOP command:

  • ServiceBase queues up an async call, to call your handler and update status
  • In the async call, ServiceBase does the following:
    • Sets status to STATE_STOP_PENDING
    • Calls your OnStop (note this is already in a separate thread)
    • When your OnStop returns, sets state to STATE_STOPPED

What should your OnStop look like?

  • If you need more time, just call RequestAdditionalTime. We’ll send this value to the SCM and update the checkpoint for you
  • If you don’t need more time, you don’t have to do any additional steps. Your method returns and we update the state for you.

If your OnStop fails to call RequestAdditionalTime or blocks for longer than 20 (default; see below) seconds, SCM marks service as unresponsive.

To prevent a service from stopping shutdown, the SCM will only wait up to a limit for your service to stop itself. The default for this limit is 20 seconds (this value is in the registry key WaitToKillServiceTimeout() in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control)

Additional Reading

The following MSDN article describes writing responsive native services.

http://msdn.microsoft.com/en-us/magazine/cc164252.aspx

Posted by BCLTeam | 9 Comments
Filed under:

Working with the ResourceManager [Kim Hamilton]

The essentials of resource fallback and how to debug failures

Resource loading failures can be tricky to debug. However, once you have a basic overview of how the ResourceManager works, as well as a few debugging tools, you’ll be able to easily get to the bottom of most problems.

This post will cover the key elements of resource lookup and debugging with a simple code sample, addressing the following:

  • Basics of resource generation and file structure
  • How to construct a ResourceManager to find your resources
  • How resource fallback works
  • How to debug resource failures

Code Sample

The code sample is posted in the BCL code gallery downloads as ResourceManagerSample.zip. The zip file contains:

  • .restext files in different languages: these are text files containing key, value pairs from which we’ll generate .resources files.  Note that the extension restext isn’t important, it can be anything you want.
  • FallbackTest.cs: sample code that looks up resources in different cultures and prints the results
  • make.bat: builds main exe and satellite assemblies

Instructions

  1. Extract the zip file and run make.bat, which does the following:
    1. Converts the .restext files to .resources files (the binary format understood by the ResourceManager) using resgen.
    2. Compiles the main exe and embeds the invariant resources, or the resources that are always expected to exist if other cultures are missing.
    3. Generates satellite assemblies for the other cultures, placing them in culture-specific subfolders

After Step 1, the directory structure looks like the following:

FallbackTest.exe                 (main executable, contains FallbackStrings.resources)
de\FallbackTest.resources.dll    (de satellite assembly, contains FallbackStrings.de.resources)
fr\FallbackTest.resources.dll    (fr satellite assembly, contains FallbackStrings.fr.resources)
fr-CA\FallbackTest.resources.dll (fr-CA satellite assembly, contains FallbackStrings.fr-CA.resources)
  1. Run FallbackTest.exe to see the results, discussed below

Before diving into the results, let’s look at the source of FallbackTest.cs to see what it’s doing.

Creating a ResourceManager

The ResourceManager can perform two types of resource lookup, depending on how you construct it.

  • File-based: resource files are directly on disk in the binary .resources files. Create this type of ResourceManager via ResourceManager.CreateFileBasedResourceManager.
  • Assembly-based: resources are embedded in an assembly or a satellite assembly. Create this type of ResourceManager with the standard constructors.

Assembly-based is by far the most commonly used; a satellite assembly has the same advantages as a regular assembly such as versioning and the ability to sign. That’s why we’re focusing on assembly-based lookup in this example.

The code sample creates a ResourceManager as follows:

ResourceManager rm = new ResourceManager("FallbackStrings",
                            Assembly.GetExecutingAssembly());

The first argument is baseName — the name of the resources files we’re searching without the culture and “.resources” extension.  In step 1a above, resgen created files named, for example, FallbackStrings.fr.resources and FallbackStrings.fr-CA.resources. So baseName in this example would be FallbackStrings.

The second argument is the main assembly for the resources. Since we’re calling from that assembly, we can just say Assembly.GetExecutingAssembly(). Note that this is the common case.

Resource Fallback Model

Let’s move to the resource lookups and sample code output. First, notice these lines:

CultureInfo ci = new CultureInfo(culture);
Thread.CurrentThread.CurrentUICulture = ci;

This is done because the ResourceManager uses the current thread’s CurrentUICulture to search for resources by default. ResourceManager.GetString also has overloads that accept a CultureInfo. If provided, that culture will be searched instead.

After setting the UI Culture, fallback test searches for a couple of localized strings and prints them to the screen.

Current UI culture: fr-CA
Greeting: bonjour
End of week: la fin de semaine
------------------------------
Current UI culture: fr-FR
Greeting: bonjour
End of week: le week-end
------------------------------
Current UI culture: de-DE
Greeting: Guten Tag
End of week: weekend
------------------------------
Current UI culture: ja-JP
Greeting: hello
End of week: weekend
------------------------------

Let’s focus on fr-CA and fr-FR. fr-CA is the French Canadian locale, which has some different words than fr-FR, the French spoken in France.

In this code sample, we’ve included resources for fr-CA, but none for fr-FR. Instead, we’ve provided resources for fr, which is the neutral French culture. A neutral culture is not region-specific and is the parent of its corresponding region-specific cultures. For example, fr is the parent culture of both fr-CA and fr-FR.

A quick aside on this decision:

Resource divisions like this are fairly common in practice; the most common words for a language (across regions) are placed in the neutral culture’s resource file, and any deviations from that are placed in the specific culture’s resource file. This minimizes duplication in resource files.  So in this example, the choice to put greeting in fr allowed us to share resources across French-speaking regions, but adding explicit resources for fr-CA allows French Canadian to differ from the most commonly-used French.

Now notice in the program output that fr-CA and fr-FR have the same greeting but different words for the end of the week. That’s because for greeting, fr-CA resources didn’t have a value, so it fell back to fr (same as fr-FR).

In general, a resource fallback chain looks like this.

Culture passed to GetString(, x) or ThreadUICulture (fr-CA) -> parent culture (fr) -> invariant culture (embedded in main assembly)

Compare the output for the other cultures above to see why the output makes sense.

The fallback chain can also vary as follows:

  • In .NET 4 (and Silverlight 2), on Windows Vista and above, we merge in user and system preferences according to the API GetThreadPreferredUILanguages (with flags MUI_MERGE_USER_FALLBACK | MUI_MERGE_SYSTEM_FALLBACK). These cultures are searched after the specified culture and its parents, but before the invariant culture
  • NeutralResourcesLanguageAttribute on the assembly: this allows performance improvements and allows ultimate fallback resources to be located in a satellite assembly (and in a different culture), instead of the main assembly. About the NeutralResourcesLanguageAttribute
  • Specify in the app’s config that only certain assembly locales should be probed. This also allows performance improvements. Note that this won’t add cultures to the fallback chain, it will only remove them. Performance tips for using resources

Debugging Resource-Related Issues

There are 3 common tools I use for debugging resource-related issues. These are:

  • Fusion: shows attempts to load satellite assemblies, which can help uncover assembly-loading problems
  • Reflector: view embedded .resources file
  • Resview: same as above but also has diagnostics to tell if there are problems

Let’s look at these in-depth by seeing what can go wrong. Comment out the call to GoodTest(), then uncomment the call to BadTest(), and rerun make.bat. This code has a bug, which is that the baseName is incorrect (“Fallback_Strings” instead of “FallbackStrings”). Running the code, we get the following exception:

System.Resources.MissingManifestResourceException: Could not find any resources appropriate for the specified culture or the neutral culture.  Make sure "Fallback_Strings.resources" was correctly embedded or linked into assembly "FallbackTest" at compile time, or that all the satellite assemblies required are loadable and fully signed.

Let’s investigate this failure showing how the different tools are used:

Fusion logs

To enable fusion logs, launch the fusion log viewer, fuslogvw.exe, which is provided as a Framework sdk tool (you can find it under Framework\tools). Choose the option “Log all binds to disk”. I also select the “Enable custom log path” checkbox and specify a path such as C:\fuslog. (Since fusion logs are written as html files, I prefer to browse the files directly on disk than view the output in the fusion log viewer.)

Then run your program and look in C:\fuslog for the results.

In C:\fuslog\Default\FallbackTest.exe\, I see there were binding attempts for fr-CA and fr, because there are files named, e.g.:

“FallbackTest.resources, Version=0.0.0.0, Culture=fr-CA, PublicKeyToken=null.HTM”

Opening those files, you can see that the assembly did load correctly, so the problem isn’t a missing satellite assembly.

If the fusion log file did indicate a problem with the satellite assembly loading, then you know that either the satellite assembly is missing or has some other problem (version or signing problem), in which case you most likely have a build or install problem to correct.

Reflector/Resview

Both of these allow you to see the contents of a .resources file embedded in an assembly, but resview (part of the Framework sdk) has additional diagnostic tools. However, Reflector provides a nice interface for browsing the resource file, and I most often use that.

Open up the assembly of interest (either satellite or main) in Reflector. Expand the “Resources” section of the assembly to verify that the baseName we specified is actually present. As expected, we have a resource file named FallbackStrings.X.resources, but not Fallback_Strings.X.resources, and the solution is to remove the underscore from the baseName.

While this file name problem seems basic, it turns out to be a very common problem, so keep it in mind.

Another simple common mistake is if the key isn’t actually in the file. You can double-click on the .resources file in reflector to see the contents.

Posted by BCLTeam | 4 Comments
Filed under:

CLR Team Blog Now Live [Justin Van Patten]

If you like this blog, you’ll want to check out and subscribe to the new CLR Team Blog that just launched last week.  The new blog will serve as one consolidated site to find information on all aspects of the CLR, brought to you by CLR team members.  It will aggregate posts from lots of existing CLR team member and feature team blogs.  Since the BCL team is a part of the larger CLR team, when we post something on the BCL Team Blog we’ll also include a link to the post on the CLR Team Blog, or cross-post in some cases.  Other CLR bloggers and features teams will do the same.  The new blog will have its own original content too!  Aarthi Ramamurthy’s introductory blog post describes in more detail what the new blog is all about.  Check it out, subscribe, and stay tuned for upcoming posts!

Posted by BCLTeam | 3 Comments
Filed under:

Introduction to Code Contracts [Melitta Andersen]

This blog post is to provide a bit more detail about the Code Contracts feature that was recently announced at the PDC and in Justin’s blog entry, and that can be found in the Visual Studio 2010 and .NET Framework 4.0 CTP.  I’ll include some information on what can be found in the CTP, some of the history and design decisions we made while developing the feature, and some places to get more information.  Both of the announcements mentioned above give details about why we added this feature, but I’ll summarize here.  The main point of contracts is to reduce bugs by helping you not write them in the first place, or at least catch them sooner.  Contracts let you express statements about the behavior of your code in a way that is accessible to tools for runtime and static analysis.

What’s not in the CTP

One thing you should note is that the tools to enable runtime checking and static analysis are not in the CTP.  However, you can still write your contracts now and then use the tools when they become available.  This works because the contracts are conditionally defined.  They’ll only appear in your code when you have the CONTRACTS_FULL symbol defined.  Until the tools are available and runtime checking is enabled, do not define this symbol.  Full contract checking will not work without the tools.  However, you also have the option of getting only preconditions with the CONTRACTS_PRECONDITIONS symbol.  Preconditions happen to be in the correct place in the code, so your program will still run with this symbol defined.  But the runtime checking tool provides many additional benefits, such as contract inheritance, so checking is still not recommended without the tools.

What is in the CTP

The CTP includes a CodeContracts class in the System.Diagnostics.Contracts namespace that allows you to write contracts in your code.  All contracts are static methods that return void.  They take a Boolean expression which encodes the condition that must be true.  They also have an overload that takes a string parameter as a message for when the contract is false.  Contracts are declarative and come at the beginning of your method.  You can think of them as part of the signature.  Here’s a rundown of what contracts are in the CTP:

  • Preconditions
    Preconditions are statements about what must be true at method entry for successful execution of the method.  It’s the responsibility of the caller to make sure these conditions are met.  Often, preconditions are used for parameter validation.  There are 3 possible ways to encode preconditions with code contracts:
     
    • CodeContract.Requires
      This method simply states a precondition.  Here’s an example:

          CodeContract.Requires(parameter >= 0);

    • CodeContract.RequiresAlways
      This method is the one exception to the conditional compilation rule.  It is always included, no matter which symbols are defined.  Thus, you can use RequiresAlways for preconditions that you want in your released code.  Here’s an example:

          CodeContract.RequiresAlways(parameter >= 0);

    • CodeContract.EndContractBlock
      This method name might seem a bit odd to include in the precondition section, so let me explain.  Much code already exists in the world that has some kind of parameter validation in the form of “if [condition] then throw [exception]”, e.g.

          if (parameter < 0)
              throw new ArgumentOutOfRangeException();


      We don’t expect everyone to go back and change their existing validation code.  However, we wanted a way to let the tools recognize these legacy contracts.  So we added the CodeContract.EndContractBlock method, which tells the tools that all if-checks of that form before the call can be considered preconditions.

          if (parameter < 0)
              throw new ArgumentOutOfRangeException();
          CodeContract.EndContractBlock();


      This method is needed only if you have no other contracts in your method, as all CodeContract preconditions and postconditions have this effect.

  • Postconditions
    Post conditions are guarantees a method makes about what must be true at the conclusion of a method.  It is the method’s responsibility to live up to those promises.  These are declared at the beginning of a method, just like preconditions.  The tools take care of checking them at the right times.  There are two types of post conditions you can write with the CodeContract class.
     
    • CodeContract.Ensures
      This method states conditions that must be true upon successful method exit.  For example, this condition says that when the method exits the value will not be null.

          CodeContract.Ensures(SomeSharedState != null);

    • CodeContract.EnsuresOnThrow<TException>
      This method makes guarantees about exceptional termination from a method.   In general, such guarantees can only be made for very specific exceptions, so letting TException be Exception is not a good idea.  For example, the following condition says that if an IOException escapes this method, the given variable is not null.

          CodeContract.EnsuresOnThrow<IOException>(SomeSharedState != null);

  • Special values for postconditions
    As you can imagine, it is often necessary to refer to certain values in postconditions, such as the result of the method, or the value of a variable at method entry.  There are methods in the CodeContract class that allow this; they are valid only in a postcondition.
     
    • CodeContract.Result<T>()
      This method represents the value returned from a method.  The T parameter indicates the return type.  For example, the following condition says that the result of this method is always non-negative.

          CodeContract.Ensures(CodeContract.Result<Int32>() >= 0);

    • CodeContract.OldValue<T>(T value)
      This method represents the value as it was at the start of the method or property.  It captures the pre-call value in a shallow copy.  For example, this condition says that the method increased the value of SomeSharedInt.

          CodeContract.Ensures(SomeSharedInt > CodeContract.OldValue(SomeSharedInt));

    • CodeContract.ValueAtReturn<T>(out T value)
      This method is just to let you refer to the final value of an out parameter in a postcondition.  Since you write postconditions at the beginning of a method, the compilers would otherwise complain as the parameter hasn’t been assigned yet.  Other by-reference parameters don’t need this method.  Normal parameters don’t need this method because the compiler doesn’t care if it sees references to their values before it sees an assignment to them.

  • Object Invariants
    The last major kind of contract that can be expressed with the CodeContract class is the object invariant.  Object invariants are statements about what must be true at all public method exits for an object.  It is up to the programmer to ensure these invariants are maintained.  Object invariants are contained in a separate method that is marked with the ContractInvariantMethodAttribute.  The name of the method does not matter, but it must be parameter-less and return void.  That method contains some number of calls to the CodeContract.Invariant method.  Here’s an example of an invariant stating that the value in Data is always non-negative.

            [ContractInvariantMethod]
          void ObjectInvariant() {
              CodeContract.Invariant(Data >= 0);
          }
  •      

  • CodeContract.Assert and CodeContract.Assume
    I’ll briefly touch on the other two types of contracts included in the class.  Assert and Assume, unlike the others, aren’t part of a method’s signature, and unlike the others they don’t come at the beginning of a method.  They’re simply statements about what must be true at a particular point in the code.  There exists many other ways to do this verification, but the main value with these methods is that they can be recognized by the tools.  The difference between Assert and Assume is that an Assume is your way to tell the static checker that instead of trying to prove the expression to be true, it should add the expression to its body of facts for your code.

Please note that this is only what is in the CTP.  This is a feature still under development, and things could change before we ship.  In fact, we’re considering a couple of changes.  One is changing the class name from CodeContract to Contract to make contracts more readable.  Another is adding more sophisticated runtime failure behavior that is customizable by applications and hosts.

History and Design Decisions

The idea for this feature originated with the Spec# project in Microsoft Research.  Spec# has its own programming language, an extension of C#, which includes contracts in the syntax of the language.  We’re working closely with a team from Microsoft Research to bring contracts to the BCL.  One of the main questions we’ve had about the way we are including contracts in the .NET Framework is why we chose to implement them as library calls instead of making them part of “the language.”

There are quite a few reasons for this, but one of them is that the CLR is the Common Language Runtime, and we wanted a feature that all of the languages using the .NET Framework could use, not just one of them.  The best way to do this was with library calls.  As far as compilers need to be concerned, these are just static method calls.  Spec# was great because it had contracts integrated into the language, but that only solved the problem for one language. 

People have brought up attributes as another way we could have accomplished this.  One argument for that approach is that contracts are declarative, and this would make them look more like part of the method signature instead of the method body.  The problem with this approach is that attributes are very limited in what they can express.  It would be difficult or impossible to use attributes for all of the contracts you can write in code. 

If you’re concerned about it because of the aesthetics, you might want to check out Scott Guthrie’s demo of VS2010, which starts about 88 minutes into this PDC2008 Keynote.

More Information

There are a few places you can go if you’re looking for more information.

Posted by BCLTeam | 20 Comments

What's New in the BCL in .NET 4.0 [Justin Van Patten]

The Visual Studio 2010 and .NET Framework 4.0 CTP is available for download as of last week.  The CTP contains new functionality throughout the .NET Framework, including several new BCL features and improvements:

  • Code Contracts
    System.Diagnostics.Contracts provides a language-agnostic way to express coding assumptions in .NET programs.  The contracts take the form of pre-conditions, post-conditions, and object invariants.  Contracts act as checked documentation of your external and internal APIs.  The contracts are used to improve testing via runtime checking, enable static contract verification, and documentation generation.  We partnered with Microsoft Research to deliver this feature in .NET 4.0.  More information and tools are available on Microsoft Research’s code contracts website.  There’s also a highly-rated PDC session available online.

  • Parallel Extensions
    We worked with the Parallel Extensions team to add the Task Parallel Library (TPL), Coordination Data Structures, and Parallel LINQ (PLINQ) to the BCL in .NET 4.0.  This includes an improved ThreadPool scheduling algorithm for tasks, the static Parallel class, concurrent collections in System.Collections.Concurrent, and other coordination data structures such as LazyInit<T>, CountdownEvent, Barrier, SemaphoreSlim, SpinLock, SpinWait, and ManualResetEventSlim. More information is available over at the PFX team’s blog.  Also, check out Daniel Moth’s PDC session on Parallel Programming for Managed Developers with the Next Version of Microsoft Visual Studio.

  • BigInteger
    System.Numerics.BigInteger is an arbitrary-precision integer data type.  We worked with the Microsoft Solver Foundation team to deliver a highly performant big integer implementation.  BigInteger supports all the standard integer operations, including bit manipulation.  It can be used from any .NET language, and some of the new .NET languages—such as F# and IronPython—have support built-in to the language.

  • Memory Mapped Files
    System.IO.MemoryMappedFiles exposes the memory mapping functionality provided by Windows as first-class managed APIs.  Memory mapped files can be used to efficiently edit very large files and can also be used to create shared memory for inter-process communication.  Along with this feature, we’re also introducing System.IO.UnmanagedMemoryAccessor, a new class that enables random access to unmanaged memory similar to how UnmanagedMemoryStream enables sequential access to such memory.

  • ResourceManager Improvements
    The ResourceManager in System.Resources has been improved to respect the user’s preferred UI languages when looking for localized resources, instead of only using the CurrentUICulture’s parent chain.  This means if the user has specified that she prefers French and Spanish, the ResourceManager will look for French and Spanish resources before falling back to the neutral resources.  This change is present in Silverlight 2 as well as .NET 4.0.

  • Compression Improvements
    The compression algorithms in System.IO.Compression have been improved in .NET 4.0.  DeflateStream and GZipStream no longer inflate already compressed data.  This means that in most cases you’ll see much better compression ratios when using these streams on .NET 4.0.  We’ve also removed the 4 GB size limit, so you can now compress streams over 4 GB in size.

  • String Security Changes
    The default partial matching overloads on System.String (StartsWith, EndsWith, IndexOf, and LastIndexOf) have been changed to be culture-agnostic (ordinal) by default.  In addition, ToUpper and ToLower on System.String and System.Char have been changed to use the invariant culture instead of the current culture.  Although we have guidance and FxCop rules that recommend always using overloads that take a StringComparison parameter, unaware developers often just use the default overloads.  In previous versions of .NET, these default overloads do a culture-sensitive comparison using the current culture.  This can often lead to subtle bugs, most notably security vulnerabilities, when unaware developers use the default overloads to do security-sensitive string comparisons.  This change helps mitigate these vulnerabilities.  The change is present in both Silverlight 2 and .NET 4.0.  Even with these changes, our guidance still stands: whenever an overload exists that takes a StringComparison parameter, use it instead of an overload that does not take this parameter.  It makes your code clearer and easier to maintain.  This is especially important because the default overloads for String.Compare and String.CompareTo will remain culture-sensitive because these methods are most often used when sorting strings to be shown to the user.  We plan to add a compat switch in the beta that will allow an app to specify whether it wants the old behavior.

We’re also evaluating a number of potential new features and improvements for .NET 4.0 beta:

  • Variance annotations
    The next versions of C# and VB support safe co- and contra-variance for generic interface and delegate types.  Co-variance means that a generic of a type, e.g. an IEnumerable<String>, can be treated as a generic of any supertype, e.g. an IEnumerable<Object>.  Contra-variance means that a generic of a type, e.g. an Action<Object>, can be treated as a generic of a subtype, e.g. an Action<String>.  In C#, co-variance is annotated with the “out” keyword and contra-variance is annotated with the “in” keyword.  We are annotating several interfaces and delegates in the BCL for variance.  You can learn more about co- and contra-variance in Anders Hejlsberg’s PDC session on The Future of C#.

  • Tuples
    We are providing common tuple types in the BCL to facilitate language interoperability and to reduce duplication in the framework.  A tuple is a simple generic data structure that holds an ordered set of items of heterogeneous types.  Tuples are supported natively in languages such as F# and IronPython, but are also easy to use from any .NET language such as C# and VB.

  • SortedSet<T>
    We plan to add a SortedSet<T> collection along with an ISet<T> interface.  SortedSet<T> uses a self-balancing tree which maintains data in sorted order for performance guarantees with insertion, deletion, and searches.  Both the new SortedSet<T> and the existing HashSet<T> implement ISet<T>.

  • File System Enumeration Improvements
    We plan to add new file system enumeration APIs to System.IO.Directory and System.IO.DirectoryInfo that return IEnumerable<T>’s instead of arrays.  These new APIs are more efficient than the array-based APIs because they do not need to allocate a (potentially large) array and you can access the first results immediately instead of waiting for the entire enumeration to take place.  We’re also planning to add new convenience APIs for efficiently reading, writing, and appending lines from/to a text file using IEnumerable<String>.  These new APIs are useful in LINQ scenarios where you may want to quickly and efficiently query the contents of a text file and write out the results to a log file without allocating any arrays.

There are also a bunch of improvements to the CLR in .NET 4.0.  Here’s a high-level summary:

You can learn more about the next version of the CLR in Joshua Goodman’s PDC session on Microsoft .NET Framework: CLR Futures.

Over the next couple of weeks we’ll be posting more about the new functionality that’s available in the CTP.  Do note that we’re working on many other improvements for 4.0 that we’re not quite ready to announce just yet.

As always, we’d love to hear what you think of the CTP and announcements so far.

Posted by BCLTeam | 60 Comments
Filed under: ,

BCL Team at PDC 2008 [Justin Van Patten]

Melitta, Kim, and I will be at PDC next week, along with several other members of the CLR team.  We’ll mostly be hanging out in the lounges chatting with folks and answering questions.  We’ll also be at the Ask-the-Experts night on Wednesday, so if you’ll be at PDC next week, stop by and say hi!  We love chatting with customers and listening to your feedback and suggestions.

This year’s PDC has tons of different sessions on a vast array of .NET technologies including ASP.NET, WCF, WF, ADO.NET, Entity Framework, Data Services, XAML, WPF, Silverlight, and many more.  Here are some that you may find of interest:

  1. Microsoft .NET Framework: CLR Futures
  2. Research: Contract Checking and Automated Test Generation with Pex
  3. Managed and Native Code Interoperability: Best Practices
  4. Parallel Programming for Managed Developers with the Next Version of Microsoft Visual Studio
  5. Framework Design Guidelines
  6. Microsoft .NET Framework: Overview and Applications for Babies
  7. Managed Extensibility Framework: Overview
  8. Microsoft .NET Framework: Declarative Programming Using XAML
  9. The Future of C#
  10. Natural Interop with Silverlight, Office, and Python in Microsoft Visual C# and Microsoft Visual Basic
  11. Future Directions for Microsoft Visual Basic
  12. Deep Dive: Dynamic Languages in Microsoft .NET
  13. IronRuby: The Right Language for the Right Job
  14. An Introduction to Microsoft F#
  15. "Oslo": The Language

The first five sessions listed above are the ones most closely related to the BCL and CLR; the first two will specifically touch on some of the features that our team (the BCL team) is delivering in .NET 4.0.  Of course there are plenty of other topics to keep an eye on, such as: parallelism, “Oslo”, Visual Studio, cloud computing, Windows 7, Internet Explorer, SQL Server, etc.

Stay tuned to this blog next week for more details on what we’ll be unveiling next week at PDC 2008.

Posted by BCLTeam | 1 Comments
Filed under: ,

The Compare Contract [Kim Hamilton]

A breaking change?

We recently heard from a customer who observed different sorting behavior in .NET FX 3.5 SP1 compared to 3.5 RTM.

The different behavior was demonstrated with the following code. The class StringWrapper provided a custom sort in which nulls (null StringWrapper references) were moved to the end of the array. To achieve this, StringWrapper implemented IComparable<StringWrapper> and in its CompareTo method, nulls were always greater than non-nulls.

public class MyClass {
    public static void Main() {
        StringWrapper a = new StringWrapper();
        a.Value = "a";
        StringWrapper b = new StringWrapper();
        b.Value = "b";
        StringWrapper c = new StringWrapper();
        c.Value = "c";
        StringWrapper d = null;

        Console.WriteLine("Sort 1:");
        StringWrapper[] src1 = new StringWrapper[] { a, c, d, b };
        Array.Sort(src1);
        PrintStringWrappers(src1); // print elements, method included at end
    }
}

public class StringWrapper : IComparable<StringWrapper> {
    private string _value;
    public string Value {
        get { return _value; }
        set { _value = value; }
    }

    // Recall that CompareTo returns:
    // <0 if this object is less than other
    //  0 if this object is equal to other
    // >0 if this object is greater than other
    public int CompareTo(StringWrapper other) {
        if (other == null) return -1; // nulls are greater than any non-null
        return Value.CompareTo(other.Value);
    }

    public override string ToString() {
        return Value;
    }
}

This custom comparison apparently worked in .NET FX 3.5 RTM, but not .NET FX 3.5 SP1.

3.5 RTM output:

a
b
c
null

3.5 SP1 output:

a
b
null
c

Did the custom comparer really work?

The custom comparer worked in that example, in which only one of the array elements was null. Let’s throw in another null and see what happens:

Console.WriteLine("Sort 2:");
StringWrapper[] src2 = new StringWrapper[] { a, d, d, c, b };
Array.Sort(src2);
PrintStringWrappers(src2);

3.5 RTM output:

a
b
null
null
c

The problem is in the CompareTo method, but it isn’t obvious. The first line in CompareTo actually violates the IComparable<T>.CompareTo contract that any object compares greater than a null reference.

public int CompareTo(StringWrapper other) {
    if (other == null) return -1; // violates CompareTo contract!
    return Value.CompareTo(other.Value);
}

The Compare Contract

IComparable<T>.CompareTo has the following requirements (from the MSDN docs)

For objects A, B, and C, the following must be true:

  • A.CompareTo(A) is required to return zero.
  • If A.CompareTo(B) returns zero, then B.CompareTo(A) is required to return zero.
  • If A.CompareTo(B) returns zero and B.CompareTo(C) returns zero, then A.CompareTo(C) is required to return zero.
  • If A.CompareTo(B) returns a value other than zero, then B.CompareTo(A) is required to return a value of the opposite sign.
  • If A.CompareTo(B) returns a value x that is not equal to zero, and B.CompareTo(C) returns a value y of the same sign as x, then A.CompareTo(C) is required to return a value of the same sign as x and y.

By definition, any object compares greater than a null reference (Nothing in Visual Basic), and two null references compare equal to each other.

The requirement that any object compares greater than null is a bit of a footnote at the end, so it makes sense that this may not be well known (we should highlight this more).

Still, why did the behavior change? (Gory details and a 3.5 RTM performance bug)

The high-level problem is that .NET’s sorting makes assumptions based on the Compare contract, so in some cases sorting will special case null, because it “knows” your comparer will adhere to the contract and return values consistent with that assumption. If you don’t adhere to the contract, you’ll get bitten at some point.

The details are messier. Over the years, a variety of changes were made to improve the performance of Sort. There was a brief window (released in 3.5 RTM) where, during QuickSort, the swap and pivot steps were broken, and in intermediate steps, it would actually unsort certain already sorted arrays (the array had to contain  null). The end result would be correct, but because the elements were incorrectly swapped, sorting took much longer than it should.

We fixed this bug in SP1, and this fix caused the different behavior between RTM and SP1.

Comply with Compare contract

The only way to ensure stability across versions is to comply with the Compare contract. Otherwise you fall prey to implementation quirks (or even bugs) in the runtime sort implementation. We’d like to be free to change it between releases, because we’d like to keep improving the performance!

Enough preaching, what are my options?

The interesting thing is that the StringWrapper implementation gets you mostly there. The apparent goal of the wrapper is to implement a special sort of strings that pushes nulls to the end. You can do what you want if you create a StringWrapper with null values, as follows:

public int CompareTo(StringWrapper other) {
    if (other == null) return 1;
    if (Value == null && other.Value == null) return 0;
    if (Value == null) return 1;
    if (other.Value == null) return -1;
    return Value.CompareTo(other.Value);
}

This actually obeys the compare contract and won’t be brittle to changes in our sort implementation.

Full Source

using System;
using System.Collections.Generic;

public class MyClass {
    public static void Main() {

        StringWrapper a = new StringWrapper();
        a.Value = "a";
        StringWrapper b = new StringWrapper();
        b.Value = "b";
        StringWrapper c = new StringWrapper();
        c.Value = "c";
        StringWrapper d = null;
        StringWrapper e = new StringWrapper();
        e.Value = "e";
        StringWrapper f = new StringWrapper();
        f.Value = "f";


        Console.WriteLine("Sort 1:");
        StringWrapper[] src1 = new StringWrapper[] { a, c, d, b };
        Array.Sort(src1);
        PrintStringWrappers(src1);
        // .NET FX 3.5 RTM output: a b c null
        // .NET FX 3.5 SP1 output: a b null c

        Console.WriteLine("-----");
        Console.WriteLine("Sort 2:");
        StringWrapper[] src2 = new StringWrapper[] { a, d, d, c, b };
        Array.Sort(src2);
        PrintStringWrappers(src2);
        // .NET FX 3.5 RTM output: a b null null c
    }

    private static void PrintStringWrappers(StringWrapper[] swArray) {
        foreach (StringWrapper sw in swArray) {
            if (sw == null)
                Console.WriteLine("null");
            else
                Console.WriteLine(sw);
        }

    }
}

public class StringWrapper : IComparable<StringWrapper> {
    private string _value;
    public string Value {
        get { return _value; }
        set { _value = value; }
    }

    // original CompareTo -- violates Compare contract!
    public int CompareTo(StringWrapper other) {
        if (other == null) return -1;
        return Value.CompareTo(other.Value);
    }

    // alternate CompareTo, which obeys Compare contract and moves null Values to the end
    /*
    public int CompareTo(StringWrapper other)
    {
        if (other == null) return 1;
        if (Value == null && other.Value == null) return 0;
        if (Value == null) return 1;
        if (other.Value == null) return -1;
        return Value.CompareTo(other.Value);
    }
    */

    public override string ToString() {
        return Value;
    }
}

Long Paths in .NET, Part 3 of 3 Redux [Kim Hamilton]

My original part 3 blog caused confusion, mostly because it didn’t tie together loose ends and explain that an immediate .NET “solution” is at best partial. To minimize confusion and answer questions in the comments, I decided to do a complete overhaul and link to the original (here).

Win32 file-naming conventions include the MAX_PATH (260 character) restriction. A subset of Win32 APIs allow you to work around the MAX_PATH restriction by adding the \\?\ prefix.

Solutions based on the \\?\ prefix

Recall that these are the problems with the \\?\ prefix:

  1. Other apps may not support this prefix, and may not be able to use these files
  2. Not all Win32 APIs allow this prefix, meaning that the file will not necessarily work with other .NET APIs

#2 isn’t obvious to many people so let’s focus on that.

.NET dependence on Win32

.NET relies heavily on Win32 and isn’t always able to provide clean workarounds to Win32 restrictions. If we introduce a concept that has partial Win32 support, we either:

  1. Open up a new set of potential failures, or
  2. Add kludges on top of existing functions to make things work

An example of (a) is: you move a file to a location enabled with the \\?\ prefix, and then pass that path to another .NET API, which results in a call to a Win32 API that doesn’t support \\?\. (e.g. LoadLibrary). This sequence of operations would fail.

An example of (b) is: we try to make things work for Win32 functions that don’t support \\?\. This would be a major undertaking of rebuilding Win32 functionality or re-building a file system in the .NET layer (for example, we associate with shorter paths that can be accessed). Either approach is extremely risky and error prone, and we don’t see this as an option at the moment.

.NET solutions based on \\?\, given Win32 restrictions

Currently, .NET doesn’t allow you to use the \\?\ prefix at all. Let’s consider how .NET might enable it:

  1. Supported by default: .NET adds the \\?\ prefix behind the scenes
    1. Because of limited support of the \\?\ prefix, this will at times force you into awkward coding practices, like having to explicitly check size to make sure the file names are supported by your other apps or other functions.
    2. Also, this would be a maintenance burden going forward if Win32 provides a solution that isn’t based around \\?\
  2. Supported on an opt-in basis: callers have to opt in, such as by adding the \\?\ prefix
    1. This is just like if we had never blocked out the option from Win32
    2. Because this turns off canonicalization, this would be associated with full trust demand, which seems reasonable for applications that want to use long paths
    3. Could add convenience API such as Path.ToLongPath(file), which would add the \\?\ prefix for you, before you pass to System.IO APIs.

Other Solutions: Softening Impact

We also considered off-by-one attempts to soften the MAX_PATH limit, such as auto-shrinking which is done in the Windows shell. It’s compelling because such a path can be supported by other Win32 APIs and the shell. However, based on feedback, we think this just makes the story more confusing. The lack of consistency makes it useful to only corner-case scenarios, and certainly apps wouldn’t want to depend on it.

Proposed “Solution” (Best attempt for now)

We won’t be able to provide seamless long path support throughout .NET until something is done on the Win32 side to broaden support of long paths throughout their APIs.

As a mitigation to at least provide parity with Win32, we propose to allow use of the \\?\ prefix (described in #2 above) to avoid the MAX_PATH limitation. The caller must explicitly use this prefix, at best aided with a helper API as follows:

String longPathEnabledName = Path.ToLongPath(@"C:\veryLongPath...\veryLongName.txt");
FileStream fs = new FileStream(longPathEnabledName);

This enables use of long paths throughout the System.IO namespace. Support of long path files outside of System.IO will be limited by support of underlying Win32 APIs.

This is not a real solution, but this provides core file (reading, writing, etc) functionality for long path files, which is compelling for certain types of apps. Such apps are best described as closed-system, file reading/writing-focused apps.

Ideal Solution

Some possibilities include:

  1. A Win32 solution, supported throughout Win32 APIs for full parity
  2. Going forward, less dependence on Strings as paths. This was touched on in my comments to long paths part 1 and is a very large discussion, for some later time.

Navigation

Posted by BCLTeam | 13 Comments
Filed under: ,

P/Invoke Interop Assistant [Justin Van Patten]

The Interop team recently released a new tool called the P/Invoke Interop Assistant.  This tool automatically generates managed p/invoke declarations (in C# or VB) from native signatures.  It includes a quick look-up for the common Win32 libraries and lets you generate p/invoke declarations for any other native library simply by passing it the native signature.  This makes it a lot easier to do interop correctly, without having to understand all the rules and attributes used when marshalling between unmanaged and managed.

Here's a screenshot of the tool in action.  Simply type in the name of a Win32 API, in this case CreateFile, and the tool will generate the correct p/invoke declaration.

P/Invoke Interop Assistant

The tool was first released as part of an MSDN Magazine article on Marshaling between Managed and Unmanaged Code back in January.  Now it's on CodePlex along with the source code.  I highly recommend checking it out.

Posted by BCLTeam | 10 Comments
Filed under:

.NET Framework Developer Documentation Survey [Matthew Connelly]

Help us improve the developer documentation by taking the Visual Studio and .NET Framework Developer Documentation Survey. This survey will give us a better understanding of the type of applications you are developing, how you use help, and how we can improve it. The survey takes only 10 minutes, and we appreciate your feedback!

Posted by BCLTeam | 3 Comments
Filed under:

Long Paths in .NET, Part 3 of 3 [Kim Hamilton]

Updated 6/10/08 2:20pm: clarified details of proposed solution

Here it is, Part 3 of the long path series, which started over a year ago. I apologize for leaving you hanging; the BCL team has been busy lighting up the web. Because of the delay, I’ll summarize the compatibility concerns as context for the proposed solution.

Summary of Compat Concerns

Recall from Part 1 that one way to bypass the MAX_PATH limit with Win32 File APIs is to prepend \\?\ to the file name. This allows you to create paths that are only subject to NTFS restrictions, and the length limit is 32K. However, \\?\ has another side-effect -- it bypasses all Win32 file name canonicalization.

BCL gets a lot of requests for long path support. Some specifically request that we allow the \\?\ prefix. This brings up the question: is \\?\ requested because it allows longer paths, or do users also want to create paths that don’t conform to Win32 naming conventions? Our investigation indicates that, while there are specialized areas where non-canonical file names are useful, the overwhelming majority of users just want longer paths.

Why is this distinction important? If you just want longer paths, you don’t necessarily want the side effect of turning off all Win32 file naming conventions. For example:

  • ‘/’ will no longer be converted to ‘\’ ; instead it’s part of the file name
  • Trailing white spaces will no longer be removed; they’re also part of the file name
  • You can create file names with reserved device names.

File names like this are problematic for other apps (independent of the path length: using \\?\ you can create a file name shorter than MAX_PATH that doesn’t adhere to Win32 naming conventions), to the extent that (I expect) a great majority of users will want the framework to enforce canonicalization, at least as the default behavior.

Note that the above statements are a commentary on unbridled use of \\?\. The problem could still be resolved as follows: behind the scenes we first canonicalize the path using GetFullPathName (since GetFullPathName isn’t subject to the MAX_PATH restriction) and then prefix\\?\. Perhaps non-canonical names could be allowed on an opt-in basis.

Either way, suppose .NET lets you create paths up to 32K in length. Now you have a new problem: you have a file that, most likely, no other app on your system can use. It would have to support the \\?\ syntax. Furthermore, many .NET APIs won’t even be able to work with this file: recall from Part 1 that this syntax only works with the Win32 file-related APIs, but not for general Win32 functions that accept paths (e.g. LoadLibrary).

Goals

This blog series has focused fairly heavily on nuances of the \\?\ prefix, simply because it’s commonly viewed as the workaround to the MAX_PATH limitation. Let’s switch focus to some reasonable goals in the absence of a unified solution (exposed, for example, by Win32 APIs).

  1. Reduce the incidence of hitting path length limit for opening existing files in a compatible way; i.e. the path can only be modified into a form that Win32 APIs accept as legal.
  2. For users that need consistent access to long paths, even if that involves bypassing Win32 restrictions, allow access to longer/non-canonical (tbd) file names.

Because of the compat concerns with Goal 2, we don’t want users to “accidentally” use this solution.

Proposed Solution

Fortunately, the Vista shell has provided a precedent of allowing longer path names in a compatible way. It’s called auto-path shrinking and it attempts to squeeze a file name into MAX_PATH by shrinking the long file names into the short name equivalents piecewise behind the scenes. Before describing that, note that the proposed solution is a hybrid approach:

 1. Try to squeeze the file name into MAX_PATH characters using auto-path shrinking. Only used for existing files, and paths that don't have the file:///?\ prefix (see below)

2. Allow use of the file:///?\ prefix for creating as well as opening (in general allow this for every operation corresponding to a Win32 file API that supports this). We will not attempt to add the file:///?\ prefix behind the scenes; at most we'll provide a helper to perform such as AddLongPathPrefix. In any case, the user must intentionally request this and not stumble into using file:///?\ by accident. This part is TBD: we think it makes sense to expose as an option whether we should always enforce other Win32 file name restrictions other than length, and enforcing file naming rules would be the default.

Let's describe auto-path shrinking a bit more. If you pass in a file name that exceeds MAX_PATH:

C:\alongdirectoryname\anotherlongdirectoryname\...

It will try to shrink it under the MAX_PATH limit by using the short name equivalents:

C:\alongd~1\anothe~1\...

This solution may seem odd at first (beyond the ironic spin that we’re coming full circle to short file names). But it’s very compelling for adoption in the framework since paths of this form are acceptable to Win32 API (it’s a valid Win32 file name).

Some important clarifications:

  1. Note that this solution wouldn’t require you to actually use short file names. When you create a file on an NT-based system, a short name is generated and associated with it*. You would be able to pass “normal” (long file name) file names to .NET APIs, and the short name conversion would happen being the scenes. (Just wanted to make it clear that we’re not reverting to the pre-Windows 95 days.)
  2. Right now, you can’t use short names to .NET APIs to get around the MAX_PATH restriction. During canonicalization, we expand short names to long names, and throw a PathTooLongException if the long name exceeds MAX_PATH.

* This brings up two questions. One is that users can turn off short file name generation via a registry value. This is discussed below. Also, you’ll notice this solution is NT-focused, but Silverlight can run on Macs. We also intend to handle platform-specific path limits with long path efforts, instead of enforcing Windows MAX_PATH (as we do currently).

Analysis

Allowing use of file:///?\ will likely require a permission demand greater than FileIOPermission, perhaps even full demand for full trust. However, for many apps that need to work with long paths, this isn't a problem. We should investigate ways to relax this demand for partial trust scenarios like isolated storage.

Let’s look at some pros and cons of auto-shrinking:

Cons:

  • Doesn't work if user has turned off short file names. (But this is uncommon.)
  • Given that shrinking is happening behind the scenes, it could make path length issues even more confusing to users. \\?\ allows a consistent higher limit of 32K. Examples and explanations are given below.

Pros:

  • A path name that can be shrunk into MAX_PATH as above is accepted by any Win32 API (clarification: assuming the name is given to the Win32 API in shrunk form. Win32 APIs do not perform auto-shrinking)
  • This is an appealing "try to make it work" solution (if the user hasn't provided file:///?\). Until there’s a standard solution in the Win32 APIs, it’s better from a maintenance and usability perspective if we’re all using a similar approach.

We’re curious to hear your feedback about this approach.

Navigation

Posted by BCLTeam | 22 Comments
Filed under: ,

.NET Framework Client Profile [Justin Van Patten]

Last week Soma and Scott Guthrie announced the availability of Visual Studio 2008 and .NET Framework 3.5 SP1 Beta.  As part of this release, we’re introducing the .NET Framework Client Profile, a smaller .NET Framework redist optimized for .NET client applications.  The new redist weighs in at around 26.5 MB, enabling a smaller, faster, more reliable installation experience for .NET client applications on machines that do not already have the .NET Framework installed.

.NET Framework Client Profile Assemblies

Here's the list of assemblies that are included in the.NET Framework Client Profile.  Please note that this is actually the list of assemblies that will be included in the RTM release of the Client Profile; the beta version released last week includes some assemblies that will not be included in the RTM release (more details below).

BCL, "Core FX," and LINQ

  • CustomMarshalers
  • ISymWrapper
  • mscorlib
  • sysglobl
  • System
  • System.AddIn
  • System.AddIn.Contract
  • System.Configuration
  • System.Configuration.Install
  • System.Core
  • System.Security

Visual Basic and Visual C++ Language Support

  • Microsoft.VisualBasic
  • Microsoft.VisualC

XML

  • System.Xml
  • System.Xml.Linq

Windows Forms

  • Accessibility
  • System.Drawing
  • System.Windows.Forms

WPF

  • PresentationCore
  • PresentationFramework
  • PresentationFramework.Aero
  • PresentationFramework.Classic
  • PresentationFramework.Luna
  • PresentationFramework.Royale
  • PresentationUI
  • ReachFramework
  • System.Printing
  • System.Windows.Presentation
  • UIAutomationClient
  • UIAutomationClientsideProviders
  • UIAutomationProvider
  • UIAutomationTypes
  • WindowsBase
  • WindowsFormsIntegration

ClickOnce

  • System.Deployment

WCF, Web Services, Remoting, and Serialization

  • System.IdentityModel
  • System.Runtime.Remoting
  • System.Runtime.Serialization
  • System.Runtime.Serialization.Formatters.Soap
  • System.ServiceModel
  • System.ServiceModel.Web
  • System.ServiceModel.Install
  • System.Transactions
  • System.Web.Services

Data Access

  • System.Data
  • System.Data.SqlXml
  • System.Data.DataSetExtensions
  • System.Data.Services.Client

Peer to Peer

  • System.Net

Active Directory and Enterprise Services

  • System.DirectoryServices
  • System.EnterpriseServices

The following assemblies are included in the beta release of the Client Profile but will be removed in the RTM release:

  • jsc
  • Microsoft.JScript
  • Microsoft.Vsa
  • System.DirectoryServices.Protocols
  • System.Management
  • System.Messaging
  • System.ServiceProcess
  • System.Web
  • System.Web.Extensions
  • System.Web.RegularExpressions

We'd love to hear your feedback on the list of assemblies in the Client Profile.  If your client app depends on an assembly that isn't listed above, let us know.  I can't guarantee that we'll add the assembly to the Client Profile for RTM, but we'll certainly consider it.  Keep in mind that the more assemblies we add, the more dependencies we may need to pull in, and the larger the package becomes.  This translates into longer download/install times and less reliable installs.  We're aiming to keep the Client Profile as small as possible while still providing the right amount of functionality to satisfy the needs of most .NET client apps.

Targeting the .NET Framework Client Profile using Visual Studio 2008 SP1

Visual Studio 2008 SP1 adds a new feature in the project Properties for targeting the Client Profile.

Client-only Framework subset checkbox

After checking the "Client-only Framework subset" checkbox, Visual Studio will generate a warning if your project references an assembly that is not part of the Client Profile or an assembly that depends on an assembly that is not part of the Client Profile.

Warning

Things to be Aware of

Visual Studio 2008 SP1 Beta generates a warning when referencing assemblies that *are* in the Client Profile

Unfortunately the list of assemblies that Visual Studio 2008 SP1 Beta uses to generate warnings is out of sync with the actual assemblies that are included in the beta release of the Client Profile.  So you may find that Visual Studio will generate warnings when referencing some of the Client Profile assemblies listed above, even though the assemblies are included in the Client Profile.

To work around this in Visual Studio 2008 SP1 Beta, you can simply ignore the warnings for any assembly in the list above (your application should still compile).

Or, you can manually replace the Client.xml files that Visual Studio uses to target the Client Profile (do this at your own risk).  Here are some replacement Client.xml files that are based on the list of assemblies that will be in the RTM release of the Client Profile.

%windir%\Microsoft.NET\Framework\v2.0.50727\SubsetList\Client.xml

<?xml version="1.0" encoding="utf-8"?>
<FileList Redist="20ClientSubsetList">
  <File AssemblyName="Accessibility" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="caspol" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="X86" InGAC="false" />
  <File AssemblyName="CustomMarshalers" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="X86" InGAC="true" />
  <File AssemblyName="dfsvc" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="InstallUtil" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="X86" InGAC="false" />
  <File AssemblyName="ISymWrapper" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="X86" InGAC="true" />
  <File AssemblyName="Microsoft.VisualBasic" Version="8.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="Microsoft.VisualC" Version="8.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="mscorlib" Version="2.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="X86" InGAC="true" />
  <File AssemblyName="RegAsm" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="X86" InGAC="false" />
  <File AssemblyName="sysglobl" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System" Version="2.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Configuration" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Configuration.Install" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Data" Version="2.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="X86" InGAC="true" />
  <File AssemblyName="System.Data.SqlXml" Version="2.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Deployment" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.DirectoryServices" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Drawing" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.EnterpriseServices" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="X86" InGAC="true" />
  <File AssemblyName="System.Runtime.Remoting" Version="2.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Runtime.Serialization.Formatters.Soap" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Security" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Transactions" Version="2.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="X86" InGAC="true" />
  <File AssemblyName="System.Web.Services" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Windows.Forms" Version="2.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Xml" Version="2.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
</FileList>

%programfiles%\Reference Assemblies\Microsoft\Framework\v3.0\SubsetList\Client.xml

<?xml version="1.0" encoding="utf-8"?>
<FileList Redist="30ClientSubsetList">
  <File AssemblyName="PresentationCFFRasterizer" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="PresentationCore" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="X86" InGAC="true" />
  <File AssemblyName="PresentationFramework" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="PresentationFramework.Aero" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="PresentationFramework.Classic" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="PresentationFramework.Luna" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="PresentationFramework.Royale" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="PresentationUI" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="ReachFramework" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="ServiceModelReg" Version="3.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.IdentityModel" Version="3.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.Printing" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="X86" InGAC="true" />
  <File AssemblyName="System.Runtime.Serialization" Version="3.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.ServiceModel" Version="3.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.ServiceModel.Install" Version="3.0.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="UIAutomationClient" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="UIAutomationClientsideProviders" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="UIAutomationProvider" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="UIAutomationTypes" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="WindowsBase" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="WindowsFormsIntegration" Version="3.0.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
</FileList>

%programfiles%\Reference Assemblies\Microsoft\Framework\v3.5\SubsetList\Client.xml

<?xml version="1.0" encoding="utf-8"?>
<FileList Redist="35ClientSubsetList">
  <File AssemblyName="System.Net" Version="3.5.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Net" Version="3.5.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.Core" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.Core" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Data.DataSetExtensions" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.Data.DataSetExtensions" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.AddIn" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.AddIn" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.AddIn.Contract" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.AddIn.Contract" Version="2.0.0.0" PublicKeyToken="b03f5f7f11d50a3a" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="AddInUtil" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="AddInProcess" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="AddInProcess32" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="X86" InGAC="false" />
  <File AssemblyName="System.Xml.Linq" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.Xml.Linq" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.ServiceModel.Web" Version="3.5.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.ServiceModel.Web" Version="3.5.0.0" PublicKeyToken="31bf3856ad364e35" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Windows.Presentation" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Windows.Presentation" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
  <File AssemblyName="System.Data.Services.Client" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="true" />
  <File AssemblyName="System.Data.Services.Client" Version="3.5.0.0" PublicKeyToken="b77a5c561934e089" Culture="neutral" ProcessorArchitecture="MSIL" InGAC="false" />
</FileList>

Regardless of the workaround you choose, you should still test your application on a machine that only has the Client Profile installed to ensure your client app works correctly on the Client Profile.

Some APIs that exist in Client Profile assemblies are not supported

Some APIs that exist in Client Profile assemblies are not supported because we have chosen not to include the dependencies required for them to function properly.  For RTM, we're planning to release some tools (such as an FxCop rule) to help prevent taking a dependency on these APIs when targeting the Client Profile.  And in future versions of the .NET Framework Client Profile, we may even remove these APIs altogether (possibly by moving them to other assemblies).  But until then, you should be aware of these APIs and be sure not to call them from your client app.

The following list of APIs are not supported on the Client Profile (even though they exist and are public).  Note: these may change slightly for RTM.

System.dll

  • System.CodeDom.* (all APIs in this namespace)
  • System.CodeDom.Compiler.* (all APIs in this namespace)
  • Microsoft.VisualBasic.VBCodeProvider
  • Microsoft.CSharp.CSharpCodeProvider

System.Runtime.Remoting.dll

  • System.Runtime.Remoting.Channels.Http.* (all APIs in this namespace)
  • System.Runtime.Remoting.Services.RemotingService

System.ServiceModel.dll

  • System.ServiceModel.Activation.* (all APIs in this namespace)
  • System.ServiceModel.ServiceHost

System.IdentityModel.dll

  • System.IdentityModel.Selectors.* (all APIs in this namespace)

System.Web.Services.dll

  • System.Web.Services.* (all APIs in this namespace)
  • System.Web.Services.Configuration.* (all APIs in this namespace)
  • System.Web.Services.Diagnostics.* (all APIs in this namespace)
  • System.Web.Services.Discovery.* (all APIs in this namespace)
  • System.Web.Services.Protocols.* (all APIs in this namespace)

Again, you should test any code that targets the Client Profile on a machine that only has the Client Profile installed to ensure it works correctly on the Client Profile.

Conclusion

The .NET Framework Client Profile should help significantly improve the experience of deploying .NET client applications on machines that do not already have the .NET Framework installed.  It has been designed to make it as easy as possible to deploy the smallest set of files necessary to run a typical .NET client application today.  Our hope is that your existing .NET client apps can be easily modified to target the Client Profile to take advantage of the improved deployment experience.  If you're having any trouble targeting the Client Profile, or you feel it is missing a crucial assembly required for client scenarios, please let us know!

Update: Troy Martez, a Program Manager on the WPF team, has an excellent blog post Introducing the .NET Framework Client Profile with more info on the Client Profile.

Posted by BCLTeam | 71 Comments
Filed under: ,
More Posts Next page »
 
Page view tracker