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

Building Secure Enterprise APIs with .NET, Azure API Management, and Entra ID (Azure AD)

1 Share

## 1 Introduction: The Zero Trust Mandate for Modern APIs

Modern enterprise systems depend on APIs to connect business processes, exchange data, and support distributed applications. These APIs operate in environments where users, workloads, and network boundaries shift constantly—across cloud platforms, on-prem systems, partner integrations, and remote access. The real challenge today isn’t building APIs; it’s securing them reliably and consistently in this changing landscape.

Using *.NET, Azure API Management (APIM), and Entra ID* together provides a strong, predictable foundation for implementing Zero Trust principles across your entire API surface.

This section sets the stage by defining the security problem and the architectural model used throughout the article.

### 1.1 The Shift from Perimeter to Identity-Centric Security

For a long time, organizations relied on firewalls and network segmentation to protect internal systems. If traffic came from inside the network, it was assumed to be trustworthy. That assumption no longer holds. Cloud adoption, mobile users, partner integrations, and public-facing APIs have blurred the concept of a “safe internal network.”

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

Responding to "The highest quality codebase"

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

Announcing Rust 1.92.0

1 Share

The Rust team is happy to announce a new version of Rust, 1.92.0. Rust is a programming language empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup, you can get 1.92.0 with:

$ rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website, and check out the detailed release notes for 1.92.0.

If you'd like to help us out by testing future releases, you might consider updating locally to use the beta channel (rustup default beta) or the nightly channel (rustup default nightly). Please report any bugs you might come across!

What's in 1.92.0 stable

Deny-by-default never type lints

The language and compiler teams continue to work on stabilization of the never type. In this release the never_type_fallback_flowing_into_unsafe and dependency_on_unit_never_type_fallback future compatibility lints were made deny-by-default, meaning they will cause a compilation error when detected.

It's worth noting that while this can result in compilation errors, it is still a lint; these lints can all be #[allow]ed. These lints also will only fire when building the affected crates directly, not when they are built as dependencies (though a warning will be reported by Cargo in such cases).

These lints detect code which is likely to be broken by the never type stabilization. It is highly advised to fix them if they are reported in your crate graph.

We believe there to be approximately 500 crates affected by this lint. Despite that, we believe this to be acceptable, as lints are not a breaking change and it will allow for stabilizing the never type in the future. For more in-depth justification, see the Language Team's assessment.

unused_must_use no longer warns about Result<(), UninhabitedType>

Rust's unused_must_use lint warns when ignoring the return value of a function, if the function or its return type is annotated with #[must_use]. For instance, this warns if ignoring a return type of Result, to remind you to use ?, or something like .expect("...").

However, some functions return Result, but the error type they use is not actually "inhabited", meaning you cannot construct any values of that type (e.g. the ! or Infallible types).

The unused_must_use lint now no longer warns on Result<(), UninhabitedType>, or on ControlFlow<UninhabitedType, ()>. For instance, it will not warn on Result<(), Infallible>. This avoids having to check for an error that can never happen.

use core::convert::Infallible;
fn can_never_fail() -> Result<(), Infallible> {
    // ...
    Ok(())
}

fn main() {
    can_never_fail();
}

This is particularly useful with the common pattern of a trait with an associated error type, where the error type may sometimes be infallible:

trait UsesAssocErrorType {
    type Error;
    fn method(&self) -> Result<(), Self::Error>;
}

struct CannotFail;
impl UsesAssocErrorType for CannotFail {
    type Error = core::convert::Infallible;
    fn method(&self) -> Result<(), Self::Error> {
        Ok(())
    }
}

struct CanFail;
impl UsesAssocErrorType for CanFail {
    type Error = std::io::Error;
    fn method(&self) -> Result<(), Self::Error> {
        Err(std::io::Error::other("something went wrong"))
    }
}

fn main() {
    CannotFail.method(); // No warning
    CanFail.method(); // Warning: unused `Result` that must be used
}

Emit unwind tables even when -Cpanic=abort is enabled on linux

Backtraces with -Cpanic=abort previously worked in Rust 1.22 but were broken in Rust 1.23, as we stopped emitting unwind tables with -Cpanic=abort. In Rust 1.45 a workaround in the form of -Cforce-unwind-tables=yes was stabilized.

In Rust 1.92 unwind tables will be emitted by default even when -Cpanic=abort is specified, allowing for backtraces to work properly. If unwind tables are not desired then users should use -Cforce-unwind-tables=no to explicitly disable them being emitted.

Validate input to #[macro_export]

Over the past few releases, many changes were made to the way built-in attributes are processed in the compiler. This should greatly improve the error messages and warnings Rust gives for built-in attributes and especially make these diagnostics more consistent among all of the over 100 built-in attributes.

To give a small example, in this release specifically, Rust became stricter in checking what arguments are allowed to macro_export by upgrading that check to a "deny-by-default lint" that will be reported in dependencies.

Stabilized APIs

These previously stable APIs are now stable in const contexts:

Other changes

Check out everything that changed in Rust, Cargo, and Clippy.

Contributors to 1.92.0

Many people came together to create Rust 1.92.0. We couldn't have done it without all of you. Thanks!

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

New Front-End Framework Ripple Blends React and Svelte Together

1 Share

Ripple is a new open-source front-end framework taking ideas from React, SolidJS, and Svelte into a TypeScript-first, component-oriented, JSX-like compiled language with fine-grained reactivity and scoped CSS. Ripple offers a reactivity system with automatic dependency tracking, and direct DOM updates without a virtual DOM. Ripple aims to support better debugging through AI agents.

By Bruno Couriol
Read the whole story
alvinashcraft
29 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

What Every Developer Should Learn as Soon as Possible in Their Personal Life

1 Share

One developer shares life lessons gained throughout his career and shares the questions that can help you move ahead.

At 17, I picked up my first book on Neuro-Linguistic Programming (NLP). Not because a mentor recommended it or out of philosophical curiosity, but because I wanted to understand how I worked and what I could become. I found the world meaningless and thought my problems were too big for me to handle. The book introduced me to an idea that seemed too obvious to be true: If you have a problem, you can solve it. Life doesn’t hand you burdens you can’t carry.

It took me years to understand what that really meant. And even more years to realize that this lesson wasn’t just about fixing code bugs.

What I’m sharing here comes from my personal experience, mistakes included. It might not apply to you, but if even one of these reflections makes you pause and think, it’s worth it.

Know Thyself (Before Life Forces You To)

“Know thyself”: Socrates said this millennia ago, but nobody teaches you how to do it in school. And for developers, this self-knowledge isn’t a philosophical luxury. It’s a survival tool.

Today, I know what sets me off in a code review. I know how I react when someone questions my architecture. I understand why I prefer working on complex features alone before presenting them to the team. But it took me a long time to get here.

The problem is that we’re several different selves: The developer who defends their technical choices tooth and nail, the team member who needs to compromise in discussions, the professional who accepts projects they don’t like to pay the bills, the friend, the son, the father. Each of these selves has its own behavior patterns. And you only discover these patterns by going through experiences, preferably by seeking them out instead of just waiting for them to come.

Early in my career, conflict situations left me stunned: How can people not see the clarity of my idea, the way I see it? Defending a different technical idea seemed like arrogance. But over time, I learned something counterintuitive: I started to enjoy conflicts. Because it’s in friction that you discover what your ideas are really made of. It’s when people lose their cool that they show who they are, and so do you.

But this only makes sense when you know yourself. When you know what your path is.

And this is work only you can do. There’s no YouTube tutorial, no framework. It must come from within.

Some Questions That Helped Me (And Might Help You)

Is what I do/work aligned with what I feel?

Not in the romantic “do what you love” sense, but in the honest sense: Does this move me or anesthetize me?

Do my opportunities make me grow?

Or am I just repeating what I already know how to do because it’s comfortable?

What do I have to learn where I am today?

If the answer is “nothing,” you should have already left.

An important aside: There’s a dangerous belief that “doing what you like” is a privilege for billionaires. That you need to suffer first, make money later and only then can you afford the luxury of liking what you do. That’s a lie.

The point here is that successful people did do many things they didn’t like, yes. But that’s not why they succeeded; it’s despite it. And curiously, neuroscience shows that doing things you don’t like (like washing dishes) strengthens your ability to deal with adversity. Children who have household responsibilities develop greater resilience and entrepreneurial tendencies.

The point isn’t to avoid discomfort. It’s knowing why you’re doing what you don’t like, whether it’s a means to a clear end or just an escape from the decision to know yourself.

Solitude Isn’t the Enemy (It’s the Laboratory)

Developers have a strange relationship with solitude. Our profession pushes us toward it, hours in front of the screen, headphones on, immersed in problems that only exist in our heads. And at the same time, they tell us we must be “collaborative,” “work as a team” and “do pair programming” (which, personally, I think is excellent).

The truth I learned is that any person’s life, no matter how social they are, is fundamentally solitary. Nobody’s going to be responsible for your commitments, your architecture choices or your career. You must count on yourself most of the time.

This doesn’t mean you don’t need friends or a team. It means you need to learn to live with yourself first, and that’s a challenge.

And for developers, this skill is even more valuable. Because developing technically is more about thinking than acting. When you’re programming, solving a complex bug or architecting a solution, solitude isn’t isolation; it’s focus. You don’t need constant interaction to deliver. In fact, interruption is often the enemy.

But, and this is crucial, you can’t think everything through alone. A healthy dose of team interaction is necessary. The trick is knowing when to be alone and when to seek others out.

Things I did to master my relationship with solitude: Going to the movies alone, to restaurants, to concerts. It sounds silly, but it’s not. It’s about learning to appreciate your own company. It’s about creating inner life.

Artur da Távola, a Brazilian thinker, said: “Music is inner life, and whoever has inner life will never suffer from loneliness” (free translation).

Quality moments alone, without electronics, without notifications, just you, good music or a good book, make a difference. It’s in this silence that you process the day’s conflicts, understand why that meeting irritated you, and notice patterns in your behavior.

Solitude isn’t punishment. It’s the laboratory where you get to know yourself.

Solitude isn’t punishment. It’s the laboratory where you get to know yourself.

Early Success: The Invisible Trap

At 21, two years after entering the IT field, I started my own company. Money came fast. A lot of money. It seemed like I had cracked the code of life.

That success stagnated me.

Early success is a dangerous drug. It addicts your brain. It fills you with false confidence because you don’t yet understand that success has context, timing and luck. You think it was all competence.

The problem isn’t success itself; it’s not realizing that the premises that got you there won’t be present at the next level. You level up, but want to play with the same strategies.

I wasn’t prepared for the next level of growth. I didn’t know how to scale people, processes and complexity. And when a serious accident caused me to stagnate for nearly a decade, I realized I had built castles in the sand.

It was during this forced pause that I did the best work of my career. I focused on developing a legal system with features nobody else had: a complete change in history, field by field, and thousands of features meticulously thought out in the most minor details. Advocati was considered the best legal software in Brazil in 2007.

But it took me until 2011 to return strongly to the market.

Those years taught me something brutal: Enjoy your success, but don’t be blinded by it. Don’t become arrogant. Lower your expectations that everything will always work out. This gives you a more realistic view.

I’m not saying dream small. Dream big, but take solid, consistent steps. Our lives are increasingly fluid, and constantly changing goals and objectives get you nowhere. Having a fixed target and mapping out the right strategy to reach it, without illusions, is the safest path.

And there’s something else: You’ll repeat your mistakes until you learn the lesson. Your life is teaching you something. If you don’t understand or don’t even realize there’s a reason behind your challenge, you’ll keep repeating the same cycle.

Life isn’t a game where you pass levels. It’s more like debugging as you run the code, see where it breaks, adjust and then rerun it. The problem only disappears when you understand its root cause.

What to Do With All This?

Knowing yourself isn’t a destination. It’s a daily journey. It’s noticing when you’re reacting on autopilot. It’s questioning why that comment on PR irritated you so much. It’s having the courage to be alone with your thoughts. It’s celebrating success without thinking you’ve become invincible.

When the next conflict comes, the subsequent failure, the next success, you’ll have something most developers never build: clarity about who you are when nobody’s watching.

What I’ve shared here comes from decades of learning. Your journey will be different. But if you start getting to know yourself now, maybe you won’t have to wait for an accident to learn what took me decades to understand.

What’s Next for Me?

Having learned my lesson, I’m always looking for new ways to challenge myself.

Today I’m working on an exciting AI project that’s pushing the boundaries of modern development, an intelligent SaaS platform creator powered by natural language prompts. This innovative tool leverages .NET 10 for a robust backend, Microsoft SQL Server for enterprise-grade data management, and React with Next.js on the frontend, all brought together with the rich UI components of the Progress KendoReact library.

The vision is simple yet powerful: Describe your SaaS platform requirements through prompts and watch as AI transforms your ideas into a fully functional, production-ready application, complete with professional interfaces powered by AI and scalable architecture.

To validate the project, we’re developing and refining it alongside five real-world systems built with this new product.

And I look forward to learning about myself in the development of this project.

What’s next for you?

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

Studying the various locale mismatch scenarios in Windows clipboard text format synthesis

1 Share

So far, we’ve learned that the conversion between Unicode and the 8-bit ANSI and OEM code pages is performed with the assistance of the CF_LOCALE clipboard format, which itself comes from the active keyboard layout. We left with the question of whether this is the right thing, giving as an example the case of highlighting some text in Hebrew and copying it to the clipboard. Shouldn’t that be set with a Hebrew LCID?

First of all, you have to specify what you mean by “copy it to the clipboard.” Suppose the English-language user selected some Hebrew text and the program set it to the clipboard as CF_UNICODE­TEXT with a Hebrew LCID. A program which reads the CF_UNICODE­TEXT will read the original Unicode text, with Hebrew characters intact. The LCID plays no role since no conversion was performed. So in the case where the string was placed as Unicode and retrieved as Unicode, everything is fine.

If the string were placed as Unicode but read as CF_TEXT, the retrieving program will get the string translated to code page 1252, since that is the ANSI code page used by the US-English LCID. Is this the correct code page? Well, if the retrieving program is using CF_TEXT, then it is a program that uses the 8-bit ANSI character set as its string encoding, and if you’re running on a US-English system, then the 8-bit ANSI character set is code page 1252. So translating the Hebrew text to ANSI via code page 1252 is correct. You need to translate the string into the ANSI code page that the retrieving program is using.

Conversely, if the Hebrew string were placed on the clipboard as 8-bit ANSI in code page 1252, then… wait, that’s a trick question! Code page 1252 doesn’t have any Hebrew characters! If a program uses the US-English 8-bit ANSI character set, it cannot represent Hebrew characters at all, so the scenario itself is flawed: There can’t be any Hebrew text on the screen to be selected since the program has no way of displaying it.

Now, I guess it could be possible if a program internally supported enough Unicode to display Hebrew characters, but still chose to put text on the clipboard in ANSI format. But in that case, it would be putting question marks on the clipboard since there are no Hebrew characters in code page 1252. Any program that does this intentionally is clearly being pathological: Why do all the work to display characters in Unicode, yet copy those character to the clipboard in 8-bit ANSI?

