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

Introducing Corvus.Text.Json V5: Schema Validation - 10× Faster

1 Share

At endjin, we maintain Corvus.JsonSchema, and in the previous post we saw how the source generator produces complete typed models from JSON Schema.

Now let's look at what happens when you call person.EvaluateSchema().

Validation is not optional

If you're working with JSON that crosses a trust boundary - API requests, message queues, configuration files, user-supplied data - you need to validate it. Not "check a couple of fields" validate. Schema validate. Against a specification that defines what valid means, and that both producer and consumer agree on.

JSON Schema is that specification, and it covers all the major drafts: 4, 6, 7, 2019-09, and 2020-12 - plus OpenAPI 3.0 and 3.1.

V5 validates over 10× faster than other .NET JSON Schema validators.

The generated validator

If you've followed the source generator approach from the previous post, validation is already built in:

using var doc = ParsedJsonDocument<Person>.Parse(
    """{"name":"Alice","age":30}""");
Person person = doc.RootElement;

bool valid = person.EvaluateSchema();  // true

That's it. The source generator produced a validation method tailored to your specific schema, with every keyword compiled into type-specific checks. There is no interpretation overhead and no runtime schema walking.

Getting diagnostic output

When validation fails and you need to know why, pass a results collector:

using var collector = JsonSchemaResultsCollector.Create(
    JsonSchemaResultsLevel.Detailed);

bool valid = person.EvaluateSchema(collector);

if (!valid)
{
    foreach (var result in collector.EnumerateResults())
    {
        if (!result.IsMatch)
        {
            Console.WriteLine(
                $"  Failed: {result.GetMessageText()} " +
                $"at {result.GetDocumentEvaluationLocationText()}");
        }
    }
}

When you call EvaluateSchema() without a collector, you get a simple pass/fail bool with maximum performance. If you need diagnostics, create a JsonSchemaResultsCollector and choose how much detail you want:

Level What it collects
Basic Failure messages only (lowest overhead)
Detailed Failures with schema location and evaluation path
Verbose Every evaluation step, including successes

Use the no-collector overload in production hot paths; use Detailed or Verbose for diagnostics.

Dynamic validation at runtime

Not every scenario has schemas known at compile time. Schema registries, configuration validators, and user-supplied schemas all need runtime compilation.

The Corvus.Text.Json.Validator package handles this. Internally, it uses the same code generation engine as the source generator, but invokes Roslyn dynamically:

using Corvus.Text.Json.Validator;

// Load a schema - from a file, string, stream, or URI
JsonSchema schema = JsonSchema.FromFile("Schemas/person.json");

// Validate
bool valid = schema.Validate("""{"name": "Alice", "age": 30}""");

Compiled schemas are cached automatically by their canonical URI, so the first validation incurs a compilation cost (around 100ms) but subsequent calls are sub-millisecond.

Multiple input formats

The Validate() method accepts JSON in whatever format you already have it:

// UTF-8 bytes (zero copy from a network buffer)
bool valid = schema.Validate(utf8Bytes);

// Stream (HTTP request body, file stream)
bool valid = schema.Validate(stream);

// Pre-parsed element
using var doc = ParsedJsonDocument<JsonElement>.Parse(json);
bool valid = schema.Validate(in doc.RootElement);

Pre-loading referenced schemas

If your schema uses $ref to reference other schema files, you can pre-load them to avoid file system or network resolution:

var options = new JsonSchema.Options(
    additionalSchemaFiles: new[]
    {
        new AdditionalSchemaFile(
            "https://example.com/schemas/address.json",
            "Schemas/address.json")
    });

JsonSchema schema = JsonSchema.FromFile("person.json", options: options);

This is particularly useful in CI/CD environments where external resolution may be unreliable or disallowed.

Conformance

We take correctness seriously. The V5 engine passes the official JSON Schema Test Suite for all supported drafts, and we publish results to Bowtie - the cross-implementation conformance project.

Bowtie runs every JSON Schema implementation against the same test suite and publishes comparative results. It's the definitive way to verify a validator's correctness, and we encourage you to check the latest results for any implementation you're evaluating.

Next up

