Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
151853 stories
·
33 followers

.NET 10 on iOS: Updates and Notes for .NET MAUI Developers

1 Share

Here’s what you may have missed in .NET 10 for .NET MAUI developers targeting iOS.

The new features in .NET 10 for .NET MAUI don’t stop ! In this article, we’ll dive into the iOS-specific updates introduced in .NET 10—improvements that directly impact performance, reliability and the overall development experience for mobile apps.

We’ll break down what’s changed, what’s been optimized and what you, as a .NET MAUI developer targeting iOS, should keep in mind to get the most out of this release.

Supported Platforms

One of the first questions I recommend asking when adopting a new version—specifically in this case for .NET iOS (although it applies to everything)—is knowing which versions are officially supported.

Why? Because this tells you which device and/or emulator versions your environment must match in order to fully take advantage of the new features!

For iOS, tvOS, Mac Catalyst and macOS, the following versions are supported:

  • iOS 18.2
  • tvOS 18.2
  • Mac Catalyst 18.2
  • macOS 15.2

Preview 7: Xcode 26 Beta 4

For now, Preview 7 still doesn’t include full builds for .NET 10, but it does introduce initial compatibility with Xcode 26 Beta 4, focused on .NET 9 projects.

Putting this into practice, to use the new APIs/bindings from iOS 26 (Xcode 26), you must add two important elements inside your <PropertyGroup> tag:

Add the TargetFramework tag:

It specifies the version of the development environment, for example:

<TargetFramework>net9.0-ios26</TargetFramework>

Then you must add a NoWarn:

<NoWarn>$(NoWarn);XCODE_26_0_PREVIEW</NoWarn>

⚠️ This NoWarn is necessary because Xcode 26 is still in Beta, and it prevents the project from showing compatibility warnings.

A complete example would look like this:

<Project Sdk="Microsoft.NET.Sdk"> 
    <PropertyGroup> 
    <TargetFramework>net9.0-ios26</TargetFramework> 
    <NoWarn>$(NoWarn);XCODE_26_0_PREVIEW</NoWarn> 
    <!-- rest of your configuration --> 
    </PropertyGroup> 
</Project>

.NET MAUI Shell Rendering Issues

⚠️ Previously, there was an issue with .NET MAUI Shell rendering on iOS 26. You can now be confident that this problem has been resolved in .NET MAUI 9 Service Release 11 and .NET MAUI 10 RC1.

Previews: Extra Information

To learn more about .NET 10 on iOS, tvOS, Mac Catalyst and macOS, the official documentation recommends reviewing the known issues in .NET 10.

You can also explore the release notes for the .NET 10.0.1xx Preview versions:

Trimmer

The trimmer is a .NET tool that performs a sort of “cleanup operation” on your app’s code. It analyzes your project, detects unused code and removes it. In other words, it helps your app become lighter, more efficient and much faster to load.

In .NET 10, two important improvements related to its behavior have been introduced.

1. Trimmer Enabled in More Configurations

With .NET 10, this “smart cleaner”—the Trimmer—can now be enabled by default in more scenarios, such as:

  • iOS Simulator/arm64 (all configurations)
  • tvOS Simulator/arm64 (all configurations)
  • Mac Catalyst/arm64 (all configurations)

When you see all configurations, this means it applies to different build configurations such as Debug, Release and others.

2. Trimmer Warnings Enabled by Default

Previously, trimmer warnings were disabled by default. This was because the base class library produced its own trimmer warnings, making it impossible for the developer to fix all the warnings detected.

The good news is that in .NET 9, all iOS-related trimmer warnings were resolved, and thanks to that, trimmer warnings are now enabled by default.

However, if for some reason you want to disable them, you can do it very easily. Just add the SuppressTrimAnalysisWarnings property to your .csproj file as follows:

<PropertyGroup>  
    <SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings> 
</PropertyGroup>

Bundling Original Resources in Libraries

Library projects can contain different types of resources, such as:

  • Storyboards
  • XIBs
  • Property lists (plist)
  • Images
  • CoreML models
  • And others

These resources require processing tasks like compiling storyboards or XIBs, optimizing plist files and more. This processing comes with some important considerations, such as:

  • Running on a Mac, because compiling storyboards/XIBs is only possible on macOS.
  • Using Apple’s toolchain (xcodebuild, ibtool, actool, etc.).

All of these requirements can complicate building libraries because:

  • You don’t always have access to a Mac.
  • You cannot make decisions in the final app based on the original resources, because they were already “processed.”
  • You only get the processed version.
  • And, therefore, this limits the flexibility of the project consuming the library.

But Now We Have an Improvement

