Wednesday, 24 September 2025

Trigger in Azure Functions

🟢 What is a Trigger in Azure Functions?

  • An Azure Function is a small piece of code that runs only when something happens.

  • That “something” is called a trigger.

  • Trigger = automatic starter for your function.

Example:
If you want a function to run every day at 9 AM, a Timer trigger starts it for you.


🧩 Key Idea

  • Each function must have exactly one trigger.

  • The trigger decides:

    1. When the function runs.

    2. What input data is passed to it.


🔑 Common Trigger Types (with Examples)

Below are the most used Azure Function triggers and what they do.

Trigger TypeWhat Starts the FunctionSimple Example
HTTP TriggerAn HTTP request (like a web API call)Someone sends a GET/POST request to a URL such as https://myfunc.azurewebsites.net/api/hello
Timer TriggerA scheduled time (like a cron job)Run cleanup every night at 2 AM
Blob TriggerA file is added or updated in Azure Blob StorageAutomatically resize an image after it’s uploaded
Queue Storage TriggerA new message is put in an Azure Storage QueueProcess new orders added to a queue
Service Bus TriggerA message arrives in an Azure Service Bus queue or topicHandle incoming payment notifications
Event Grid TriggerAn Azure event occurs (e.g., new file in a storage account, resource change)Send a Slack message when a new file arrives
Event Hub TriggerA batch of event-stream data arrives (IoT or telemetry)Analyze live sensor data
Cosmos DB TriggerA document changes in a Cosmos DB collectionUpdate a cache or run analytics whenever a record changes
SignalR Trigger (rare)A SignalR event happensSend real-time messages to connected clients

🛠️ How It Works Step by Step

  1. Binding in Code
    In the function’s code you specify the trigger type and connection details.

    [FunctionName("MyHttpFunction")] public static IActionResult Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req, ILogger log) { log.LogInformation("HTTP trigger fired."); return new OkObjectResult("Hello World!"); }
  2. Runtime Listens
    Azure Functions runtime listens for that event (HTTP call, queue message, timer schedule, etc.).

  3. Event Happens
    When the event occurs, the runtime starts the function automatically and passes in the data (like the HTTP body, message text, or blob contents).


⚙️ Details About Each Trigger

1. HTTP Trigger

  • Use for: APIs or webhooks.

  • Input: Request body, query strings, headers.

  • Return: HTTP response.

  • Security: Set AuthorizationLevel (Anonymous, Function, Admin).

2. Timer Trigger

  • Use for: Scheduled tasks like cleanup, backups.

  • Schedule Format: CRON expression, e.g., "0 0 2 * * *" (2 AM daily).

  • Example: Nightly email reports.

3. Blob Trigger

  • Use for: Processing files.

  • Works with: Azure Blob Storage containers.

  • Example: Process a CSV when someone uploads it.

4. Queue Storage Trigger

  • Use for: Simple messaging between services.

  • Example: One system drops a message when an order is placed; the function picks it up and processes it.

5. Service Bus Trigger

  • Use for: Enterprise messaging (queues or topics).

  • Example: Payment gateway sends a Service Bus message when a payment succeeds.

6. Event Grid Trigger

  • Use for: Reacting to Azure events in near real-time.

  • Example: Notify a team when a new blob is created.

7. Event Hub Trigger

  • Use for: High-volume event streams like IoT telemetry.

  • Example: Analyze millions of device signals per minute.

8. Cosmos DB Trigger

  • Use for: Reacting to database changes.

  • Example: Automatically update a search index when a product record changes.


🧠 Best Practices

  1. One Trigger per Function

    • Each function listens to exactly one event source.

  2. Keep Functions Short

    • Do small tasks quickly to avoid timeouts.

  3. Scale Automatically

    • Triggers like Queue, Event Hub, and Blob scale the number of function instances based on event volume.

  4. Use Bindings for Input/Output

    • You can directly read or write to storage, queues, etc., with simple parameters—no extra code.


Quick Recap

  • Trigger = automatic starter for your code.

  • Common triggers: HTTP, Timer, Blob, Queue, Service Bus, Event Grid, Event Hub, Cosmos DB.

  • Each function must have exactly one trigger.

  • Azure Functions automatically listens for the event and runs your code when it happens.