But wait, let’s rewind to a simpler scenario where there are no character set conversions at all. A program sets text on the clipboard in 8-bit ANSI, and another program reads it. If we consult our table, we see that the entry for this is “N/A”: There is no conversion. This holds true even if the program that put the text on the clipboard and the program that reads the text from the clipboard disagree on what the 8-bit ANSI code page is.

Prior to the introduction of the activeCodePage manifest declaration, the identity of the 8-bit ANSI code page was the same for all applications running in the same desktop. There was no opportunity for mismatch, so if one program put the text on the clipboard in 8-bit ANSI, and another read it out in 8-bit ANSI, they necessarily agreed on what the 8-bit ANSI code page was, since there was only one. But now that we have the ability for different programs to have a different value for the 8-bit ANSI code page, this nop-transformation will result in mojibake if the reader and writer have different ideas about what the 8-bit ANSI code page is.

You have the same problem with the Ansi­To­Oem conversion: Historically, all programs agreed on what the 8-bit ANSI and 8-bit OEM code pages are, so the system maintains a single “ANSI⇆OEM” conversion table that is shared by all processes. But now that programs can choose (indirectly) their ANSI and OEM code pages, you have a problem if those choices don’t match those the system would have chosen.

The people who added activeCodePage support hooked it up to the GetACP() and GetOEMCP() functions, as well as the to the A-suffixed functions which convert their 8-bit ANSI string parameters to Unicode before forwarding the result to the W-suffixed functions. But there are other places that didn’t get updated because doing so would require larger architectural changes, would affect performance of programs that didn’t use the activeCodePage feature, would introduce regression risk, and could lead to compatibility problems. Not saying that they couldn’t have done it, but it would have taken longer, and maybe it’s better to have a good-enough feature than a perfect one.

While doing fact-checking on this series of articles, I wrote some test programs that tried to trigger the CF_TEXT-to-CF_OEM­TEXT conversion, and they didn’t behave as I expected.

// Note: Test program doesn't do error-checking.

// Put the ANSI string "\xD0\x00" on the clipboard,
// with the locale 1049 (ru-ru).
int main()
{
    if (OpenClipboard(hwnd)) {
        EmptyClipboard();

        // Put an ANSI string on the clipboard.
        HGLOBAL glob = GlobalAlloc(GMEM_MOVEABLE, 2);
        PSTR message = (PSTR)GlobalLock(glob);
        message[0] = 0xD0;
        message[1] = 0x00;
        GlobalUnlock(glob);
        SetClipboardData(CF_TEXT, glob);

        // Mark it as locale 0x0419 = 1049 = ru-ru
        glob = GlobalAlloc(GMEM_MOVEABLE, sizeof(LCID));
        (LCID*)GlobalLock(glob) = 0x0419;
        GlobalUnlock(glob);
        SetClipboardData(CF_LOCALE, glob);

        CloseClipboard();
    }
}

And here’s the program to read the string back out in the OEM code page.

int main()
{
    if (OpenClipboard(hwnd)) {
        HGLOBAL glob = GetClipboardData(CF_OEMTEXT);
        PSTR message = (PSTR)GlobalLock(glob);
        printf("%0x02x\n", message[0]);
        GlobalUnlock(glob);

        CloseClipboard();
    }
}

I ran this on a US-English system, so the LCID is 0x0409 = 1033, the ANSI code page is 1252, and the OEM code page is 437. The character D0 in code page 1252 is Ð = U+00D0. This character does not exist in code page 437, so Ansi­To­Oem uses the best-fit character D = U+0044, which is in position 44 in code page 437.

When I ran this program, I expected the CF_OEM­TEXT string to have the byte 44, but it didn’t. It had the byte 90. We will start unraveling this mystery next time.

The post Studying the various locale mismatch scenarios in Windows clipboard text format synthesis appeared first on The Old New Thing.

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