In .NET 9, optional support (opt-in) was introduced that allowed including the original resources inside the library without processing them.

In .NET 10, things get even better! This support is now the default behavior (opt-out).

This makes our apps more flexible, removes the hard dependency on having a Mac available and results in much more consistent CI/CD builds.

How Do I Enable or Disable This Option?

If for some reason you want to revert this default behavior—meaning you don’t want to include the original resources and prefer the library to contain the processed ones—you can do so by adding the following tag in your project file:

<PropertyGroup> 
    <BundleOriginalResources>false</BundleOriginalResources> 
</PropertyGroup>

Build Binding Projects on Windows

Before, binding projects depended on Apple’s ecosystem tools (meaning you needed a Mac to compile them).

With .NET 10, this changed!

Binding projects can now be built entirely on Windows, without requiring a Mac or any remote connection. This results in much faster builds on Windows. Woohoo!

This is a VERY big improvement for anyone working on Windows devices!

NSUrlSessionHandler No Longer Sets Minimum TLS Protocol Automatically

In case you didn’t know, TLS (Transport Layer Security) is a security protocol that protects communication between two endpoints—for example, your app and the server.

Previously, we had behavior like this:

  • NSUrlSessionHandler relied on the value of ServicePointManager.SecurityProtocol to determine the minimum TLS protocol to use.
  • But that approach is now deprecated, because ServicePointManager is no longer used.

So starting with .NET 10, if you want to define the minimum TLS protocol, you must do it manually before creating the NSUrlSessionHandler, as shown below:

var sessionConfiguration = NSUrlSessionConfiguration.DefaultSessionConfiguration;
    
sessionConfiguration.TlsMinimumSupportedProtocolVersion = TlsProtocolVersion.Tls13;
    
var handler = new NSUrlSessionHandler(sessionConfiguration);

The NSUrlSessionHandler.BypassBackgroundSessionCheck Property Is Now Ignored

This property existed as a workaround for an old issue in the Mono runtime. Since it’s no longer needed, the property is now ignored.

Conclusion

And that’s it! In this article, you explored the key improvements that .NET 10 brings to iOS, tvOS, macOS and Mac Catalyst development. From expanded trimmer support and improved resource handling to faster Windows-based binding builds and updated networking defaults, these changes work together to create a more efficient, consistent and modern development experience.

Now you have a clearer understanding of how these updates impact your workflow—helping you build lighter apps, reduce platform-specific friction and take full advantage of what .NET 10 offers for Apple platforms.

If you have any questions or want me to cover more related topics, feel free to leave a comment—I’d be happy to help you!

See you in the next article! ‍♀️✨

References

The explanation was based on the official documentation:

Read the whole story
alvinashcraft
50 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

TypeScript 7 On Course For Early 2026

1 Share
Read the whole story
alvinashcraft
50 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Additional notes on color-keyed overlays as a way of doing smooth video rendering

1 Share

A little while ago, I wrote about the use of color-keyed overlays to render video smoothly. The idea is that the CPU itself produces an image with a block of solid color (green in my example), and the graphics card is instructed to replace those pixels with the pixels from an off-screen image that it generated separately. Rather than doing the image composition in the CPU, the composition happens in the video card as the image leaves the card and goes to the monitor.

In the subsequent discussion, some people remembered this technique but noted that in their recollection, the color-key was not green but some other color. What’s going on?

When you set up the color-keying with the video card, you gave it a few instructions. You told it where to find the off-screen replacement image and how big it was. You told it the size and location of the on-screen rectangle where the replacement image should go. And you told it the magic color to look for inside that rectangle.

So the CPU got to pick the color-key color.

Choosing a color-key color was a bit tricky. If another window overlapped your video playback window, and they used your color-key color, then your video would play “through” the other window at any place it used that color. Therefore, when choosing a color-key color, you wanted to pick a color that is not commonly encountered. You didn’t want white or black, for example, because those are all over the place. Common choices were either neon-bright colors such as bright green or bright magenta because they are so ugly that nobody would even use them on purpose, or very dark colors like #010000 because they are so close to black that most normal people would just pick black outright.

The neon-bright colors were also useful when debugging because it’s extremely noticeable when you messed up.

Video card support for overlays was extremely varied. Some cards didn’t support them. Others did, but with restrictions. For example, “Oh, I can do overlays, but no more than four at a time, and they cannot have overlapping destination rectangles, and furthermore, I cannot apply a scale factor smaller than 1.0 or larger than 1.3.” Navagating all of these limitations and restrictions was quite a cumbersome undertaking for programs that wanted to use the feature.