In short:
Azure Function triggers let you run code automatically whenever a specific event (like a request, message, or file upload) occurs—no servers to manage, just write the function and choose the trigger.

CDC

🟢 What is CDC?

CDC is a feature in databases that records every change—when a row is added, updated, or deleted.

Think of it like a CCTV camera for your database.
Whenever data changes, CDC quietly writes a note about it.


💡 Why is it useful?

  • You can send only new changes to another system (like a data warehouse) instead of copying everything.

  • You can trigger actions when data changes (e.g., send an email when an order ships).

  • It helps with auditing (who changed what and when).


⚙️ How it works (step by step)

  1. Turn it on

    • An admin tells the database: “Watch this table for changes.”

  2. Database watches the transaction log

    • Every insert, update, or delete is already recorded in the database log.

    • CDC reads that log.

  3. Change table created

    • CDC puts details of each change into a special table (e.g., cdc.Orders_CT).

    • This table shows:

      • What kind of change happened (insert/update/delete)

      • Old and new values

      • The time of the change.

  4. Your app reads the changes

    • Your app or ETL job asks: “Give me all changes since last time.”

    • It processes those and remembers the last point it read.


🧠 Simple Example

  • You have an Orders table.

  • You update order #5’s status to “Shipped.”

  • CDC writes a row into its change table:
    “Order #5 changed from Pending → Shipped at 10:32 AM.”


✅ Good Things

  • No triggers needed: It uses the existing transaction log.

  • Fast: Only new changes are read.

  • Real-time: You see changes almost immediately.


⚠️ Things to keep in mind

  • Change tables can grow big—set cleanup rules.

  • Only users with permission should read CDC data.


🏁 Quick Summary

CDC = Automatic change tracker for your database.
It watches every insert, update, or delete and stores those details in a special table, so other apps can easily know exactly what changed without scanning everything.

Tuesday, 23 September 2025

Web API Versioning

1️⃣ Why API Versioning Matters

Imagine you published a REST API for mobile apps:

GET /api/products
  • Later you need a new field or change a parameter.

  • You can’t break old mobile apps that still call the old format.

API versioning lets you:

  • Publish new versions of your API

  • Keep old versions running until clients migrate.


2️⃣ Common Ways to Show the Version

You must tell the server which version the client wants.
Popular options:

ApproachExample callProsCons
URL path/api/v1/productsVery clear, cache friendlyURL changes with every version
Query string/api/products?api-version=1.0Easy to testLess obvious in logs
HTTP headerGET /api/products + x-api-version:1.0Clean URLsHarder to debug in browser
Accept header (media type)Accept: application/json; v=1.0Follows REST best practiceRequires custom header setup

You can even combine them.


3️⃣ Official Microsoft Library

Use the NuGet package:

Microsoft.AspNetCore.Mvc.Versioning

This library makes versioning easy.


4️⃣ Basic Setup (Path-based Versioning)

1. Install Package

dotnet add package Microsoft.AspNetCore.Mvc.Versioning

2. Configure in Program.cs (or Startup.cs)

builder.Services.AddApiVersioning(options => { options.AssumeDefaultVersionWhenUnspecified = true; options.DefaultApiVersion = new ApiVersion(1, 0); options.ReportApiVersions = true; // adds headers: api-supported-versions });
  • AssumeDefaultVersionWhenUnspecified: if client doesn’t pass a version, use default (1.0).

  • ReportApiVersions: tells clients which versions are available.

3. Version Your Controllers

[ApiVersion("1.0")] [Route("api/v{version:apiVersion}/[controller]")] [ApiController] public class ProductsController : ControllerBase { [HttpGet] public string GetV1() => "This is V1"; }

Add a second version:

[ApiVersion("2.0")] [Route("api/v{version:apiVersion}/[controller]")] [ApiController] public class ProductsV2Controller : ControllerBase { [HttpGet] public string GetV2() => "This is V2 with more fields"; }

Now clients call:

/api/v1/products /api/v2/products

5️⃣ Query-String Versioning

If you prefer ?api-version=1.0:

builder.Services.AddApiVersioning(options => { options.ApiVersionReader = new QueryStringApiVersionReader("api-version"); });

Then the route can simply be [Route("api/[controller]")].
Clients call:

/api/products?api-version=1.0

6️⃣ Header-Based Versioning

builder.Services.AddApiVersioning(options => { options.ApiVersionReader = new HeaderApiVersionReader("x-api-version"); });

Client adds header:

x-api-version: 2.0

7️⃣ Multiple Versions in One Controller

You can keep both actions in the same file:

[ApiVersion("1.0")] [ApiVersion("2.0")] [Route("api/products")] [ApiController] public class ProductsController : ControllerBase { [HttpGet, MapToApiVersion("1.0")] public string GetV1() => "Old result"; [HttpGet, MapToApiVersion("2.0")] public string GetV2() => "New result"; }

8️⃣ Deleting or Deprecating Versions

Mark an old version as deprecated:

[ApiVersion("1.0", Deprecated = true)]

The response header api-deprecated-versions warns clients.


9️⃣ Best Practices

  1. Choose one clear versioning style and stick to it.

  2. Document which versions exist and when they’ll be retired.

  3. Use semantic versioning (1.0, 1.1, 2.0) to show backward compatibility.

  4. Automate tests for every active version.

  5. When possible, design for backward compatibility to avoid breaking clients.


🔟 Quick Flow Recap

  1. Client requests with a version (URL / query / header).

  2. ASP.NET Core checks the version using the configured reader.

  3. The correct controller/action for that version executes.

  4. Response headers tell the client which versions are supported.


🧠 Key Takeaways

  • API versioning keeps old clients working while you release improvements.

  • Microsoft.AspNetCore.Mvc.Versioning makes it almost plug-and-play.

  • Pick a strategy (URL path, query, or header) and stay consistent.

  • Mark old versions as deprecated before removal.

Monday, 22 September 2025

Kubernetes

🟢 1️⃣ What is Kubernetes?

  • Kubernetes (K8s) is a container orchestration platform.

  • It manages, deploys, and scales containers automatically.

  • Think of it as a manager for Docker containers in a large system.

Analogy:

  • Docker = single shipping container

  • Kubernetes = entire shipping port with cranes, storage, and delivery trucks


🟢 2️⃣ Why Kubernetes for .NET Core?

  1. Scaling: Automatically increase or decrease the number of instances.

  2. Self-healing: Restarts failed containers automatically.

  3. Load balancing: Distributes traffic between multiple instances.

  4. Rolling updates: Update services without downtime.

  5. Service discovery: Easy communication between microservices.


🟢 3️⃣ Key Kubernetes Concepts

TermMeaning
PodSmallest deployable unit (usually 1 container, can have multiple)
NodeA server (VM or physical machine) running Kubernetes
ClusterA group of nodes managed by Kubernetes
DeploymentDefines how many replicas of a pod to run and manages updates
ServiceExposes pods internally or externally for communication
ConfigMapStores configuration (key-value) for pods
SecretStores sensitive info (passwords, API keys) securely
NamespaceLogical separation of resources in a cluster

🟢 4️⃣ Example: Deploy a .NET Core API to Kubernetes

Step 1: Dockerize Your .NET Core App

  • Create Dockerfile and build image as explained earlier.

Step 2: Push Docker Image to Registry

docker tag mywebapi:1.0 mydockerhubuser/mywebapi:1.0 docker push mydockerhubuser/mywebapi:1.0

Step 3: Create Kubernetes Deployment

deployment.yaml

apiVersion: apps/v1 kind: Deployment metadata: name: mywebapi-deployment spec: replicas: 3 selector: matchLabels: app: mywebapi template: metadata: labels: app: mywebapi spec: containers: - name: mywebapi image: mydockerhubuser/mywebapi:1.0 ports: - containerPort: 80
  • replicas: number of pods (instances) to run.

Step 4: Expose the Deployment as a Service

service.yaml

apiVersion: v1 kind: Service metadata: name: mywebapi-service spec: type: LoadBalancer selector: app: mywebapi ports: - protocol: TCP port: 80 targetPort: 80
  • LoadBalancer exposes your API to the outside world.


Step 5: Apply Config to Cluster

kubectl apply -f deployment.yaml kubectl apply -f service.yaml
  • Check pods: kubectl get pods

  • Check services: kubectl get svc


🟢 5️⃣ How Microservices Work on Kubernetes

  • Each microservice runs in its own deployment + pods.

  • Services communicate internally via Kubernetes Service (DNS name).

  • Messages/events can be processed asynchronously using message queues (RabbitMQ, Kafka).


🟢 6️⃣ Benefits for .NET Core Apps

  1. Easy to scale APIs or background workers independently.

  2. Can run cross-platform containers (.NET Core works on Linux).

  3. Automatic updates and self-healing reduce downtime.

  4. Supports microservices architecture with multiple small services.


🟢 7️⃣ Quick Summary

  • Docker: packages app into container

  • Kubernetes: manages many containers automatically

  • .NET Core + Docker + K8s → scalable, resilient microservices architecture

Docker

🟢 1️⃣ What is Docker?

  • Docker is a tool to package applications with all dependencies into a container.

  • Container = isolated environment that runs your app anywhere (Windows, Linux, cloud).

  • Benefit: “It works on my machine” problem is solved.

Analogy: Docker is like a shipping container for your app. It includes your app, .NET runtime, libraries, and everything needed.


🟢 2️⃣ Why Use Docker with .NET Core?

  1. Cross-platform: Run .NET Core apps on Linux, Windows, or cloud.

  2. Easy deployment: Package app + dependencies.

  3. Isolation: No conflicts between apps.

  4. Microservices: Each service can run in its own container.


🟢 3️⃣ Steps to Dockerize a .NET Core App

Step 1: Create a .NET Core App

dotnet new webapi -n MyWebApi cd MyWebApi dotnet build dotnet run
  • Your API runs locally on http://localhost:5000.


Step 2: Create a Dockerfile

  • In the root folder, create a file named Dockerfile (no extension):

# 1. Base image with .NET runtime FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 # 2. Build image with SDK FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src COPY ["MyWebApi.csproj", "./"] RUN dotnet restore "./MyWebApi.csproj" COPY . . RUN dotnet publish "MyWebApi.csproj" -c Release -o /app/publish # 3. Final image FROM base AS final WORKDIR /app COPY --from=build /app/publish . ENTRYPOINT ["dotnet", "MyWebApi.dll"]

Explanation:

  • Stage 1 (base): Runtime image to run the app.

  • Stage 2 (build): SDK image to build and publish the app.

  • Stage 3 (final): Copy published files to runtime image and run.


Step 3: Build Docker Image

docker build -t mywebapi:1.0 .
  • mywebapi → image name, 1.0 → version tag.

  • Docker reads the Dockerfile and creates the image.


Step 4: Run the Container

docker run -d -p 8080:80 --name mywebapi_container mywebapi:1.0
  • -d → run in background

  • -p 8080:80 → map container port 80 to local port 8080

  • --name → container name

Now open http://localhost:8080 → your API is running inside a Docker container!


Step 5: (Optional) Docker Compose

  • Useful if you have multiple services (like API + database).

  • Create docker-compose.yml:

version: '3.8' services: webapi: image: mywebapi:1.0 ports: - "8080:80" db: image: mcr.microsoft.com/mssql/server:2019-latest environment: SA_PASSWORD: "Your_password123" ACCEPT_EULA: "Y" ports: - "1433:1433"
  • Run with: docker-compose up -d


🟢 4️⃣ Tips

  1. Always use multi-stage Dockerfile → keeps image size small.

  2. Expose only needed ports (EXPOSE 80).

  3. Use environment variables for secrets/configuration.

  4. Use .dockerignore to exclude unnecessary files (like bin, obj).


🟢 5️⃣ Summary

  • Docker packages your .NET Core app + dependencies into a container.

  • Steps:

    1. Create .NET Core app

    2. Write Dockerfile

    3. Build Docker image (docker build)

    4. Run container (docker run)

  • Optional: Use Docker Compose for multi-container apps.

Concurrency

🟢 1️⃣ What is Concurrency?

Concurrency means doing multiple things at the same time, or overlapping tasks in your program.

  • In C#, this usually means using multiple threads or tasks.

  • Goal: make your program faster, or responsive (like not freezing UI).

Example:

  • Downloading 5 files at once instead of waiting for one file to finish before starting the next.


🟢 2️⃣ Ways to Achieve Concurrency in .NET Core

1. Task Parallel Library (TPL)

  • Use the Task class to run work asynchronously.

  • Example:

using System; using System.Threading.Tasks; class Program { static void Main() { Task t1 = Task.Run(() => Console.WriteLine("Task 1 running")); Task t2 = Task.Run(() => Console.WriteLine("Task 2 running")); Task.WaitAll(t1, t2); // wait until all tasks finish Console.WriteLine("All tasks done"); } }

Task.Run() runs work on a thread pool thread.


2. Async / Await

  • For IO-bound tasks (like reading files, HTTP calls), use async and await.

  • Example:

using System; using System.Net.Http; using System.Threading.Tasks; class Program { static async Task Main() { HttpClient client = new HttpClient(); Task<string> t1 = client.GetStringAsync("https://example.com"); Task<string> t2 = client.GetStringAsync("https://example.org"); string[] results = await Task.WhenAll(t1, t2); foreach (var r in results) Console.WriteLine(r.Substring(0, 50)); } }
  • async/await does not block the thread, so the program can do other work while waiting.


3. Parallel Loops

  • Use Parallel.For or Parallel.ForEach to run loop iterations concurrently.

using System; using System.Threading.Tasks; class Program { static void Main() { Parallel.For(0, 5, i => { Console.WriteLine($"Processing {i} on thread {Task.CurrentId}"); }); } }
  • Automatically splits work across available CPU cores.


4. Concurrent Collections

  • When multiple threads access a collection, use thread-safe collections like:

using System; using System.Collections.Concurrent; using System.Threading.Tasks; class Program { static void Main() { ConcurrentBag<int> bag = new ConcurrentBag<int>(); Parallel.For(0, 10, i => bag.Add(i)); foreach (var item in bag) Console.WriteLine(item); } }
  • Other options: ConcurrentQueue, ConcurrentStack, ConcurrentDictionary.


5. Locks (Optional)

  • If you need to protect a resource, use lock:

class Counter { private int count = 0; private object lockObj = new object(); public void Increment() { lock(lockObj) { count++; } } }
  • Only one thread can access the block at a time.


🟢 3️⃣ Key Tips

  1. CPU-bound workTask.Run, Parallel.For

  2. IO-bound workasync/await

  3. Shared data → use Concurrent collections or lock

  4. Avoid blocking threads unnecessarily; async is usually better than Thread.Sleep.


🟢 4️⃣ Quick Summary Table

TypeWhen to UseExample
Task / TPLCPU-bound or simple backgroundTask.Run(() => DoWork())
Async / AwaitIO-bound (file, API, DB)await HttpClient.GetStringAsync(url)
Parallel.ForLoop with independent iterationsParallel.For(0, 10, i => ...)
ConcurrentCollectionMultiple threads accessing dataConcurrentBag<int>
LockProtect shared resourceslock(obj) { ... }

💡 Rule of Thumb:

  • Use async/await for non-CPU tasks.

  • Use Task / Parallel for CPU-heavy tasks.

  • Use concurrent collections to safely share data

JWT

🟢 1. What is JWT?

  • JWT stands for JSON Web Token.

  • It is a secure way to transmit information between a client (like a browser) and a server.

  • The information is digitally signed so it cannot be tampered with.

Analogy:

  • Think of JWT like a sealed envelope with a message inside.

  • Only the server can verify the seal (signature) to know it’s authentic.


🟢 2. Structure of JWT

A JWT is a string divided into 3 parts separated by dots (.):

Header.Payload.Signature
  1. Header – says what type of token it is and the algorithm used.

    { "alg": "HS256", "typ": "JWT" }
  2. Payload – the actual information (claims). Example:

    { "userId": 123, "email": "user@example.com", "role": "admin" }
  3. Signature – a hash created from header + payload + secret key.

    • Ensures the token is authentic and unchanged.


🟢 3. How JWT Works

  1. User logs in with username/password.

  2. Server verifies credentials.

  3. Server generates JWT (with user info in payload) and sends it to client.

  4. Client stores JWT (usually in local storage or cookies).

  5. For future requests, client sends JWT in HTTP header:

    Authorization: Bearer <token>
  6. Server verifies JWT signature. If valid, user is authenticated.


🟢 4. JWT in C# (.NET Core / .NET 5+)

Step 1: Install NuGet package

Install-Package System.IdentityModel.Tokens.Jwt

Step 2: Create a JWT

using System; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using Microsoft.IdentityModel.Tokens; using System.Text; class Program { static void Main() { string secretKey = "my_super_secret_key_123!"; // keep it safe var key = Encoding.ASCII.GetBytes(secretKey); // 1. Create claims (user info) var claims = new[] { new Claim("userId", "123"), new Claim(ClaimTypes.Email, "user@example.com"), new Claim(ClaimTypes.Role, "Admin") }; // 2. Create token descriptor var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(claims), Expires = DateTime.UtcNow.AddHours(1), SigningCredentials = new SigningCredentials( new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; // 3. Create token var tokenHandler = new JwtSecurityTokenHandler(); var token = tokenHandler.CreateToken(tokenDescriptor); var jwt = tokenHandler.WriteToken(token); Console.WriteLine("JWT Token:"); Console.WriteLine(jwt); } }

Step 3: Validate JWT

var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(secretKey); var validationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false, ClockSkew = TimeSpan.Zero }; try { var principal = tokenHandler.ValidateToken(jwt, validationParameters, out var validatedToken); Console.WriteLine("Token is valid!"); Console.WriteLine("UserId: " + principal.FindFirst("userId")?.Value); } catch { Console.WriteLine("Invalid Token"); }

🟢 5. Important Points

  • Keep secret key safe! If leaked, attackers can create valid tokens.

  • Do not store sensitive info like passwords in the payload. JWT is only base64 encoded, not encrypted.

  • Expiration is important. Never issue a token without expiry.

  • Bearer token in HTTP header is standard.


🟢 Summary

  • JWT = Header + Payload + Signature

  • Used for authentication and authorization

  • Signed so server can trust it

  • In C#, use System.IdentityModel.Tokens.Jwt to create & verify tokens

delegate vs event

🟢 1. Delegate

  • Think of it as: A variable that can store a method.

  • Purpose: Let you pass methods around like data.

  • Analogy: A remote control that can point to different TVs (methods).

Example

// Define a delegate type (method signature) public delegate void MyDelegate(string msg); class Program { static void Print(string m) => Console.WriteLine(m); static void Main() { MyDelegate d = Print; // store method in delegate d("Hello from delegate"); // call it } }
  • You can assign, combine, or call (d(...)) a delegate directly.


🟢 2. Event

  • Think of it as: A special wrapper around a delegate used for notifications.

  • Purpose: Publisher/Subscriber system — when something happens, tell all listeners.

  • Analogy: A doorbell. Many people can listen (subscribe). Only the house owner can ring (raise) it.

Example

using System; class Door { public event Action DoorOpened; // event based on built-in delegate public void Open() { Console.WriteLine("Door opened"); DoorOpened?.Invoke(); // only Door can trigger } } class Program { static void Main() { var door = new Door(); door.DoorOpened += () => Console.WriteLine("Guest notified!"); door.Open(); } }
  • Others use += or -= to subscribe/unsubscribe.

  • Only the class that defines the event can raise (Invoke) it.


🟢 Key Differences

FeatureDelegateEvent
What is it?Type-safe reference to a methodA delegate with extra rules for publish/subscribe
Who can call (invoke)?Anyone holding the delegateOnly the declaring class
UsagePass methods as parameters, callbacksNotify subscribers when something happens
SubscriptionNot required; can directly assignMust use += or -=
EncapsulationNoneProvides safety: outsiders can’t overwrite the list

🟢 Simple Rule

  • Delegate: “Point to a method and call it.”

  • Event: “Many listeners can sign up; only the owner can fire it.”


Tiny Summary

  • Delegate = function pointer (method reference).

  • Event = delegate used for notifications with extra safety and += / -= subscription.