|
| 1 | +--- |
| 2 | +title: Migrating Modern Desktop Applications |
| 3 | +description: Everything you need to know about the migration process for modern desktop applications. |
| 4 | +ms.date: 09/16/2019 |
| 5 | +--- |
| 6 | + |
| 7 | +# Migrating Modern Desktop Applications |
| 8 | + |
| 9 | +In this chapter, we're exploring the most common issues and challenges you can |
| 10 | +face when migrating an existing application from .NET Framework to .NET Core. |
| 11 | + |
| 12 | +A complex desktop application doesn't work in isolation and needs some kind of |
| 13 | +interaction with subsystems that may reside on the local machine or on a remote |
| 14 | +server. It will probably need some kind of database to connect as a persistence |
| 15 | +storage either locally or remotely. With the raise of Internet and |
| 16 | +service-oriented architectures, it's common to have your application |
| 17 | +connected to some sort of service residing on a remote server or in the cloud. |
| 18 | +You may need to access the machine file system to implement some functionality. |
| 19 | +Alternatively, maybe you're using a piece of functionality that resides inside |
| 20 | +a COM object outside your application, which is a common scenario if, for |
| 21 | +example, you're integrating Office assemblies in your app. |
| 22 | + |
| 23 | +Besides, there are differences in the API surface that is exposed by .NET |
| 24 | +Framework and .NET Core, and some features that are available on .NET Framework |
| 25 | +aren't available on .NET Core. So, it's important for you to know and take them |
| 26 | +into account when planning a migration. |
| 27 | + |
| 28 | +## Configuration files |
| 29 | + |
| 30 | +Configuration files offer the possibility to store sets of properties that are |
| 31 | +read at run time and affect the behavior of our apps, such as where to locate a |
| 32 | +database or how many times to execute a loop. The beauty of this technique is |
| 33 | +that you can modify some aspects of the application without the need to recode |
| 34 | +and recompile. This comes in handy when, for example, the same app code runs on a |
| 35 | +development environment with a certain set of configuration values and in |
| 36 | +production with a different one. |
| 37 | + |
| 38 | +### Configuration on .NET Framework |
| 39 | + |
| 40 | +If you have a working .NET Framework desktop application, chances are you have an |
| 41 | +*app.config* file accessed through the <xref:System.Configuration.AppSettingsSection> class from the `System.Configuration` namespace. |
| 42 | + |
| 43 | +Within the .NET Framework infrastructure, there's a hierarchy of configuration |
| 44 | +files that inherit properties from its parents. You can find a *machine.config* file |
| 45 | +that defines many properties and configuration sections that can be used |
| 46 | +or overridden in any descendant configuration file. |
| 47 | + |
| 48 | +### Configuration on .NET Core |
| 49 | + |
| 50 | +In the .NET Core world, there's no *machine.config* file. And even though you can continue |
| 51 | +to use the old fashioned <xref:System.Configuration> namespace, you may consider switching to the |
| 52 | +modern <xref:Microsoft.Extensions.Configuration>, which offers a good number of enhancements. |
| 53 | + |
| 54 | +The configuration API supports the concept of configuration provider, which |
| 55 | +defines the data source to be used to load the configuration. There are different |
| 56 | +kinds of built-in providers, such as: |
| 57 | + |
| 58 | +- In-memory .NET objects |
| 59 | +- INI files |
| 60 | +- JSON files |
| 61 | +- XML files |
| 62 | +- Command-line arguments |
| 63 | +- Environment variables |
| 64 | +- Encrypted user store |
| 65 | + |
| 66 | + Or you can build your own. |
| 67 | + |
| 68 | +The new configuration allows a list of name-value pairs that can be grouped |
| 69 | +into a multi-level hierarchy. Any stored value maps to a string, and there's |
| 70 | +built-in binding support that allows you to deserialize settings into a custom |
| 71 | +plain old CLR object (POCO) object. |
| 72 | + |
| 73 | +The <xref:Microsoft.Extensions.Configuration.ConfigurationBuilder> object lets you add as many configuration providers you |
| 74 | +may need for your application, using a precedence rule to resolve preference. |
| 75 | +So, the last provider you add in your code will override the others. This is a |
| 76 | +great feature for managing different environments for execution since you can |
| 77 | +define different configurations for development, testing and production |
| 78 | +environments, and manage them on a single function inside your code. |
| 79 | + |
| 80 | +### Migrating Configuration files |
| 81 | + |
| 82 | +You can continue to use your existing app.config XML file. However, you could take this opportunity to migrate your configuration to benefit from the several enhancements made on .NET Core. |
| 83 | + |
| 84 | +To migrate from an old-style *app.config* to a new configuration file, |
| 85 | +you should choose between an XML format and a JSON format. |
| 86 | + |
| 87 | +If you choose XML, the conversion is straightforward. Since the content is the same, just rename the *app.config* file |
| 88 | +to a file with XML extension. Then, change the code that references AppSettings to use the `ConfigurationBuilder` class. This change should be easy. |
| 89 | + |
| 90 | +If you want to use a JSON format and you don't want to migrate by hand, |
| 91 | +there's a tool called [dotnet-config2json](https://www.nuget.org/packages/dotnet-config2json/) available on .NET Core that |
| 92 | +can convert an *app.config* file to a JSON configuration file. |
| 93 | + |
| 94 | +You may also come across some issues when using configuration sections that were |
| 95 | +defined in the *machine.config* file. For example, consider the following configuration: |
| 96 | + |
| 97 | +```xml |
| 98 | +<configuration> |
| 99 | + <system.diagnostics> |
| 100 | + <switches> |
| 101 | + <add name="General" value="4" /> |
| 102 | + </switches> |
| 103 | + <trace autoflush="true" indentsize="2"> |
| 104 | + <listeners> |
| 105 | + <add name="myListener" |
| 106 | + type="System.Diagnostics.TextWriterTraceListener, |
| 107 | + System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" |
| 108 | + initializeData="MyListener.log" |
| 109 | + traceOutputOptions="ProcessId, LogicalOperationStack, Timestamp, ThreadId, Callstack, DateTime" /> |
| 110 | + </listeners> |
| 111 | + </trace> |
| 112 | + </system.diagnostics> |
| 113 | +</configuration> |
| 114 | +``` |
| 115 | + |
| 116 | +If you take this configuration to a .NET Core, you'll get an exception: |
| 117 | + |
| 118 | +Unrecognized configuration section system.diagnostics |
| 119 | + |
| 120 | +This exception occurs because that section and the assembly responsible for handling that section was |
| 121 | +defined in the *machine.config* file, which now doesn't exist. |
| 122 | + |
| 123 | +To easily fix the issue, you can copy the section definition from your old |
| 124 | +machine.config to your new configuration file: |
| 125 | + |
| 126 | +```xml |
| 127 | +<configSections> |
| 128 | + <section name="system.diagnostics" |
| 129 | + type="System.Diagnostics.SystemDiagnosticsSection, |
| 130 | + System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> |
| 131 | +</configSections> |
| 132 | +``` |
| 133 | + |
| 134 | +## Accessing Databases |
| 135 | + |
| 136 | +Almost every desktop application needs some kind of database. For desktop, it's |
| 137 | +common to find client-server architectures with a direct connection between the |
| 138 | +desktop app and the database engine. These databases can be local or remote |
| 139 | +depending on the need to share information between different users. |
| 140 | + |
| 141 | +From the code perspective, there have been many technologies and frameworks to |
| 142 | +give the developer the possibility to connect, query, and update a database. |
| 143 | + |
| 144 | +The most common examples of database you can find when talking about Windows |
| 145 | +Desktop application are Microsoft Access and Microsoft SQL Server. If you have |
| 146 | +more than 20 years of experience programming for the desktop, names like ODBC, |
| 147 | +OLEDB, RDO, ADO, ADO.NET, LINQ, and Entity Framework will sound familiar. |
| 148 | + |
| 149 | +### ODBC |
| 150 | + |
| 151 | +You can continue to use ODBC on .NET Core since Microsoft is providing the |
| 152 | +`System.Data.Odbc` library compatible with .NET Standard 2.0. |
| 153 | + |
| 154 | +### OLE DB |
| 155 | + |
| 156 | +[OLE DB](https://msdn.microsoft.com/library/ms722784(v=vs.85).aspx) has |
| 157 | +been a great way to access various data sources in a uniform manner. But it was |
| 158 | +based on COM, which is a Windows-only technology, and as such wasn't the best |
| 159 | +fit for a cross-platform technology such as .NET Core. It's also unsupported in |
| 160 | +SQL Server versions 2014 and later. For those reasons, OLE DB won't be |
| 161 | +supported by .NET Core. |
| 162 | + |
| 163 | +### ADO.NET |
| 164 | + |
| 165 | +You can still use ADO.NET from your existing desktop code on .NET Core. You |
| 166 | +just need to update some NuGet packages. |
| 167 | + |
| 168 | +### EF Core vs. EF6 |
| 169 | + |
| 170 | +There are two currently supported versions of Entity Framework (EF), Entity Framework 6 (EF6) and EF Core. |
| 171 | + |
| 172 | +The latest technology released as part of the .NET Framework world is Entity |
| 173 | +Framework, with 6.4 being the latest version. With the launch of .NET Core, |
| 174 | +Microsoft also released a new data access stack based on Entity Framework and |
| 175 | +called Entity Framework Core. |
| 176 | + |
| 177 | +You can use EF 6.3 and EF Core from both .NET Framework and .NET Core. So, what |
| 178 | +are the decision drivers to help to decide between the two? |
| 179 | + |
| 180 | +EF 6.3 is the first version of EF6 that can run on .NET Core and work |
| 181 | +cross-platform. In fact, the main goal of this release is to make it easier |
| 182 | +to migrate existing applications that use EF6 to .NET Core. |
| 183 | + |
| 184 | +EF Core was designed to provide a developer experience similar to EF6. Most of |
| 185 | +the top-level APIs remain the same, so EF Core will feel familiar to developers |
| 186 | +who have used EF6. |
| 187 | + |
| 188 | +Although compatible, there are differences on the implementation you should |
| 189 | +check before making a decision. |
| 190 | +For more information, see [Compare EF Core & EF6](/ef/efcore-and-ef6/). |
| 191 | + |
| 192 | +The recommendation is to use EF Core if: |
| 193 | + |
| 194 | +* The app needs the capabilities of .NET Core. |
| 195 | +* EF Core supports all of the features that the app requires. |
| 196 | + |
| 197 | +Consider using EF6 if both of the following conditions are true: |
| 198 | + |
| 199 | +* The app will run on Windows and .NET Framework 4.0 or later. |
| 200 | +* EF6 supports all of the features that the app requires. |
| 201 | + |
| 202 | +### Relational databases |
| 203 | + |
| 204 | +#### SQL Server |
| 205 | + |
| 206 | +SQL Server has been one of the databases of choice if you were developing for |
| 207 | +the desktop some years ago. With the use of <xref:System.Data.SqlClient> in .NET |
| 208 | +Framework, you could access versions of SQL Server, which encapsulates |
| 209 | +database-specific protocols. |
| 210 | + |
| 211 | +In .NET Core, you can find a new `SqlClient` class, fully compatible with the one |
| 212 | +existing in the .NET Framework but located in the <xref:Microsoft.Data.SqlClient> |
| 213 | +library. You just have to add a reference to the [Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient/) |
| 214 | +NuGet package and do some renaming for the namespaces and everything should work as expected. |
| 215 | + |
| 216 | +#### Microsoft Access |
| 217 | + |
| 218 | +Microsoft Access has been used for years when the |
| 219 | +sophisticated and more scalable SQL Server wasn't needed. You can still connect |
| 220 | +to Microsoft Access using the <xref:System.Data.Odbc> library. |
| 221 | + |
| 222 | +## Consuming services |
| 223 | + |
| 224 | +With the raise of service-oriented architectures, desktop applications began to |
| 225 | +evolve from a client-server model to the three-layer approach. In the |
| 226 | +client-server approach, a direct database connection is established from the |
| 227 | +client holding the business logic usually inside a single EXE file. On the other |
| 228 | +hand, the three-layer approach establishes an intermediate service layer |
| 229 | +implementing business logic and database access allowing for better security, |
| 230 | +scalability, and reusability. Instead of working directly with datasets of data, |
| 231 | +the layer approach relies in a set of services implementing contracts and types |
| 232 | +objects as a way to implement data transfer. |
| 233 | + |
| 234 | +If you have a desktop application using a WCF service and you want to migrate it |
| 235 | +to .NET Core, there are some things to consider. |
| 236 | + |
| 237 | +The first thing is how to resolve the configuration to access the service. |
| 238 | +Because the configuration is different on .NET Core, you'll need to make |
| 239 | +some updates in your configuration file. |
| 240 | + |
| 241 | +Second, you'll need to regenerate the service client with the new tools |
| 242 | +present on Visual Studio 2019. In this step, you must consider activating the |
| 243 | +generation of the synchronous operations to make the client compatible with your |
| 244 | +existing code. |
| 245 | + |
| 246 | +After the migration, if you find that there are libraries you need that aren't |
| 247 | +present on .NET Core, you can add a reference to the [Microsoft.Windows.Compatibility](https://www.nuget.org/packages/Microsoft.Windows.Compatibility) |
| 248 | +NuGet package and see if the missing functions are there. |
| 249 | + |
| 250 | +If you're using the <xref:System.Net.WebRequest> class to perform web service calls, you may |
| 251 | +find some differences on .NET Core. The recommendation is to use the |
| 252 | +System.Net.Http.HttpClient instead. |
| 253 | + |
| 254 | +## Consuming a COM Object |
| 255 | + |
| 256 | +Currently, there's no way to add a reference to a COM object from Visual Studio |
| 257 | +2019 to use with .NET Core. So, you have to manually modify the project file. |
| 258 | + |
| 259 | +Insert a `COMReference` structure inside the project file like in the following example: |
| 260 | + |
| 261 | +```xml |
| 262 | +<ItemGroup> |
| 263 | + <COMReference Include="MSHTML"> |
| 264 | + <Guid>{3050F1C5-98B5-11CF-BB82-00AA00BDCE0B}\</Guid> |
| 265 | + <VersionMajor>4</VersionMajor> |
| 266 | + <VersionMinor>0</VersionMinor> |
| 267 | + <Lcid>0</Lcid> |
| 268 | + <WrapperTool>primary</WrapperTool> |
| 269 | + <Isolated>false</Isolated> |
| 270 | + </COMReference> |
| 271 | +</ItemGroup> |
| 272 | +``` |
| 273 | + |
| 274 | +## More things to consider |
| 275 | + |
| 276 | +Several technologies available to .NET Framework libraries aren't available for |
| 277 | +.NET Core. If your code relies on some of these technologies, consider |
| 278 | +the alternative approaches outlined in this section. |
| 279 | + |
| 280 | +The [Windows Compatibility Pack](../../core/porting/windows-compat-pack.md) provides access to APIs that were previously |
| 281 | +available only for .NET Framework. It can be used on .NET Core and .NET Standard projects. |
| 282 | + |
| 283 | +For more information on API compatibility, the CoreFX team maintains a list of |
| 284 | +behavioral changes/compat breaks and deprecated/legacy APIs at GitHub. |
| 285 | +<https://github.com/dotnet/corefx/wiki/ApiCompat>) |
| 286 | + |
| 287 | +### AppDomains |
| 288 | + |
| 289 | +Application domains (AppDomains) isolate apps from one another. AppDomains |
| 290 | +require runtime support and are expensive. Creating additional |
| 291 | +app domains isn't supported. For code isolation, we recommend separate |
| 292 | +processes or using containers as an alternative. For the dynamic loading of |
| 293 | +assemblies, we recommend the new <xref:System.Runtime.Loader.AssemblyLoadContext> class. |
| 294 | + |
| 295 | +To make code migration from .NET Framework easier, .NET Core exposes some of |
| 296 | +the AppDomain API surface. Some of the APIs function normally (for |
| 297 | +example, <xref:System.AppDomain.UnhandledException?displayProperty=nameWithType>), some members do nothing (for |
| 298 | +example, <xref:System.AppDomain.SetCachePath%2A>), and some of them throw |
| 299 | +<xref:System.PlatformNotSupportedException> (for example, <xref:System.AppDomain.CreateDomain%2A>). |
| 300 | + |
| 301 | +### Remoting |
| 302 | + |
| 303 | +.NET Remoting was used for cross-AppDomain communication, which is no longer |
| 304 | +supported. Also, Remoting requires runtime support, which is expensive to |
| 305 | +maintain. For these reasons, .NET Remoting isn't supported on .NET Core. |
| 306 | + |
| 307 | +For communication across processes, you should consider inter-process |
| 308 | +communication (IPC) mechanisms as an alternative to Remoting, such as |
| 309 | +the <xref:System.IO.Pipes?displayProperty=nameWithType> or the <xref:System.IO.MemoryMappedFiles.MemoryMappedFile> class. |
| 310 | + |
| 311 | +Across machines, use a network-based solution as an alternative. Preferably, use |
| 312 | +a low-overhead plaintext protocol, such as HTTP. The Kestrel web server, the |
| 313 | +web server used by ASP.NET Core, is an option here. |
| 314 | + |
| 315 | +### Code Access Security (CAS) |
| 316 | + |
| 317 | +Sandboxing, which relies on the runtime or the framework to constrain which |
| 318 | +resources a managed application or library uses or runs, isn't supported on .NET |
| 319 | +Core. |
| 320 | + |
| 321 | +Use security boundaries that are provided by the operating system, such as |
| 322 | +virtualization, containers, or user accounts for running processes with the |
| 323 | +minimum set of privileges. |
| 324 | + |
| 325 | +### Security Transparency |
| 326 | + |
| 327 | +Similar to CAS, Security Transparency separates sandboxed |
| 328 | +code from security critical code in a declarative fashion but is no longer |
| 329 | +supported as a security boundary. |
| 330 | + |
| 331 | +Use security boundaries that are provided by the operating system, such as |
| 332 | +virtualization, containers, or user accounts for running processes with the |
| 333 | +least set of privileges. |
| 334 | + |
| 335 | +>[!div class="step-by-step"] |
| 336 | +>[Previous](whats-new-dotnet-core.md ) |
| 337 | +>[Next](windows-migration.md) |
0 commit comments