We've seen validation from the caller's perspective. In the next post, we'll go deeper into the V5 memory model. We'll look at how ParsedJsonDocument<T> uses ArrayPool to achieve just 136 bytes per document.



Read the whole story
alvinashcraft
just a second ago
reply
Pennsylvania, USA
Share this story
Delete

Multi-agent patterns with the GitHub Copilot SDK

1 Share

We've covered a lot of ground in this series: sessions and lifecycle, deployment and scaling, MCP integration, and skills. Each post added a new capability layer to a single agent. This post changes the shape of the problem: instead of one agent doing more things, we compose multiple agents doing the right things.

There are two different levels at which you can do this. Inside the Copilot SDK itself, custom agents let the Copilot runtime orchestrate specialised sub-agents automatically within a single session. Beyond the SDK, the Microsoft Agent Framework lets you compose Copilot SDK agents with agents from any other provider in structured multi-agent workflows.

In this post we stay inside the SDK. Our next and final post will look at the broader ecosystem and Microsoft Agent Framework integration.

The problem with a single agent

A single session with a broad system prompt is fine for many use cases. But as tasks grow more complex, the cracks show:

  • A general agent needs a large context to cover all domains, which drives up token usage and increases the chance of confusion
  • Tool access becomes an all-or-nothing decision — you either give the agent everything or nothing
  • The agent's behaviour is hard to constrain to specific task types without prompt gymnastics

Custom agents solve this by letting you define specialised agents with scoped prompts, restricted tool sets, and their own optional MCP servers — all within a single session. The Copilot runtime acts as the orchestrator, automatically delegating user requests to the most appropriate sub-agent based on the task.

Custom agents

Custom agents are lightweight agent definitions you attach to a session. Each agent has its own system prompt, tool restrictions, and optional MCP servers. When a user's request matches an agent's expertise, the Copilot SDK runtime automatically delegates to that agent as a sub-agent — running it in an isolated context while streaming lifecycle events back to the parent session.

Here's the minimal .NET setup:

using GitHub.Copilot.SDK;

var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    CustomAgents =
    [
        new CustomAgentConfig
        {
            Name = "researcher",
            DisplayName = "Research Agent",
            Description = "Explores codebases, reads files, and answers questions. " +
                          "Use for analysis, investigation, and understanding tasks.",
            Tools = ["grep", "glob", "view"],       // read-only tools only
            Prompt = "You are a research assistant. Analyse code and answer questions " +
                     "without making any changes."
        },
        new CustomAgentConfig
        {
            Name = "editor",
            DisplayName = "Editor Agent",
            Description = "Writes and modifies code. Use for implementation, " +
                          "refactoring, and code generation tasks.",
            Tools = ["grep", "glob", "view", "edit", "write"],
            Prompt = "You are a code editor. Make minimal, precise changes. " +
                     "Always verify the change compiles before finishing."
        }
    ]
});

With this setup, a prompt like "explain what this authentication middleware does" will route to the researcher agent, while "add retry logic to the HTTP client" will route to the editor agent. The user doesn't know which agent is handling their request — they just get a better, more focused answer.

On descriptions: a good description helps the runtime match user intent to the right agent. Be specific about the agent's expertise and capabilities. Think of the description the same way you'd write a skill description: it's a semantic index, not a display label.

Pre-selecting an agent

By default, the runtime picks the most appropriate agent for each turn. If you want to start a session with a specific agent active — for a workflow where you know the first task type — set the Agent property on SessionConfig:

var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    Agent = "researcher",   // start with the researcher active
    CustomAgents = [ /* ... */ ]
});

The value must match the Name of one of the agents defined in CustomAgents. This is useful when your application's entry point is task-specific — a "review this PR" button should probably start in the researcher agent rather than letting the runtime decide from a cold start.

The three orchestration patterns

Custom agents support three orchestration patterns, each suited to different workflow shapes.

Pattern 1: Automatic delegation

The simplest pattern. You define agents, send prompts, and the runtime routes automatically. The user (or calling code) stays unaware of which agent is active.

This is the default behaviour shown above. It works well for interactive sessions where task types are mixed and unpredictable. The runtime's delegation logic is based on the agent descriptions. Precise descriptions produce more reliable routing.

