Issues with proposed WinJS support in 2.2

Topics: General
Nov 11, 2012 at 8:23 PM
Edited Nov 11, 2012 at 8:30 PM

Hi,

I wanted to summarize a few issues that I believe would cause major issues and confusion with the way the Win8-JavaScript target framework is currently implemented for 2.2. I know it's close to the 2.2 release, but I strongly believe that the feature should be postponed for a future release until the issues below can be resolved in a better way before creating confusion and causing frustration among the users.

I also wanted to preface this by saying that I've been actively developing a mixed WinJS/C# application, so the following is based on a real project.

The issue is that if a WinMD file references other assemblies, then things get confusing real fast. In order for the packaging to work correctly, the referenced dll's need to be in the same directory as the winmd file. WinJS cannot directly reference the dll files, but the WinMD file can. When things are packed, up, it'll correctly include the files alongside the winmd file.

Making things complicated, if the same dll is in two different directories, then AppX packaging gets confused and errors out: 

1>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\AppxPackage\Microsoft.AppXPackage.Targets(374,9): error APPX1101: Payload contains two or more files with the same destination path 'TimeZones.dll'. Source files:

1>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\AppxPackage\Microsoft.AppXPackage.Targets(374,9): error APPX1101: C:\Users\Oren\Documents\Visual Studio 2012\Projects\SampleApps\packages\WinRTTimeZones.0.7.2\WinRT\TimeZones.dll

1>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\AppxPackage\Microsoft.AppXPackage.Targets(374,9): error APPX1101: C:\Users\Oren\Documents\Visual Studio 2012\Projects\SampleApps\packages\WinRTTimeZones.0.7.2\lib\netcore45\TimeZones.dll

In this case, Nuget is adding a reference to the TimeZones.Dll from the \lib\netcore45 directory, as it should be. That file is in a different location than where it'd be for the WinJS app (pretend the WinRT dir in the path is \libs\win8-javascript).

Here's the scenario:

WinJSApp

DataAccess - WindowsRuntime component (netcore45)

CoreLogic - PCL(net45/netcore45)

DataAccess references CoreLogic. WinJSApp references DataAccess, as it's the only WinRT library.

There's also a TimeZones package (WinRTTimeZones) that supports PCL, NetCore45, WP8 and WinRT (let's say this is Win8-JavaScript).

You can see the repro in this project.

That alone isn't the entire issue. What happens if the WinMD file needs references that reside in a different package? There's currently no way to resolve this as the reference cannot be added to the WinJS project -- it has to be alongside the winmd file. This also doesn't take C++ WinMD files into account where there are platform-specific versions (x86/x64/ARM).

The better/correct way to deal with WinJS references (and Windows Runtime in general) is to fully support ExtensionSDKs as per Garrett's spec here and the comments in this thread: http://nuget.codeplex.com/discussions/396720. Unfortutely, I believe Garrett has been called onto other things and isn't currently able to work on the feature.

The reason Extension SDK's solve this problem is that they have the concept of both a redist and references directory. In the above example, the WinMD file would be in the references dir and the supporting DLLs would be in the redist folder. They also support the notion of dependencies -- so one Extension SDK can depend on another one. The contents of any required dependencies would be in that pacakges redist dir, so they'd all get copied to the output dir without needing to be directly referenced (Only the ExtensionSDK itself would be referenced and it'd all work). Extension SDK's also handle release/debug and platforms.

 

 

Nov 11, 2012 at 9:01 PM

First of all, I appreciate that you raise the issue. I'll research more about the situation of a WinMD file referencing a managed library. However, I disagree that we have to postpone the support for WinJS project.

The primary goal of adding WinJS support is for the case in this thread: http://nuget.codeplex.com/discussions/398222. So, it's definitely valuable. Plus, there's a solution for your scenario when both the WinMD and managed assemblies reside in the same package. You can use the <references> attribute in the metadata to filter out managed assemblies.

I believe Garrett is still working on the Extensions SDK support. It's slated for 2.3.

Btw, this discussion should be created in the General category, not the Ecosystem.

Nov 11, 2012 at 9:47 PM
Edited Nov 11, 2012 at 11:53 PM

I've moved this into the General category.

My concern is that the current solution is actually going to cause more problems as people don't yet realize the indirect ramifications (or haven't really fully tested) the scenarios.

Unfortunately, the references metadata is not a workaround in this case. First, it's impossible to currently do different references per target platform. In this case, I'd want the winmd to be referenced by the WinJS and the others by the .NET libs. That said, what if I have the following:

\libs\win8-managed
pcl.dll
Bar.dll

\libs\win8-javascript
pcl.dll
Bar.dll
BarWrapper.winmd

Suppose BarWrapper depends on the other libs. If my solution has a C# project that needs to use my Bar.dll and the WinJS needs BarWrapper.Winmd, I'm stuck. Even if only the winmd file is added as a reference to the WinJS, I'll still hit that AppX packaging issue as the path will be different. Filtering won't work because they all need the same references.

My concern is that if this goes forward, then it'll cause an irrevocable mess (as it'd be very hard to remove this behavior later). You'll have projects breaking and it'll be painful to fix it.

Here's another scenario: What happens to 3rd party references. So now I want my winmd file to use a logging package (MetroLog, for example). Do I put the MetroLog dlls in my \libs\win8-javascript dir? That'll create instant conflicts if a newer version of MetroLog comes out -- and is completely against the NuGet model of separating dependencies.

An additional issue: the current win8-javascript doesn't really support "any" winmd file; specifically, it can only support managed ones that are AnyCPU. C++ can also create Winmd files that WinJS can reference, but that'd require platform-specifics, etc (the extension sdk stuff).

