Migrating a WPF App to .NET Core 3 (2/5)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
>> Welcome back to Migrating a .NET Framework WPF app to .NET Core 3. In this second video, we're going to actually start the migration, now that we've done the preparatory work, we're going to create a new Csproj make sure that we have updated versions of our NuGet packages. So that will be all set up for a video three where we actually start making code changes. So again, I see migration has a four-step process where you prepare, you get the project file setup and adjust NuGet packages and other third-party dependency references. Then a fourth step where you fix the code and then you run and you test and you find any runtime differences and you account for those. So we're on step two now. Now, one of the first things we have to think about when we're setting up our new Csproject file is where does this project file live? That might not seem on the surface like a very interesting decision, but it actually is because it's going to, no matter what answer we give to that question we're going to have some challenges. Now, the first option and the one that I would recommend starting maybe six months from now or whatever .NET Core 3 is in a state that you can go live on it would be to just replace the old project file. You could imagine getting rid of the old project file putting a new one in its place, and if you want to target both .NET Framework and .Net Core you could use multitargeting to do that. Right now that's not a great option because multitargeting doesn't work well with the designer. So, if you need to go in and use the WPF designer to shift some UI elements or drop something in you're not going to get to do that with this new project or at least it may not always work well and multitargeting allows it to work occasionally but you can't count on it. So you'll just be doing your UI updates in the XAML. The whole multitargeting process I think is the way we're going to want to do this eventually but I don't think that experience is there yet in the .NET Core 3 previews. So if we don't do that yet, then we're going to have to project files assuming that we want to continue building for .NET Framework since that's the thing that we can go live on now and it has the designer support. So we either can put this C# project files next to each other in same directory or we put them in separate directories. If we put them next to each other in the same directory, that's going to make it easy to reference all the source, the XAML and the resources because they're all going to be at the same place as relatively. But that's going to introduce a challenge because these two Csproj files are going to have the same default, intermediate output and the same bin folders. They're going to get in each other's way when they're restoring packages, when they're building. So you're going to have to make some changes to actually have them you separate output folders. Unfortunately, there's actually a couple of issues right into how with publishing a .NET Core app when you've changed the intermediate output folder or at least a .NET Core WPF app, such that you do a .NET clean prior to running .NET publish, totally something you can work around. But there's just some rough edges here, and it's going to be a little bit of a hustle. Now again, this is a perfectly good option but we're going to have to do a little bit of work to make it do what we want as far as just updating these output paths. So you might think okay, well, I'll avoid that by putting these in separate directories. So that's going to solve all the problems I just talked about, but now you're going to have a problem. The new .NET Core project file format doesn't need to explicitly depend on C-Sharp source, XAML, pages, or resurrects files that are in its directory or in directories underneath it's directory. If you're in a separate folder with your Csproj you don't get that benefit, you're going to have to explicitly reference all those things worse because just adding those references isn't so bad that's just like we used to do it with the old project file format. Worse there's currently some issues I can go out and show you this GitHub issue where right now you have to explicitly link those files the automatic link generation isn't working. So in order for some XAML built processes, you actually need to add a link element to your pages so that they show up in the right relative path from your project files point of view. So you might say, "I'm going to reference../old projects/mainwindow.XAML." But you also need to add a link element to that saying that we'd link it to just main Window.XAML so that it doesn't see that directory traversal because that will mess up some of the WPF built stops. So again, that's totally solvable not blocking at all. It just means if we go this route there's a few extra steps we have to take. So eventually, a year from now six months from now whatever, we're just going to replace the old project file with a new one that multitarget everything will be great. In the interim, we have to decide between these other two options both of which have a couple of rough edges but should it be blocking? So just a heads up about that. So for this demo let's go ahead and create a new project. We're going to actually use in the same directory approach, because I know they've had some other videos recently where people put them in separate directories, and so just for variety's sake. Let's see what this path looks like and we'll go from there. So, here we are at visual studios. So we need to create a new .NET Core project. This could just be right-click "Add New Project.'' But again, I want to put in the same folder and I don't want like the program.Cs it gets auto-generated all that stuff. So I'm actually just going to create the Csproj directly and rather than created by hand which would be one option, I'm going to go to a temporary directory. I'm going to say .NET new WPF this way, I get the template and I don't have to remember what the SDK is called and stuff like that. Because you can see here's the contents of this auto-generated Csproj file. It's got that nice Windows desktop SDK, it's got .NET Core App 3.0 is the target framework WIN XL put uses WPF true. This is what we want our project file to look like initially. So I'm going to become into VS code, add a file and call it BeanTraderClient.Core.Csproject because I can't call it Bean Trader Client.Csproject that would conflict. I'm just going to paste this in. There we go. We've got a CS platform now for a simple app maybe a Hello, World or something a little bit more complicated we would be done. Because if I come over into Visual Studio and I add that project to my solution, what you're going to see, let's see come in here and add it. You'll see that we already have all of the C-Sharp sources referenced by Rezek files are here, we've got our XAML in the views folder because a lot of that stuff automatically included by the new project file format. It automatically looks for those and include them in the right way in the project. In a more complex project like this one though we're going to want to go through and actually look at the old Csproj to see if there's anything else we have to change, because there will be some things that will be a little bit different here that we want to make sure are done right in the new project file. So what I'm going to do is I'm going to come over here, VS code, I'm going to open both the old and the new project file, I'm going to put up side-by-side. Let's go ahead and look through the old project file to see which parts of it we need to bring over into the new project file. So let's go through and see which of these properties and items we need in our new Csproj. So we've got these imports. We don't need this because we referenced an SDK and an SDK attribute on the project will imply that we're importing prompts, the targets that are necessary to build this type of a project. So that takes care of the standard imports. So we skip over that. We do probably want root namespace and assembly name, because if we add new files we want them to use that namespace by default and we want the app to build be called BeanTraderClients it looks exactly like the old one. Not BeanTraderClient Core despite the different Csproj name. We don't need to auto-generate binding redirects because .NET Core doesn't use binding redirects. I don't use these constants in my project but this reminds me that I do probably want to add a constant. Because I find it's useful to define a constant indicating that we're building for .NET Core, so that if we have sources shared between the .NET Framework and .NET Core projects, in some cases we may need to do one thing for .NET Core one thing for .NET Framework if they're small API differences or something. So having this constant available makes it easy to use a pound if to do that. >> There's Application icon, we need that, so we'll bring our app icon over. Here's the things that we're building. Most of these we only need, like the application definition including app.xaml, that's done by default, all C# files in or under this directory or compiled by default, so we skip those, XAML pages are included by default, so we skip those. Here's a resource. Embedded resources are included, but resources are not. So we need an item group, where we can add this resource. We also have to add content. Well I mean some things will be added by default as content, but this one is interesting because it's a XAML file, but I'm adding it as content. The reason I'm doing this is because I'm using my apps theming, to change like the color scheme or the accent of my app dynamically, and customers could choose which theme they want. But I'm actually loading some of the themes from disk so that we can have a style defined in XAML on disk and then at run time we load that dynamically and we use it as a theme. So that means that this XAML file does not need to be a page, but it should be content. So I'm actually going to copy it as content because actually if I come over and look at Visual Studio, you will see that XAML page is right now included as a page because that's what happens by default. So instead, we're going to add it as content, and I'm actually going to remove it as a page. I'm not only gotten to remove default accent.xaml, I'm going to remove, I mean use a globing patterns like you can with the new project files, I'm going to remove that file in any folder, not just the resources themes defaults, so that way after we copy it to our output directory or to an intermediate output directory, we won't start building it as a XAML page from there either. These ones are fine. Assembly info.cs is an interesting one, it's included automatically, so that's good, but if we look at what assembly info.cs is, it has a bunch of assembly attributes, and this was part of our new project template when we created the WPF app originally on.Net framework. It has these attributes for things like assembly, title, copyright, culture and so on. These assembly level attributes are auto-generated in.Net Core based on properties in your project files. So we actually can run into an issue here because these attributes will conflict with the auto-generated ones. Now, if this was a new project, it wouldn't be a problem because we wouldn't have assembly info.cs, we would just set properties in our Csproj to define those values, but in this case, it does become a problem. So I'm going to add a property called generate assembly info and I will change that to false instead of its default true. What that means is that we're not going to auto-generate those assembly level attributes, and therefore we'll just use this one instead. Other things that might be interesting, the AppConfig is included automatically, embedded resources are included automatically. Resources are not like I said, if we come over here and we can take a look at the images and these images can build type none, so they're in the none group. In fact, I want them to be resources so that they're embedded in my assembly, so I need to add more resources here. But again, we could use that globing patterns. So instead of adding each image individually, I could add all PNG files anywhere under the directory, the CS projects, or if I want I could say just under resources or resource images, you can scope it. But I'm going to include all the PNG files as resources. Finally, remember I said in the last video that by switching our NUGET dependencies to use package reference syntax, instead of using a packages that config file that would make things easier later. Well, here's what it makes it easier, it means that I can copy and just paste that item group and this is going to work in this Csproj, the same as it would've worked previously. So we don't need to make any changes here, we just pick up our do our NUGET references, we plop them down here and we are good to go. So at this point, the Csproj file is essentially done, the only thing that's left to be done is to update the NuGet packages to the right versions or to change them if we need to change them. So I can come out to my command prompt here and to a .NET restore, and I've specified which projects since I have to Csproj files here now and I can do this for Visual Studio as well. There's a lot of stuff that can be done either from the Visual Studio IDE or from the command prompt, both are great, it's just a matter of preference. So I'll bounce back and forth so you can see both ways for a lot of the operations that I'm doing. In this case, I did a .NET restore, I get some warnings that there are packages that are targeting .NET framework that I'm using instead of .NET Core. Remember, we talked about this previously that's expected. This is the point where I'm going to need to update some of those. There's different ways we can update them. One way is to do a .NET add, and then I specify the package that I'm adding to. I then say package, and I need to give the name of the package, so I'll say MahApps.Metro, and this will update the My Apps reference, actually it will updated to the latest stable version. In our case we don't want stable version, we want the one we found out on NuGet that's supported .NET Core, so I will search for MahApps.Metro, it's this Tuo alpha that we want. So I'll actually copy that version so I get the version right, we will add that. So by doing a .NET AD package, I'm now updating the package version that we're depending on to a more recent one which supports .NET Core. If we come over to Visual Studio, we can do the same thing from here. We go to Manage NuGet packages, see the ones that are installed. So we can take things like the Microsoft Azure common, I know the 2.0 version did not support .NET standard or .NET Core, but the latest stable one does support that. So we're going to update, say "Yes", let that update. Then you can see here some of the other warnings, there's Microsoft Identity Model, Clients Active Directory did not target .NET frame or .NET Core, but the newer version does, so I update that one to 451, instead of version 229. Then the Neato async is another one, that has a pre-release that supports .NET Core. So I'm going to update from 401 to 500 pre05. That should be all of my packages that need to be updated. Again, in the first step, we went through and understood what our packages were, so that we knew if we were going to have any issue. So we know now what needs updated and we can do those updates pretty quickly. Let's do one more .NET restore. I have to save changes. When I make changes with the new get package manager here, it doesn't actually save the changes until I hit that "Save" button. So now I'll do a .NET restore. I still have one warning. There's this Microsoft XAML behaviors WPF, so what is that? I'm not depending on that directly, it must be a transitive dependency that comes in, thanks to the closure of dependencies of things that I depend on at a top level. An easy way to find out how things are being pulled in, is to go look in your object folder, there should be a file called Project.assets.JSON. This is produced when you do a .NET restore, and it shows everything that's pulled in from NUGET. The're libraries, there's the files, which packages they're part of, why those packages are referenced. So I can search for that Microsoft XAML behaviors, I see it is included because it's a dependency of the controls EX package. Controls EX in turn is included because it's a dependency of MahApps.Metro. Okay. So this is interesting. My project is depending on a NuGet package that targets .NET framework instead of .NET Core. You remember I said that's not really what you want, it's okay, but it's not best. In this case, there's not a lot I could do about it because it's not a direct dependency. If I really wanted to use a different version of this Microsoft XAML behaviors WPF library, I could add a reference to a particular version of the NuGet package as a top-level dependency and then everything would use that. But in this case, I don't think there even is a newer version, that's the latest version, so there's nothing to switch to. But because it's not a top-level dependency, it's more likely to be okay. MahApps.Metro with their version 2.0 has said this targets .NET Core. So they have a dependency which depends on .NET framework, but presumably when they targeted .NET Core, they test it on that platform, and they said, "Yeah. This works on .NET Core, it's safe to use." So I'm going to trust the owners of the packages I'm depending on directly and say if they're pulling at something transitively that targets .NET framework, it's probably fine. Because again, many .NET framework packages can be used, and this one probably is safe, at least in the ways that MahApps.Metro it controls EX or using it, otherwise they would have trouble targeting .NET Core. So this particular warning is probably safe and we can consider our project file done at this point, it looks a lot like our old project file, but way smaller. We automatically include a bunch of stuff, we make a few modifications with globing patterns and we've got our references to other packages or projects. That's really all you need to do, and now we have two project files, one that targets .NET framework, one that targets .NET Core. Next stop, we're going to do a .NET build, and we're going to just start going through build errors. That's the majority of the work in a migration efforts, so that's probably can be two videos. So I think coming up in videos three and four, we're going to be doing the code level changes that we need to make this app work on .NET Core.
Info
Channel: Microsoft Visual Studio
Views: 3,973
Rating: undefined out of 5
Keywords: WPF, .NET Core 3.0, .NET, .NET Core, Github
Id: Ea3o4DqnsG0
Channel Id: undefined
Length: 20min 31sec (1231 seconds)
Published: Thu Jun 06 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.