Pattern 2: Agent handoffs

Handoffs work best when you want a clear human-in-the-loop moment, such as reviews, approvals, or sensitive checks. One agent completes its work and explicitly transfers control to another, optionally passing a summary of what it did.

A practical example: a security review followed by a remediation step, where you want to inspect the findings before allowing code changes:

var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    CustomAgents =
    [
        new CustomAgentConfig
        {
            Name = "auditor",
            Description = "Reviews code for security vulnerabilities. Read-only.",
            Tools = ["grep", "glob", "view"],
            Prompt = """
                You are a security auditor. Review the code for vulnerabilities.
                When done, produce a structured findings report and hand off to
                the 'remediator' agent with a summary of what needs fixing.
                """
        },
        new CustomAgentConfig
        {
            Name = "remediator",
            Description = "Applies security fixes identified by the auditor.",
            Tools = ["grep", "glob", "view", "edit", "write"],
            Prompt = """
                You are a security engineer. You receive findings from the auditor.
                Apply the minimum change necessary to address each finding.
                Explain each change as you make it.
                """
        }
    ]
});

// Auditor runs, produces findings, hands off to remediator
var result = await session.SendAndWaitAsync(new MessageOptions
{
    Prompt = "Audit the authentication module for security vulnerabilities and fix any issues found"
});

The handoff happens inside the session — the remediator picks up where the auditor left off, with access to the auditor's findings in context.

Pattern 3: Explicit sub-agent delegation

With explicit sub-agent delegation, a primary agent programmatically invokes other custom agents to handle well-defined subtasks. Unlike handoffs, the user does not switch agents. A parent orchestrator breaks down complex tasks and dispatches them to specialists, then assembles the results.

This is the most structured pattern, and the right choice for repeatable, multi-step pipelines:

var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    CustomAgents =
    [
        new CustomAgentConfig
        {
            Name = "orchestrator",
            Description = "Coordinates the full code review pipeline. Entry point for all requests.",
            Tools = [],   // orchestrator doesn't use tools directly
            Prompt = """
                You are a pipeline orchestrator. For every code review request:
                1. Delegate to the 'linter' agent to check style and formatting
                2. Delegate to the 'tester' agent to verify test coverage
                3. Delegate to the 'security' agent to check for vulnerabilities
                4. Synthesise all findings into a single structured report
                Never perform any of these tasks yourself — always delegate.
                """
        },
        new CustomAgentConfig
        {
            Name = "linter",
            Description = "Checks code style, formatting, and conventions.",
            Tools = ["grep", "glob", "view"],
            Prompt = "You are a linting specialist. Check code against established style conventions."
        },
        new CustomAgentConfig
        {
            Name = "tester",
            Description = "Reviews test coverage and test quality.",
            Tools = ["grep", "glob", "view"],
            Prompt = "You are a testing specialist. Evaluate test coverage and flag gaps."
        },
        new CustomAgentConfig
        {
            Name = "security",
            Description = "Reviews code for security vulnerabilities.",
            Tools = ["grep", "glob", "view"],
            Prompt = "You are a security specialist. Review for OWASP Top 10 and common .NET security issues."
        }
    ],
    Agent = "orchestrator"
});

The prompt always enters the orchestrator, which breaks the task into sub-tasks and dispatches each to the appropriate specialist. The caller writes one prompt; three specialised agents execute.

Giving Custom Agents Their Own MCP Servers

Custom agents can each have their own MCP server configuration, independent of what the session-level MCP servers provide. This is powerful for tight tool scoping: the researcher agent can read from a knowledge base, while the editor agent has access to a build system, and neither can use the other's tools:

new CustomAgentConfig
{
    Name = "azure-ops",
    Description = "Manages and queries Azure resources.",
    Prompt = "You are an Azure operator. Use Azure tools to answer questions and take actions.",
    McpServers = new Dictionary<string, McpServerConfig>
    {
        ["azure"] = new McpStdioServerConfig
        {
            Command = "npx",
            Args = ["-y", "@azure/mcp@latest", "server", "start"],
            Tools = ["azure_resource_group_list", "azure_storage_account_list"]
        }
    }
}

