 Welcome back to migrating a WPF app to .NET Core 3. We're up to the third step of the migration process, which is actually fixing build issues and adjusting to account for API differences between .NET framework and .NET Core. As you may remember, we've already done the preparation and the CS project creation. So now we're ready to go in and try to build the project and make necessary changes to get things up and running. So in general, the sorts of things that we're going to have to change are we're going to have to add some packages that we weren't referencing before to include APIs that maybe aren't in the .NET Core runtime package. This especially would include window-specific APIs like registry, ACLs, WCF client APIs. These are types and methods that work on .NET Core, but aren't included in the .NET Core runtime package by default because they don't work cross-platform. Of course, .NET Core itself runs on Linux, Mac, Windows. So there's actually a helper meta package called Microsoft Windows Compatibility. I'll how about Nuget to show you that, that we're going to want to add. So Microsoft.Windows.Compatibility. In general, if you're porting a WPF or a WinForms app to .NET Core, you'll probably just want to add this reference upfront because it's going to be useful. We also will have to make some small differences where one code path is necessary on .NET Core, another one is necessary on .NET Framework. We can use a pound ifs for that and constant definitions that will allow us to differentiate between when we're building for .NET Core and when we're building for .NET Framework. Then as we go through this, we'll also want to be aware of just the things that we'll need to change. These things all would have showed up in the portability report at the very beginning. But if you want to go learn more, you can go out to a documentation where we talk about some of the APIs that are different between .NET Framework.NET Core. App domains are different. Many of the App domain APIs are still available. So if you're just using App domain APIs to get information about the domain, that's likely to work, but creating new App domains is not supported. Remotings is another one where some pieces of remoting like proxying can be done with system reflection dispatch proxy and stuff like that. But most of the IPC portions of remoting no longer work, so you'll need an alternative for that. Code access security is no longer supported. Security should not be done at the managed code level. It should be done at the system level. So these are sorts of things that we may run into. In this particular app, I don't use any of these APIs because I understand that these are not supported and I wanted this to be a project that was reasonable to port quickly. But in your own apps, these are things that may require a little bit more re-architecture. You might want to think about those up front before you dive into the porting process. So let's go ahead and demo fixing some compilation errors. There's going to be a few here. Well, start in Visual Studio like I did before. I'll do some of this in Visual Studio, some of it from the command line. Actually, the first error we're going to see, it may be belonged in the previous video. Something I see here is that this is actually an error trying to build the original.net framework project that we started from, that we haven't really changed yet. The issue is that it says there's no reference for .net framework 472. I need to rerun Nougat Restore. The reason it's giving me this is remember that for this porting effort, I decided to put the .csproj files for the .net core project and the .net framework project in the same directory. That's one of a few different ways you can set this up. It's just as good as any, but they each have their own unique challenges. The unique challenge of having them in the same directory is exactly this. What's happening here, if I come to the right window, we have this project.assets.json that's created when we restore. It gets put in our intermediate output folder. This is restored for .net core app 3.0, because this is the file that was generated when we did a .net restore on our new .net core project. So there's a conflict here between the output paths for our new .net core project and our previous .net framework project. So what we're going to want to do is we're going to update these so that they're building to different locations. Now the obvious way to do that would be to come into the .csproj and add a base output path is something base intermediate output path to something else, but that doesn't work initially because we're using this SDK attribute. Let me tell you what this is. So in the new project file format, you can specify an SDK and that will automatically import some props and targets files that you need to build that project type. So in this case, we're using the Windows desktop SDK. As part of importing those props, it's going to make use of the intermediate output path so that if you change it later, it won't have an effect. So if I were to set some properties here for my intermediate output path, that's too late. And I already will have restored things or built to the wrong folders. So there's a couple of ways to work around that. One option is to not use an SDK. Instead, you can get rid of this part of the project element and you can just import the necessary props and targets files yourself and you can put them a little bit farther down, maybe, in your csproj file so that you have an opportunity to change things beforehand. The other possibility is that you can use what's called a directory.build.props file. Let me show you how that works. If I add directory.build.props, by convention, MSBuild knows to look for files named directory.build.props or directory.targets or directory.build.targets in the same folder as the project that it's building or in any parent or ancestor directory. And if it finds one of those files, then it uses whatever props or targets are in there and applies them to the project as if they were in that project file. And so we can use this as a way and this is actually processed prior to any of the SDK stuff. So by having a directory.build.props file, we're able to change things like the intermediate output path before the SDK kicks in and so it will take effect. If you're interested to read more about this challenge and the different ways of solving it, there is, let me find it here. Here we go. There's a GitHub issue that I think does a good job explaining why this is important and how to solve the problem. So here, I've got the Microsoft MSBuild GitHub repository and look at issue 1603. There are some good explanations in here that you can read about how to solve this problem. So for us, I think the easiest thing is just to use a directory.build.props file. So I'm going to say here in that file that my base output path is gonna be MSBuildProjectDirectory slash out slash the project name slash bin. Similarly, I'm going to use this Similarly, the base intermediate output path will be the same path but with OBJ. So now what that means is I can get rid of bin and OBJ hopefully unless VS has them locked. And when I build, both of these projects can build and they'll build to their own folders in the bin and OBJ directories. Therefore, when I do a .NET restore, I'll get two separate project.assets.json files. One in, you know, bean trader client dot c, bean trader client slash OBJ and one in bean trader client dot core slash OBJ. So if I come back over here, this point I should be able to rebuild the solution and it should pick up that change. Okay, awesome, it did. I've got the warning from using a .NET Framework 4.6 package, which remember is allowed and in this case should be fine. So I ignore the warning. We've just got this error about a property on my maps metro window not being available. Well remember one of the things we changed in the previous video was we updated some NuGet packages to get versions that target .NET core and one of the ones we updated was the my apps package and I guess I can't navigate from there but I can hop in here and do it. And what we're discovering is that some APIs have changed previously. There was a property on the metro window type called title caps, but now there is not. Instead, if I search for like title, there are some other properties we have title character casing which is going to do the same thing but it's a slightly more flexible API. So this is a difference between my apps metro 165 and 2.0. In general, when you upgrade your NuGet packages, especially if you upgrade across a major version boundary, you're likely to find these sorts of small differences and you may need to make some changes to make sure that things are going to work using the new versions. So in this case, the fix is very simple. Instead of using title caps, we can use title, what was it, it was title character casing and the value will be, it's not auto completing form, maybe I can come over here and see that the value needs to be normal. Okay, there we go. Having made that change, I can now build and that should take care of that error. I'm actually going to build both my projects separately because I do want to make sure as we're making changes, I want to keep building the .NET framework version of this project to make sure that it builds. Sure enough, it succeeds, it builds successfully. That's good. That means that this title character casing property must exist on my apps metro 165 and 2.0. If it only was on 2.0, then I might have to have differences in how .NET Core .NET framework versions of this project set this property or maybe the simplest thing, I can just update the previous project to also use the newer version of the NuGet package so that the code that they share will be the same. In this particular case, that's not necessary because the API that I'm using now is available on both versions, so it works fine. Okay, so we're able to build the old project. That's good. We've got separate option bin folders. Let's go ahead and hop out to the console and I'm going to do a .NET build. And again, we've got the two project files, so I have to specify which one I'm building. I'm doing a .NET build on BeanTrader Client Core. So let's check this out. That's interesting. So that's complaining about auto-generated XAML source not being available. I find that this is still sometimes a little bit flaky if I have VS open as well because VS is building in the background. So I mean, most people won't be using both the command line and Visual Studio at the same time. If you are and you see these sorts of errors, they could be transient and you just need to rebuild. Okay, now we've got 196 errors. So, you know, not too bad. I've ported projects to .NET Core that had way more than that and you're going to see that these actually will be able to take care of these pretty quickly. Just sort of glancing through them. I'm seeing a lot of this thing already contains a definition for. There's a lot of things that already, it seems like they're being defined multiple times. And if we start looking at some of these files, what we're going to realize, BeanTrader Client Core Obj and BeanTrader Client Obj, WPF is going to build some source automatically for your XAML pages and drop it in the intermediate output folder. That stuff gets picked up, it gets built, great. However, we're picking up things from the wrong intermediate output folder here. Look, we're picking things up from the .NET Frameworks folder. And of course, you know, this is the sort of thing you're going to run into from time to time because we have this new style csproj file that automatically includes all the cs files that are under it. And so, we moved the output folders but they're still underneath the path where we have our csproj files. So we need to explicitly come in here and if there are folders, maybe output folders for different projects and other things like that, you want to exclude those from being auto included. So I'm going to remove from compiling anything that's under out BeanTrader Client and any subdirectory under that that is unrelated to this project. So I'm going to ignore that part of the output folder. And that should make a big difference. Come back in here. We get 102 errors, so we're making some progress. Now these errors appear to mostly be related to not being able to find types for WCF communication. Now remember, I was saying that when you have a .NET Core app, by default it's going to include the .NET Core runtime assemblies, things like the base class libraries and some core file IO APIs, anything that's in that core cross platform .NET Core product. But there are a lot of packages that don't get included by default because they don't make sense in all scenarios. One of the ones that doesn't make sense in all scenarios is these service model APIs. So these need to be added in a separate package. Now there's different ways we can go about this. If we didn't know where these lived, if we weren't sure, there's a few ways we can go investigate. One very useful website that you might want to check out is called APIs of .NET. Let me take you out there. It's a catalog of all of the .NET APIs so I could search for something like system service model, operation contract attribute is one way and I can see that beginning with .NET Core 3.0 this is available for .NET Core so that's good news, previously it wasn't. But I can see the assembly it's in is system service model primitives. So that's going to give me an idea of what sort of package I might need to include that in my project. So if I search for system service model primitives, sure enough there's a NuGet package with that name. Now this particular package, being called primitives, it gives me a clue that probably I don't want to include this directly. There's probably a higher level system service model package that depends on this. If I search for system service model, sure enough we've got system service model, net TCP, system service model duplex. Well I'm using net TCP duplex communication so those are probably the things I'm going to need. I can come over here and now it's pretty easy to do a .NET add to bean trader client core.csproj, package system.servicemodel.duplex and once that's finished I'll do system.servicemodel.nettcp. Now I went through that to show you some of the websites and some of the process I use when I'm trying to figure out where a particular API came from so that I can include the right .NET related NuGet package. For many of these things though, you won't even need to do this if you preemptively include the Microsoft Windows compatibility package that I mentioned in an earlier video. This is a meta package that includes many useful .NET framework packages that can be used on .NET Core but aren't useful in cross-platform scenarios. So they're not in the box automatically but if you know you're only going to be running on Windows like with a WPF or a WinForms app then you can add a reference to Microsoft Windows compatibility and that's going to pull in for you your registry APIs, some Codem APIs, some directory services and IO stuff, some crypto APIs that have different signatures than the cross-plat alternatives, some service model stuff, some ACLs APIs. These are all things that are available on .NET Core but you wouldn't get if you were running on a different OS. So let's go ahead and add this package as well because we do have registry usage. We're going to use some of these APIs and I didn't add it initially because I wanted you to see these errors and how we fix them but in your own porting I would recommend you just add this up front. It'll save you a little hassle because now if we come in and we build we're going to find it's a lot cleaner. In fact, we're down to let's see, a single error. So you see that cleaned a lot up. So it says that TradingViewModel2 doesn't implement an interface member. Okay, let's go check out this old unused ViewModel file and see what this is all about. Okay, it implements, I notify property changed but it doesn't have a property changed event. So yeah, the error is correct. This will not compile. This is not good C sharp. So how did this get in here if our .NET Framework project compiled? Where's this thing live? This is under ViewModels. Here it is, right here. But you know, if I look at my old project it's not there. This C sharp file is on disk but it's not included in the project previously. And of course I did this on purpose. You can see I put a comment here that this is just here for demonstration purposes but this is a pattern that I see a lot when I'm working with customers. They might have a lot of C sharp files on disk that weren't being used and that's fine with the old CS project format. They're ignored if they're not mentioned in the project file but now with the new project file we automatically include everything. So just be aware that in a migration scenario if you've got extra sources sitting around on disk we're gonna try and build it. Now if you had a lot of these you might want to change the CS project. You might want to not auto include everything under under the current directory and you might want to explicitly just include the C sharp files you know that you need and you could copy that list from the old project. But in this case it's just one file. If it's sort of scoped you can just add a compiler remove the same way we did for items that were in the other projects output path or even easier if this is something you actually don't need. If it's not being used for reference or something if you really truly don't need it anymore take this opportunity to clean up your disk and just delete it. And at this point now that was that last error so let's go ahead and do a .NET build and see what happens. Okay we've got 11 more errors. So it went up because the C sharp compiler is a two pass compiler. During its first pass it just looks at method signatures that tries to make sure that all of your references are available and that they line up. And those were the errors we were fixing up until now. You know that interfaces are implemented properly and so on. Well now that we've addressed those problems this C sharp compiler is successful enough that it moves on to its second passes which is where it actually looks at implementation. So it's actually trying to turn our C sharp into IL at this point. And so now taking a look at the implementation of our methods there's a second round of errors that the C sharp compiler finds. So you're gonna see this sort of two phase pattern when you're working on a project with a lot of issues. And you know especially if you're doing like a migration from one .NET platform to another. We're at about 20 minutes now though and I don't want each of these individual videos to get too long so I'm gonna end this one and in the next video in session four we'll go ahead and we'll finish fixing the remaining compilation errors that we have from this second pass and we'll get this project actually building on .NET Core.