I'm really just suggesting that we think this through, along with the various ramifications, before it's "too late." I really do want proper WinJS/WinRT support (and have been wanting it for a long time). I'm afraid the current approach has the appearance of being broad support for winjs components whereas what's supported is actually fairly narrow in scope.

Regards,
Oren

Nov 11, 2012 at 11:57 PM

Perhaps a workaround for now would be to enable support for just win8-javascript as a content reference for js/html/image files, etc and explicitly not support \lib references. Extension SDK support later on will enable that scenario properly.

That would seem to address the needs of the other thread without causing future headaches.

Nov 12, 2012 at 4:40 PM

In 2.3, we're planning to allow you to specify different <references> elements for different target frameworks. I think that will solve your scenario.

I'll think more about the other cases that you brought up. I'll also discuss with the team.

Nov 12, 2012 at 5:22 PM

Also, I want to add that the new framework moniker, windows8-javascript, that we are adding does not exacerbate this problem. The current windows8, (or netcore45) has the same issue. You point out that it fails for the case when a WinMD component references a managed .dll, but at least it works for the simple cases when the WinMD component doesn't reference a managed .dll or only references other WinMD components.

So I'm still reluctant to postpone the support for WinJS.

Nov 12, 2012 at 5:24 PM

I'm still not clear on the issue with the AppX packaging error though. Can you put a concrete repro steps, please?

Nov 12, 2012 at 5:27 PM

You're right that it's not the only thing that can cause the issue. I'd merely ask that adding lib\ support  goes beyond the initial request and might be best suited for extension sdk's later. I don't see any issues with supporting the monitor with the win8-javascript for content.

The repro project is referenced earlier; do you need something else?

To repro, create two components: A C# Windows Runtime lib and a WinJS one. Then create a NuGet package with the following:

\lib\windows8-managed
foo.dll

\lib\windows8-javascript
foo.dll
fooWrapper.winmd

Now add add the reference to each component. Also, add a reference from the WinJS to your C# WinRT lib. You should get the error then.

 

 

Nov 13, 2012 at 12:17 AM

Is foo.dll a random assembly and fooWrapper.winmd references foo.dll?

If I understand correctly, this error will happen even if you put both foo.dll and fooWrapper.winmd into 'windows8' folder, right?

Nov 13, 2012 at 12:26 AM

Yes, in this case, FooWrapper.winmd references the Netcore45 foo.dll to expose parts as a WinRT component -- a common pattern to reuse existing stuff.

If both the C# assembly and the WinJS one reference it from the same place, it'll be ok. The problem is if one is in Win8-managed and the other is in Win8-javascript.

This issue creeps up with PCLs too as they're in different folders.

Suppose you have a PCL package with the following:

portable-net45+win8
myPcl.dll

netcore45
myPcl.dll
myPcl.NetCore45.dll <-- platform specific assembly that mypcl.dll detects and loads via reflection.

Now I have a solution with the following:

PCL lib (A) which targets net45 and netcore45 and references myPcl.dll (nuget resolves the portable-*)
Windows Runtime component (B) that references the PCL and myPcl.dll & myPcl.NetCore45.dll (Nuget resolution is correct here as its a netcore45 assembly)

Either a WinJS or possibly C# WinStore app that references just the WinRT library (B). When the appx packaging happens, it'll get confused as there the assembly is in different locations.

 Ultimately, a better fix might be to write a set of msbuild targets that patches/fixes the problem and squishes the duplicate entries so that one of them will win.

Nov 13, 2012 at 9:26 PM

So we're thinking of dropping support for the windows8-javascript moniker altogether, but still keep windows8-managed. What do you think?

Nov 13, 2012 at 9:35 PM

The only thing I'd wonder is if there's still value in delivering win8-javascript for content files only. That'd still enable the original scenario and provide a way of distributing javascript libraries, images and static content to WinJS via NuGet.

Nov 13, 2012 at 9:41 PM

We thought about keeping it for content files, but we're afraid it may cause confusion to users. We haven't had a feature where it's allowed for 'contents' and 'tools' but not for 'lib'.

Another point is regarding the dependency's target framework. If we allow a dependencyGroup to have targetFramework as 'windows8-javascript', then it'll have the same issue as you pointed out. So we may have to kill it too.

Nov 13, 2012 at 9:54 PM

Yeah, I'm sure you're right about the confusion. I hate to be a "downer" on this feature as it'd be super-helpful, but I'd suspect that if Extension SDKs can be done for 2.3 that'd be a huge win that'd bring all of WinRT into the fold. Even WinJS-only libraries can (And are) shipped as Extension SDKs today, so they could be packed up for NuGet that way.

Nov 14, 2012 at 12:44 AM

Actually -- one question on "Windows8-managed" - is the intent for that moniker to replace the former winrt/netcore45 one? While netcore45 morphed into win8, does it make more sense just to revert back to the netcore45 designation and reserve "win8" for something else?

Nov 14, 2012 at 8:55 PM

No, we're not changing the moniker. It will break existing packages.

To summary, we treat winrt, netcore45 and windows8 exactly the same. They all match C#, VB.NET, C++ and JS Windows Store projects. I know it's inaccurate to apply netcore45 to JS, but we made a mistake and now we're stuck with them forever.

 

Nov 14, 2012 at 10:35 PM

Not that it's worth it for this (or this release), but it might be worth considering adding a schemaVersion attribute/element somewhere in the NuSpec file. That'd enable a "quirks" mode where you can change the schema or meaning of the elements while still preserving the older behavior for older packages.