Observing sub-agent activity

Sub-agent lifecycle events flow through the same event system as the parent session. You can distinguish parent and sub-agent events by the AgentName property on the event data:

session.On<SubagentStartedEvent>(evt =>
    _logger.LogInformation(
        "[{Agent}] started: {Tool}",
        evt.Data.AgentDisplayName,
        evt.Data.ToolCallId));

session.On<SubagentCompletedEvent>(evt =>
    _logger.LogInformation(
        "[{Agent}]completed",
        evt.Data.AgentDisplayName));

If OpenTelemetry is configured, each sub-agent's work appears as a child span under the parent invoke_agent span, giving you a complete trace of delegation chains without additional instrumentation.

When to use custom agents vs. multiple sessions

Custom agents are the right tool when tasks share a conversation — when earlier context should inform later steps, and delegation happens within a single coherent workflow. Multiple independent sessions are the right tool when tasks are fully isolated — separate users, unrelated jobs, or workflows where shared context would be a liability rather than an asset.

A useful heuristic: if the agents need to read each other's outputs, use custom agents in one session. If they don't, use separate sessions.


What’s next

Although the support for custom agents in the GitHub Copilot SDK is a good starting point, the level of control and flexibility in a multi-agent setup is still limited compared to other frameworks like the Microsoft Agent Framework. The good news is that the GitHub Copilot SDK integrates nicely and that is exactly we’ll take a look at in our final post tomorrow. 

More information

Custom Agents
Read the whole story
alvinashcraft
16 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Postgres 19 beta1 vs sysbench on a small server

1 Share

This has results from sysbench on a small server with Postgres 19 beta1, 18.4 and 17.10. Sysbench is run with low concurrency (1 thread) and a cached database. The purpose is to search for changes in performance, often from new CPU overheads.

tl;dr

  • 19beta1, 18.4 and 17.10 have mostly similar performance
  • There might be small regressions (about 2%) from 17.10 to 19beta1 but my tests are not good at spotting that.
  • 19beta1 is much faster on one test (read-only-count) thanks to a new query plan

Builds, configuration and hardware

I compiled Postgres from source. 

The server is a Beelink SER7 7840HS with an AMD Ryzen 7 7840HS CPU and 32G RAM. Storage uses an NVMe device with ext-4 and discard enabled. The OS is Ubuntu 24.04. 

The config files are here for 17.10, 18.4 and 19 beta1.

Benchmark

I used sysbench and my usage is explained here. To save time I only run 32 of the 42 microbenchmarks 
and most test only 1 type of SQL statement. Benchmarks are run with the database cached by Postgres.

The read-heavy microbenchmarks run for 600 seconds and the write-heavy for 900 seconds.

The benchmark is run with 1 client, 1 table and 50M rows. The purpose is to search for CPU regressions.

Results

The microbenchmarks are split into 4 groups -- 1 for point queries, 2 for range queries, 1 for writes. For the range query microbenchmarks, part 1 has queries that don't do aggregation while part 2 has queries that do aggregation. 

I provide charts below with relative QPS (rQPS). The relative QPS is the following:
(QPS for some version) / (QPS for base version)
When the relative QPS is > 1 then some version is faster than base version.  When it is < 1 then there might be a regression. Values from iostat and vmstat divided by QPS are also provided here. These can help to explain why something is faster or slower because it shows how much HW is used per request.

Here, base version is Postgres 17.10 and some version is either 18.4 or 19 beta1.

I describe performance changes (changes to relative QPS) in terms of basis points. Performance changes by one basis point when the difference in rQPS is 0.01. When rQPS decreases from 0.95 to 0.85 then it changed by 10 basis points.

Results: point queries

Summary:
  • 19beta1 is better than 17.10 by ~3 basis points for most tests
  • 19beta1 is slightly better than 18.4
Relative to Postgres 17.10
col-1 : Postgres 18.4
col-2 : Postgres 19 beta1