The key to all this overlay trickery is that the magic happened inside the video card, and the result went out to the monitor without ever being sent back to the CPU. Programs themselves never saw the result of the overlay. All that programs saw or knew about were the color-keyed pixels. When you took the screen shot, you got the green (or whatever) pixels. When you loaded the bitmap into Paint, it showed green pixels, (but if an overlay was active, the video card changed them to something else before sending them to the monitor). When Paint saved the bitmap, it just saved green pixels. As far as anybody on the computer could tell, those pixels were just boring green pixels.

The post Additional notes on color-keyed overlays as a way of doing smooth video rendering appeared first on The Old New Thing.

Read the whole story
alvinashcraft
50 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Top .NET Blog Posts of 2025

1 Share

2025 was a big year for .NET developers. We kicked things off with early .NET 10 previews, kept momentum with steady tooling and runtime improvements, and wrapped it all up with the launch of .NET 10 in November.

🚀 .NET 10

.NET 10 was the headline event of the year: the latest Long Term Support (LTS) release with improvements across the runtime, SDK, libraries, languages, workloads, and tooling.

Announcing .NET 10

⚡ Performance

Performance posts are one of the best ways to learn what really changed, because they come with benchmarks and code you can try yourself.

Performance Improvements in .NET 10

🤖 AI

AI reshaped day-to-day .NET workflows in 2025, from Copilot experiences to agent and tool integration patterns.

Introducing Microsoft Agent Framework (Preview)

🛠 Productivity

Some of the most practical posts of the year were about shortening feedback loops, whether that meant better Copilot workflows or faster “try this now” experiences.

Ask Mode vs Agent Mode

🌐 Aspire

Aspire kept leveling up in 2025, making it easier to build and operate distributed apps with first-class diagnostics.

Aspire 9.3: enhanced with GitHub Copilot

If you want one Aspire post to start with, read Aspire 9.3: enhanced with GitHub Copilot for a clear tour of the dashboard experience and why Aspire pairs so well with modern observability.

For ongoing Aspire updates, follow the dedicated Aspire blog at https://devblogs.microsoft.com/aspire.

🧑‍🤝‍🧑 Community

If you want a broader view of the platform and ecosystem beyond individual posts, catch up on .NET Conf.

.NET Conf 2025 recap

📣 Announcements

Some of the most important posts of the year weren’t about new features—they were about how .NET ships, how it’s supported, and how the ecosystem stays secure.

.NET STS releases supported for 24 months

🧰 Tooling

Big platform releases matter, but day-to-day workflows are shaped by tooling improvements.

Introducing support for SLNX

🙏 Thanks for reading

Whether you came for .NET 10, performance deep dives, new CLI capabilities, or the wave of AI tools, thanks for building with us in 2025.

Don’t forget to subscribe to the blog in your favorite RSS reader or through e-mail notifications.

The post Top .NET Blog Posts of 2025 appeared first on .NET Blog.

Read the whole story
alvinashcraft
50 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Building Multi-Agent Workflows in .NET with AgentFactory and Handoff

1 Share

⚠ This blog post was created with the help of AI tools. Yes, I used a bit of magic from language models to organize my thoughts and automate the boring parts, but the geeky fun and the 🤖 in C# are 100% mine.

🎥 Video coming soon!
I’m preparing a short walkthrough video where I’ll run this sample live, explain the design decisions, and show how everything fits together step by step. But hey, it’s christmas time, so I’m taking this easy 😉


When building AI-powered applications, the moment you move beyond a single “chatbot”, things get interesting very quickly.

You start asking questions like:

  • How do I split responsibilities across agents?
  • How do I avoid hard-coding routing logic?
  • How do I keep agent creation simple and consistent?

In this post, I’ll show a clean and practical pattern using the Microsoft Agent Framework (MAF) in .NET that answers all of those questions using two key concepts:

  • AgentFactory – to create agents consistently and with minimal boilerplate
  • Handoff workflows – to let agents transfer control between each other instead of routing in code

We’ll do this with a small but realistic “Mini Concierge” example.


The scenario: a Mini Concierge with specialists

Our app has four agents:

  • Triage agent – decides who should handle the request
  • General agent – handles normal Q&A
  • Travel agent – handles travel questions and can call a weather tool
  • Vision agent – analyzes images (multimodal)

The key idea is simple:

The triage agent does not answer questions.
It only decides who should own the task and hands it off.

No if/else.
No routing methods.
No orchestration logic in our app code.


Why AgentFactory matters

Without a factory, agent creation quickly turns into repeated setup code:

  • chat client
  • tools
  • defaults
  • configuration

With AgentFactory, we define all shared configuration once, then create as many agents as we want by only changing:

  • name
  • instructions

