Projectreunion: UWP/WinRT Libraries should be able to expose .NET interfaces and classes

Created on 19 May 2020  路  15Comments  路  Source: microsoft/ProjectReunion

Proposal:

UWP/WinRT Libraries should be able to expose .NET interfaces and classes

Summary

It should be possible to create UWP controls which implement .NET Standard interfaces in an UWP control library. Currently it's only possible when the control is moved to the project of the host application. This prevents the reusability of the control.

Rationale

When implementing an UWP control using ReactiveUI, we need to put an IViewFor<TViewModel> interface on the control.

For reusability with non-UWP Apps, the ViewModel might be a class from an .NET Standard project. Also the IViewFor<> Interface is defined in a .NET standard library.

As long as the control is defined in the UWP app project, everything works fine. However, the code does not compile when the control is moved to an external library.

Scope

It shouldn't be required to reimplement .NET Standard libraries as WinRT libraries.

| Capability | Priority |
| :---------- | :------- |
| This proposal will allow developers to expose .NET Standard interfaces and classes in WinRT libraries | Must |

Important Notes

Open Questions

It is unclear to me how to best approach this issue.

area-Projections feature proposal

Most helpful comment

Ah, it seems you are using "WinRT" to mean "the collection of technologies we called UWP." Our naming / marketing is not great here, sorry. (And if I misunderstood you - sorry as well :)).

WinRT is just a way to define APIs; _WinRT_ doesn't provide improved security - _running in an AppContainer_ (aka Native Container) provides you with improved security.

Most WinRT APIs are now available for .NET projects - add the Microsoft.Windows.SDK.Contracts package, the Microsoft.UI.XAML package and most things will work. Some still require identity - packaging as MSIX solves that - and a small number require AppContainer, which there isn't really an easy way to solve that.

(Please note I am not meaning to push back or claim everything is perfect today - it's not - but I'm trying to learn what you need... "public .NET types in WinRT assemblies" is a _very specific implementation ask_ that has a set of possibly-bad ramifications and you might not actually need that).

All 15 comments

Thank you! Are you aware of any samples we could look at to understand the request further? I think you're asking:

  • A C# project defines a type Contoso.IMuffin and has APIs that accept/generate IMuffin
  • A C++ type wants to implement Contoso.IMuffin on one of its objects and pass it to the C# type accepting IMuffin

Hey @Scottj1s or @kennykerr , any suggestions?

Here is a minimal example project:

WinRTTest.zip

I'd need to see a more concrete example, ideally one not involving Xaml. If this is specific to Xaml, we'd need to WinUI folks to chime in on how they recommend supporting this.

The problem is not specific to XAML. The XAML controls are just my use case.

When you do it like this instead:

public sealed class Foobar : IViewFor<MyViewModel>
{
    object IViewFor.ViewModel
    {
        get => ViewModel;
        set => ViewModel = value as MyViewModel;
    }

    public MyViewModel ViewModel { get; set; }
}

you have the same problem. In fact, exposing ANY .NET Standard interface will prevent the project to compile, which is unexpected, since WinRT libraries can perfectly consume .NET Standard interfaces.

A wild guess - without knowing the internals - is that the metadata exposed by the WinRT library is insufficient to describe the .NET interfaces.

To clarify: Are you trying to build a WinRT Library (because...?) and you want to expose .NET Standard types from that Library (because...?).

Do you expect 100% of the APIs to work for both WinRT and .NET clients, or do you expect "graceful degradation" where (eg) if you are using the API from C++ you can't use any APIs that require (eg) a System.IO.FileInfo object, but you can use the others that don't?

It's about how to structure a project. In a given solution I usually have the following projects:

  • the system specific host library, containing the Program.cs/App.xaml
  • the controls library containing the system specific UI logic
  • a business layer containing view models and other device indepent logic
  • data access layer libraries, containing database or API access

So in this case I need to expose the .NET interface in the controls library, because i need those for dependency injection configuration in the application host.

This kind of separation works perfectly well in all project types, including ASP.NET MVC, ASP.NET Blazor (Server and Client), WPF, Xamarin Android, Xamarin iOS and others. it only breaks in WinRT/UWP projects.

do you expect "graceful degradation" where (eg) if you are using the API from C++ you can't use any APIs that require (eg) a System.IO.FileInfo object, but you can use the others that don't?

I would expect full functionality and be able to use those interfaces from C++ too, because you can already use 'pure' .NET Standard libraries in WinRT Host projects without issue.

So I am unsure why degragation would be needed. However, it might be an option using a special moniker that marks the library such that it can be used from managed projects only.

Your guess is correct in that the WinRT type system cannot express all .NET types, and hence the compiler complains. The compiler is overly-aggressive in this case, since "who cares?" if your app has implementation details that aren't expressible, but that's the current design.

Is the Controls Library in your example supposed to be reusable from other languages like C++ or Python etc. or is it just private to your application? (I'm trying to figure out if you actually need a WinRT library that has non-standard types, or if you would be happy with just a .NET Standard library). I'm also curious what specific technique you are using to access the .NET Standard library from C++ today.

In the meantime, if you want a work-around, you could consider making your .NET types internal and use the InternalsVisibleTo attribute to access them from other assemblies. The compiler won't care about those, since they're not public.

since the goal is to create a UWP component library to be used by multiple UWP projects, so yes, this is the goal.

Using the internalsvissibleto is not a proper solution, since it inverses the dependency from host -> component to component -> host. (but I'll try that)

We're not using C++ and Python, so this is not my immediate need.

I guess the proper solution is to extend the WinRT type system to support .NET standard types.

since the goal is to create a UWP component library to be used by multiple UWP projects, so yes, this is the goal.

But do you require WinRT for that? (Pretend that the current tools didn't force you down that path... would you independently choose to build a WinRT library instead of just a .NET library? Why?).

I asked about C++ (or any non-.NET language, really) since you mentioned that you expected native .NET types to work without degradation in other languages, which surprised me because that's not generally the case today.

But do you require WinRT for that? (Pretend that the current tools didn't force you down that path... would you _independently_ choose to build a WinRT library instead of just a .NET library? Why?).

No. I always switch to WPF, because this issue prevents me from using UWP. Which is a shame, because UWP provides improved security features, portability and APIs which aren't available in .NET Projects.

An partial alternative would be to access the WinRT APIs from .NET projects.

Ah, it seems you are using "WinRT" to mean "the collection of technologies we called UWP." Our naming / marketing is not great here, sorry. (And if I misunderstood you - sorry as well :)).

WinRT is just a way to define APIs; _WinRT_ doesn't provide improved security - _running in an AppContainer_ (aka Native Container) provides you with improved security.

Most WinRT APIs are now available for .NET projects - add the Microsoft.Windows.SDK.Contracts package, the Microsoft.UI.XAML package and most things will work. Some still require identity - packaging as MSIX solves that - and a small number require AppContainer, which there isn't really an easy way to solve that.

(Please note I am not meaning to push back or claim everything is perfect today - it's not - but I'm trying to learn what you need... "public .NET types in WinRT assemblies" is a _very specific implementation ask_ that has a set of possibly-bad ramifications and you might not actually need that).

@MovGP0 I see you 'heart'-ed the response; does that mean we can close the issue, or are you still looking for the specific ask of _public .NET Types in WinRT assemblies_?

@MovGP0 I see that you're using the Windows Runtime Component project type, this project type creates a .winmd and is limited to only exposing WinRT types, which for all the reasons @ptorr-msft said, can't contain .NET types. We do support you creating regular .NET class libraries, in which case you can expose these .NET APIs to your customers. You do this by using the Class Library project type.

Screenshot below that should better articulate what I'm referring to:
image

Was this page helpful?
0 / 5 - 0 ratings