col-1   col-2
1.01    1.00    hot-points
0.98    0.97    point-query
1.01    1.03    points-covered-pk
1.00    1.04    points-covered-si
1.00    1.02    points-notcovered-pk
1.00    1.03    points-notcovered-si
0.99    0.99    random-points_range=10
1.00    1.03    random-points_range=100
1.01    1.03    random-points_range=1000

Results: range queries without aggregation

Summary:
  • 19beta1 is worse than 17.10 by ~3 basis points in 4 of 5 tests
  • 19beta1 is better than 17.10 by 5 basis points in the scan test
  • 19beta1 and 18.4 are similar except for the scan test where 19beta1 did better
Relative to Postgres 17.10
col-1 : Postgres 18.4
col-2 : Postgres 19 beta1

col-1   col-2
0.98    0.97    range-covered-pk
0.96    0.96    range-covered-si
0.98    0.98    range-notcovered-pk
0.99    0.99    range-notcovered-si
0.95    1.05    scan

Results: range queries with aggregation

Summary:
  • 19beta1 is worse than than 17.10 on two tests
  • 19beta1 is better than 17.10 on five tests
  • 19beta1 and 17.10 are the same on one test
  • 19beta1 is ~2.5X better than 17.10 on the read-only-count test
  • 19beta1 and 18.4 have similar results except for the read-only-count test
The query for the read-only-count test appears to have a different plan in 19beta1 and that might explain the ~2.5X speedup. In 17.10 and 18.4 it gets Index Scan while in 19beta1 it gets Index Only Scan.

Query plans for the read-only-count test ...

For 17.10
explain SELECT count(c) FROM sbtest1 WHERE id BETWEEN 17704460 AND 17705459
        Aggregate  (cost=1424.42..1424.43 rows=1 width=8)
          ->  Index Scan using sbtest1_pkey on sbtest1  (cost=0.56..1421.93 rows=996 width=121)
                Index Cond: ((id >= 17704460) AND (id <= 17705459))

For 18.4
explain SELECT count(c) FROM sbtest1 WHERE id BETWEEN 11575278 AND 11576277
        Aggregate  (cost=1310.09..1310.10 rows=1 width=8)
          ->  Index Scan using sbtest1_pkey on sbtest1  (cost=0.56..1307.89 rows=882 width=121)
                Index Cond: ((id >= 11575278) AND (id <= 11576277))

For 19beta1
explain SELECT count(c) FROM sbtest1 WHERE id BETWEEN 11686801 AND 11687800
        Aggregate  (cost=32.32..32.33 rows=1 width=8)
          ->  Index Only Scan using sbtest1_pkey on sbtest1  (cost=0.56..30.13 rows=878 width=0)
                Index Cond: ((id >= 11686801) AND (id <= 11687800))

Relative to Postgres 17.10
col-1 : Postgres 18.4
col-2 : Postgres 19 beta1

col-1   col-2
1.04    2.47    read-only-count
1.00    0.99    read-only-distinct
1.02    1.01    read-only-order
0.98    0.97    read-only_range=10
1.00    1.00    read-only_range=100
1.02    1.03    read-only_range=10000
1.09    1.09    read-only-simple
1.01    1.01    read-only-sum

Results: writes

Summary:
  • 19beta1 is worse than 17.10 by 2 to 5 basis points
  • 18.4 is worse than 17.10 by 2 to 3 basis points
Relative to Postgres 17.10
col-1 : Postgres 18.4
col-2 : Postgres 19 beta1

col-1   col-2
0.97    0.97    delete
0.99    0.96    insert
0.98    0.97    read-write_range=10
0.98    0.98    read-write_range=100
0.96    0.95    update-index
0.99    0.97    update-inlist
0.97    0.96    update-nonindex
0.97    0.95    update-one
0.97    0.95    update-zipf
0.98    0.97    write-only

Read the whole story
alvinashcraft
44 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

2.2 Experimental 9 (2.2.2-experimental9) 🧪

1 Share

Windows App SDK 2.2 Experimental 9 (2.2.2-experimental9) 🧪

Windows App SDK 2.2 Experimental 9 is the latest experimental release. It ships alongside Windows App SDK 2.2.0 stable and generally brings over the changes from that release; the highlights below describe the experimental-only additions.