In this sample, the factory is the backbone of the entire solution.

You can find the complete code here:
https://github.com/microsoft/Generative-AI-for-beginners-dotnet/tree/main/samples/AgentFx/AgentFx-MultiAgents-Factory-01


Step-by-step overview

1. Shared chat client

We start with a single chat client. In this case, I’m using Ollama running locally, but this could just as easily be Microsoft Foundry or another provider.

IChatClient chatClient = new OllamaApiClient(
    new Uri("http://localhost:11434/"),
    "ministral-3");

2. Tools once, reused everywhere

The travel agent can answer weather questions using a simple tool.
Tools are registered once and reused by all agents created by the factory.

AIFunction[] tools = [
    AIFunctionFactory.Create(GetWeather, "GetWeather")
];

3. Create the AgentFactory

This is the most important line in the whole sample.

var agentFactory = new ChatClientPromptAgentFactory(chatClient, tools);

From here on, every agent is created the same way, with no duplicated wiring.


4. Define agents by intent, not infrastructure

Each agent is defined only by:

  • a name
  • a role
  • clear instructions

For example, the triage agent:

var triageAgent = await agentFactory.CreateAsync(
    promptAgent: new GptComponentMetadata(
        name: "triage_agent",
        instructions: ToInstructions("""
            You are a triage agent for a mini concierge.

            Decide who should own the task, then HANDOFF to exactly ONE agent:
            - travel_agent: travel planning, destinations, weather
            - vision_agent: anything that requires looking at an image
            - general_agent: everything else

            Do not answer the user yourself. Always handoff.
        """)));

The same factory creates the travel, vision, and general agents with different instructions.


Handoff workflows: no routing code

Instead of routing logic in C#, we define handoff rules declaratively using a workflow.

Func<Workflow> workflowFactory = () =>
    AgentWorkflowBuilder.CreateHandoffBuilderWith(triageAgent)
        .WithHandoffs(triageAgent, [travelAgent, visionAgent, generalAgent])
        .WithHandoff(travelAgent, triageAgent)
        .WithHandoff(visionAgent, triageAgent)
        .WithHandoff(generalAgent, triageAgent)
        .Build();

What this means:

  • The triage agent can hand off to any specialist
  • Specialists can optionally return control to triage
  • The runtime manages ownership and execution flow

If you want to dive deeper into this concept, this is the official documentation:
https://learn.microsoft.com/en-us/agent-framework/user-guide/workflows/orchestrations/handoff?pivots=programming-language-csharp


Running the demos

We run three simple demos:

Demo 1 – General Q&A

What is the capital of France?

Output:

[AGENT: triage_agent]
[AGENT: general_agent]
Final Answer: The capital of France is Paris.

Demo 2 – Tool calling

I'm going to Amsterdam tomorrow. What's the weather in celsius?

Output:

[AGENT: triage_agent]
[AGENT: travel_agent]
Final Answer: ...weather response...

Demo 3 – Multimodal vision

What do you see in this image?

Output:

[AGENT: triage_agent]
[AGENT: vision_agent]
Final Answer: ...image analysis...

Notice how:

  • The app never decides who answers
  • Agent ownership is explicit and visible
  • Each response is clean and readable

Why this pattern scales

This approach scales naturally because:

  • AgentFactory centralizes creation and configuration
  • Handoff workflows remove routing logic from your app
  • Adding a new agent is just:
    • define instructions
    • add a handoff rule

What’s next?

  • 🎥 A short video walkthrough of this exact sample (coming soon)
  • A follow-up post showing how to:
    • persist conversations
    • add background responses
    • connect this to Azure AI Foundry

If you want to experiment now, grab the code here:
https://github.com/microsoft/Generative-AI-for-beginners-dotnet/tree/main/samples/AgentFx/AgentFx-MultiAgents-Factory-01

And as always—feedback welcome. This pattern is powerful, simple, and very easy to grow with.

Happy coding!

Greetings

El Bruno

More posts in my blog ElBruno.com.

More info in https://beacons.ai/elbruno






Read the whole story
alvinashcraft
50 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Warp Wrapped: 2025 in Review

1 Share
2025 was the year Warp stopped being “just a terminal” and became an Agentic Development Environment (ADE): a platform where the default unit of work shifted from ‘open file, type code’ or ‘open terminal, type command’ to write a ‘prompt, steer agents, and ship with confidence’. The numbers tell part of the story. Warp’s agents edited 3.2 billion lines of code, indexed and synced 120,000+ codebases for richer context, and processed tens of trillions of LLM tokens. Internally, we merged 10,000+ ...

Read the whole story
alvinashcraft
51 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories