You're Paying Too Much to Run Your LLM (Sponsored)
Your endpoint streams tokens too slowly, so you move to a bigger GPU and watch the bill double.
Runpod, The AI Developer Cloud, just launched Overdrive: it takes any vLLM-compatible model you already host and runs it on the same H100 - up to 3.5x faster token streaming on Llama 3.1 8B, with near-lossless eval scores. You give them your model, context length, and traffic pattern; they benchmark your endpoint before and after. If Overdrive doesn't beat your baseline, you pay nothing.
Vector search finds things by meaning, which is perfect when your AI agent needs to answer a question like "what blocked the renewal?" But ask it to pull up invoice "INV-48291" and it comes back empty - an exact code carries almost no meaning to an embedding model, so vector search keeps missing the IDs, SKUs, and error codes your app runs on.
The fix is hybrid search: pair semantic recall for questions with plain text matching for identifiers, so one query handles both.
Oracle AI Agent Memory is a database-backed memory layer that does this out of the box, keeping messages, durable facts, and embeddings together in Oracle AI Database. To see it work, run their support-copilot notebook: one agent handles both an exact policy-code search and an open-ended 'what went wrong?' question in the same workflow.
EF Core is the most popular way to work with a database in .NET.
Azure SQL Database is the managed SQL Server you get in the cloud, with backups, patching, and high availability handled for you.
Putting the two together is straightforward, but the cloud adds a few things you never deal with on a local SQL Server.
Connections drop under load. The firewall blocks you by default. And a database password sitting in your connection string is a risk you want to remove before production.
Today I want to present you with a complete guide to getting started with Azure SQL Database in .NET.
In this post, we will explore:
What Azure SQL Database is
How to create an Azure SQL Database in the Azure Portal
Connecting EF Core to Azure SQL
Running EF Core migrations against Azure SQL
Adding connection resilience for transient faults
Setting up Azure SQL with .NET Aspire
Passwordless authentication with Microsoft Entra ID
Azure SQL Database is a fully managed database service built on the SQL Server engine.
Because it is the same engine, EF Core talks to it through the exact provider you already use for SQL Server.
You do not need a special "Azure" provider - only a connection string that points to the cloud.
Azure manages the parts you do not want to: the operating system, patching, backups, and failover.
You manage your schema and your data.
You pick from two main purchasing models:
Provisioned - a fixed amount of compute that is always on. Predictable cost for steady workloads.
Serverless - compute that scales automatically and pauses when idle. You pay per second of use, which is ideal for development and test environments.
Creating an Azure SQL Database in the Azure Portal
Follow these steps:
1. Open the Azure Portal, search for "SQL databases", and click Create.
2. On the next page, select your Azure subscription and click Create:
3. Enter your database name and set up a logical SQL server to host the database:
4. Create a new one, select a location, give it a unique name, set the identification method, and set an admin login and password.
5. For the compute tier, choose Serverless while you are testing.
It pauses when idle, so you only pay while you use it.
6. After the database is created, you need to open the firewall. By default, Azure SQL blocks every connection.
Go to the server's Networking settings, and add your client IP address so you can connect from your machine.
Turn on "Allow Azure services and resources to access this server" so apps you deploy in Azure can connect to it.
Note: The firewall is the most common reason a first connection fails. If you see a "Cannot open server" error, check that your current IP is in the firewall rules.
With the database ready, let's connect EF Core to it.
In the Azure Portal, open your database's Connection strings blade and copy the ADO.NET string - it already has the correct server name and options.
You only replace the password placeholder with your own.
Two things matter here.
Encrypt=True is required - Azure SQL only accepts encrypted connections.
And the password is a secret, so keep it out of source control.
In development, store it with user-secrets (add it to disallow list to prevent AI agents from reading it):
Create the first migration and apply it to Azure SQL:
bash
1dotnet ef migrations add InitialCreate
2dotnet ef database update
dotnet ef database update connects to Azure SQL using your connection string and creates the Products and Orders tables, along with the foreign key between them.
Because this runs against the real database, your client IP must be allowed through the firewall - the same rule you added earlier.
Note: Running dotnet ef database update from your machine is fine for development. For production, apply migrations from your CI/CD pipeline or generate a migration bundle to ensure deployments are repeatable and independent of a developer's laptop.
You can build that bundle as a single self-contained executable, then run it on deploy:
bash
1dotnet ef migrations bundle
A local SQL Server rarely drops a connection. Azure SQL does, so the next step is to handle that.
Now EF Core automatically retries a failed command up to 5 times, with increasing delays between attempts.
It only retries transient errors, so it will not mask a real bug, such as a constraint violation.
Important note: With a retrying execution strategy, you cannot start a transaction with BeginTransaction directly. Wrap the work in an execution strategy instead, so the whole block can be retried as a unit:
var strategy = context.Database.CreateExecutionStrategy();await strategy.ExecuteAsync(async () => { ... });
This single line is one of the most important changes you can make for a cloud database.
You can wire it all up automatically with .NET Aspire.
.NET Aspire models your application and its dependencies in one place.
It can provision Azure SQL and pass the connection string to your app.
Add the Azure SQL resource in the AppHost project:
csharp
1var builder = DistributedApplication.CreateBuilder(args);23var sql = builder.AddAzureSqlServer("sql")4.RunAsContainer();// run a local SQL Server container in development56var shopDb = sql.AddDatabase("shopdb");78builder.AddProject<Projects.Shop_Api>("shop-api")9.WithReference(shopDb)10.WaitFor(shopDb);1112builder.Build().Run();
In the API project, register the DbContext with the Aspire integration:
This replaces the manual AddDbContext and connection-string lookup.
Aspire injects the connection string for the shopdb resource, and its integration wires in sensible defaults, including connection retries.
In development, RunAsContainer spins up a local SQL Server container so you do not touch Azure at all.
When you publish, Aspire provisions a real Azure SQL Database.
One thing remains before production: removing the password.
The Authentication=Active Directory Default setting tells the SQL client to get a token through DefaultAzureCredential.
On your machine, it uses your Azure CLI or Visual Studio login.
In Azure, it uses your app's managed identity - an identity Azure manages so you never see a secret.
To make this work, enable a managed identity on your App Service or Container App, then create a matching user in the database and grant it permissions:
sql
1CREATEUSER[shop-api]FROM EXTERNAL PROVIDER;2ALTER ROLE db_datareader ADD MEMBER [shop-api];3ALTER ROLE db_datawriter ADD MEMBER [shop-api];
Here, shop-api is the name of your app's managed identity. The database now trusts that identity directly.
The result is a connection with no password anywhere - not in your config, not in a key vault, not in your pipeline. There is nothing to leak or rotate.
Connecting EF Core to Azure SQL is mostly the EF Core you already know, plus a few cloud-specific steps.
Let's recap the key takeaways:
The provider does not change. Use Microsoft.EntityFrameworkCore.SqlServer and point the connection string at Azure SQL, with Encrypt=True.
Open the firewall. Azure SQL blocks all connections by default. Allow your IP for local work and Azure services for deployed apps.
Run migrations against the cloud database. Use dotnet ef in development, and your CI/CD pipeline or a migration bundle for production.
Always enable retries.EnableRetryOnFailure handles the transient faults that are normal for a shared cloud database.
Go passwordless in production. Microsoft Entra authentication with a managed identity removes the database password entirely.
Azure SQL is a strong default when your data is relational, and you want a managed database without running SQL Server yourself.
Start with a connection string to get moving, then add resilience and passwordless auth before you ship.
If you want to go deeper, read these related articles:
Hope you find this newsletter useful. See you next time.
Whenever you're ready, here's how I can help you:
The .NET Senior Playbook is built to:
Fast-track you from junior or mid-level to senior
Keep you growing as a senior
Help you beat any .NET interview
Covers everything: C#, ASP.NET Core, EF Core, system design β answer each question first, reveal the solution, and a test after every chapter proves it stuck. Finish, and you earn a verifiable certificate for your LinkedIn.
Not sure where you stand? Take the free .NET Interview Run:
Find out your real level β Junior to Senior+
A realistic mock .NET interview β across 13 areas of C#, .NET, ASP.NET Core and System Design
No credit card required. When you finish, you get a personalized report: your level, your strongest and weakest areas, and where to focus next β the perfect way to benchmark yourself before diving into the Playbook.
Comments