What's new in WinAppSDK 2.2 Experimental 9:

  • Language Model APIs on GPU [Experimental]. The Language Model APIs now run on non-Copilot+ PCs equipped with a supported GPU, bringing local language model capabilities to a broader range of Windows 11 devices. Supported hardware includes NVIDIA GeForce RTX 30 series and newer with 6+ GB vRAM. GPU inference requires Developer Mode to be enabled and a Windows Insider Experimental Channel build. The GPU model is not pre-installed; it is downloaded on demand via EnsureReadyAsync through Windows Update. Apps should check GetReadyState and display a consent dialog before triggering the download. Users can manage the model at Settings > System > AI Components. For responsible AI guidance, see the new Transparency Note: Language Model APIs on Non-Copilot+ PCs.
  • Speech Recognition APIs [Experimental]. New on-device speech recognition APIs in Microsoft.Windows.AI.Speech enable both batch and streaming speech-to-text. BatchRecognition recognizes a complete audio source in a single call, and StreamingRecognition raises Recognizing and Recognized events. Audio can be sourced from a device (AudioConfiguration.FromAudioDevice), file (FromFile), input stream (FromStream), or pushed by the caller via SpeechAudioProvider (16 kHz, 16-bit, single-channel PCM). The on-device model is managed via SpeechRecognitionModel.EnsureReadyAsync / TryCreateAsync, with download and load progress reported through SpeechRecognitionModelProgress.
  • New NpuType API. A new Microsoft.Windows.Workloads.NpuType enum surfaces the NPU class on the current device (for example, Qnn, Lnl, Stx, Win365, Unknown, None), so apps and Workloads infrastructure can route AI workloads to the appropriate execution path.

This release also rolls forward all changes from the 2.2.0 stable release: the new Microsoft.Windows.AI.Video.VideoScaler Video Super Resolution API, the new Microsoft.Windows.Storage.ApplicationData.GetForUnpackaged() entry point for unpackaged apps, the new XamlBindingHelper boxing-free setter overloads, and the WinUI / Windows ML reliability fixes shipped in 2.2.0.

New or updated APIs (since 2.1 Experimental 8):

Microsoft.UI.Xaml

    Setter
        ValueProperty
Microsoft.UI.Xaml.Markup

    XamlBindingHelper
        SetPropertyFromColor
        SetPropertyFromCornerRadius
        SetPropertyFromThickness
Microsoft.Windows.AI.Speech

    AudioConfiguration
    BatchRecognition
    SpeechAudioProvider
    SpeechContract
    SpeechRecognitionModel
    SpeechRecognitionModelProgress
    SpeechRecognitionModelProgressStatus
    SpeechRecognitionModelResult
    StreamingRecognition
    StreamingRecognizedEventArgs
    StreamingRecognizingEventArgs
Microsoft.Windows.AI.Text.Experimental

    LanguageModelExperimental
        CompressPromptAsync
        GenerateResponseAsync
        GenerateResponseFromEmbeddingsAsync

    LanguageModelOptionsExperimental
        PreferredRetentionRatio
Microsoft.Windows.Workloads

    NpuType

Try it out

Getting started

To get started using Windows App SDK to develop Windows apps, check out the following documentation:


This discussion was created from the release 2.2 Experimental 9 (2.2.2-experimental9) 🧪.
Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete

Windows App SDK 2.2.0

1 Share

Windows App SDK 2.2.0

WinAppSDK 2.2.0 is the latest stable servicing release for 2.0, with a new Windows AI video upscaling API, a first-class ApplicationData entry point for unpackaged apps, additions to XamlBindingHelper, and a batch of WinUI and Windows ML reliability fixes.

