diff --git a/src/entries/sourcegear_bridge.html b/src/entries/sourcegear_bridge.html new file mode 100644 index 0000000..a19c739 --- /dev/null +++ b/src/entries/sourcegear_bridge.html @@ -0,0 +1,264 @@ +--- +layout: post +title: SourceGear Bridge preview: Swift with .NET in Xcode +date: 2021-09-20 12:00:00 +keywords: swift dotnet front aspnet bridge +teaser: TODO +--- + +

For quite some time I have been working on various +things involving interop between .NET and other ecosystems. +If you follow my blog or tweets, you've seen me talk about "Llama", +and then "Alpaca", and so on. Generally speaking, I have +referred to these efforts as my exploratory projects.

+ +

But now, one of those efforts (the one previously called "Alpaca") is +now called "SourceGear Bridge", and the new name reflects +our intention to develop this into a production-ready +solution with support available. (Note that I'm not +saying that it is production-ready now, simply that now we +are focused on getting it there.)

+ +

In broad brush strokes, we will describe SourceGear Bridge in terms of +delivering great interop between .NET and other things. +We hope to expand to more languages in the future, but for now the +primary focus is Swift. And for that reason, most of +my attention lately has been on providing the user +experience that Swift developers expect. In +other words, everything needs to work well in Xcode on a +Mac.

+ +

Preview release 0.2.0 is now available, and in this +blog entry I will walk through a simple demo. If you +want to follow along on a Mac, you will need Xcode 13, +configured to run Swift 5.5 on the command-line. The +non-Xcode parts of this demo will also work on Linux +if you install a Swift 5.5 development snapshot.

+ +

And of course you will need .NET 6 rc1:

+ +

https://dotnet.microsoft.com/download/dotnet/6.0

+ +

(If you're on a Mac, I recommend using the installer.)

+ +

For this blog entry, I'm going to start with the command-line +for a while and then switch to Xcode a bit later.

+ +

The .NET command-line interface

+ +

The .NET command-line interface is called dotnet, and its +basic design is similar to swift, where the first argument is +the name of a command. +Building with .NET? Use dotnet build. +Building with Swift? Use swift build.

+ +

To create a new web project with .NET, +you would use dotnet new:

+ +
+mkdir foo
+cd foo
+dotnet new web -lang C#
+
+ +

(The -lang C# argument is usually optional because +it's the default language for .NET.)

+ +

This will result in several files being generated. +The two important ones are foo.csproj (the project +file) and Program.cs (the source file).

+ +

You can take a look at these files if you like, but +I just wanted to mention them and move on to focus on how +to create the equivalent project in Swift.

+ +

Using dotnet with Swift

+ +

Many things about the .NET command-line interface +can be customized, including support for other languages. +So the first thing we want to do here is to install +some templates to let dotnet know about Swift:

+ +
+dotnet new --install sourcegear.bridge.swift.templates
+
+ +

In the command just above, sourcegear.bridge.swift.templates +is the ID of a package on nuget.org. NuGet is the package +manager for .NET.

+ +

Having installed the templates, we can can list the templates like this:

+ +
+dotnet new --list
+
+ +

And we can see that a couple of new templates are now available, +both of which are for the Swift language.

+ +

Let's use one of those templates to create the same project we did above, +except now in Swift: + +

+mkdir bar
+cd bar
+dotnet new web -lang Swift
+
+ +

This should create three things:

+ +
+bar.swiftproj
+Package.swift
+Sources/
+
+ +

The presence of the Package.swift file indicates that this +directory is now a SwiftPM package, and can be used with any +Swift tooling that supports Swift Package Manager, including the swift command +line tool as well as Xcode.

+ +

(For .NET devs: Package.swift looks like a Swift +source file but it's actually a project file, the equivalent of +a csproj.)

+ +

The presence of the bar.swiftproj file means that this +directory is also a .NET project, and can be used with +the dotnet command-line interface as well. +This file is the Swift equivalent of the +foo.csproj file. It's in a format called MSBuild, but +Swift developers shouldn't need to worry about that. Mostly +what this file does is explain to MSBuild how to get the information it +needs from Package.swift.

+ +

The source code for project is in +Sources/app/Program.swift just as one would expect for a +Swift package. We'll take a look at the code itself +later when we open it up in Xcode.

+ +

Continuing on the command-line a bit more, try swift build. +The first time you build the project +will take longer because it has to compile all the bindings. +The result of the build should appear as a shared library (on Mac, a dylib) in +.build/debug/.

+ +

The compilation model here is to build the +Swift code into a shared library. Then the tooling +generates a trivial .NET host program that +(1) initializes the bindings so that Swift +can call .NET APIs, and (2) passes control to the +the Swift code.

+ +

Now we can do dotnet run and you should see messages indicating +that the web server is running on port 5000:

+ +
+TODO replace this
+eric@LAPTOP-6A6HQVJ9:~/dev/bridge/swift/projects/minimal$ dotnet run
+info: Microsoft.Hosting.Lifetime[14]
+      Now listening on: http://localhost:5000
+info: Microsoft.Hosting.Lifetime[14]
+      Now listening on: https://localhost:5001
+info: Microsoft.Hosting.Lifetime[0]
+      Application started. Press Ctrl+C to shut down.
+info: Microsoft.Hosting.Lifetime[0]
+      Hosting environment: Production
+info: Microsoft.Hosting.Lifetime[0]
+      Content root path: /home/eric/dev/bridge/swift/projects/minimal
+
+ +

And now you should be able to go to a browser and access http://localhost:5000/ +to see: Hello World!

+ +

In the IDE

+ +

Okay, let's try opening the Package.swift file in Xcode, +either from Finder, or from the command-line, like this:

+ +
+open Package.swift
+
+ +

Here in Xcode, things should mostly work as you would expect, +like any other Swift project, with syntax coloring and code completion +and other niceties.

+ +TODO screen shot of the code in Program.swift + +

Most .NET APIs have documentation comments, and that +information is propagated through the bindings to make it +available with Quick Help:

+ +TODO screen shot of Quick Help + +

Code completion is especially helpful for a framework +like ASP.NET Core, which has many features and a large +surface area:

+ +TODO screen shot of code completion for a .NET API + +

A brief look at the code

+ +

Looking at Program.swift, there are import statements, typealias declarations, some +error handling, and a function declaration, but the essence of the matter is:

+ +
+let app = try WebApplication.Create()
+
+try app.MapGet(
+	pattern: "/",
+	handler:
+		Func
+		{
+			() -> System.String in
+			"Hello World!"
+		}
+	);
+
+try app.Run();
+
+ +

Three API calls:

+ + + +

The most interesting call here is the second one, the call to MapGet(pattern:handler:), which basically says "when somebody accesses the root URL, run this closure, which returns a string".

+ +

One thing you might notice is that the C# version is more concise +than its Swift equivalent. Both are using the same 3 +API calls from the so-called +"minimal" APIs which are new in ASP.NET Core 6. +TODO +https://www.hanselman.com/blog/minimal-apis-at-a-glance-in-net-6 +But currently the Swift incarnation ends up more verbose. +There are some things we can do in the future to +make things tighter. +A full explanation would fill another blog entry, but +for now I'll highlight a few of the ways that the Swift and C# code differ:

+ + + +

Next steps

+ +

We have lots to do as we move SourceGear Bridge toward a production-ready release. +Here's a few things in progress but not yet finished:

+ + + +

Enjoy!

+