Elena Canorea
Communications Lead
Microsoft raises the stakes for cross-platform applications with .NET MAUI. We will review Microsoft’s new framework and see what’s new with respect to Xamarin.Forms that will allow us to be more productive and develop applications for macOS.
We will also see the new possibilities that open up when moving from .NET Standard to .NET6. All with the aim of seeing how it helps us to reduce development time and, ultimately, the costs of a product.
The development industry has been making an important effort to improve the cross-platform ecosystem for some time now. To name a few examples, on the one hand we have frameworks like Flutter that are evolving a lot and very fast: they even reach desktop and web. On the other, we also have Kotlin multiplatform, whose goal is to write the application logic once and use it in different projects.
With the arrival of .NET 6, Microsoft also increases its efforts for mobile and desktop applications and has presented .NET Multi-platform App UI (.NET MAUI), a framework that allows us to develop native applications for Android, IOS, MacOS, and Windows with C# and XAML. That is, having a single shared code project, both logic, and UI.
.NET MAUI is open source and the evolution of Xamarin.Forms; it increases desktop support and greatly improves performance. If you have developed in Xamarin.Forms, you will notice that they share many similarities, with the difference that .NET MAUI reduces the time when using resources or designing user interfaces: the .NET MAUI team has focused efforts on making sure that we only have the interface definition once, as well as declaring resources such as icons or fonts in a single point.
.NET MAUI not only uses .NET 6, but is part of the .NET sdk and is a part of the dotnet workloads.
This has several implications. On a business level, it shows Microsoft’s commitment to cross-platform development, including it within .NET itself and not as a separate product. On a technical level, it means on the one hand using the latest .NET features such as HotReload, performance improvements, global using…
On the other hand, it also means that we have compatibility with all .net6 projects; for example, a data access library or models between ASP.NET projects, WPF, or any technology that uses .net6, without having to go through the .NET Standard, which had some limitations when it came to taking advantage of the latest benefits of the framework.
.NET MAUI allows us to ‘host’ a Blazor web development within our application. This way, from Blazor we can integrate and use services from each platform.
This integration can be complete (a web application in Blazor ‘hosted’ in a .NET MAUI application) or partial (one or several screens of the application are made in Blazor).
This allows us to take the apps already developed in Blazor to native applications for mobile and desktop reusing the same source code. On the other hand, it allows web developers who develop in Blazor the possibility to reach a wider market by reusing their knowledge.
Microsoft has a good example of a Blazor application hosted on .NET MAUI:
What is really interesting about .NET MAUI is how it can help companies to reduce costs, which is perhaps the most determining factor when choosing a technology to develop a product. Obviously this depends on the technological stack of the team of developers and their knowledge. Let’s try to see the most relevant points:
A single developer can develop an application for four different platforms using the same logic and UI definition. In addition, these developments are done in parallel, that is to say, one platform is not developed and then another one, but at the same time, since the logic and UI are shared.
In .NET MAUI resources such as images, fonts and others are also shared, unifying their use and configuration for all platforms.
When using C# and XAML, the learning curve if you come from WPF is very small; even, if you come from ASP.NET, you will also find everything very familiar, since the same tools are used, such as VS, so the developer will be much more productive from day one than if he has to learn a new IDE.
As all the logic of your application is in a single point, the problems and the cost of applying these changes or repairs are minimized. In a project where the server is developed in Go and the applications in Kotlin (Android), Swift (iOS and MacOS) and WinUI (Windows), a change of model, or business logic, would involve modifying the five projects, with different developers and / or without being in parallel.
With .NET MAUI we can directly share models with the server if it is .NET6, and by making the change in a single class we would have the problem solved in server, Android, iOS, MacOS and Windows. At the cost level it is a remarkable difference.
.NET MAUI officially supports MacOS, Apple’s desktop operating system. This is more important than it sounds: not only does it mean that our applications will run on MacOS, but it opens up a new market share and more business opportunities. And I’m not just talking about Mac.
In recent years web technologies have been gaining market share and the answer is very simple: all the usual operating systems (IOS, Android, Windows, and MacOS) can access the services offered by such software through a browser. .NET MAUI opens the possibility to reach all the customers reached by the web with the advantages of native applications; in this way, it is an interesting alternative and very much to consider when choosing a technology for our next project.
When doing a complete analysis of .NET MAUI, we have to talk about the disadvantages. First of all, it is a new product that has just been released and, although the released version is stable, some essential controls such as maps are still missing. Although they are upcoming in the roadmap, they are not available as I write this post.
Sometimes, creating shared interfaces for mobile and desktop can be complex, because they are different worlds. MAUI is designed to achieve this, but sometimes creating interfaces for desktop and mobile, with user interactions, is more difficult than creating them separately.
There are several applications available made with .NET MAUI that we can use to orient ourselves, see best practices and observe how the platform works.
A few months ago the GA version of .NET MAUI was officially presented and, along with it, an application in whose development Plain Concepts has collaborated. I leave you a link to this app and others made with the platform. You also have available other .NET MAUI examples, both official and made by the community:
Elena Canorea
Communications Lead
Cookie | Duration | Description |
---|---|---|
__cfduid | 1 year | The cookie is used by cdn services like CloudFare to identify individual clients behind a shared IP address and apply security settings on a per-client basis. It does not correspond to any user ID in the web application and does not store any personally identifiable information. |
__cfduid | 29 days 23 hours 59 minutes | The cookie is used by cdn services like CloudFare to identify individual clients behind a shared IP address and apply security settings on a per-client basis. It does not correspond to any user ID in the web application and does not store any personally identifiable information. |
__cfduid | 1 year | The cookie is used by cdn services like CloudFare to identify individual clients behind a shared IP address and apply security settings on a per-client basis. It does not correspond to any user ID in the web application and does not store any personally identifiable information. |
__cfduid | 29 days 23 hours 59 minutes | The cookie is used by cdn services like CloudFare to identify individual clients behind a shared IP address and apply security settings on a per-client basis. It does not correspond to any user ID in the web application and does not store any personally identifiable information. |
_ga | 1 year | This cookie is installed by Google Analytics. The cookie is used to calculate visitor, session, campaign data and keep track of site usage for the site's analytics report. The cookies store information anonymously and assign a randomly generated number to identify unique visitors. |
_ga | 1 year | This cookie is installed by Google Analytics. The cookie is used to calculate visitor, session, campaign data and keep track of site usage for the site's analytics report. The cookies store information anonymously and assign a randomly generated number to identify unique visitors. |
_ga | 1 year | This cookie is installed by Google Analytics. The cookie is used to calculate visitor, session, campaign data and keep track of site usage for the site's analytics report. The cookies store information anonymously and assign a randomly generated number to identify unique visitors. |
_ga | 1 year | This cookie is installed by Google Analytics. The cookie is used to calculate visitor, session, campaign data and keep track of site usage for the site's analytics report. The cookies store information anonymously and assign a randomly generated number to identify unique visitors. |
_gat_UA-326213-2 | 1 year | No description |
_gat_UA-326213-2 | 1 year | No description |
_gat_UA-326213-2 | 1 year | No description |
_gat_UA-326213-2 | 1 year | No description |
_gid | 1 year | This cookie is installed by Google Analytics. The cookie is used to store information of how visitors use a website and helps in creating an analytics report of how the wbsite is doing. The data collected including the number visitors, the source where they have come from, and the pages viisted in an anonymous form. |
_gid | 1 year | This cookie is installed by Google Analytics. The cookie is used to store information of how visitors use a website and helps in creating an analytics report of how the wbsite is doing. The data collected including the number visitors, the source where they have come from, and the pages viisted in an anonymous form. |
_gid | 1 year | This cookie is installed by Google Analytics. The cookie is used to store information of how visitors use a website and helps in creating an analytics report of how the wbsite is doing. The data collected including the number visitors, the source where they have come from, and the pages viisted in an anonymous form. |
_gid | 1 year | This cookie is installed by Google Analytics. The cookie is used to store information of how visitors use a website and helps in creating an analytics report of how the wbsite is doing. The data collected including the number visitors, the source where they have come from, and the pages viisted in an anonymous form. |
attributionCookie | session | No description |
cookielawinfo-checkbox-analytics | 1 year | Set by the GDPR Cookie Consent plugin, this cookie is used to record the user consent for the cookies in the "Analytics" category . |
cookielawinfo-checkbox-necessary | 1 year | This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary". |
cookielawinfo-checkbox-necessary | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary". |
cookielawinfo-checkbox-necessary | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary". |
cookielawinfo-checkbox-necessary | 1 year | This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary". |
cookielawinfo-checkbox-non-necessary | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Non Necessary". |
cookielawinfo-checkbox-non-necessary | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Non Necessary". |
cookielawinfo-checkbox-non-necessary | 11 months | This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Non Necessary". |
cookielawinfo-checkbox-non-necessary | 1 year | This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Non Necessary". |
cookielawinfo-checkbox-performance | 1 year | Set by the GDPR Cookie Consent plugin, this cookie is used to store the user consent for cookies in the category "Performance". |
cppro-ft | 1 year | No description |
cppro-ft | 7 years 1 months 12 days 23 hours 59 minutes | No description |
cppro-ft | 7 years 1 months 12 days 23 hours 59 minutes | No description |
cppro-ft | 1 year | No description |
cppro-ft-style | 1 year | No description |
cppro-ft-style | 1 year | No description |
cppro-ft-style | session | No description |
cppro-ft-style | session | No description |
cppro-ft-style-temp | 23 hours 59 minutes | No description |
cppro-ft-style-temp | 23 hours 59 minutes | No description |
cppro-ft-style-temp | 23 hours 59 minutes | No description |
cppro-ft-style-temp | 1 year | No description |
i18n | 10 years | No description available. |
IE-jwt | 62 years 6 months 9 days 9 hours | No description |
IE-LANG_CODE | 62 years 6 months 9 days 9 hours | No description |
IE-set_country | 62 years 6 months 9 days 9 hours | No description |
JSESSIONID | session | The JSESSIONID cookie is used by New Relic to store a session identifier so that New Relic can monitor session counts for an application. |
viewed_cookie_policy | 11 months | The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data. |
viewed_cookie_policy | 1 year | The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data. |
viewed_cookie_policy | 1 year | The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data. |
viewed_cookie_policy | 11 months | The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data. |
VISITOR_INFO1_LIVE | 5 months 27 days | A cookie set by YouTube to measure bandwidth that determines whether the user gets the new or old player interface. |
wmc | 9 years 11 months 30 days 11 hours 59 minutes | No description |
Cookie | Duration | Description |
---|---|---|
__cf_bm | 30 minutes | This cookie, set by Cloudflare, is used to support Cloudflare Bot Management. |
sp_landing | 1 day | The sp_landing is set by Spotify to implement audio content from Spotify on the website and also registers information on user interaction related to the audio content. |
sp_t | 1 year | The sp_t cookie is set by Spotify to implement audio content from Spotify on the website and also registers information on user interaction related to the audio content. |
Cookie | Duration | Description |
---|---|---|
_hjAbsoluteSessionInProgress | 1 year | No description |
_hjAbsoluteSessionInProgress | 1 year | No description |
_hjAbsoluteSessionInProgress | 1 year | No description |
_hjAbsoluteSessionInProgress | 1 year | No description |
_hjFirstSeen | 29 minutes | No description |
_hjFirstSeen | 29 minutes | No description |
_hjFirstSeen | 29 minutes | No description |
_hjFirstSeen | 1 year | No description |
_hjid | 11 months 29 days 23 hours 59 minutes | This cookie is set by Hotjar. This cookie is set when the customer first lands on a page with the Hotjar script. It is used to persist the random user ID, unique to that site on the browser. This ensures that behavior in subsequent visits to the same site will be attributed to the same user ID. |
_hjid | 11 months 29 days 23 hours 59 minutes | This cookie is set by Hotjar. This cookie is set when the customer first lands on a page with the Hotjar script. It is used to persist the random user ID, unique to that site on the browser. This ensures that behavior in subsequent visits to the same site will be attributed to the same user ID. |
_hjid | 1 year | This cookie is set by Hotjar. This cookie is set when the customer first lands on a page with the Hotjar script. It is used to persist the random user ID, unique to that site on the browser. This ensures that behavior in subsequent visits to the same site will be attributed to the same user ID. |
_hjid | 1 year | This cookie is set by Hotjar. This cookie is set when the customer first lands on a page with the Hotjar script. It is used to persist the random user ID, unique to that site on the browser. This ensures that behavior in subsequent visits to the same site will be attributed to the same user ID. |
_hjIncludedInPageviewSample | 1 year | No description |
_hjIncludedInPageviewSample | 1 year | No description |
_hjIncludedInPageviewSample | 1 year | No description |
_hjIncludedInPageviewSample | 1 year | No description |
_hjSession_1776154 | session | No description |
_hjSessionUser_1776154 | session | No description |
_hjTLDTest | 1 year | No description |
_hjTLDTest | 1 year | No description |
_hjTLDTest | session | No description |
_hjTLDTest | session | No description |
_lfa_test_cookie_stored | past | No description |
Cookie | Duration | Description |
---|---|---|
loglevel | never | No description available. |
prism_90878714 | 1 month | No description |
redirectFacebook | 2 minutes | No description |
YSC | session | YSC cookie is set by Youtube and is used to track the views of embedded videos on Youtube pages. |
yt-remote-connected-devices | never | YouTube sets this cookie to store the video preferences of the user using embedded YouTube video. |
yt-remote-device-id | never | YouTube sets this cookie to store the video preferences of the user using embedded YouTube video. |
yt.innertube::nextId | never | This cookie, set by YouTube, registers a unique ID to store data on what videos from YouTube the user has seen. |
yt.innertube::requests | never | This cookie, set by YouTube, registers a unique ID to store data on what videos from YouTube the user has seen. |