Skip to content

Commit

Permalink
Update .NET MAUI app to .NET 9 (#581)
Browse files Browse the repository at this point in the history
* Update project to .NET 9.0 and various code improvements

Updated App.xaml.cs to override CreateWindow and adjust SetStatusBar.
Targeted .NET 9.0 in ClientApp.csproj and updated packages.
Removed XML declarations from Styles.xaml and view files.
Handled end group tags in Basket.cs protobuf parsing.
Changed DisplayAlert usage in DialogService.cs.
Modified TitleUseAzureServices property in SettingsViewModel.cs.
Updated ClientApp.UnitTests.csproj with newer package versions.

* Refactor App initialization and update dependencies

Updated App.xaml.cs to use CreateWindow method for main window initialization.
Repositioned ManagePackageVersionsCentrally in HybridApp.csproj.
Updated SupportedOSPlatformVersion for iOS and MacCatalyst to 15.0.
Upgraded PackageReference versions to 9.0.0-rc.2.
Reformatted Routes.razor and _Imports.razor for consistency.

* Update network settings for Android and iOS

- MainPage.xaml: Added XML namespace `local` for `eShop.HybridApp.Components`.
- MauiProgram.cs: Updated `MobileBffHost` URL for Android to `http://10.0.2.2:11632/` and kept `http://localhost:11632/` for other platforms.
- AndroidManifest.xml: Enabled cleartext traffic and added network security config.
- Info.plist: Relaxed network security policies to allow HTTP connections.
- network_security_config.xml: Created to permit cleartext traffic for `10.0.2.2`.

* Add Basket.API project to ClientApp solution

Added Basket.API project to ClientApp.sln with GUID {0F0B89AF-EDEA-4479-941A-CCE9FFDBD057}. Updated solution configuration platforms to include build and active configuration settings for Debug and Release configurations.

* not needed

* Fix XamlC warnings in .NET MAUI app (#585)

* Add missing x:DataType

* Reenable warnings

* Update some styles

* Update src/HybridApp/App.xaml.cs

Co-authored-by: Eilon Lipton <[email protected]>

* Use source-generated JSON serialization in .NET MAUI app (#587)

* Use source-generated JSON serialization in ClientApp

* Refactor serialization of JSON content

* Add ConfigureHandlers method for iOS and Mac Catalyst

The MauiProgram class has been updated to include a new method
ConfigureHandlers. This method is conditionally compiled for
iOS and Mac Catalyst platforms and adds custom handlers for
CollectionView and CarouselView controls. The ConfigureHandlers
method is called in the CreateMauiApp method to ensure these
handlers are configured during the app's initialization.

* Remove Grid.ColumnSpan="0" from <Image> in LoginView.xaml

Removed the Grid.ColumnSpan="0" attribute from the <Image> element
in LoginView.xaml. This attribute was likely incorrect or
unnecessary, and its removal may correct the layout behavior of
the image within the grid.

* Refactor LoginView.xaml layout and clean up code

- Added `LoginPanel` grid with specific properties and bindings.
- Introduced a new logo image element for better visual structure.
- Reformatted and re-added the login button with necessary properties.
- Removed commented-out `<ScrollView>`, `<ContentView>`, and register button.
- Enhanced code readability by eliminating unused commented code.

---------

Co-authored-by: Šimon Rozsíval <[email protected]>
Co-authored-by: Eilon Lipton <[email protected]>
Co-authored-by: James Montemagno <[email protected]>
  • Loading branch information
4 people authored Oct 31, 2024
1 parent 842dfc0 commit 5401748
Show file tree
Hide file tree
Showing 30 changed files with 245 additions and 165 deletions.
10 changes: 7 additions & 3 deletions src/ClientApp/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Diagnostics;
using System.Globalization;
using eShop.ClientApp.Services;
using eShop.ClientApp.Services.AppEnvironment;
Expand Down Expand Up @@ -32,11 +32,15 @@ public App(

InitApp();

MainPage = new AppShell(navigationService);

Current.UserAppTheme = AppTheme.Light;
}

protected override Window CreateWindow(IActivationState activationState)
{
return new Window(new AppShell(_navigationService));
}

private void InitApp()
{
if (VersionTracking.IsFirstLaunchEver)
Expand Down Expand Up @@ -86,7 +90,7 @@ private void App_RequestedThemeChanged(object sender, AppThemeChangedEventArgs e

private void SetStatusBar()
{
var nav = Current.MainPage as NavigationPage;
var nav = Windows[0].Page as NavigationPage;

if (Current.RequestedTheme == AppTheme.Dark)
{
Expand Down
36 changes: 18 additions & 18 deletions src/ClientApp/ClientApp.csproj
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst;net8.0</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst;net9.0</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net9.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
<!-- <TargetFrameworks>$(TargetFrameworks);net9.0-tizen</TargetFrameworks> -->

<!-- Note for MacCatalyst:
The default runtime is maccatalyst-x64, except in Release config, in which case the default is maccatalyst-x64;maccatalyst-arm64.
Expand All @@ -13,13 +13,14 @@
either BOTH runtimes must be indicated or ONLY macatalyst-x64. -->
<!-- ex. <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers> -->

<OutputType Condition="'$(TargetFramework)' != 'net8.0'">Exe</OutputType>
<OutputType Condition="'$(TargetFramework)' != 'net9.0'">Exe</OutputType>
<RootNamespace>eShop.ClientApp</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<MauiEnableXamlCBindingWithSourceCompilation>true</MauiEnableXamlCBindingWithSourceCompilation>
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
<NoWarn>$(NoWarn);XC0022;XC0023</NoWarn>
<NoWarn>$(NoWarn);XC0103</NoWarn>

<!-- Display name -->
<ApplicationTitle>AdventureWorks</ApplicationTitle>
Expand All @@ -31,15 +32,14 @@
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>

<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-ios|AnyCPU'">
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net9.0-ios|AnyCPU'">
<CreatePackage>false</CreatePackage>
</PropertyGroup>
<ItemGroup>
Expand All @@ -61,21 +61,21 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.26.1" />
<PackageReference Include="Grpc.Net.Client" Version="2.62.0" />
<PackageReference Include="Grpc.Tools" Version="2.63.0">
<PackageReference Include="Google.Protobuf" Version="3.28.2" />
<PackageReference Include="Grpc.Net.Client" Version="2.66.0" />
<PackageReference Include="Grpc.Tools" Version="2.67.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="IdentityModel.OidcClient" Version="6.0.0" />
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.70" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.70" />
<PackageReference Include="Microsoft.Maui.Controls.Maps" Version="8.0.70" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.*-*" />
<PackageReference Include="Microsoft.Maui.Controls" Version="9.0.0-rc.2.24503.2" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="9.0.0-rc.2.24503.2" />
<PackageReference Include="Microsoft.Maui.Controls.Maps" Version="9.0.0-rc.2.24503.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.*-*" />

<PackageReference Include="CommunityToolkit.Maui" Version="9.0.1" />
<PackageReference Include="CommunityToolkit.Maui" Version="9.1.0" />
<PackageReference Include="IdentityModel" Version="7.0.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
</ItemGroup>

<ItemGroup>
Expand Down
14 changes: 14 additions & 0 deletions src/ClientApp/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,26 @@ public static MauiApp CreateMauiApp()
#if !WINDOWS
.UseMauiMaps()
#endif
.ConfigureHandlers()
.RegisterAppServices()
.RegisterViewModels()
.RegisterViews()
.Build();
}

public static MauiAppBuilder ConfigureHandlers(this MauiAppBuilder mauiAppBuilder)
{
#if IOS || MACCATALYST
mauiAppBuilder.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler<Microsoft.Maui.Controls.CollectionView, Microsoft.Maui.Controls.Handlers.Items2.CollectionViewHandler2>();
handlers.AddHandler<Microsoft.Maui.Controls.CarouselView, Microsoft.Maui.Controls.Handlers.Items2.CarouselViewHandler2>();
});
#endif

return mauiAppBuilder;
}

public static MauiAppBuilder RegisterAppServices(this MauiAppBuilder mauiAppBuilder)
{
mauiAppBuilder.Services.AddSingleton<ISettingsService, SettingsService>();
Expand Down
1 change: 0 additions & 1 deletion src/ClientApp/Resources/Styles/Styles.xaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>

<ResourceDictionary
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Expand Down
72 changes: 60 additions & 12 deletions src/ClientApp/Services/Basket/Protos/Basket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,11 @@ public void MergeFrom(pb::CodedInputStream input) {
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
Expand All @@ -195,7 +199,11 @@ public void MergeFrom(pb::CodedInputStream input) {
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
Expand Down Expand Up @@ -351,7 +359,11 @@ public void MergeFrom(pb::CodedInputStream input) {
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
Expand All @@ -370,7 +382,11 @@ public void MergeFrom(pb::CodedInputStream input) {
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
Expand Down Expand Up @@ -570,7 +586,11 @@ public void MergeFrom(pb::CodedInputStream input) {
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
Expand All @@ -593,7 +613,11 @@ public void MergeFrom(pb::CodedInputStream input) {
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
Expand Down Expand Up @@ -757,7 +781,11 @@ public void MergeFrom(pb::CodedInputStream input) {
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
Expand All @@ -776,7 +804,11 @@ public void MergeFrom(pb::CodedInputStream input) {
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
Expand Down Expand Up @@ -918,7 +950,11 @@ public void MergeFrom(pb::CodedInputStream input) {
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
Expand All @@ -933,7 +969,11 @@ public void MergeFrom(pb::CodedInputStream input) {
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
Expand Down Expand Up @@ -1071,7 +1111,11 @@ public void MergeFrom(pb::CodedInputStream input) {
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
Expand All @@ -1086,7 +1130,11 @@ public void MergeFrom(pb::CodedInputStream input) {
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
if ((tag & 7) == 4) {
// Abort on any end group tag.
return;
}
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
Expand Down
17 changes: 11 additions & 6 deletions src/ClientApp/Services/Catalog/CatalogMockService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using eShop.ClientApp.Models.Catalog;
using eShop.ClientApp.Models.Catalog;

namespace eShop.ClientApp.Services.Catalog;

Expand All @@ -22,7 +22,8 @@ public class CatalogMockService : ICatalogService
CatalogBrandId = 2,
CatalogBrand = MockCatalogBrands[1],
CatalogTypeId = 2,
CatalogType = MockCatalogTypes[1]
CatalogType = MockCatalogTypes[1],
Description = "Navigate with confidence using the Adventurer GPS Watch by Adventurer. This rugged and durable watch features a built-in GPS, altimeter, and compass, allowing you to track your progress and find your way in any terrain. With its sleek black design and easy-to-read display, this watch is both stylish and practical. The Adventurer GPS Watch is a must-have for every adventurer."
},
new CatalogItem
{
Expand All @@ -33,7 +34,8 @@ public class CatalogMockService : ICatalogService
CatalogBrandId = 2,
CatalogBrand = MockCatalogBrands[1],
CatalogTypeId = 2,
CatalogType = MockCatalogTypes[1]
CatalogType = MockCatalogTypes[1],
Description = "Stay safe on your cycling adventures with the Trailblazer Bike Helmet by Green Equipment. This lightweight and durable helmet features an adjustable fit system and ventilation for added comfort. With its vibrant green color and sleek design, you'll stand out on the road. The Trailblazer Bike Helmet is perfect for all types of cycling, from mountain biking to road cycling."
},
new CatalogItem
{
Expand All @@ -44,7 +46,8 @@ public class CatalogMockService : ICatalogService
CatalogBrandId = 2,
CatalogBrand = MockCatalogBrands[1],
CatalogTypeId = 2,
CatalogType = MockCatalogTypes[1]
CatalogType = MockCatalogTypes[1],
Description = "The AlpinePack backpack by Green Equipment is your ultimate companion for outdoor adventures. This versatile and durable backpack features a sleek navy design with reinforced straps. With a capacity of 45 liters, multiple compartments, and a hydration pack sleeve, it offers ample storage and organization. The ergonomic back panel ensures maximum comfort, even on the most challenging treks."
},
new CatalogItem
{
Expand All @@ -55,7 +58,8 @@ public class CatalogMockService : ICatalogService
CatalogBrandId = 2,
CatalogBrand = MockCatalogBrands[1],
CatalogTypeId = 1,
CatalogType = MockCatalogTypes[0]
CatalogType = MockCatalogTypes[0],
Description = "Enhance your skiing experience with the Alpine Fusion Goggles from WildRunner. These goggles offer full UV protection and anti-fog lenses to keep your vision clear on the slopes. With their stylish silver frame and orange lenses, you'll stand out from the crowd. Adjustable straps ensure a secure fit, while the soft foam padding provides comfort all day long."
},
new CatalogItem
{
Expand All @@ -66,7 +70,8 @@ public class CatalogMockService : ICatalogService
CatalogBrandId = 1,
CatalogBrand = MockCatalogBrands[0],
CatalogTypeId = 2,
CatalogType = MockCatalogTypes[1]
CatalogType = MockCatalogTypes[1],
Description = "The Solstix Alpine Peak Down Jacket is crafted for extreme cold conditions. With its bold red color and sleek design, this jacket combines style with functionality. Made with high-quality goose down insulation, the Alpine Peak Jacket provides exceptional warmth and comfort. The jacket features a removable hood, adjustable cuffs, and multiple zippered pockets for storage. Conquer the harshest weather with the Solstix Alpine Peak Down Jacket."
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/ClientApp/Services/Dialog/DialogService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ public class DialogService : IDialogService
{
public Task ShowAlertAsync(string message, string title, string buttonLabel)
{
return Application.Current.MainPage.DisplayAlert(title, message, buttonLabel);
return AppShell.Current.DisplayAlert(title, message, buttonLabel);
}
}
21 changes: 21 additions & 0 deletions src/ClientApp/Services/EShopJsonSerializerContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Text.Json.Serialization;
using eShop.ClientApp.Models.Catalog;
using eShop.ClientApp.Models.Orders;
using eShop.ClientApp.Models.Token;

namespace eShop.ClientApp.Services;

[JsonSourceGenerationOptions(
PropertyNameCaseInsensitive = true,
NumberHandling = JsonNumberHandling.AllowReadingFromString)]
[JsonSerializable(typeof(CancelOrderCommand))]
[JsonSerializable(typeof(CatalogBrand))]
[JsonSerializable(typeof(CatalogItem))]
[JsonSerializable(typeof(CatalogRoot))]
[JsonSerializable(typeof(CatalogType))]
[JsonSerializable(typeof(Models.Orders.Order))]
[JsonSerializable(typeof(Models.Location.Location))]
[JsonSerializable(typeof(UserToken))]
internal partial class EShopJsonSerializerContext : JsonSerializerContext
{
}
Loading

0 comments on commit 5401748

Please sign in to comment.