AI 资讯
🌱 Spring Boot Learning Series — Episode 2 | Spring Core
Episode 2 | Spring Core | Understanding IoC, Dependency Injection & Beans In Episode 1, I covered the WHY behind Spring — tight coupling, and how Spring takes over creating and providing objects (IoC + DI) instead of classes creating their own dependencies. This episode picks up from there with the parts I hadn't covered yet: how Spring actually does that under the hood — Beans, the Spring Container, and Component Scanning. 🔑 Keywords → 🧠 Understand → 💡 Why? → 💻 Practice → 🎯 Interview Questions → 🛠️ Project 🔑 Keywords for This Episode IoC & Dependency Injection (quick recap) Spring Bean Spring Container / ApplicationContext Component Scanning 1️⃣ Quick Recap: IoC & Dependency Injection From Episode 1: instead of a class creating its own dependency — public class TicketService { private TicketRepository repository ; public TicketService () { repository = new TicketRepository (); } } — Spring creates the dependency and hands it to the class. That's Inversion of Control (IoC) . In code, this usually looks like a constructor parameter: public class TicketService { private final TicketRepository repository ; public TicketService ( TicketRepository repository ) { this . repository = repository ; } } TicketService no longer says "let me create a TicketRepository." It says "I need a TicketRepository" — and Spring supplies one. That act of supplying it is Dependency Injection (DI) . IoC = who's in control of creating/managing objects → Spring. DI = how a class actually receives what it needs → passed in, not self-created. That's the recap. Now — where do these objects Spring creates actually come from, and where do they live? 2️⃣ Spring Bean — what Spring actually manages When Spring creates and manages an object for you, that object is called a Bean . This is the vocabulary you'll see everywhere in Spring code and docs, so it's worth being precise about it. @Service public class TicketService { } The @Service annotation is a signal to Spring: "this class should be managed b
AI 资讯
Scalable Guardrail Service ASP.NET Core Kubernetes: Architecture, Code, and Ops
Scalable Guardrail Service ASP.NET Core Kubernetes: Architecture, Code, and Ops Quick Answer Scalable Guardrail Service ASP.NET Core Kubernetes: A dedicated ASP.NET Core guardrail microservice on Kubernetes validates LLM requests, enables instant policy updates via Redis, and scales with custom HPA for high‑throughput. Scalable Guardrail Service ASP.NET Core Kubernetes: Why a Dedicated Guardrail Microservice Matters When you expose an LLM‑powered API to the world, every request is a potential compliance risk. A single malformed prompt can surface PII, trigger a policy violation, or even cause a brand‑damaging output. In my experience, the first version of such a system is a set of ad‑hoc filters sprinkled across controllers. Under load, those filters become latency bottlenecks, policy updates race, and audit trails vanish. The root cause is a missing architectural layer that treats guardrails as a first‑class microservice that can scale horizontally, be updated live, and be observed independently. Guardrail Layer Requirements We need a guardrail layer that: Validates every request before it hits the LLM engine. Can be updated without redeploying the entire API surface. Provides per‑tenant isolation and versioning. Logs every decision for compliance and red‑team analysis. Runs at the same scale as the LLM inference service. When This Fails in Production Policy updates are applied via a shared ConfigMap and the pods do not reload, so new rules are never enforced. The guardrail service is single‑instance; a spike in requests triggers a queue that exceeds the LLM engine’s rate limit, causing a cascading failure. Audit logs are written to local disk; a pod crash loses events. Latency spikes because each request performs a synchronous Redis lookup for every policy. Common Mistakes Engineers Make Embedding guardrail logic inside the API controller rather than a dedicated middleware. Using in‑memory policy caches without a TTL, leading to stale rules. Ignoring the fact that
AI 资讯
Morphing Feature in WebForms Core 2.1
WebForms Core 2.1 is coming soon from Elanat . The new version introduces a collection of capabilities designed to further expand the server-driven approach of WebForms Core. One of these new capabilities is Morphing . Morphing provides a way to synchronize an existing DOM element with a new HTML structure without necessarily replacing the existing element itself . This makes it possible to update HTML structures while preserving the identity of existing DOM elements. Morphing Morphing is a DOM synchronization mechanism that compares an existing HTML element with a new HTML structure and applies the required changes to the existing DOM. Unlike a traditional replacement operation such as: element . outerHTML = html ; Morphing does not simply discard the existing element and create another one. Instead, it analyzes the existing element and the new element and performs the necessary operations: Add new attributes Update existing attributes Remove attributes that no longer exist Add new child elements Update existing child elements Remove obsolete child elements Match elements using id and cb-data-id Preserve existing DOM element identity whenever possible Preserve registered event listeners when new Nodes have to be created The goal is to make the smallest necessary changes to the DOM. Reflection vs Morphing WebForms Core 2.1 contains both Reflection and Morphing , but they serve different purposes. Reflection is primarily a merge operation . For example, if the target contains: <div id= "userCard" > <h3> User </h3> </div> and the source contains: <div class= "premium" > <button> VIP </button> </div> Reflection can merge the source into the target, adding the class and child without treating the source as a complete replacement definition. Morphing has a different philosophy. The source represents the desired structure . If the source does not contain an element or attribute that exists in the target, Morphing can remove it. Therefore: Reflection Target + Source ↓ Merg
科技前沿
Review: Chuwi's $449 Unibook laptop is a funhouse-mirror MacBook Neo
The Unibook is a weird entry-level laptop for people with patience.
AI 资讯
.NET 11 Preview 7 Brings Updates Across C#, ASP.NET Core, EF Core, and Windows Forms
Last week Microsoft released .NET 11 Preview 7, with updates across C#, ASP.NET Core, .NET MAUI, Entity Framework Core, Windows Forms, and F#. C# adds labeled break and continue. ASP.NET Core brings Blazor circuit pausing, CacheView, and built-in validation localization. Windows Forms gains an opt-in modern rendering pipeline, and EF Core adds Half type support on SQLite. By Almir Vuk
AI 资讯
ASP.NET Core Output Caching: How to Make Web APIs Faster in .NET
ASP.NET Core Output Caching: How to Make Web APIs Faster in .NET When an API receives the same request repeatedly, performing the same database query and rebuilding the same response every time can waste valuable resources. For example, imagine this endpoint: GET /api/products If thousands of users request the same product catalog, your application might repeatedly: HTTP Request ↓ Controller ↓ Database Query ↓ Business Logic ↓ JSON Response For data that doesn't change frequently, this can create unnecessary database load. ASP.NET Core provides Output Caching to help solve this problem. Instead of executing the complete request pipeline every time, the application can temporarily store the generated response and reuse it for subsequent requests. In this tutorial, we'll look at how Output Caching works, how to configure it, how to invalidate cached responses, and when you should avoid using it. What Is Output Caching? Output caching stores the generated response from an endpoint. For example: First request ↓ GET /api/products ↓ Execute controller ↓ Query database ↓ Generate response ↓ Store response in cache Later: Second request ↓ GET /api/products ↓ Cached response ↓ Return immediately The database doesn't need to be queried again while the cached response is valid. Output Caching vs Response Caching These two concepts are often confused. Response Caching Response caching mainly relies on HTTP caching semantics and headers. Output Caching Output caching is controlled by ASP.NET Core and allows your application to decide which responses should be cached and for how long. Output caching provides more control over server-side response caching. 1. Add Output Caching Start by registering the output-cache services. var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddOutputCache(); var app = builder.Build(); app.UseOutputCache(); app.MapControllers(); app.Run(); The important pieces are: AddOutputCache() ↓ Configure cac
AI 资讯
MFA Enabled Is Not MFA Verified
A two-factor flag in the user store looks like a reassuring authorization check. It tells us the account has a second factor configured. For a sensitive operation, however, that is only half the question. The other half is about the session in front of us: did this cookie actually complete a second-factor challenge? Those facts can change independently. Treating them as interchangeable can silently promote an old password-only session after the account enables MFA. Two questions that look like one Account capability answers questions such as: Is a factor enrolled now? Could the account complete an MFA challenge? Has that capability since been disabled? Session assurance answers different questions: Which authentication steps produced this session? Did the framework issue this cookie after an MFA challenge? Is the evidence trusted, or merely a user-supplied claim? An enrolled account can still have a password-only session. A previously verified session can also outlive a later change to the account’s factor state. One signal cannot safely stand in for both. The transition that exposes the gap Snapshot tests often miss this because the final state looks correct. The account has MFA enabled, the user is authenticated, and a policy succeeds. Now test the transition instead: Sign in with a password and receive a normal application cookie. Enable MFA for the account without replacing that cookie. Use the original cookie against a sensitive operation. If authorization checks only the current enrolment flag, step three may succeed. Nothing about the original authentication ceremony changed, but the session has effectively been upgraded by a later database write. That is the important boundary: changing account capability must not rewrite the history of an already-issued session. Use two independent signals A generalized policy can be expressed like this: if (! session . IsAuthenticated || ! session . HasTrustedMfaEvidence ) return Deny ; if (! await accountStore . IsMfaStil
AI 资讯
Agent Identity and Durable Workflows: The Two Problems MCP Can't Solve
MCP 2026-07-28 dropped sessions. The initialize handshake is gone. The Mcp-Session-Id header is gone from Streamable HTTP. Protocol version, client info, and capabilities now travel in a _meta field on every request, so any instance can serve any call. The protocol is cleaner for it. This is the largest revision since launch, and it leaves both of the questions that block enterprise agent deployments exactly where they were. MCP standardizes how a model reaches a tool. Neither question lives inside that scope, and no future revision is likely to put them there: Who is the agent acting as, and what is it allowed to do? What happens when a process takes three days and the model context is gone? The spoiler: on AWS the parts already exist. Policy in AgentCore evaluates every Gateway call in Cedar against a principal, an action, and a resource, and writes the allow or deny to an audit log. Temporal policies, added in August 2026, extend that across an agent's trajectory, including human approval ahead of a privileged action. AgentCore Identity distributes the credentials. Step Functions holds anything measured in days. The remaining work is composition: deciding which principal each agent acts as, and what it may commit to. No service ships that decision. What the stateless redesign actually solved The stateless redesign removes real pain. Long-held SSE connections forced sticky routing, which pushed teams into shared session stores and gateway packet inspection just to scale horizontally. The new model provisions for request rate instead of concurrent users. A round-robin load balancer is now enough. Lambda, Cloud Run, and Workers become viable backends. Multi Round-Trip Requests (SEP-2322) handle elicitation without a held connection. The server returns an InputRequiredResult carrying what it still needs plus an opaque requestState blob. The client collects the answers and re-issues the same call with inputResponses and the echoed state. Any instance picks up the retr
AI 资讯
Why Isn't the AWS Blocks Agent Built on AgentCore? What the Repository Reveals About What's Next
Since AWS Blocks entered public preview in June 2026, I have been making small contributions to the open-source project. AWS Blocks on GitHub In my previous post on AWS Blocks, Amplify, and App Studio , I looked at how these tools differ and what each is trying to achieve. While revisiting the Agent Block, one detail caught my attention: The AWS Blocks Agent is not currently running on Amazon Bedrock AgentCore. At a glance, it is easy to assume the relationship looks like this: AWS Blocks └─ Agent └─ Amazon Bedrock AgentCore But that is not how the current implementation works—at least not on main as of August 12, 2026. Then the story gets interesting. When I wondered whether an agent should simply use AgentCore directly, I found a fairly concrete set of pull requests that proposes moving the Agent Block's execution model to AgentCore Runtime. I contribute to AWS Blocks, but this is not an AWS statement or a roadmap. It is my reading of the public documentation and the open-source repository, from the perspective of both a user and a contributor. TL;DR The Agent Block on the current main branch does not run on AgentCore Runtime. It combines the Strands Agents SDK with AsyncJob , Realtime , FileBucket , and DistributedTable . A five-PR stack proposes migrating the Agent Block's execution model to AgentCore Runtime. As of August 12, 2026, all five migration PRs are still draft and unmerged. They are not an official roadmap. A separate open PR proposes Blocks for AgentCore Memory, Gateway, and Identity. So the most accurate conclusion today is this: AWS Blocks Agent is not AgentCore today, but the repository contains concrete proposals for bringing the two together. The Agent Block today is not AgentCore Let's start with the implementation on main . The Agent Block uses the Strands Agents SDK . But it is not a standalone agent runtime; it composes several Blocks to handle execution, streaming, and persistence. At a high level, the structure looks like this: Agent ├─ St
AI 资讯
Encore AI raises $30M to build AI agents that learn from customer calls
The startup analyzes calls, messages, and CRM data to identify effective sales techniques and turn them into playbooks for AI agents.
AI 资讯
600 Filters and a 414: The New QUERY Method in .NET 10
A product search, a filter list that kept growing, and a status code I hadn't seen in years. Filters went in the query string, the way they always do. That held up fine until someone saved a "filter set" with a few hundred SKUs in it and the endpoint started answering with 414. I rebuilt a small version of it to find the exact wall. Same search, filters as repeated ?sku= values, count going up in steps of a hundred: 1) GET with filters in the URL 100 filters | request line 1534 bytes | 200 OK 200 filters | request line 3034 bytes | 200 OK 300 filters | request line 4534 bytes | 200 OK 400 filters | request line 6034 bytes | 200 OK 500 filters | request line 7534 bytes | 200 OK 600 filters | request line 9034 bytes | 414 RequestUriTooLong Kestrel's default max request line is 8 KB, and the request line is the method plus the URL plus the HTTP version. Somewhere between 500 and 600 filters, my URL stopped being a URL. Every fix I knew was a compromise. A body on GET is undefined by spec and some proxies quietly drop it. POST works, but POST announces "this might change something", so caches skip it, gateways won't auto-retry it, and anyone reading your API docs has to guess whether POST /search is actually a search. Cramming the filters into a header is the kind of idea that sounds clever for about a day. The method that was missing RFC 10008 defines QUERY , and it's exactly the thing that spot in the matrix was waiting for. The body carries the query. The method is safe and idempotent, so it can be retried after a dropped connection without anyone panicking. Responses are cacheable, and the spec is explicit that the cache key has to be built from "the request content and related metadata". There's also a nice touch on the response side: Content-Location can point at a URL where those exact results can be fetched with a plain GET. The one-line version I keep giving people: it's a GET with a body, and that's the entire point. Wiring it up in ASP.NET Core 10 .NET 10 shi
AI 资讯
EF Core Is Already a Repository. Stop Wrapping It in Another One.
Open a lot of .NET projects and you'll find the repository pattern sitting on top of Entity Framework Core. IProductRepository, GetById, Add, Save, the whole set. Underneath, every method just calls the EF Core DbContext and passes the result straight back. The wrapper adds a name and nothing else. So do you need the repository pattern with EF Core? For most apps, no. EF Core already gives you one. DbSet is a repository. It already does the thing the pattern is for. The reason this keeps happening is that the repository pattern got taught alongside EF, so people assume you need one to use the other. You don't. What the Pattern Was For The repository pattern came before EF Core. It started in a time when data access meant hand-written SQL, SqlCommand, and mapping DataReader rows to objects by hand. Wrapping all of that behind an interface was worth it. It hid a real mess, and it let you swap what was underneath without the rest of the app noticing. EF Core already does that. DbContext is the unit of work. DbSet is the repository. SaveChanges() is the commit. The pattern you're adding is one the tool already gives you. What the Wrapper Actually Does Here's the shape you see in most codebases: public class ProductRepository : IProductRepository { private readonly AppDbContext _db ; public ProductRepository ( AppDbContext db ) => _db = db ; public async Task < Product ?> GetById ( int id ) => await _db . Products . FindAsync ( id ); public async Task < List < Product >> GetAll () => await _db . Products . ToListAsync (); public void Add ( Product product ) => _db . Products . Add ( product ); } Read what each method does. GetById calls FindAsync. GetAll calls ToListAsync. Add calls Add. It's a passthrough. Every line hands the call straight to EF Core and returns whatever comes back. You wrote an interface, a class, and a registration to rename methods that already existed. This is what people mean by a generic repository over EF Core, and it's the most common version y
AI 资讯
Skip the Middleman: Connecting Your UI Directly to an AI Agent via WebSocket
I've been building AI agents for a while now, and streaming responses to a UI has always been the painful part. In previous projects I tried API Gateway streaming, Lambda response streaming, and even AppSync Events via an agent tool call to notify the UI. I also looked at adding my own WebSocket API through API Gateway, which requires managing $connect , $disconnect , and $default routes, storing connection IDs in DynamoDB, and posting messages back through @connections . All of these approaches felt like too much ceremony for what should be simple. That's when I found that AgentCore has built-in WebSocket support. The browser can just connect directly to the agent. No middleman. I built WearCast to demonstrate this functionality. This is an AI agent that helps you pick out what to where based on the weather. I've found this very helpfu when packing for a trip. The code for this application is public and you can find the full implementation on this GitHub repo . The problem with the traditional approach We usually build app applications as we do REST APIs User → REST API → Lambda → AI Service → Lambda → REST API → User Every message makes a round trip through multiple intermediaries. The response waits until the entire generation is complete, and then it all comes back at once. For a chat interface, this feels sluggish. Users stare at a spinner while the model generates hundreds of tokens they could already be reading. Even if you add Server-Sent Events or long-polling, you're still stitching together a real-time experience on top of infrastructure that seemed like overkill. I wanted something better. The architecture Here's what I ended up with: ┌─────────────┐ ┌──────────────────┐ │ React UI │─── JWT ─▶│ API Gateway + │──▶ Lambda (presigned URL) │ (Cognito) │ │ Cognito Auth │ └──────┬──────┘ └──────────────────┘ │ │ WebSocket (SigV4 presigned URL) │ ← No middleman! Direct connection → ▼ ┌──────────────────────────────────┐ ┌────────────────────┐ │ AgentCore Runtim
AI 资讯
Manticore Speaks MySQL - So I Made It a Laravel Database Driver Instead of a Scout Engine
The problem I've been working with Manticore Search for about two years at EricaPRO , building the search layer for two financial data platforms. For the past year, that work has been a Laravel API. Manticore was never the problem. It's fast and it's stable. The problem was the gap between Manticore and Laravel. I had already built a package for this — laravel-manticore-search , a fluent builder over Manticore's HTTP/JSON API. It works, and it's still in use. But it's a client wrapper. Every feature had to be implemented manually. Every new filter or facet meant more custom architecture around the client, and none of the things Laravel gives you for free — models, migrations, pagination, casts — applied to it. Scout doesn't close that gap either. Scout gives you search() . No full query builder, no migrations for your indexes, sync is your problem. That's not a criticism — Scout abstracts over engines with completely different APIs, so it exposes the lowest common denominator. It just wasn't what I needed. What I needed was simple to describe and annoying to not have: something plug and play. Something Laravel way. Point Eloquent at Manticore and use Eloquent. The insight Manticore speaks the MySQL wire protocol. Out of the box, port 9306. You can connect to it with any MySQL client and run SQL. I had been using that port for two years without thinking about what it meant for Laravel. Because here's the thing: all of Eloquent — models, query builder, migrations, pagination, chunking — sits on top of a Connection and a Grammar . The grammar compiles builder calls into SQL for a specific dialect. That's the entire mechanism behind Laravel supporting MySQL, Postgres, SQLite and SQL Server with one codebase. So the real question was never "how do I re-implement Eloquent on top of Manticore's client?" It was "how thin can a Manticore grammar be?" If Manticore accepts MySQL-protocol connections and mostly-MySQL SQL, then a Laravel database driver — a custom connection plu
AI 资讯
LLM Evaluation System Prompts Scored Rubrics Runtime Guardrails: A Practical Guide for Production
LLM Evaluation System Prompts Scored Rubrics Runtime Guardrails: A Practical Guide for Production Learn how to evaluate LLM outputs in production using system prompts, scored rubrics, and runtime guardrails to prevent hallucinations and ensure quality. TL;DR: To evaluate LLM outputs in production, combine system prompts that define evaluation criteria, scored rubrics using LLM-as-a-judge for dimensions like correctness and relevance, and runtime guardrails that filter or flag unsafe outputs. This approach scales better than human review, adapts via prompt changes, and catches failures that status codes miss, as seen in the Air Canada chatbot case. Why Production LLM Evaluation Demands More Than Status Codes A 200 status code only confirms the server processed the request—it says nothing about whether the generated text is factual, safe, or useful. The Air Canada chatbot that invented a non-existent bereavement discount returned perfectly valid HTTP responses, yet the hallucinated policy led to a tribunal ruling against the airline. Production evaluation must therefore separate operational health (latency, error rates) from output quality (correctness, relevance, harmlessness). Consider a typical API call that succeeds operationally but fails qualitatively: import requests response = requests . post ( " https://api.example.com/v1/chat " , json = { " model " : " gpt-4o " , " messages " : [{ " role " : " user " , " content " : " What is Air Canada ' s bereavement policy? " }]}, headers = { " Authorization " : " Bearer $KEY " } ) print ( response . status_code ) # 200 print ( response . json ()[ " choices " ][ 0 ][ " message " ][ " content " ]) # Output: "Air Canada offers full refunds for bereavement-related cancellations..." A 200 status code and a well-formed JSON body mask a completely fabricated policy. To catch this, you need a separate evaluation layer that scores the output against a rubric. LLM-as-a-judge is a common approach, using a second model to assess the
AI 资讯
HTTP Server — Request Lifecycle
Request lifecycle: một HTTP request đi qua đâu, và vì sao "quên gọi next()" làm request treo cho tới khi socket timeout Một request tới một Express hay Fastify server không phải là "gọi handler rồi trả về response". Nó là một chuỗi các bước theo thứ tự cố định: parse HTTP, chạy qua middleware/hook, match route, gọi handler, serialize, gửi response, đóng. Nếu bất kỳ bước nào không chuyển tiếp — Express không gọi next() , Fastify hook không reply.send() hay không return — request treo cho tới khi client hoặc server timeout đóng socket. Đây là loại lỗi không ném exception, không xuất hiện trong error log, chỉ hiện ra qua p99 latency phình lên và số socket ở trạng thái ESTABLISHED tăng dần. Hiểu chính xác lifecycle này là điều kiện tiên quyết để debug những request "biến mất" và để đặt middleware đúng thứ tự. Cơ chế hoạt động Bước dưới cùng giống nhau ở cả hai framework: Node core http.Server nhận TCP connection, parse HTTP request line + headers, phát event request với hai object IncomingMessage (req) và ServerResponse (res). Điểm khác nhau là những gì framework làm giữa lúc nhận request và lúc response ra khỏi socket. Express dựng một chuỗi middleware qua Router . Mỗi lần app.use(fn) hay app.get(path, fn) được gọi, Express bọc fn vào một Layer với path regex (thông qua path-to-regexp ) rồi push vào một stack. Khi request đến, Router.handle duyệt stack tuần tự: với mỗi layer, nếu path match, gọi fn(req, res, next) . next() là closure trỏ vào layer kế tiếp; chỉ khi nó được gọi thì layer sau mới chạy. Error handler được nhận diện bằng arity — hàm 4 tham số (err, req, res, next) — và chỉ được duyệt tới khi next(err) được gọi: import express from ' express ' const app = express () app . use ( express . json ({ limit : ' 1mb ' })) // 1. parse body app . use (( req , _res , next ) => { // 2. request id req . id = crypto . randomUUID () next () }) app . use (( req , _res , next ) => { // 3. auth const token = req . headers . authorization if ( ! token ) return next ( new Erro
AI 资讯
Chrome for Developers a Berlino: cosa aspettarsi dall’ecosistema web nel 2026
Tra performance, piattaforma e toolchain: i temi che contano davvero per chi costruisce frontend oggi. Il frontend nel 2026 è diventato una disciplina sempre più “di prodotto”: non basta far funzionare l’interfaccia, serve che sia veloce, stabile, accessibile e misurabile in produzione. E quando l’ecosistema Chrome parla di “connessione” tra developer e piattaforma, il messaggio utile per chi lavora sul web è semplice: capire dove investire tempo per ottenere impatto reale sugli utenti . Di seguito, una lettura pratica dei temi che continuano a emergere come prioritari per chi costruisce applicazioni e siti moderni. 1) Performance: meno benchmark, più realtà La performance non è più un esercizio di ottimizzazione a fine progetto. È un requisito continuo che va gestito con strumenti, metriche e processi. Cosa significa “misurabile” oggi Metriche di campo (real user monitoring) : le prestazioni che contano sono quelle che arrivano dai dispositivi reali, su reti reali. Metriche di laboratorio : restano utili per regressioni e CI, ma vanno interpretate come “segnali” e non come verità assolute. Implicazione pratica Imposta una pipeline dove: le metriche sintetiche bloccano regressioni evidenti (build/PR), le metriche reali guidano le priorità (release e backlog). 2) DevTools: dal debug al controllo qualità Gli strumenti di sviluppo non servono più solo a “trovare il bug”, ma a ridurre il rischio : regressioni di layout, memory leak, risorse inutili, dipendenze pesanti. Abitudini che fanno differenza Profilare prima di ottimizzare: CPU, rete e rendering hanno colli di bottiglia diversi. Isolare i cambiamenti: una variazione di bundling o di immagini può ribaltare il profilo prestazionale più di una micro-ottimizzazione in JS. 3) La piattaforma web continua a crescere (e chiede scelte più consapevoli) La Web Platform oggi offre API potenti, ma la parte difficile non è “usarle”: è scegliere quando usarle. Un criterio utile Se una feature riduce complessità (meno librerie,
AI 资讯
Ensuring Thread Safety — .NET core-centric
Prefer immutability What: Make data read-only after construction. Instead of editing objects, create new ones. Why: If nothing changes, many threads can read safely with no locks . How (.NET): public readonly record struct Money ( decimal Amount , string Currency ); public record Order ( Guid Id , IReadOnlyList < OrderLine > Lines ) { public Order AddLine ( OrderLine line ) => this with { Lines = Lines . Append ( line ). ToList () }; } Use record / readonly struct , IReadOnlyList<> , and with (copy-on-write). Keep collections immutable ( ImmutableList<T> , ImmutableDictionary<K,V> ). Avoid shared state What: Don’t let unrelated code touch the same mutable object. Why: If each operation owns its data, there’s nothing to synchronize. How: Per-request scope : create new service instances that hold request-specific state. No static mutable fields; if you must cache, use ConcurrentDictionary : private static readonly ConcurrentDictionary < string , Widget > _cache = new (); var widget = _cache . GetOrAdd ( key , k => LoadWidget ( k )); Use lock / SemaphoreSlim cautiously What: Synchronization primitives that serialize access to critical sections. When: Short, minimal critical sections where mutation is unavoidable. lock for synchronous code; SemaphoreSlim when await is involved (never block in async code). Patterns & pitfalls: private readonly object _gate = new (); void Update () { lock ( _gate ) // keep work tiny inside { // mutate a small piece of shared state _count ++; } } private readonly SemaphoreSlim _sem = new ( 1 , 1 ); async Task UpdateAsync () { await _sem . WaitAsync (); try { _count ++; } finally { _sem . Release (); } } Never lock(this) or a public object (external code could deadlock you). Keep lock duration short; avoid I/O under locks. If multiple locks are needed, fix a global order to prevent deadlocks. Atomic counters (avoid locks entirely): Interlocked . Increment ( ref _count ); Leverage actor-style or message queues What: Push work as messages to
AI 资讯
Synchronous vs asynchronous in .NET core - how decide
Rule of thumb If your action waits on something external , make it async . If it’s instant CPU , keep it sync ; for expensive CPU , offload . The core idea Async shines for I/O-bound work (DB calls, HTTP calls, queues, files). It frees the request thread while waiting, so the server can serve more requests with the same thread pool . Sync is fine for trivial, short CPU work (formatting, small calculations) where you’re not awaiting anything and the handler returns in a few milliseconds. When to choose async You call EF Core ( SaveChangesAsync , ToListAsync ), HttpClient , Azure SDK ( ServiceBusClient , BlobClient ), file I/O, or any API with Async methods. You expect latency from a dependency (tens–hundreds of ms). You need cancellation and timeouts (propagate HttpContext.RequestAborted ). When sync is acceptable The action is pure CPU and trivial (e.g., quick math, mapping, input validation) and returns immediately. There are no I/O waits and no benefit from freeing the thread. If it’s CPU-heavy (image processing, big JSON transforms), do not just make it async—offload to a background queue/worker or a separate compute service. Async won’t make CPU faster. Pitfalls to avoid Don’t block async : never use .Result / .Wait() on Tasks (deadlocks/thread-pool starvation). Async all the way down : if the controller is async, downstream calls should be too. Don’t fake async : returning Task.Run around synchronous I/O just burns threads. Keep concurrency bounded when fanning out to multiple I/O calls. Mini decision checklist Any I/O? → Use async (end-to-end). Pure CPU? Tiny (≤ a few ms) → Sync is fine. Heavy/variable → Offload to background worker; controller returns 202/Location or uses a queue. ASP.NET Core examples Async (I/O-bound) — recommended [ ApiController ] [ Route ( "orders" )] public class OrdersController : ControllerBase { private readonly OrdersDbContext _db ; private readonly HttpClient _http ; public OrdersController ( OrdersDbContext db , IHttpClientFactory
开发者
Service Discovery in Modern .NET Applications and Azure
This article is part of the Comprehensive Guide to Microservices Architecture in .NET Core, Cloud and Azure series. Service Discovery in Kubernetes How Kubernetes DNS Works Kubernetes automatically creates DNS entries for services, enabling simple name-based discovery. A service named order-service in the production namespace becomes accessible at order-service.production.svc.cluster.local . For services within the same namespace, you can use the short name order-service . Service Definition: apiVersion : v1 kind : Service metadata : name : order-service namespace : production labels : app : order-service version : v1 spec : selector : app : order-service ports : - name : http protocol : TCP port : 80 targetPort : 8080 type : ClusterIP Native Service Discovery in .NET 9 .NET 9 introduces enhanced service discovery capabilities with improved configuration and resilience features. Basic Configuration: // Program.cs var builder = WebApplication . CreateBuilder ( args ); // Add service discovery with .NET 9 enhancements builder . Services . AddServiceDiscovery (); // Configure HTTP client with service discovery builder . Services . AddHttpClient < IOrderServiceClient , OrderServiceClient >( client => { // Use service name - discovery resolves to actual endpoint client . BaseAddress = new Uri ( "http://order-service" ); }) . AddServiceDiscovery () . AddStandardResilienceHandler (); // .NET 9 resilience patterns var app = builder . Build (); Advanced Configuration with appsettings.json: { "ServiceDiscovery" : { "Providers" : { "Kubernetes" : { "Namespace" : "production" , "RefreshPeriod" : "00:01:00" } }, "Services" : { "order-service" : { "Scheme" : "https" , "EndpointNames" : [ "http" , "https" ], "HealthCheckPath" : "/health" }, "payment-service" : { "Scheme" : "http" , "AllowAllHosts" : false } }, "AllowAllHosts" : true , "AllowedHosts" : [ "*.svc.cluster.local" ] } } Service-to-Service Communication Patterns Using Typed HTTP Clients: public interface IOrderServiceCli