What's new in WinAppSDK 2.2.0:

  • Video Super Resolution AI API. The new Microsoft.Windows.AI.Video.VideoScaler API delivers real-time video enhancement through advanced AI upscaling, optimized for streams featuring people in conversation. It enables developers to provide sharper, clearer visuals across conferencing, streaming, and editing platforms, even under poor network conditions. The API supports customization of output resolution, frame rate, and regions of interest, with compatibility for multiple video formats including BGR, RGB, and NV12. VideoScaler is disposable, and includes a capability check so apps can validate VSR support at runtime. Explicit Windows ML initialization is not required.
  • New ApplicationData API for unpackaged apps. Microsoft.Windows.Storage.ApplicationData.GetForUnpackaged() gives unpackaged apps a first-class WinRT entry point to per-user / per-machine application data, matching the surface previously available only to packaged apps. This simplifies future packaged ↔ unpackaged migration and removes the need for Registry-API workarounds.
  • New XamlBindingHelper APIs. Added boxing-free value setter overloads to XamlBindingHelper (SetPropertyFromThickness, SetPropertyFromCornerRadius, SetPropertyFromColor) and exposed the Setter.ValueProperty dependency property.

Bug fixes:

Bug fix Runtime Compatibility Change
Fixed a crash in RenderTargetBitmap when the target element leaves the visual tree (for example, a popup closes) before PreCommit completes. RenderAsync now returns E_ABORT instead of crashing. RenderTargetBitmap_PreCommitCrashOnTreeLeave
Fixed a use-after-free crash in ScrollView when the control is destroyed while its hide-indicators timer tick is still pending. See microsoft/microsoft-ui-xaml#10514. ScrollView_HideIndicatorsTimerUseAfterFree
Fixed a potential crash in Microsoft.UI.Xaml.dll!DirectUI::DXamlCore::GetPeerPrivate caused by attempting to access an object scheduled to be freed. GetPeerPrivate_UseAfterFree
Fixed an issue where Microsoft.UI.System.ThemeSettings could crash an app if it was destroyed on a background thread (for example, when destroyed by the .NET garbage collector). ThemeSettings_OffThreadDestructorFix
Fixed a crash that could occur on certain devices when active touch contacts were canceled by input hardware, such as when pen input overrides them. InputPointerSource_PointerCancelCrashFix
Fixed an issue where sparse-packaged apps were unable to discover module-specific PRI files. See microsoft/WindowsAppSDK#6375. MRTCore_SparsePackagedPriFallback
Fixed a string ownership bug when using the Flat-C Windows ML Catalog API. WindowsMLFlatCCatalog_CallbackStringOwnership
Fixed a potential issue in Windows ML during process shutdown. WindowsML_ComRundownFix
Fixed potential COM initialization and teardown issues in Windows ML. WindowsML_ComInitializationFix

New or updated APIs (since 2.1.3):

Microsoft.UI.Xaml

    Setter
        ValueProperty
Microsoft.UI.Xaml.Markup

    XamlBindingHelper
        SetPropertyFromColor
        SetPropertyFromCornerRadius
        SetPropertyFromThickness
Microsoft.Windows.AI.Video

    VideoScaler
    VideoScalerOptions
    VideoScalerResult
    VideoScalerStatus
Microsoft.Windows.Storage

    ApplicationData
        GetForUnpackaged

Try it out

  • Download the 2.2.0 NuGet package to use WinAppSDK 2.0 in your app.
  • Download and update the WinUI Gallery to see the WinUI 3 updates firsthand.

Getting started

To get started using Windows App SDK to develop Windows apps, check out the following documentation:


This discussion was created from the release Windows App SDK 2.2.0.
Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete

Windows App SDK 1.8.9 (1.8.260529003)

1 Share

Windows App SDK 1.8.9 (1.8.260529003)

WinAppSDK 1.8.9 is the latest stable servicing release for 1.8, with two reliability fixes in WinUI input and items controls.

Bug fixes:

Bug fix Runtime Compatibility Change
Fixed a memory leak in ItemsRepeater where recycled elements were never garbage collected due to a reference cycle through the RecyclePool, which could also cause crashes in InvalidateChildrenMeasure. ItemTemplateWrapper_RecyclePoolLeak
Fixed a potential crash when releasing touch contacts in a ScrollViewer before scrolling. InputPointerSource_TouchUpScrollCrashFix

Try it out

Getting started

To get started using Windows App SDK to develop Windows apps, check out the following documentation:


This discussion was created from the release Windows App SDK 1.8.9 (1.8.260529003).
Read the whole story
alvinashcraft
1 minute ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories