It’s been a week since the Microsoft MVP Summit, and now I finally sit at Javier’s home trying to write about my trip and experience there. So let’s start!
The Journey
First, I needed to fly via Istanbul. That meant waking up around 2:00 AM to go to the airport and catch my flight at 6:00 AM. In Istanbul, I was really lucky because I was in the new airport which is huge and it has a great business lounge to wait in, so I could get some rest between my flights from Istanbul to Seattle.
I tried to sleep a little. The main problem was that the business lounge was on one side of the airport and my gate was on the other side, about 1 kilometer away. It’s a really big airport! I had to walk all that distance, and they announced the gate really late, so I only had about 15 minutes to get there—a really short time.
After that, I took my flight to the States, from Istanbul to Seattle. The route goes through the Arctic (near the North Pole)—you go up and then a little bit to the right, and then you end up in Seattle. It was a strange route; I’d never used it before. The flight was long, around 15 hours, but it wasn’t bad. I enjoyed Turkish Airlines when they use the big airplanes.
Arrival Challenges
I landed in Seattle around 6:00 PM. Then I had to go through immigration control and collect my luggage, which took almost two hours. After that, I went to the Airbnb, which was super beautiful, but I couldn’t get in because the owners had left the gate closed from the inside, and there were no lights at all, so it was impossible to enter. I waited for two hours for Javier to contact them, and after a while, it started raining, so I decided to go to a hotel. I booked a hotel for the night and took a 30-minute taxi ride. I finally went to bed on Monday at 11:00 PM, which was really late.
Day One at the Summit
The next day, I needed to drop my bags at the Airbnb and go to the MVP Summit. It was a nice experience. Javier was flying in that day and arrived around 3:00 PM, so I went to the first part alone. I missed the keynote because I had to drop off my bags and do all that stuff, so I ended up arriving around 11:00 AM.
The first person I met was Veronica, and we talked for a bit. Then I went to one of the sessions—of course, it was a Copilot session. In the afternoon, I met up with Javier, we grabbed some swag, and went to the Hub. Then I met Pablo from Argentina, and by the end of the day, I got together with Michael Washington, who I always hang out with during the MVP Summits.
Time to go home—it was a long day. We went back to the Airbnb, but didn’t do much. We just watched a TV show that our friend Hector recommended on Netflix.
Day Two: Meeting Peers
For day two, the sessions were great, but what I recall most are my meetings with specific people. When you go to the MVP Summits, you get to meet your peers. Usually, it’s like you’re good at one thing—for example, Javier and I do AI courses, and most of what we write about is general development—but there are people who really specialize.
For instance, I met the people from the Uno team, amazing people. Jerome and his team are always on the bleeding edge of .NET. We talked about the “black magic” they’ve written for their multi-target single application for Uno. It’s always nice to meet the Uno team.
I met with Michael Washington again several times in the hallways of Microsoft, and we talked about how to redirect Microsoft AI extensions to use LLM Studio, which is kind of tricky. It’s not something you can do really easily, like with Semantic Kernel where you only need to replace the HTTP client and then you’re good to go. In LLM Studio, it’s a different trick, so I’ll write about it later.
In one of the sessions, Mads Kristensen sat by my side, and I was trying to get some information from him on how to create an extension. Long ago, there was an extension from Oliver Sturm called “Instant Program Gratification” or something similar that displayed a huge congratulation message on the screen every time your compile succeeded, and if it failed, it would display something like “Hey, you need more coffee!” on the screen. I asked Mads how to achieve that with the new extension toolkit, and he explained it to me—he’s the king of extensions for Visual Studio.
Then I met someone new, Jeremy Sinclair, whom Javier introduced me to. We had one of those deep technical conversations about how Windows runs on ARM CPUs and the problems this can bring or how easy some things can be. It’s ironic because the Android architecture is usually ARM, but it doesn’t run on ARM computers because ARM computers emulate x64. We talked a lot about the challenges you might encounter and how to address them. Jeremy has managed to do it; he’s written some articles about what to expect when moving to an ARM computer. He also talked about how the future and the present for MAUI is at the moment.
He was also wearing the Ray-Ban Meta glasses, and I asked him, “Hey, how are they?” He told me they’re nice, though the battery life isn’t great, but they’re kind of fun. So I ordered a pair of Meta Ray-Ban AI glasses, and I like them so far.
More Memorable Conversations
Another great conversation that we had with Javier was with James Montemagno. We met him in the Hub, and then we talked a lot about how we started. I’ve been a long-term fan of Merge Conflict, their podcast, and Javier introduced me to that podcast a long time ago when we met around 9 years ago. When he was traveling to work, he called me, we talked mostly about development for about one hour on his way to work, and then he told me, “Hey, I listen to this and this podcast, I listen to that and that podcast.” So I became a follower of Merge Conflict after that.
James explained all the adventures on the Xamarin team, how it went when Xamarin joined Microsoft, about the difference between Xamarin from Microsoft and Xamarin from Xamarin Forms, and how life is changing for him as more of a project manager than an advocate. So he’s kind of busy all the time, but we had this really long conversation, like 40 minutes or so. He was really open about talking about his adventure of joining Microsoft and eventually working in the MAUI team.
We also met David from the MAUI team, and he was so nice. Long time ago, he featured our company in the list of companies that have made apps with MAUI, and we were on the list they showed in one of the conferences. So we thanked him for that.
That’s everyone I met at the MVP Summit. I had a great time, and I can’t believe it’s been a year already. I’m looking forward to meeting everyone next year and seeing what we come up with during 2025!
When developing cross-platform mobile applications with .NET MAUI (or previously Xamarin), you may encounter situations where your app works perfectly with public APIs but fails when connecting to internal network services. These issues often stem from HTTP client implementation differences, certificate validation, and TLS compatibility. This article explores how to identify, troubleshoot, and resolve these common networking challenges.
Understanding HTTP Client Options in MAUI/Xamarin
In the MAUI/.NET ecosystem, developers have access to two primary HTTP client implementations:
Consistent behavior across different operating systems
May handle SSL/TLS differently than platform-native implementations
Uses the .NET certificate validation system
2. Native HttpClient (Android’s implementation)
Leverages the platform’s native networking stack
Typically offers better performance on the specific platform
Uses the device’s system certificate trust store
Follows platform-specific security policies and restrictions
Switching Between Native and Managed HttpClient
In MAUI Applications
MAUI provides a flexible handler registration system that lets you explicitly choose which implementation to use:
// In your MauiProgram.cs
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureMauiHandlers(handlers =>
{
// Use the managed implementation (Microsoft's .NET HttpClient)
handlers.AddHandler(typeof(HttpClient), typeof(ManagedHttpMessageHandler));
// OR use the native implementation (platform-specific)
// handlers.AddHandler(typeof(HttpClient), typeof(PlatformHttpMessageHandler));
});
return builder.Build();
}
In Xamarin.Forms Legacy Applications
For Xamarin.Forms applications, set this in your platform-specific initialization code:
// In MainActivity.cs (Android) or AppDelegate.cs (iOS)
HttpClientHandler.UseNativePlatformHandler = false; // Use managed handler
// OR
HttpClientHandler.UseNativePlatformHandler = true; // Use native handler
Creating Specific Client Instances
You can also explicitly create HttpClient instances with specific handlers when needed:
// Use the managed handler
var managedHandler = new HttpClientHandler();
var managedClient = new HttpClient(managedHandler);
// Use the native handler (with DependencyService in Xamarin)
var nativeHandler = DependencyService.Get<INativeHttpClientHandler>();
var nativeClient = new HttpClient(nativeHandler);
Using HttpClientFactory (Recommended for MAUI)
For better control, testability, and lifecycle management, consider using HttpClientFactory:
// In your MauiProgram.cs
builder.Services.AddHttpClient("ManagedClient", client => {
client.BaseAddress = new Uri("https://your.api.url/");
})
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler());
// Then inject and use it in your services
public class MyApiService
{
private readonly HttpClient _client;
public MyApiService(IHttpClientFactory clientFactory)
{
_client = clientFactory.CreateClient("ManagedClient");
}
}
Common Issues and Troubleshooting
1. Self-Signed Certificates
Internal APIs often use self-signed certificates that aren’t trusted by default. Here’s how to handle them:
// Option 1: Create a custom handler that bypasses certificate validation
// (ONLY for development/testing environments)
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
};
var client = new HttpClient(handler);
For production environments, instead of bypassing validation:
Add your self-signed certificate to the Android trust store
Configure your app to trust specific certificates
Generate proper certificates from a trusted Certificate Authority
2. TLS Version Mismatches
Different Android versions support different TLS versions by default:
Android 4.1-4.4: TLS 1.0 by default
Android 5.0+: TLS 1.0, 1.1, 1.2
Android 10+: TLS 1.3 support
If your server requires a specific TLS version:
// Force specific TLS versions
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
3. Network Configuration
Ensure your app has the proper permissions in the AndroidManifest.xml:
Test with both HTTP client implementationsSwitch between native and managed implementations to isolate whether the issue is specific to one implementation
Test the API endpoint outside your appUse tools like Postman or curl on the same network
Enable logging for network calls
// Add this before making requests
HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "YourApp/1.0");
Capture and inspect network trafficUse Charles Proxy or Fiddler to inspect the actual requests/responses
Check certificate information
# On your development machine
openssl s_client -connect your.internal.server:443 -showcerts
Verify which implementation you’re using
var client = new HttpClient();
var handlerType = client.GetType().GetField("_handler",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic)?.GetValue(client);
Console.WriteLine($"Using handler: {handlerType?.GetType().FullName}");
Debug specific errors
For Java.IO.IOException: “Trust anchor for certification path not found” – this means your app doesn’t trust the certificate
For HttpRequestException with “The SSL connection could not be established” – likely a TLS version mismatch
Conclusion
When your MAUI Android app connects successfully to public APIs but fails with internal network services, the issue often lies with HTTP client implementation differences, certificate validation, or TLS compatibility. By systematically switching between native and managed HTTP clients and applying the troubleshooting techniques outlined above, you can identify and resolve these networking challenges.
Remember that each implementation has its advantages – the native implementation typically offers better performance and follows platform-specific security policies, while the managed implementation provides more consistent cross-platform behavior. Choose the one that best fits your specific requirements and security considerations.
Over time, I transitioned to using the first versions of my beloved framework, XAF. As you might know, XAF generates a polished and functional UI out of the box. Using XAF made me more of a backend developer since most of the development work wasn’t visual—especially in the early versions, where the model designer was rudimentary (it’s much better now).
Eventually, I moved on to developing .NET libraries and NuGet packages, diving deep into SOLID design principles. Fun fact: I actually learned about SOLID from DevExpress TV. Yes, there was a time before YouTube when DevExpress posted videos on technical tasks!
Nowadays, I feel confident creating and publishing my own libraries as NuGet packages. However, my “old monster” was still lurking in the shadows: UI components. I finally decided it was time to conquer it, but first, I needed to choose a platform. Here were my options:
Windows Forms: A robust and mature platform but limited to desktop applications.
WPF: A great option with some excellent UI frameworks that I love, but it still feels a bit “Windows Forms-ish” to me.
Xamarin/Maui: I’m a big fan of Xamarin Forms and Xamarin/Maui XAML, but they’re primarily focused on device-specific applications.
Blazor: This was the clear winner because it allows me to create desktop applications using Electron, embed components into Windows Forms, or even integrate with MAUI.
Recently, I’ve been helping my brother with a project in Blazor. (He’s not a programmer, but I am.) This gave me an opportunity to experiment with design patterns to get the most out of my components, which started as plain HTML5 pages.
Without further ado, here are the key insights I’ve gained so far.
Building high-quality Blazor components requires attention to both the C# implementation and Razor markup patterns. This guide combines architectural best practices with practical implementation patterns to create robust, reusable components.
1. Component Architecture and Organization
Parameter Organization
Start by organizing parameters into logical groups for better maintainability:
public class CustomForm : ComponentBase
{
// Layout Parameters
[Parameter] public string Width { get; set; }
[Parameter] public string Margin { get; set; }
[Parameter] public string Padding { get; set; }
// Validation Parameters
[Parameter] public bool EnableValidation { get; set; }
[Parameter] public string ValidationMessage { get; set; }
// Event Callbacks
[Parameter] public EventCallback<bool> OnValidationComplete { get; set; }
[Parameter] public EventCallback<string> OnSubmit { get; set; }
}
Building effective Blazor components requires attention to both the C# implementation and Razor markup. By following these patterns and practices, you can create components that are:
Highly reusable
Performant
Accessible
Easy to maintain
Flexible for different use cases
Remember to adapt these practices to your specific needs while maintaining clean component design principles.
The ARM, x86, and Itanium CPU architectures each have unique characteristics that impact .NET developers. Understanding how these architectures affect your code, along with the importance of using appropriate NuGet packages, is crucial for developing efficient and compatible applications.
ARM Architecture and .NET Development
1. Performance and Optimization:
Energy Efficiency: ARM processors are known for their power efficiency, benefiting .NET applications on devices like mobile phones and tablets with longer battery life and reduced thermal output.
Performance: ARM processors may exhibit different performance characteristics compared to x86 processors. Developers need to optimize their code to ensure efficient execution on ARM architecture.
2. Cross-Platform Development:
.NET Core and .NET 5+: These versions support cross-platform development, allowing code to run on Windows, macOS, and Linux, including ARM-based versions.
Compatibility: Ensuring .NET applications are compatible with ARM devices may require testing and modifications to address architecture-specific issues.
3. Tooling and Development Environment:
Visual Studio and Visual Studio Code: Both provide support for ARM development, though there may be differences in features and performance compared to x86 environments.
Emulators and Physical Devices: Testing on actual ARM hardware or using emulators helps identify performance bottlenecks and compatibility issues.
x86 Architecture and .NET Development
1. Performance and Optimization:
Processing Power: x86 processors are known for high performance and are widely used in desktops, servers, and high-end gaming.
Instruction Set Complexity: The complex instruction set of x86 (CISC) allows for efficient execution of certain tasks, which can differ from ARM’s RISC approach.
2. Compatibility:
Legacy Applications: x86’s extensive history means many enterprise and legacy applications are optimized for this architecture.
NuGet Packages: Ensuring that NuGet packages target x86 or are architecture-agnostic is crucial for maintaining compatibility and performance.
3. Development Tools:
Comprehensive Support: x86 development benefits from mature tools and extensive resources available in Visual Studio and other IDEs.
Itanium Architecture and .NET Development
1. Performance and Optimization:
High-End Computing: Itanium processors were designed for high-end computing tasks, such as large-scale data processing and enterprise servers.
EPIC Architecture: Itanium uses Explicitly Parallel Instruction Computing (EPIC), which requires different optimization strategies compared to x86 and ARM.
2. Limited Support:
Niche Market: Itanium has a smaller market presence, primarily in enterprise environments.
.NET Support: .NET support for Itanium is limited, requiring careful consideration of architecture-specific issues.
CPU Architecture and Code Impact
1. Instruction Sets and Performance:
Differences: x86 (CISC), ARM (RISC), and Itanium (EPIC) have different instruction sets, affecting code efficiency. Optimizations effective on one architecture might not work well on another.
Compiler Optimizations: .NET compilers optimize code for specific architectures, but understanding the underlying architecture helps write more efficient code.
2. Multi-Platform Development:
Conditional Compilation: .NET supports conditional compilation for architecture-specific code optimizations.
#if ARM
// ARM-specific code
#elif x86
// x86-specific code
#elif Itanium
// Itanium-specific code
#endif
Libraries and Dependencies: Ensure all libraries and dependencies in your .NET project are compatible with the target CPU architecture. Use NuGet packages that are either architecture-agnostic or specifically target your architecture.
3. Debugging and Testing:
Architecture-Specific Bugs: Bugs may manifest differently across ARM, x86, and Itanium. Rigorous testing on all target architectures is essential.
Performance Testing: Conduct performance testing on each architecture to identify and resolve any specific issues.
Supported CPU Architectures in .NET
1. .NET Core and .NET 5+:
x86 and x64: Full support for 32-bit and 64-bit x86 architectures across all major operating systems.
ARM32 and ARM64: Support for 32-bit and 64-bit ARM architectures, including Windows on ARM, Linux on ARM, and macOS on ARM (Apple Silicon).
Itanium: Limited support, mainly in specific enterprise scenarios.
2. .NET Framework:
x86 and x64: Primarily designed for Windows, the .NET Framework supports both 32-bit and 64-bit x86 architectures.
Limited ARM and Itanium Support: The traditional .NET Framework has limited support for ARM and Itanium, mainly for older devices and specific enterprise applications.
3. .NET MAUI and Xamarin:
Mobile Development: .NET MAUI (Multi-platform App UI) and Xamarin provide extensive support for ARM architectures, targeting Android and iOS devices which predominantly use ARM processors.
Using NuGet Packages
1. Architecture-Agnostic Packages:
Compatibility: Use NuGet packages that are agnostic to CPU architecture whenever possible. These packages are designed to work across different architectures without modification.
Example: Common libraries like Newtonsoft.Json, which work across ARM, x86, and Itanium.
2. Architecture-Specific Packages:
Performance: For performance-critical applications, use NuGet packages optimized for the target architecture.
Example: Graphics processing libraries optimized for x86 may need alternatives for ARM or Itanium.
Conclusion
For .NET developers, understanding the impact of ARM, x86, and Itanium architectures is essential for creating efficient, cross-platform applications. The differences in CPU architectures affect performance, compatibility, and optimization strategies. By leveraging cross-platform capabilities of .NET, using appropriate NuGet packages, and testing thoroughly on all target architectures, developers can ensure their applications run smoothly across ARM, x86, and Itanium devices.
I have been using XPO from DevExpress since day one. For me is the best O.R.M in the dot net world, so when I got the news that XPO was going to be free of charge I was really happy because that means I can use it in every project without adding cost for my customers.
Nowadays all my customer needs some type of mobile development, so I have decided to master the combination of XPO and Xamarin
Now there is a problem when using XPO and Xamarin and that is the network topology, database connections are no designed for WAN networks.
Let’s take MS SQL server as an example, here are the supported communication protocols
TCP/IP.
Named Pipes
To quote what Microsoft web site said about using the protocols above in a WAN network
In a fast-local area network (LAN) environment, Transmission Control Protocol/Internet Protocol (TCP/IP) Sockets and Named Pipes clients are comparable with regard to performance. However, the performance difference between the TCP/IP Sockets and Named Pipes clients becomes apparent with slower networks, such as across wide area networks (WANs) or dial-up networks. This is because of the different ways the interprocess communication (IPC) mechanisms communicate between peers.”
So, what other options do we have? Well if you are using the full DotNet framework you can use WCF.
So, it looks like WCF is the solution here since is mature and robust communication framework but there is a problem, the implementation of WCF for mono touch (Xamarin iOS) and mono droid (Xamarin Android)
You can read about Xamarin limitations in the following links
I don’t want to go into details about how the limitation of each platform affects XPO and WCF but basically the main limitation is the ability to use reflection and emit new code which is needed to generate the WCF client, also in WCF there are problems in the serialization behaviors.
So basically, what we need to do is to replace the WCF layer with some other technology to communicate to the database server
The technology I’ve selected for this AspNetCore which I would say is a really nice technology that is modern, multi-platform and easy to use. Here below you can see what is the architecture of the solution
AspNetCore
Rest API
So, what we need basically is to be able to communicate the data layer with the data store through a network architecture.
The network architecture that I have chosen is a rest API which is one of the strong fronts of AspNetCore. The rest API will work as the server that forward the communication from XPO to the Database and vice versa, you can find a project template of the server implementation here https://www.jocheojeda.com/download/560/ this implementation references one nuget where I have written the communication code, you can fine the nuget here https://nuget.bitframeworks.com/feeds/main/BIT.Xpo.AgnosticDataStore.Server/19.1.5.1