Back to "एनईएसी में अनुरोधों के बीच राज्य रखना. nenet कोर: एक व्यावहारिक, कोई संक्षिप्त मार्गदर्शक नहीं (MVC, राजेर पृष्ठ, न्यूनतम एपीआई)"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

AI-Article ASP.NET ASP.NET Core State Web Development

एनईएसी में अनुरोधों के बीच राज्य रखना. nenet कोर: एक व्यावहारिक, कोई संक्षिप्त मार्गदर्शक नहीं (MVC, राजेर पृष्ठ, न्यूनतम एपीआई)

Sunday, 09 November 2025

UUDATE (2025- 11- 10): मेरे वास्तविक कोड से और अधिक व्यावहारिक उदाहरण जोड़े वास्तव में दुनिया के पैटर्न, व्यापार - समाप्त, मिल गया, और जटिल राज्य प्रबंधन के प्रति सरल से विकास शामिल है. विस्तृत मैं मेमोरी मॉडलों, दृश्य Babag का उपयोग (सही और गलत), अनुक्रिया Cacs/ tuts, और उत्पादन से सीखा.

परिचय

HTTP प्रसिद्ध है. आपका एएसटीम नहीं है. आपका एएसएसएसए नहीं है. उपयोक्ता साइन इनबॉक्स में से कुछ वस्तुओं को जोड़ता है, जो कि पृष्ठ, कल, और आपको याद दिलाने की आशा करते हैं.

यह पोस्ट कैटलॉग विकल्प दिखाता है, ठोस, नक़ली उदाहरण सभी तीन ढेरों में नक़ली उदाहरण दिखाता है, और आपको मार्गदर्शन देता है ताकि आप काम के लिए सही औज़ार चुन सकें.

नोट: यह मेरे परीक्षण का हिस्सा है एआई (के रूप में ड्राफ्टिंग) + मेरी खुद का संपादन. एक ही आवाज, एक ही स्फीतिवाद; सिर्फ तेजी से उंगलियों के साथ.

जीव - रसायन में लैंडस्केप

flowchart LR
  subgraph Client
    Q[Query String]
    R[Route Values]
    H[Headers]
    F[Form/Hidden Fields]
    CK[Cookies]
    LS[Local/Session Storage]
  end
  subgraph Server
    I[HttpContext.Items<br/>\nper request only]
    TD[TempData<br/>\none redirect]
    SS[Session]
    MC[IMemoryCache]
    DC[IDistributedCache]
    AU[Auth Cookie / Claims]
    JT[JWT / Bearer]
    DB[Database / Durable Store]
    BUS[Outbox / Queue]
  end
  Q --> Model[Model Binding]
  R --> Model
  F --> Model
  H --> Model
  CK --> App[Your Code]
  Model --> App
  App -->|Set| CK
  App -->|Set| TD
  App -->|Set| SS
  App -->|Set| MC
  App -->|Set| DC
  App -->|Issue| AU
  App -->|Issue| JT
  App -->|Persist| DB
  • क्लाएंट-कार: क्वैरी, मार्ग, शीर्ष, फ़ॉर्म, कुकीज़. स्केल्स क्षैतिज, सिवाय क्लाइंट के लिए दृश्‍य है (जहाँ उचित हो.)
  • सर्वर- रेफ़रिट: टेंप डाटा, सत्र, कैश्स. आवश्यकता है समानता या वितरण नीति.
  • प्रति-पुष्टि:;...

सुनहरे नियम (से पहले हम एपीआईओं में उतरने से पहले)

  1. सुरक्षा: राज्य रिसाव एक वास्तविक ख़तरा है । सर्वर के किनारे की स्थिति (सर्मी कैश में) उपयोगकर्ताों के लिए त्रुटियों, जाति की परिस्थितियों, या गलत जीवन प्रबंधन के माध्यम से लीक कर सकते हैं. सरकारी पैटर्न सिर्फ और अधिक आत्मीय नहीं हैं, वे अधिक सुरक्षित हैं.
  2. "नेटपूर्ण सर्वर" पैटर्न को वरीयता दें जब आपको क्षैतिज रूप से (शश की स्थिति से ग्राहक चिह्नों, सोने के भंडार, या वितरण कैशों के लिए आवश्यक है).
  3. क्लाएंटपरेड स्थिति पर भरोसा मत करें. वैध, हस्ताक्षर, और/या एनक्रिप्ट करें.
  4. कुकीज़ तथा शीर्षों से बड़े डेटा रखें; वे हर निवेदन पर परदा डालते हैं.
  5. सिर्फ पोस्ट- आर- आर- आर (RP) संदेशों के लिए मोनोक्रोम डाटा इस्तेमाल करें.
  6. सत्र का प्रयोग करें जब आपको सर्वर के साइडबार वार्तालाप स्थिति को बनाए रखना है और आपने वितरण की योजना बनाई है - और सुरक्षा के बारे में बात नहीं की है.
  7. तथ्य पहचान के लिए कर रहे हैं और दोषक प्राधिकार के लिए, सामान्य एएसटी स्थिति नहीं.
  8. कैश सच्चाई का स्रोत नहीं है । यदि डेटा मामलों में है तो इसे एक अटल स्टोर के साथ वापस लें.

PR-RERAT स्टेट: ... वचनों.

  • स्कोप: मौजूदा निवेदन (स्थानीय के अंत में उलटा)
  • के लिए प्रयोग करें: मध्य- बिन्दुओं तथा अंत- बिन्दुओं के बीच से गुजरी मूल्यों का प्रयोग करें
  • स्केल: कोई प्रभाव नहीं
  • सुरक्षा: सर्वर सिर्फ
sequenceDiagram
  participant M as Middleware
  participant E as Endpoint/Controller
  M->>M: Compute TenantId
  M->>E: HttpContext.Items["TenantId"] = 42
  E->>E: Read Items["TenantId"]

मध्य- एलबम उदाहरण (सभी ढेर):

app.Use(async (context, next) =>
{
    var tenantId = context.Request.Headers["X-TenantId"].FirstOrDefault() ?? "public";
    context.Items["TenantId"] = tenantId;
    await next(context);
});
  • न्यूनतम एपीआई अंत बिन्दु:
app.MapGet("/whoami", (HttpContext ctx) => new { Tenant = ctx.Items["TenantId"] });
  • एमवीसी नियंत्रक:
public IActionResult WhoAmI() => Json(new { Tenant = HttpContext.Items["TenantId"] });
  • रार्जर पेज हैंडलर:
public IActionResult OnGet() => new JsonResult(new { Tenant = HttpContext.Items["TenantId"] });

ट्रांजीशन क्लाएंट- सी स्थिति: रूट मान तथा क्वैरी वाक्यांश

  • स्कोप: वर्तमान निवेदन; क्लाएंट इसे प्रत्यक्ष रूप से रखता है.
  • के लिए: नेविगेशन संदर्भ, फ़िल्टरिंग, सुधार, रिसोर्स पहचान इस्तेमाल करें
  • सुरक्षा: वैध/ bibit; रहस्य को एम्बेड नहीं करें

उदाहरण

  • न्यूनतम एपीआई:
app.MapGet("/orders/{id:int}", (int id, int? page) => Results.Ok(new { id, page }));
// GET /orders/5?page=2
  • वीवीसी:
[HttpGet("/orders/{id:int}")]
public IActionResult Details(int id, int? page)
  => View(new { id, page });
  • राजेर पृष्ठ (ards/ विवरण. shtml:
public IActionResult OnGet(int id, int? page)
  => Page();

लिंक बनाया जा रहा है जो संरक्षित स्थिति को बनाए रखता है:

// Razor Pages
<a asp-page="/Orders/Details" asp-route-id="@Model.Id" asp-route-page="@Model.Page">Next</a>

// MVC
@Html.ActionLink("Next", "Details", "Orders", new { id = Model.Id, page = Model.Page }, null)

शीर्ष- सूचना आईडी, Idmidid कुंजी, भारी ध्वज

  • स्कोप: मौजूदा निवेदन, जवाब में वैकल्पिक रूप से इको्ड
  • उपयोग के लिए: सताने वाला, सुरक्षित जगह, A/B फ्लैग फिर से कोशिश करें.
  • सुरक्षा: अविश्वसनीय इनपुट के रूप में, वैध/ @ info: whatsthis
app.Use(async (ctx, next) =>
{
    var correlationId = ctx.Request.Headers["X-Correlation-Id"].FirstOrDefault()
                      ?? Guid.NewGuid().ToString("n");
    ctx.Response.Headers["X-Correlation-Id"] = correlationId;
    await next(ctx);
});

आईएसडी- एएस- पैटर्न: (p)

flowchart TD
  C[Client POST /pay\nIdempotency-Key:k] --> S{Seen k?}
  S -- No --> E[Execute charge]
  E --> P[Persist result by k]
  P --> R[Return 200 + result]
  S -- Yes --> L[Load result by k]
  L --> R

फ़ॉर्म तथा छुपा फ़ील्ड (पीजीजी)

  • स्कोप: अगला निवेदन (केवल पोस्ट पोस्ट्स इन मान से पीछे)
  • के लिए इस्तेमाल करें: जादूगर चरणों, अटल लक्षणों का इस्तेमाल करें, साथ ही PRGG के पार राज्य के छोटे टुकड़े
  • सुरक्षा: हमेशा वैध; एन्टीप्शन के साथ साझेदारी

एमवीसी/आरएम्ब्टर पृष्ठ में पजीजी पैटर्न:

sequenceDiagram
  participant U as User
  participant P as POST Action
  participant R as Redirect
  participant G as GET Action
  U->>P: POST form
  P-->>R: 302 Redirect
  U->>G: GET redirected
  G-->>U: Final page (no resubmits)
  • वीवीसी:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Save(SettingsModel model)
{
    // validate & persist
    return RedirectToAction(nameof(Summary), new { tab = model.SelectedTab });
}
  • राजेर पृष्ठ:
public IActionResult OnPost(SettingsModel model)
{
    return RedirectToPage("/Settings/Summary", new { tab = model.SelectedTab });
}

कुकीज़: छोटा, साइन किया, कभी-कभी

  • स्कोप: ब्राउज़र से प्रत्येक निवेदन मियाद तक@ info: whatsthis
  • के लिए प्रयोग करें: वरीयता, नॉन- संवेदनशील फ्लैग, सहमति; कनेक्शन कुकीज़ (अप्रयोग भाग)
  • ट्रेफ्स: आकार सीमा (0-24B प्रति कुकी), प्रदर्शन प्रभाव, सहमति नियम के अनुसार पालन करना चाहिए

न्यूनतम एपीआई उदाहरण:

app.MapPost("/prefs/theme/{value}", (HttpContext ctx, string value) =>
{
    ctx.Response.Cookies.Append("theme", value, new CookieOptions
    {
        HttpOnly = false,
        Secure = true,
        SameSite = SameSiteMode.Lax,
        Expires = DateTimeOffset.UtcNow.AddYears(1)
    });
    return Results.Ok();
});

app.MapGet("/prefs/theme", (HttpContext ctx)
  => Results.Text(ctx.Request.Cookies["theme"] ?? "system"));

MVC/RUror पृष्ठ उपयोग एक जैसे है HttpContext.

अखंडता के लिए, एनईसी का उपयोग करें. एनईसी डाटा सुरक्षा तंत्र को सुरक्षित रखने के लिए आप अपने आप को कुकीज़ में डाल देते हैं.


टेंप डाटा: एक- तरफा संदेश बस

  • स्कोप: एक पुनर्निदेश से बचने के लिए
  • बैकप स्टोर: कुकी (डिफ़ॉल्ट) या सत्र
  • के लिए प्रयोग करें: फ्लैश संदेश, PAG के बाद वैधीकरण

सेटअप ( प्रोग्राम.c):

builder.Services.AddControllersWithViews().AddSessionStateTempDataProvider(); // optional
builder.Services.AddSession();
var app = builder.Build();
app.UseSession();

नियंत्रण में:

TempData["StatusMessage"] = "Saved!";
return RedirectToAction("Index");

राइसर पेज हैंडलर में:

TempData["StatusMessage"] = "Saved!";
return RedirectToPage("/Index");

दृश्य/पेज में:

@if (TempData["StatusMessage"] is string msg) {
  <div class="alert alert-success">@msg</div>
}
flowchart LR
  A[POST /save] -->|TempData set| B[302 Redirect]
  B --> C[GET /index]
  C -->|TempData read consumed| D[Render message]

सत्र: सर्वर-इड वार्तालाप स्थिति

  • स्कोप: ब्राउज़र सत्र (ली कुंजी + सर्वर स्टोर)
  • इस्तेमाल करें: बहु- स्टेप विज़ार्ड, छोटे कार डाटा, अण्डेक्टिंग उलटा
  • व्यापार समाप्त: स्टिकी सत्रों या वितरण स्टोर की जरूरत है, सीमा स्केल कर सकते हैं

कॉन्फ़िगर:

builder.Services.AddDistributedMemoryCache(); // or AddStackExchangeRedisCache
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(20);
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});
var app = builder.Build();
app.UseSession();

सत्र इस्तेमाल किया जा रहा है (कोई ढेर नहीं):

app.MapPost("/cart/add/{id:int}", (HttpContext ctx, int id) =>
{
    var key = "cart";
    var bytes = ctx.Session.Get(key);
    var list = bytes is null ? new List<int>() : System.Text.Json.JsonSerializer.Deserialize<List<int>>(bytes)!;
    list.Add(id);
    ctx.Session.Set(key, System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(list));
    return Results.Ok(list);
});

सत्र सहायक:

public static class SessionExtensions
{
    public static void Set<T>(this ISession session, string key, T value)
      => session.SetString(key, System.Text.Json.JsonSerializer.Serialize(value));

    public static T? Get<T>(this ISession session, string key)
      => session.TryGetValue(key, out var data)
         ? System.Text.Json.JsonSerializer.Deserialize<T>(data)
         : default;
}

एक सावधानीपूर्वक कहानी: जब सत्र स्थिति बोतलक बन जाती है

मैं एक बार एक विशाल यूके सरकार पर काम किया है यह परियोजना जहाँ सत्र राज्य का दुरुपयोग (बहुत से अन्य निर्माणीय पापों के बारे में) एक प्रदर्शन का उपयोग कर रहे हैं . टीम का सामान लूट लिया था सभी सत्र में: उपयोक्ता वरीयता, बहु- चरण फ़ॉर्म डाटा, खोज परिणाम, अस्थायी गणना, यहाँ तक कि कैश देखना चाहिए कि एक उचित कैश या डाटाबेस में किया गया है.

समस्या: सत्र स्थिति वेब में भंडारित किया गया था (SueT सत्र सत्र स्थिति में.config, यह पहले से ही था.config, यह हर निवेदन भारी सत्र वस्तुओं को चलाने के लिए था. जैसा कि लोड किया गया था, सत्र स्तर में अधिकतम किया गया है प्रति उपयोगकर्ता के दस उपयोगकर्ता के साथ. हजार गैरक्शन उपयोगकर्ता के साथ, सर्वर स्मरण के बाहर भाग गया.

कठिन समाधान: हम Warttttttttttttttttta की सुविधा के लिए हवाई जहाज पर उड़ान चलाने के लिए उनके सुपरddy पर जाँच चलाने के लिए, समय पर, यूरोप के सबसे शक्तिशाली विंडोज़ मशीन. यह एक जानवर था: येलेनियम प्रक्रियाकों के दर्जनों दर्जनों लोग, रैम के सैकड़ों टाइटाबाइट्स. विचार यह साबित करने के लिए था कि पर्याप्त हार्डवेयर के साथ व्यवस्था माँगों को पूरा कर सकती थी.

परिणाम: सुपरdome पर भी, हम जरूरी गैर मौज़ूदा उपयोक्ता लक्ष्य को नहीं मारा. सत्र की संरचना बुनियादी रूप से टूटी थी. खड़े स्केलिंग बुरा डिजाइन नहीं बचा सकता था. सत्र सीरियलीकरण / उच्च ऊंचाई, विशाल सत्र वस्तुओं से दबाव के साथ, तंत्र बस कुछ भी नहीं किया जा सकता था - किसी भी उचित लागत पर नहीं.

सुरक्षा सपना: प्रदर्शन मुद्दों से भी बदतर, हमने एक coding त्रुटि पायी जिससे सत्र स्थिति का कारण हुआ उपयोक्ता के बीच रिसाव. उपयोक्ता का सत्र डाटा कभी उपयोक्ता B के सत्र में प्रकट होगा. यह सिर्फ शर्मिंदा नहीं था - यह भयानक था. उपयोक्ता मौजूद थे. एनएचएस लाठी मरीज़ रिकॉर्ड और इंफेक्शन सिस्टम पर पहुंचना। हमने अनजाने में एक डेटा सुरक्षा भंग व्यवस्था बनाई थी जो विभिन्न स्वास्थ्य पेशेवरों के सत्रों के दौरान संवेदनशील चिकित्सा जानकारी का विरोध कर सकता है।

क्या हुआ होगा:

  1. डिफ़ॉल्ट से रहितNext %s: उस सत्र डाटा का अधिकांश कभी अस्तित्व में नहीं होना चाहिए था
  2. स्थायी अवस्था के लिए डाटाबेस: बहु- स्टेप फ़ॉर्मेस डाटाबेस में कार्य फ्लो आईडी के साथ किया जाना चाहिए
  3. तलाशों के लिए कैश: मेग्मीश या वितरण में साझा तलाशों का हिस्सा
  4. वरीयता के लिए क्लाएंट- साइड: उपयोक्ता पसंद कुकीज़ या स्थानीय भंडारण में हो सकता है
  5. यदि आवश्यक हो तो संग्रहित सत्र: यदि सत्र वास्तव में जरूरी होता, रेड- बैकिट सत्र लोड में शामिल होते

सबक: सत्र स्थिति खड़ा नहीं है और मुश्‍किल से तराजू आड़ा (जो कि स्टिकी सत्र या वितरित किए गए भंडारों के साथ भी, आप अभी भी हर निवेदन पर लगाए जा रहे हैं)। सुपर-सेटो का प्रयोग साबित किया गया कि निर्माण समस्याओं में हार्डवेयर फेंक देना महँगे और अक्सर बेकार है।

लेकिन अधिक महत्वपूर्ण: सत्र स्थिति बग सुरक्षा viobans हो जाते हैं. थ्रेड सुरक्षित मुद्दों, जाति की स्थिति, गलत सत्र आईडी नियंत्रण - इन सिर्फ प्रदर्शन समस्याओं का कारण नहीं है, वे उपभोक्ताओं के बीच संवेदनशील डाटा पैदा कर सकते हैं. एक स्वास्थ्य के संदर्भ में (या बैंकिंग, या किसी भी विनियमित उद्योग) यह एक प्रस्ताव और संभावना आपराधिक अपराधी है.

आधुनिक सलाह:

  • यदि आप अपने आप को सत्र डाटा के कुछ के किब से अधिक की जरूरत है, आपके पास संभवतः एक डिजाइन समस्या है
  • यदि आप सत्र में संवेदनशील डाटा जमा कर रहे हैं, तो आप एक सुरक्षा हमले की सतह बना रहे हैं
  • राज्यहीन निर्माणों सिर्फ बेहतर नहीं है - वे स्वाभाविक रूप से और अधिक सुरक्षित हैं क्योंकि वहाँ लीक करने के लिए कोई सर्वर साइड स्थिति नहीं है
  • अपने राज्य प्रबंधन रणनीति फिर से विचार करें इससे पहले कि आप Sttttttttttttttttttttttt करने के लिए जाना चाहिए (या या जानकारी अधिकारी के लिए एक डेटा उल्लंघन समझाने)

कैशिंग: मैं रिसीक और आईडीिस्टीश

  • स्कोप: सर्वर प्रक्रिया (आईएससीसीसी) या वितरण (आईडीडीडीसीश)
  • उपयोग के लिए: प्राप्त डाटा, तलाश, छोटे जीवन की स्थिति
  • ट्रेफ्स: कैश अवैधीकरण, वितरित करने के लिए सीरियलीकरण

मैं ओसीश:

builder.Services.AddMemoryCache();

app.MapGet("/rates", (IMemoryCache cache) =>
{
    var key = "fx:usd:eur";
    if (!cache.TryGetValue(key, out decimal rate))
    {
        rate = 0.92m; // pretend fetch
        cache.Set(key, rate, TimeSpan.FromMinutes(5));
    }
    return Results.Ok(rate);
});

आईडीदीश (उदा., रेड):

builder.Services.AddStackExchangeRedisCache(o => o.Configuration = "localhost:6379");

app.MapGet("/feature/{name}", async (IDistributedCache cache, string name) =>
{
    var val = await cache.GetStringAsync($"feat:{name}");
    return Results.Text(val ?? "off");
});

कैश- एन्टी- स्पैम पैटर्न चेतावनी: यदि यह ठोस या आधिकारिक हो, इसे डाटाबेस में जमा करें तथा उसे वैकल्पिक रूप से कैश करें.

मैं मेपलक और आईडीपेसी के बीच चुनाव

  • मैं ओसीश:
    • तेज, प्रक्रिया में, वस्तुओं को वस्तुओं के रूप में बनाए रखें (कोई सीरियल नहीं).
    • मेमोरी दबाव, आकार सीमा, निरपेक्ष/ निर्भरि, तथा प्राथमिकता.
    • नोड्स के पार साझा नहीं है; apppoop/dopoy पर साफ.
    • प्रति-nodewsets के लिए महान, गणना की तलाश, छोटे TTLLs.
  • आईडीडीडीक (Ruds/ एसक्यूएल/etc):
    • एक खेत के पार साझेदारी; ऐक्सीशन को पुनः आरंभ करने के लिए सीरियलीकरण की आवश्यकता है (र्क्स/बाइट्स).
    • बहुत देर से ज़्यादा समय की बात है; शर्त के माध्यम से नेटवर्क और बैकएण्ड पर निर्भर करता है ।
    • पूर्ण/ अटलिंग एक्सपायरेशन एक्स- अववेल्यूशन, रेड ऑएसमैप पिल्यूशन को चालू होने पर एक्सेस के लिए अद्यतन करता है.
    • क्रॉस-nodemit, बड़ा प्रशंसक रूप से पढ़ा, फीचर, और सत्र के लिए आदर्श.

सामान्य कैश नीति

  • कैश अगल (सबसे आम):

    1. कैश कोशिश करें; 2) यदि चूक हो, स्रोत से लोड करें; 3) कैश को लिखें; 4) वापसी.
    • P: सरल; सत्य का स्रोत डाटाबेस बना रहता है.
    • कॉनस: मियाद ख़त्म होने के बाद पहली बार निवेदन धीमी है; संभव है कि हारें जाते हैं.
  • पढ़ने के लिए फ़ाइल सिस्टम: कैश बार्वर पर लोड होता है.

  • लिखने के लिए: कैश तथा समर्थन के लिए लिखते हैं.

  • लिखें: कैश को लिखें, अतुल्यकालिक रूप से स्टोर करने के लिए फ्लश करें (पारिंक: नुकसान/in).

  • ताज़ा सिर: ठंडे यादों से बचने के लिए पहले गर्म कुंजियाँ ताज़ा करें.

समय - समय पर सेवा करना, हिम्मत जुटाना और काम करना

  • निरपेक्ष एक्सपायरेशन: हमेशा स्थिर अवधि के बाद ( बजाए बाहरी डाटा ताजा करने के लिए) का समय बीतता है.
  • स्लाइडिंग एक्सपोजरिंग: एक्सेस पर टीटीएल विस्तार करता है (कार्य/उपयोक्ता डाटा के लिए उपयुक्त है.
  • आकार आधारित रिपरेशन (IMMocic): प्रविष्टि सेट. आकार तथा आकार सीमा को याद रखने के लिए कॉन्फ़िगर करें.
  • प्राथमिकता (I) कैशेसीश: कैशेएम. उच्च/ सामान्य/Lin/ nowin दबाव के तहत newaces को प्रभावित करता है.
  • जेटर: छोटे बेतरतीब ऑफसेट को TTL में जोड़ने के लिए TTL से दूर रखें

कैश फेंकना रोकें (पारेड़ों के नीचे)

  • प्रति नोड सुनिश्चित करने के लिए या बनाएँ या फिर फिर बनाएँ (Icrcrycs) प्रयोग करें.
  • डिजीशनेड: छोटे- दिन के लॉक कुंजी का उपयोग करें (AXXEXXXXE) या लाइब्रेरी समर्थन; TTL जिटर जोड़ें; पृष्ठभूमि ताज़ा करें.
  • CHAR-DRAT- CLARTE: के साथ एक द्वितीय कुंजी बनाए रखें जब तक कि नया मूल्य गणना किया जा रहा हो.

कुंजी डिजाइन तथा नाम

  • वरीयता, कोस्टेंट कुंजी: se: 123 या दसरे:Userns: 42.
  • बिना मिटाया सभी कुंजियों को अवैध करने के लिए संस्करण खण्ड शामिल करें: v2:prods: 123
  • अस्थायी-रूप: अंश या संगठन आईडी के साथ प्रश्नों और आसानी से शुद्ध करने से बचने के लिए प्रीफ़िक्स.
  • कुंजियों को छोटा रखें परंतु वर्णनित है, बिना सामान्य किए उपयोक्ता के रॉ इनपुट से बचे रहें.

कुंजी का पूर्वनिर्धारित सेट (टैग/समूह)

जब आपको बहुत से संबंधित प्रविष्टियों को गलत करना होगा:

  • संस्करणित प्रीफिक्सेस (प्रोसेफिक्स): छोटी कुंजी में वैश्विक संस्करण जांचें तथा इसके साथ कुंजी को लिखना.

    // version key: "v:products"; keys like $"{version}:product:{id}"
    var version = await cache.GetStringAsync("v:products") ?? "1";
    var key = $"{version}:product:{id}";
    

    सभी उत्पादों को रिप करने के लिए: विbss: prods (स्वाभाविक रूप से पुरानी उपसर्ग गुम हो जाएगा).

  • टैग प्रति समूह नियत करें (Rdds): प्रति टैग प्रति टैग के कुंजी का सेट रखें; अवैध, सदस्यों को लाने और मिटाने पर.

    // using StackExchange.Redis directly for sets + efficient deletes
    var mux = await ConnectionMultiplexer.ConnectAsync("localhost:6379");
    var db = mux.GetDatabase();
    var tag = "tag:category:42";
    var key = $"prod:{prodId}";
    await db.StringSetAsync(key, serialized, expiry: TimeSpan.FromMinutes(30));
    await db.SetAddAsync(tag, key); // remember membership
    
    // later, invalidate the whole tag
    var members = await db.SetMembersAsync(tag);
    if (members.Length > 0)
    {
        var keys = Array.ConvertAll(members, m => (RedisKey)m);
        await db.KeyDeleteAsync(keys);
    }
    await db.KeyDeleteAsync(tag);
    
  • Phr/ sler अवैध: एक "अवैध:keye" संदेश प्रकाशित करें; प्रत्येक नोड अपने स्थानीय मे से कुंजी हटा देता है।

  • पैटर्न के साथ स्कैन: STAN/CATTT को गर्म पथों में से दूर किया जाना चाहिए, छोटे कुंजी स्पेस पर नौकर के लिए ठीक है.

व्यावहारिक सहायक

  • मैं मेमोरीCCKC-सेट विकल्प के साथ मिलता है:
    T GetOrAdd<T>(IMemoryCache cache, string key, Func<ICacheEntry, T> factory)
      => cache.GetOrCreate(key, e =>
      {
          e.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10);
          e.SlidingExpiration = TimeSpan.FromMinutes(2);
          e.Priority = CacheItemPriority.Normal;
          e.Size = 1;
          return factory(e);
      });
    
  • JSON तथा एक्सपायंट के साथ आईडी आईडी:
    static async Task<T?> GetOrSetJsonAsync<T>(IDistributedCache cache, string key, Func<Task<T>> factory, TimeSpan ttl)
    {
        var json = await cache.GetStringAsync(key);
        if (json is not null)
            return System.Text.Json.JsonSerializer.Deserialize<T>(json);
    
        var value = await factory();
        var opts = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = ttl };
        await cache.SetStringAsync(key,
            System.Text.Json.JsonSerializer.Serialize(value),
            opts);
        return value;
    }
    

मॉनीटर व दृश्यता

  • ट्रैक हिट/mis दर और औसत लोड समय; प्रति कुंजी समूह में मुझे सम्मिलित करें (प्रोसिमस).
  • कैश जनसंख्या के आसपास लॉगिंग जोड़ें और मैं मेमोरी scips के लिए कॉल्स.
  • रेडिस के लिए, प्रमुख स्पेस हिट्स, देर - देर में, और स्मृति विभाजन; अधिमर्मी नीति उचित के रूप में नियत करें.

वास्तविक विश्‍व दर्शन

यहाँ है कि मैं वास्तव में अपने ब्लॉग मंच में Racrac का उपयोग कैसे करते हैं, परीक्षण और त्रुटि के माध्यम से विकास. मैं आप तीन असली पैटर्न दिखाएगा जटिल के लिए सरल तरीके.

पैटर्न 1: छोटे से कम डाटा ( श्रेणी के लिए)

यह मेरा पहला कवरिंग कार्यान्वयन था. ब्लॉग श्रेणियाँ अक्सर बदलता नहीं है, इसलिए 30 मिनट के लिए उन्हें कैश करें:

// From BaseController.cs
private const string CacheKey = "Categories";

private async Task<List<string>> GetCategories()
{
    baseControllerService.MemoryCache.TryGetValue(CacheKey, out var value);

    if (value is List<string> categories) return categories;

    logger.LogInformation("Fetching categories from BlogService");
    categories = (await BlogViewService.GetCategories(true)).OrderBy(x => x).ToList();
    baseControllerService.MemoryCache.Set(CacheKey, categories, TimeSpan.FromMinutes(30));
    return categories;
}

क्यों यह काम करता है:

  • वर्ग प्रत्येक पृष्ठ पर पढ़ा जाता है (लंबा में दिखाया गया है)
  • वे बहुत ही परिवर्तन करते हैं (सिर्फ तभी जब मैं नए ब्लॉग पोस्ट को नए वर्गों के साथ जोड़ता हूँ)
  • 30 मिनट के भीतर उपयोक्ता उन्हें 30 मिनट के भीतर देखते हैं
  • निरपेक्ष एम्बिएंट केवल (कोई स्लाइड नहीं) क्योंकि हमें परवाह नहीं कि यह कितनी बार पहुँचा है

मिल गया मैं मारा: शुरू में मैं एक स्ट्रिंग कुंजी "चार" का उपयोग किया। ठीक काम करता हूँ जब तक आप कई नियंत्रण है और एक ही बार फिर एक ही कुंजी को फिर से प्रयोग करता है। अब मैं स्थिर या गंभीर प्रकार की कुंजियों का उपयोग करता हूँ (यह पहले भाग है झगड़े से दूर होने से बचने के लिए)।

पैटर्न 2: पर- पाक स्थिति आकार सीमा तथा एक्सपायरेशन जैसे (संत्रकारी कार्य)

यह कैश्स अनुवाद स्थिति प्रति उपयोक्ता है. यह अधिक जटिल है क्योंकि यह सीमाओं की जरूरत है और जब तक उपयोक्ता सक्रिय है जीवित रहना चाहिए:

// From TranslateCacheService.cs - tracks translation tasks per user
public void AddTask(string userId, TranslateTask task)
{
    CachedTasks CachedTasks() => new()
    {
        Tasks = new List<TranslateTask> { task },
        AbsoluteExpiration = DateTime.Now.AddHours(6)
    };

    if (memoryCache.TryGetValue(userId, out CachedTasks? tasks))
    {
        tasks ??= CachedTasks();
        var currentTasks = tasks.Tasks;

        // Keep only the 5 most recent tasks
        currentTasks = currentTasks.OrderByDescending(x => x.StartTime).ToList();
        if (currentTasks.Count >= 5)
        {
            var lastTask = currentTasks.Last();
            currentTasks.Remove(lastTask);
        }

        currentTasks.Add(task);
        currentTasks = currentTasks.OrderByDescending(x => x.StartTime).ToList();
        tasks.Tasks = currentTasks;

        memoryCache.Set(userId, tasks, new MemoryCacheEntryOptions
        {
            AbsoluteExpiration = tasks.AbsoluteExpiration,
            SlidingExpiration = TimeSpan.FromHours(1) // Extends on access
        });
    }
    else
    {
        var absoluteExpiration = DateTime.Now.AddHours(6);
        var cachedTasks = CachedTasks();
        memoryCache.Set(userId, cachedTasks, new MemoryCacheEntryOptions
        {
            AbsoluteExpiration = absoluteExpiration,
            SlidingExpiration = TimeSpan.FromHours(1)
        });
    }
}

क्यों यह भिन्‍न है:

  • स्लाइडिंग एक्सपायरेशन: यदि उपयोक्ता अनुवाद स्थिति चेक करता है, तो कैश को 6 घंटे अधिकतम तक जीवित रखें
  • आकार सीमा: सिर्फ 5 सिर्फ एक उपयोक्ता को याद रखने के लिए कम से कम 5 कार्य बनाए रखें
  • मैनुअल प्रबंधन: मैं स्पष्ट रूप से सीमा आकार क्योंकि स्मृतिCCCT प्रविष्टि- स्तर की सीमा लागू नहीं करता (केवल पूर्ण कैश आकार)

मैंने बनाया है: शुरू में मैं कार्यों की संख्या को सीमित नहीं कर पाया. एक शक्ति उपयोगकर्ता 50+ संस्करण उत्पन्न होता है और मेरे पास एक स्मृति लीक था. अब मैं अधिकतम 5 प्रति उपयोक्ता बनाए रखें.

ट्रायल- ऑफः यह लाखों उपयोक्ताओं के लिए स्केल नहीं होगा. यदि यह एक समस्या बन जाता है, तो मैं आईडीिस्टीसीक (Rdeds) के लिए ले जाया करता हूँ या उपयोक्ता Id + प्रारंभ समय के साथ डाटाबेस में स्टोर करता हूँ.

पैटर्न ३: कैश

इस कैश से से सर्लॉगबिल का उपयोग करने में सक्षम और ट्रैक कैश सक्षम होता है:

// From UmamiDataSortService.cs - caches Umami analytics metrics
public async Task<List<MetricsResponseModels>?> GetMetrics(DateTime startAt, DateTime endAt, string prefix = "")
{
    using var activity = Log.Logger.StartActivity("GetMetricsWithPrefix");
    try
    {
        var cacheKey = $"Metrics_{startAt:yyyyMMdd}_{endAt:yyyyMMdd}_{prefix}";

        if (cache.TryGetValue(cacheKey, out List<MetricsResponseModels>? metrics))
        {
            activity?.AddProperty("CacheHit", true);
            return metrics;
        }

        activity?.AddProperty("CacheHit", false);
        var metricsRequest = new MetricsRequest
        {
            StartAtDate = startAt,
            EndAtDate = endAt,
            Type = MetricType.url,
            Limit = 500
        };

        var metricRequest = await dataService.GetMetrics(metricsRequest);
        if (metricRequest.Status != HttpStatusCode.OK) return null;

        var filteredMetrics = metricRequest.Data
            .Where(x => x.x.StartsWith(prefix))
            .ToList();

        cache.Set(cacheKey, filteredMetrics, TimeSpan.FromHours(1));

        activity?.AddProperty("MetricsCount", filteredMetrics?.Count() ?? 0);
        activity?.Complete();
        return filteredMetrics;
    }
    catch (Exception e)
    {
        activity?.Complete(LogEventLevel.Error, e);
        return null;
    }
}

क्या इस उत्पादन को तैयार करता है:

  • ऑब्सर्वेटरी: सेरिएंट गतिविधि ट्रैक कैश्स की दर और रिकॉर्ड
  • घटकर कुंजीकुंजी विभाजन से बचने के लिए तारीख सीमा तथा उपसर्ग शामिल करें
  • तिथि फ़ॉर्मेटिंग: इस्तेमाल yyyyMMdd कुंजी में इतना भिन्न समय फ़ॉर्मेट कैश साझा करें
  • नल हैंडल: यदि बाहरी सर्विस असफल हो तो वापसी न करें, कैश असफल नहीं
  • फिल्टर्ड क कैशिंग: फिल्टरिंग परिणाम को कैश करता है, रॉ अनुक्रिया नहीं

एवोल्यूशन: शुरू में मैं 10 मिनट के लिए कैश. लेकिन उममी मेरे लिए भारी हैं लाने के लिए और ज्यादा नहीं बदल रहे हैं, तो 1 घंटे ठीक है. मैंने यह खोज निकाला डेटा देखने और अत्यधिक कैश देखने के द्वारा.

क्रिया में मॉनीटर किया जा रहा है: Seqt में (Magrider), मैं प्रश्न कर सकता हूँ:

ActivityName = "GetMetricsWithPrefix" and CacheHit = false

यह मुझे बताता है मेरे कैश याद दर. यदि यह उच्च है, तो मैं TTL या कुंजी रणनीति समायोजित करता हूँ.

तीन दृष्टिकोण की तुलना करना

उर्फ पैटर्न केस का प्रयोग करें (c) |---------|----------|------------|--------------|---------------| | कोटियाँ INRWACACKS, कम से कम 30 मिस्ट्री की आवश्यकता नहीं (छोटे से छोटा) मूल लॉगिंग की जरूरत नहीं है | अनुवाद कार्य PRECT पर-user, 6h + 1h स्लाइडिंग मैनुअल (5 वस्तु अधिकतम) Advious (d!) | मेट्रिक्स STEGRESENTHANTHIENTHARENTHARECHANTHANTH (समय- set- seted)

कुंजी सबकः

  1. सरल प्रारंभ करें ( पैटर्न १), केवल जब ज़रूरत पड़े तो जटिलता जोड़ता है
  2. प्रत्येक उपयोक्ता कैश के लिए कैश मेमोरी उपयोग सीमा हमेशा के बारे में सोचें
  3. महँगे ऑपरेशनों के लिए, एक दिन से अनुमानीयता जोड़ें
  4. वास्तविक डाटा बदलने पर टीटीएल को समायोजित करें, अनुमान नहीं

जब मैं McrryCCacs का उपयोग नहीं करते हैं:

  • उपयोक्ता प्रमाणीकरण स्थिति के लिए ( बजाए प्रमाणीकरण कुकी में घोषणा)
  • खरीदारी के लिए (डीबी + वितरित किए गए कैश)
  • ब्लॉग पोस्ट सामग्री के लिए (डीबी में पहले से ही लोड हो गया है)
  • क्रॉस- सर्वर स्थिति (संपारीक/ यूसीएस की आवश्यकता होगी)

सत्यापन कुकीज़ तथा आरोप

  • स्कोप: बीते समय के लिए निवेदन के दौरान@ info: whatsthis
  • के लिए इस्तेमाल करें: पहचान, भूमिका/ रिपरेशन, प्रोफ़ाइल डाटा की छोटी मात्रा
  • ट्रेफ्स: कुकी आकार, ओवरफ्ट नहीं होना चाहिए.

कुकी अनुमोदन सेटअप करें:

builder.Services.AddAuthentication("Cookies")
    .AddCookie("Cookies", o =>
    {
        o.LoginPath = "/login";
        o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        o.SlidingExpiration = true;
    });
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();

दावाों के साथ हस्ताक्षर करें (एमवीसी/मिन):

app.MapPost("/login", async (HttpContext ctx) =>
{
    var claims = new[]
    {
        new Claim(ClaimTypes.NameIdentifier, "123"),
        new Claim(ClaimTypes.Name, "Alice"),
        new Claim(ClaimTypes.Role, "Admin")
    };
    var identity = new ClaimsIdentity(claims, "Cookies");
    await ctx.SignInAsync("Cookies", new ClaimsPrincipal(identity));
    return Results.Redirect("/");
});

पढ़ने का दावा (कोई ढेर नहीं):

[Authorize]
app.MapGet("/me", (ClaimsPrincipal user)
  => Results.Ok(new { user.Identity!.Name, Roles = user.Claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value) }));

जे. डब्ल्यू.

  • स्कोप: क्लाएंट में टोकन है, राज्य रहित सर्वर
  • के लिए इस्तेमाल करें:
  • व्यापार समाप्त: चिह्न आकार; घुमाव/ ताज़ा; स्टोर न्यूनतम दावाों का उपयोग करें यदि आवश्यक हो
builder.Services.AddAuthentication("Bearer")
   .AddJwtBearer("Bearer", o =>
   {
       o.Authority = "https://demo.identityserver.io"; // example
       o.Audience = "api";
       o.RequireHttpsMetadata = true;
   });

प्रयोक्ता:

[Authorize(AuthenticationSchemes = "Bearer")]
app.MapGet("/secure", () => "ok");

मेरिफ़ॉयर ने दृश्‍य दिखाया:

sequenceDiagram
  participant C as Client
  participant STS as Token Service
  participant API as API
  C->>STS: Authenticate (username/password)
  STS-->>C: JWT (signed)
  C->>API: GET /secure (Authorization: Bearer <jwt>)
  API->>API: Validate signature, expiry, audience
  API-->>C: 200

योग्य नागरिक: डाटाबेस और मित्र

  • स्कोप: सदा के लिए (इसे मिटाने के लिए)
  • इस्तेमाल करें: कोई भी चीज़ जिसे खो नहीं जाना चाहिए: गाड़ी, आदेश, आदेश, प्रोफाइल, लंबा सफर तय करने के लिए
  • पैटर्न: ईएफ कोर के साथ मानकयूडी; CQQRS; घटना बिगड़ रही है; डाक भेजना भरोसेमंदता के लिए पैटर्न

ईएफ कोर रंग:

builder.Services.AddDbContext<AppDb>(o => o.UseSqlServer(cs));

app.MapPost("/cart/items", async (AppDb db, AddItem cmd) =>
{
    var cart = await db.Carts.FindAsync(cmd.CartId) ?? new Cart(cmd.CartId);
    cart.Add(cmd.ProductId, cmd.Qty);
    await db.SaveChangesAsync();
    return Results.Created($"/cart/{cart.Id}", cart);
});

अनुक्रिया कैशिंग, ई- मेल टैग, और शर्त निवेदन

  • नहीं निश्चित रूप से "नहीं ले जाना" लेकिन ग्राहक/proxs द्वारा फिर से प्रतिक्रिया दिखाने के द्वारा बार-बार काम कम करता है. अक्सर प्रश्न/s स्थिति के साथ जोड़ा गया.
builder.Services.AddResponseCaching();
var app = builder.Build();
app.UseResponseCaching();

app.MapGet("/products", (HttpContext ctx) =>
{
    ctx.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue { Public = true, MaxAge = TimeSpan.FromSeconds(30) };
    return Results.Ok(new[] { new { Id = 1, Name = "Widget" } });
}).CacheOutput();

टैग उदाहरण:

app.MapGet("/resource", (HttpContext ctx) =>
{
    var version = "W/\"abc123\""; // compute based on data hash
    ctx.Response.Headers.ETag = version;
    if (ctx.Request.Headers.IfNoneMatch == version)
        return Results.StatusCode(StatusCodes.Status304NotModified);
    return Results.Text("payload");
});

अनुक्रिया scipt आउटपुटC: उत्पादों में वास्तविक विश्वव्यापी उपयोग

मैं दोनों प्रतिक्रियाओं का उपयोग भिन्न कारणों से मेरे ब्लॉग पर एक साथ करते हैं. यहाँ है क्यों आप दोनों को चाहते हैं और वे कैसे अलग हैं.

गड़बड़ी: दो कलिंग गुण?

एनईएस.ENTC कोर है दो समान दिखाई देने वाली कैश सिस्टम्स:

  1. अनुक्रिया चांस (H-8859- कलिंग): एचटीटीपी हेडर सेट करता है ()Cache-Control, Vary) खंगालक्स तथा सीडीएन को बताता है कि कैश कैसे करें ई
  2. **आउटपुट- मुख (सर्वर- बाजू)**फ़ाइलों को बन्द करने के लिए सर्वर पर निर्दिष्ट आउटपुट को कैश करें.

वे एक दूसरे को मेल खाते हैं. अनुक्रिया चांसिया क्लाएंट/CDNs संभालता है; आउटपुटCT सर्वर को साइड कैशिंग संभालता है.

मेरे ब्लॉग पोस्ट क्रिया (दोनों कैश्स लागू होते हैं)

// From BlogController.cs
[Route("{slug}")]
[HttpGet]
[ResponseCache(Duration = 300, VaryByHeader = "hx-request",
    VaryByQueryKeys = new[] { nameof(slug), nameof(language) },
    Location = ResponseCacheLocation.Any)]
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request" },
    VaryByQueryKeys = new[] { nameof(slug), nameof(language) })]
public async Task<IActionResult> Show(string slug, string language = "en")
{
    var post = await blogViewService.GetPost(slug, language);
    if (post == null) return NotFound();

    // ... populate user info, comments, etc ...

    if (Request.IsHtmx()) return PartialView("_PostPartial", post);
    return View("Post", post);
}

जब कोई अनुरोध करता है तो क्या होता है /blog/my-post:

  1. आउटपुटCT जांच प्रथम: क्या मेरे पास इसके लिए कैशेड प्रतिक्रिया है my-post + en भाषा?

    • हिट: रिटर्न कैश्ड एचटीएमएल, क्रिया विधि कभी नहीं चलाता (तेज! ~ 1ms)
    • कुमारी: कार्रवाई, रेंडर दृश्य, 3600 सेकेंड के लिए कैश परिणाम (1 घंटे)
  2. अनुक्रिया (_C): आउटपुटCCK के बाद प्रतिक्रिया उत्पन्‍न होती है, प्रतिक्रिया प्रतिक्रिया बताता है:

    Cache-Control: public, max-age=300
    Vary: hx-request
    
  3. ब्राउज़र कलोनComment: 300 सेकंड के लिए ब्राउज़र कैश जवाब (5 मिनट). उपक निवेदन उसी उपयोक्ता से भी रद्द नहीं होता.

  4. सीडीएन कैशिंग (यदि बादल के उपयोग से पता लगाएँ/ तेज: सीडीएन कैश 5 मिनट के लिए. उपयोक्ताओं ने दुनिया भर में सीडीN को मारा, मेरे सर्वर नहीं.

अलग - अलग अवधि क्यों? (300 v0)

[ResponseCache(Duration = 300)]    // 5 minutes client/CDN cache
[OutputCache(Duration = 3600)]     // 1 hour server cache

कारण:

  • सर्वर कैश अब 1 घंटे का है: मैं अपने सर्वर को नियंत्रित करता हूँ, मैं कैश को शुद्ध कर सकता हूँ यदि मैं एक पोस्ट अद्यतन करता हूँ
  • क्लाएंट कैश छोटा है (5 मिनट): मैं उपयोगकर्ता ब्राउज़र या CDN आसानी से शुद्ध नहीं कर सकते; 5 मिनट एक कोमल scriptness विंडो है
  • व्यापार- ऑफ: यदि मैं पोस्ट संपादित करता हूँ, तो नई सामग्री प्रकट होती है:
    • सर्वर के किनारे: तत्काल (मैं कैश अवैध कर सकता हूँ)
    • सीडीएन/ ब्राउज़र: 5 मिनट के भीतर (या मैं सीधे ही सीडीएन को साफ करता हूँ)

एवोल्यूशन: शुरू में तो मैं 5 मिनट में दोनों था. लेकिन इसका मतलब था कि मेरा सर्वर हर 5 मिनट फिर से दे रहा था, भले ही सामग्री में परिवर्तन न हों. अब:

  • सर्वर खुशी से एचटीएमएल को 1 घंटे के लिए कैशित करता है
  • क्लाएंटों को ताजा- सरल सामग्री मिलता है हर 5 मिनट

HMAX के लिए दर्ज किया गया

VaryByHeader = "hx-request"  // ResponseCache
VaryByHeaderNames = new[] { "hx-request" }  // OutputCache

ऐसा क्यों: HMAX निवेदन शामिल हैं hx-request: true शीर्षक. मैं अलग जवाब देता हूँ:

  • पूरा निवेदनखाका के साथ एचटीएमएल पृष्ठ पूर्ण करें
  • एचएमएमएक्स निवेदनख़ाका के बगैर आंशिक दृश्य

के बगैर VaryBy, कैश गलत फ़ॉर्मेट को लौटा देगा. VaryBy, मैं हर पृष्ठ के दो संस्करण कैश.

उदाहरण:

User requests /blog/my-post → Cache key: "blog/my-post:en:hx=false" → Full HTML cached
HTMX requests /blog/my-post → Cache key: "blog/my-post:en:hx=true" → Partial HTML cached

भाषा तथा पधन के लिए वेलिडेशनComment

[ResponseCache(VaryByQueryKeys = new[] { nameof(slug), nameof(language) })]
[OutputCache(VaryByQueryKeys = new[] { nameof(slug), nameof(language) })]

इस के बिना समस्या: /blog/my-post?language=fr अंग्रेज़ी कैश्ड संस्करण सेवा करते ।

वीआई के द्वाराQuery @ info: whatsthis कैश प्रविष्टि अलग करें:

  • /blog/my-post?language=en कैश कुंजी में "en" शामिल हैं
  • /blog/my-post?language=fr कैश कुंजी में "fr" शामिल हैं

ब्लॉग सूची से वास्तविक उपयोग:

[Route("blog")]
[ResponseCache(Duration = 300, VaryByHeader = "hx-request",
    VaryByQueryKeys = new[] { "page", "pageSize", "startDate", "endDate", "language", "orderBy", "orderDir" })]
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request" },
    VaryByQueryKeys = new[] { "page", "pageSize", "startDate", "endDate", "language", "orderBy", "orderDir" })]
public async Task<IActionResult> Index(int page = 1, int pageSize = 20, /* ... */)

कैश विस्फोट चेतावनी: पैरामीटर = अलग कैश प्रविष्टि का प्रत्येक अद्वितीय संयोजन:

  • page=1&pageSize=20&language=en नीचे एक प्रविष्टि
  • page=2&pageSize=20&language=en ✔ एक और प्रविष्टि
  • page=1&pageSize=10&language=en ✔ एक और प्रविष्टि

माइिगेशन:

  • अधिकतम कैश आकार (कम से कम- मुद्रा- से- कम उपयोग में)
  • सामान्य पैरामीटर कैश (पेज 1, डिफ़ॉल्ट पृष्ठ आकार)
  • उपयोग किए जा रहे संयोजन को कैश याद कर सकते हैं (प्रचलित किया जा सकता है)

सेटअप जरूरी

अनुक्रिया- केस बक्स के बाहर काम करता है, लेकिन के लिए आउटपुटCTCKt आपको सेटअप की आवश्यकता है:

// Program.cs
builder.Services.AddOutputCache(options =>
{
    options.MaximumBodySize = 64 * 1024 * 1024; // 64 MB max response size
    options.SizeLimit = 100 * 1024 * 1024; // 100 MB total cache size
});

var app = builder.Build();
app.UseOutputCache(); // Must be in middleware pipeline

जब आउटपुटCT की मदद नहीं करता है

आउटपुटCTCT के लिए छोड़ दिया गया है:

  • सत्यापित किए गए निवेदन ( भिन्न उपयोक्ता भिन्न डाटा देखें)
  • रूट/ आउटपुट/डीवेशन (सिर्फ प्राप्त/ महत्वपूर्ण कैश)
  • के साथ अनुक्रिया Set-Cookie शीर्षिका
  • प्रतिक्रिया जो सुस्पष्ट रूप से नियत है Cache-Control: no-store

उदाहरण जहाँ मैं इसका उपयोग नहीं करता:

// Comment submission - authenticated, POST, and per-user
[HttpPost]
[Authorize]
public async Task<IActionResult> AddComment(CommentModel model)
{
    // No caching attributes - this is user-specific and changes state
}

काम करने में कुशल

मैं Piences का उपयोग ट्रैक करने के लिए (मेरे आईएओ के माध्यम से) का उपयोग करें:

// Pseudo-code for metrics
cache_hits_total{cache="output"} 45230
cache_misses_total{cache="output"} 892

मेरा कैश हिट दर: ~98% ब्लॉग पोस्टों के लिए (सबसे लोकप्रिय पोस्टों को बार - बार मारता है).

प्रभाव:

  • कैशिंग के बगैर: ~50ms औसत प्रतिक्रिया समय (डीबीबी क्वैरी + मार्क रेंडरिंग)
  • आउटपुटCT के साथ: कैश्ड जवाब के लिए ~1- 2ms
  • 25x गति

जब मैं अस्थायी रूप से कैशिंग करता हूँ

कभी कभी मैं डिबगिंग कर रहा हूँ और हर बार ताजा जवाब की जरूरत है:

// During development, comment out caching
// [ResponseCache(Duration = 300, ...)]
// [OutputCache(Duration = 3600, ...)]
public async Task<IActionResult> Show(string slug, string language = "en")

या एनवायरनमेंट- विशिष्ट विन्यास इस्तेमाल करें:

#if DEBUG
    // No caching in development
#else
    [ResponseCache(Duration = 300, ...)]
    [OutputCache(Duration = 3600, ...)]
#endif

बेहतर तरीका: कॉन्फ़िगरेशन इस्तेमाल करें:

[ResponseCache(Duration = responseCacheDuration, ...)]

कहाँ responseCacheDuration विकास में 0 है, 300 उत्पादन में.

इस दोहरे-श रणनीति की इकाई और cases

प्रोविडेंस:

  • सर्वर ऊर्जा: आउटपुटCT सीपीयू/DB लोड को 98% द्वारा कम करता है
  • क्लाएंट/sDN लाभ: जवाब में जवाब देने से मेरी मैडाइ को नुकसान पहुँचता है और पूरी दुनिया में देर हो जाती है
  • गतिशीलता: सर्वर vs vs ग्राहक के लिए भिन्न टीएल
  • कीमत बचत: कम से कम डीबोज़, कम बिटरेट

कनेक्शनः

  • स्टेलापन: क्लाएंटों को बढ़ाने के लिए सामग्री अद्यतन 5 मिनट तक ऊपर ले जाता है
  • कैश अवैध जटिलता: पोस्ट को अद्यतन करने के लिए सर्वर व सीडीएन कैश को अवैध रूप से अद्यतन किया जाना चाहिए
  • स्मृति प्रयोग: सर्वर मेमोरी में एचटीएमएल का प्रतिनिधित्व करता है
  • डिबगिंग गड़बड़ी: कभी कभी कैश भूल जाना और आश्चर्य है कि परिवर्तन क्यों नहीं प्रकट होता

जब मैं कैशिंग छोड़ दूँ:

  • वास्तविक समय डाटा (किंग कीमत, खेल)
  • निजी सामग्री (उपयोक्ता विशिष्ट सलाह)
  • कम- fontrowd पृष्ठ (किंग ऊपर > लाभदायक है)
  • पृष्ठ जो बहुत बार बदलता है

मेरा फैसला: ज़्यादातर लोगों के लिए एक ब्लॉग के लिए और उच्च पठन अनुपात के लिए, दो सीलिंग एक बहुत ही जीतने वाला है. मैं अधिकारी पैनलों में इस का उपयोग जल्दी से डाटा बदलने के साथ नहीं करेगा.


ब्लॉग, दृश्य डाटा तथा टेंप डाटा देखें: नियंत्रक- व्यू राज्य (और मैं ज़्यादातर इन दोनों से कैसे दूर रह सकता हूँ)

ये तीन अक्सर उलझन में हैं. यहाँ वे कैसे अलग हैं और मैं उत्पादन में वास्तव में क्या इस्तेमाल करते हैं.

इन तीनों की तुलना

// ViewData: string-keyed dictionary
ViewData["Title"] = "Blog";
ViewData["Categories"] = new List<string> { "ASP.NET", "C#" };

// ViewBag: dynamic wrapper around ViewData
ViewBag.Title = "Blog";
ViewBag.Categories = new List<string> { "ASP.NET", "C#" };

// TempData: survives one redirect (backed by session or cookie)
TempData["Message"] = "Post saved!";
return RedirectToAction("Index");

दिखाई दे रहा है (R) |---------|----------|---------|----------| | क़िस्म | ViewDataDictionary कामों के लिए अर्ज़ी भरनीName ITempDataDictionary | | जीवन समय भौगोलिक मौजूदा निवेदनmahjongg मौजूदा आग्रह एक पुनर्निदेशित कर रहा है | कुंजी पहुँच स्ट्रिंग कुंजी यूनिडायरेक्शनल | सुरक्षा क़िस्म माइक्रोसेंकेंड कुछ नहीं (सेकेंड की जरूरत है) ( पाएगा)Nonecal-reces)None | कम्पाइल- समय जाँच एनटीएलएमNext %s | रूट से बच गए एनटीएलएम Noएमएमई जीएमईName

क्या मैं वास्तव में उपयोग करता हूं: वैश्विक खाका डाटा के लिए दृश्यBag

मेरे चिट्ठे में, मैं सिर्फ देखने के लिए दृश्य का उपयोग करता हूँ नियंत्रण से बाहर डाटा (नात्र, वर्ग, आदि) साझा करने के लिए।

// From BaseController.cs - runs before every action
public override async Task OnActionExecutionAsync(ActionExecutingContext filterContext,
    ActionExecutionDelegate next)
{
    logger.LogInformation("OnActionExecutionAsync");

    if (!Request.IsHtmx())
    {
        // Analytics settings for layout
        ViewBag.UmamiPath = AnalyticsSettings.UmamiPath;
        ViewBag.UmamiWebsiteId = AnalyticsSettings.WebsiteId;
        ViewBag.UmamiScript = AnalyticsSettings.UmamiScript;
    }

    logger.LogInformation("Adding categories to viewbag");
    ViewBag.Categories = await GetCategories(); // Cached list

    await base.OnActionExecutionAsync(filterContext, next);
}

तो मेरे खाका में,_Layout.cshtml):

@if (ViewBag.Categories is List<string> categories)
{
    <nav>
        @foreach (var cat in categories)
        {
            <a asp-controller="Blog" asp-action="Category" asp-route-category="@cat">@cat</a>
        }
    </nav>
}

@if (!string.IsNullOrEmpty(ViewBag.UmamiPath))
{
    <script async src="@ViewBag.UmamiScript"
            data-website-id="@ViewBag.UmamiWebsiteId"></script>
}

क्यों यह नमूना कार्य करता है:

  • वैश्विक: हर पृष्ठ को अलग श्रेणी की आवश्यकता होती है
  • एक बार गणना किया गया: आधार नियंत्रणकर्ता हर काम से पहले दौड़ता है
  • एचएसएमएक्स अनुकूलन: आंशिक अनुरोधों पर एक औपचारिक स्क्रिप्ट छोड़ें (HMX)
  • कैश्ड: वर्ग कैशे हैं (मैं अपने रिपरिक पैटर्न को ऊपर देखते हैं) तो डीबी हर निवेदन को मार नहीं देते

मैंने जल्दी बनाया है: मैं सेटिंग कर रहा था ViewBag.Categories हर एक क्रिया विधि में । OnActionExecutionAsync आधार नियंत्रण में यह हल किया.

पृष्ठ- विशिष्ट डाटा के लिए बीग देखें (प्रयोग योग्य पैटर्न को प्रदान किया जा सकता है)

// From BlogController.cs
[Route("category/{category}")]
public async Task<IActionResult> Category(string category, int page = 1, int pageSize = 10)
{
    ViewBag.Category = category; // Used in view for heading
    ViewBag.Title = category + " - Blog"; // Used in layout <title>

    var posts = await blogViewService.GetPostsByCategory(category, page, pageSize);
    // ... populate posts model ...

    if (Request.IsHtmx()) return PartialView("_BlogSummaryList", posts);
    return View("Index", posts);
}

दृश्य में:

@{
    ViewData["Title"] = ViewBag.Title; // Standard MVC convention for <title>
}

<h1>Category: @ViewBag.Category</h1>

यह ठीक है क्योंकि:

  • सरल स्केल मान ( वाक्यांश, int)
  • सिर्फ दृश्य में उपयोग में आता है, न कि आसपास से पारित किया गया
  • वैकल्पिक जोड़ दिया जाएगा Title और Category प्रत्येक दृश्य मॉडल को गुणों में गुण

क्या मैं दूर हूँ: दृश्य में जटिल वस्तुओं को दृश्य में

एन्टी- पैटर्न:

// DON'T DO THIS
ViewBag.User = new UserViewModel { Name = "Scott", IsAdmin = true };
ViewBag.Posts = new List<Post> { ... };
ViewBag.Metadata = new { Tags = new[] { "a", "b" }, Date = DateTime.Now };

समस्याएँ:

  • कोई कंपाइल- रहित समय सुरक्षा नहीं (यूपोजरी) ViewBag.Usr असफल एट
  • ट्रैक करने के लिए कठिन कि क्या डेटा दृश्य में उपलब्ध है
  • जाँच कठिन बनाता है (माना को देखने की जरूरत है Bagig शब्दकोश का निरीक्षण करने के लिए)
  • कोई इनस्टिटेंस नहीं

बेहतर: अत्यंत- क़िस्म का दृश्य मॉडल:

// DO THIS instead
public class BlogIndexViewModel : BaseViewModel
{
    public string Category { get; set; }
    public List<PostSummary> Posts { get; set; }
    public PaginationInfo Pagination { get; set; }
}

public IActionResult Category(string category, int page = 1)
{
    var model = new BlogIndexViewModel
    {
        Category = category,
        Posts = await GetPosts(category, page),
        // Inherited from BaseViewModel:
        Authenticated = user.LoggedIn,
        Name = user.Name,
        AvatarUrl = user.AvatarUrl
    };
    return View("Index", model);
}

हीरो: मैं इसका इस्तेमाल नहीं करता (और यहाँ क्यों है)

मानक टेंप डाटा केस का प्रयोग करें:

[HttpPost]
public IActionResult SavePost(PostModel model)
{
    // Save post...
    TempData["SuccessMessage"] = "Post saved successfully!";
    return RedirectToAction("Index");
}

public IActionResult Index()
{
    // TempData["SuccessMessage"] available here (consumed on read)
    return View();
}

क्यों मैं अपने ब्लॉग में टेंप डाटा का प्रयोग नहीं करता:

  1. मैं पुनर्निदेशित के बजाय HMMX प्रयोग करें: HMMMX के द्वारा मेरे फ़ॉर्म जमा करें और इनलाइन सफलता/त्रुटि संदेश के साथ आंशिक राय वापस.
[HttpPost]
public async Task<IActionResult> Submit(ContactViewModel model)
{
    if (!ModelState.IsValid)
        return PartialView("_ContactForm", model); // Show errors inline

    await sender.SendEmailAsync(contactModel);

    // Return success view directly (no redirect)
    return PartialView("_Response", new ContactViewModel
    {
        Email = model.Email,
        Name = model.Name,
        Comment = "Message sent!"
    });
}
  1. **पारंपरिक PAG के लिए (प्रेषित- री- आउटिंग)**लेकिन मैं बेहतर यूएक्स के लिए संभव जब यादों से दूर रहना पसंद करता हूँ.

जब टेंप डाटा समझ आता है:

  • पोस्ट- रूट के बाद पूरा पृष्ठ पुनर्निदेशित के साथ पारंपरिक एमवीसी ऐक्सीक
  • मल्टी- स्टेप विजार्ड जहाँ आप कदमों के बीच पुनर्निदेशित करते हैं
  • सत्यापन तुल्यकालन के बाद संदेशों को फ्लैश करें

टेंप डाटा मिला: कुकीज़ द्वारा डिफ़ॉल्ट पर वापस (बीस. वेनॉट कोर 2. 0). यदि आप बहुत सारे वस्तुओं को स्मिट्स में डाल देते हैं तो आप कुकी को हर निवेदन के साथ भेज रहे हैं. बड़ी स्थिति के लिए, सत्र समर्थन या डीबी के साथ इस्तेमाल करें.

तेज निर्णय ट्री

flowchart TD
    A[Need to pass data to view?] --> B{What kind?}
    B -->|Global layout data| C[ViewBag in BaseController]
    B -->|Simple page-specific| D[ViewBag in action]
    B -->|Complex model| E[Strongly-typed ViewModel]
    B -->|Survive redirect| F{Using HTMX?}
    F -->|Yes| G[Return partial with message]
    F -->|No| H[TempData for flash message]

मेरे नियम:

  1. वैश्विक खाका सामग्री के लिए Gag देखें (नादी, nabs, रोटीदार)
  2. सरल पृष्ठ शीर्षक/ हेडन्स के लिए Bag देखें (वैकल्पिक; दृश्य मोड का प्रयोग कर सकता है)
  3. कॉम्प्लेक्स वस्तुओं के लिए कभी देखें (n) (स्फीयर्स दृश्य इस्तेमाल करें)
  4. डाटा कभी नहीं देखें (Vag में अच्छा सिंटेक्स है)
  5. केवल अगर आपको वास्तव में PRODUG की जरूरत है (मैं नहीं, HMAX के लिए धन्यवाद)

पैटर्न: विजार्ड तथा मल्टी- स्टेप प्रवाह

कौन - सी सरकार का इस्तेमाल करती है?

flowchart TD
  A[Start Wizard] --> B{Short-lived?\nSingle browser?}
  B -- Yes --> S[Session/TempData]
  B -- No/Complex --> D[DB + key in route]
  S --> PRG[Use PRG between steps]
  D --> PRG
  • छोटा, एकल- टेक: चरणों के बीच सत्र सत्र या मेक्रो डाटा.
  • क्रॉस- अप/क्रम: DB तक जारी रखें, यूआरएल में कुंजी ले जाएँ.

उदाहरण (डीबी + रूट कुंजी):

app.MapPost("/wizard/{id}", async (AppDb db, Guid id, StepInput input) =>
{
    var flow = await db.Flows.FindAsync(id) ?? new Flow(id);
    flow.Apply(input);
    await db.SaveChangesAsync();
    return Results.Redirect($"/wizard/{id}/next");
});

पैटर्न: टेंप डाटा के साथ फ्लैश संदेश

  • रूट में सेट करें; जब पुनर्निदेशित हो, तो एक बार पढ़ें.
TempData["Flash"] = "Profile saved";
return RedirectToAction("Index");

राजेर दृश्य:

@if (TempData["Flash"] is string flash) {
  <div class="alert alert-info">@flash</div>
}

पैटर्न: खरीदारी कारटी

  • छोटा गाड़ी: सत्र (यदि आपका स्केल छोटा है और आपके पास स्टिकी/दूरी सत्र है).
  • बड़ा कार्ट्रि/ multide: कुकी या URL में डीबी + गाड़ीid. कैश को कम करने के लिए कैश.
flowchart LR
  U[User] -- cart-id cookie --> S[Server]
  S --> DB[(Cart Table)]
  S <--> Cache[Distributed Cache]

सुरक्षा, गोपनीयता, और कम्पलीशन जांचसूची

  • सभी क्लाएंट- प्रबंधन स्थिति जा रहा है: क्वैरी, शीर्ष, फ़ॉर्म, कुकीज़, डब्ल्यूटी दावा करता है.
  • संवेदनशील क्लाएंट- टेक्ड स्थिति संरक्षित करें: आपके कुकीज़ के लिए डाटा सुरक्षा प्रयोग करें, प्रश्नों में गुप्त प्रविष्टि कभी नहीं भंडारित करें.
  • कुकी फ्लैग सेट करें: Secure, HttpOnly, SameSite, IsEssential (यदि सहमति/ अनुकूलनशीलता से आवश्यक हो)
  • विशेषाधिकार परिवर्तनों पर प्रमाणीकरण कुकीज़ को फिर से प्रारंभ करें; दावा करते हैं कि कम हैं.
  • सर्वर के किनारे के लिये आराम से एनक्रिप्ट करें, कुंजी घूर्णन (डायल सुरक्षा कुंजी), जे.
  • GDRP/CCP: उपयोगकर्ता डाटा निर्यात/dation पथ प्रदान करता है; कम से कम ध्यान दें.

निर्णय मैट्रिक्स (CSSScent शीट)

classDiagram
  class Items {
    +Per-request only
    +Great for middleware->endpoint handoff
  }
  class QueryRoute {
    +Explicit, linkable
    -User-controlled
  }
  class Headers {
    +Tracing, idempotency
    -Noisy, untrusted
  }
  class Cookies {
    +Persist small prefs
    -Size, perf, consent
  }
  class TempData {
    +One-redirect messages
    -Ephemeral
  }
  class Session {
    +Conversational state
    -Scaling complexity
  }
  class MemoryCache {
    +Fast, in-proc
    -Not shared across instances
  }
  class DistributedCache {
    +Shared across servers
    -Serialization, ops
  }
  class AuthCookieClaims {
    +Identity, roles
    -Don’t overstuff
  }
  class JWT {
    +Stateless, cross-domain
    -Revocation/rotation
  }
  class DB {
    +Durable, authoritative
    -Latency, complexity
  }

क्विक लेने का तरीका:

  • एक से अचानक फ्लैश की जरूरत है ? Uphatatom.
  • एक सत्र में अनेक निवेदनों के दौरान विशेषज्ञ की आवश्यकता है? (या DB + कुंजी यदि लंबा सफर/ pri-rodi-rewiod.)
  • स्थिति के लिए अपर्याप्तता और राज्य- पद की जरूरत है? जे. डब्ल्यू.टी.
  • केवल इबराहीम के अंदर डेटा पास करने की जरूरत है?
  • मैं बार - बार गुस्सा करती हूँ; एक खेत के पार IDidiociodik.

एमवीसी राजेर पृष्ठ वी- एपीआई्स: उसी तरह के मानक, भिन्न आकार

सभी तीन tuts एक ही पुरातन पर बैठते हैं ( सर्वोत्तम संदर्भ, मॉडल बाइंडिंग, प्राधिकार, डेटा सुरक्षा). ऊपर दिए उदाहरण दिखाते हैं कि एपीआई्स में अधिकतर अलग होते हैं:

  • न्यूनतम एपीआई: मार्ग/ठी/पर्शन/ लोगो से पैरामीटर बाइंडिंग; रिटर्न Results.*.
  • एमवीसी: विशेषताएँ, फ़िल्टर, मॉडल बाइंडिंग को पैरामीटर/ दृश्य मॉडल में बाध्य करता है.
  • रोटर पृष्ठ: लिंक बनाने के लिए पृष्ठ हैंडलर्स तथा टैग सहायकों के साथ पृष्ठ हैंडलर्स.

वे सभी यहाँ चर्चा की गयी एक ही स्थिति में भाग लेते हैं ।


प्लास्टिक तथा एन्टी- वायरस

  • कुकीज़ या टेंप डाटा में बड़े या संवेदनशील डाटा भंडारित किया जा रहा है.
  • सहीपन के लिए कैश पर निर्भर किया जा रहा है (यह एक कैश नहीं है).
  • सर्वर जांच किए बगैर ग्राहक के भेजे गए मार्ग/query फ्लैग पर सत्यापन बनाया जा रहा है.
  • अजीब दावे के साथ कनेक्शनिंग कुकीज़ या डब्ल्यूआईटीसी.
  • सत्र वितरण रणनीति के बिना (स्थानीय कार्य करता है, स्केल पर टूटता है).

वास्तविक विश्वव्यापी राज्य प्रबंधन: क्या मैं वास्तव में उपयोग करता हूं (और उपयोग नहीं)

इन सभी विकल्पों को दिखाने के बाद, मेरा ईमानदारी से पता चलता है कि मेरे ब्लॉग मंच के लिए उत्पादन में क्या काम करता है।

मेरी स्थिति प्रबंधन स्टैक ( आवृत्ति के क्रम में)

DIRERYEALLLLYEARTEANT का प्रयोग करें |-----------|-----------|-----------|--------------| | मैं मेमोरीCak बहुत अधिक उच्च पंखीय श्रेणी, मेगन, अनुवाद कार्य sciptivix | आउटपुटCTCKt SMTP उच्च दिन का अधिकतम भारदार ब्लॉग पोस्टों को दिया गया है, जो कि UNDRICWWL की सूची देते हैं | अनुक्रिया- केस INBTH ("1एलीकिंग शीर्ष CTHATKSTCKT के साथ संचालित करता है | बाजू पट्टी देखें (a) डिजीटीटीटीटीएस विन्यास, पृष्ठ शीर्षकों को सादा सामान के लिए संक्षिप्त रूप से ठीक करता है | प्रमाणीकरण सीडी- एसक्यूएल उपयोक्ता पहचान, प्रशासक झंडा- ऋण के लिए दायाँ दायाँ औजार | रूट/Query मध्यम विसम्मेलन, फ़िल्टरिंग, clugssmoltest और लिंकेबल | डाटाबेस ब्लॉग ब्लॉग पोस्ट, टिप्पणी करता है, स्टेटCART सत्य का स्रोत | कुकीज़ DURENT उपयोक्ता वरीयता (प्रयोग) DULLONEDLLLONK, अभी तक समर्थित नहीं है | सत्र अतुल्यकालिक स्थिति कभी नज़रअंदाज़ नहीं की - औऱ कोई वितरित स्टोर सेटअप सेटअप सेटअप नहीं किया गया | टेंप डाटा DTATCKS - प्रमाण की आवश्यकता नहीं | Yiva. Tiks गीत-सूची कभी नहीं इस्तेमाल किया गया | आईडीदीश INBLAN - gowCKS एकल सर्वर (अब के लिए) Advirous सर्वर

उत्पादन अनुभव से विस्तृत

मैं मेमोरीCak scipta

मैं इसके लिए क्या इस्तेमाल करता हूं:

  • श्रेणियाँ सूची (विश्वव्यापी, 30 मिनट TTL)
  • पर-user अनुवाद कार्य ट्रैक किया जा रहा है (6hh + 1 तोड़)
  • बाहरी एपीआई प्रतिक्रिया (सुन्स, 1 tTL)

अभ्यास:

  • तेज (in- प्रक्रिया में)
  • कोई सीरियलीकरण नहीं
  • ~95% द्वारा सीमित DB/JA लोड
  • लागू करने के लिए आसान
  • सेंस-लॉग के द्वारा ऑब्सविटी

मैनें मारा है:

  • स्मृति रिसाव अगर आप प्रति-उपयोक्ता कैश सीमा नहीं है
  • फिर से प्रारंभ करने पर साफ (मेरा उपयोग योग्य)
  • सर्वर पर साझा नहीं (एक इंस्टैंस के लिए अच्छा)
  • कैश का अवैध भाग मैनुअल (साफ- साफ) है

स्केलिंग सीमाः अगर मैं कई सर्वरों के लिए मिलता है, मुझे साझा स्थिति के लिए आईडीiriocioc (Reds) की आवश्यकता होगी. अब, एकल सर्वर + स्मृति कैश सही है.

आउटपुटCT + reCTCCT

मैं इसके लिए क्या इस्तेमाल करता हूं:

  • ब्लॉग पोस्ट रेंडरिंग (1 घंटे सर्वर, 5 मिनट ग्राहक/DN)
  • ब्लॉग सूची/ श्रेणी पृष्ठ
  • पंचांग डाटा

अभ्यास:

  • 25x गति (50 मीक्स 2ms)
  • बिना पसीना चलाते वक्‍त भारी ट्रैफ़िक में कटौती कीजिए
  • सर्वर वीएस क्लाएंट के लिए अलग टीटीएल
  • HMMAX (के द्वारा विस्तृत) के साथ समुद्री कार्य करता है
  • हृदय रोग - प्रतिरक्षा तंत्र द्वारा प्रभावित किया जा सकने योग्य प्रभाव

मैनें मारा है:

  • डिबगिंग गड़बड़ी (अनुप्रयोगी कैश पर है)
  • कैश को अनेक क्वैरी पैरामीटरों से विस्फोट किया जा रहा है
  • स्टेसी विंडो (5 मिस्टर्स के लिए)
  • सामग्री अद्यतन पर दस्ती रूप से असत्य की आवश्यकता है

के लिए उत्तम: सिर्फ स्थिर सामग्री के साथ पढ़ें. व्यक्तिगत या वास्तविक समय डाटा के लिए अच्छा नहीं है.

बी. बी.

मैं इसके लिए क्या इस्तेमाल करता हूं:

  • वैश्विक ख़ाका डाटा (नायिक, वर्ग)
  • पृष्ठ शीर्षक

अभ्यास:

  • खाका- लेवल डाटा के लिए सरल तथा त्वरित
  • एक बार बेस कंट्रोलर में सेट करें, उपलब्ध हर जगह
  • कैश्ड श्रेणियाँ सूची के साथ भले काम करता है

मैनें मारा है:

  • कोई क़िस्म सुरक्षा नहीं (संत्र चालू होने पर असफल)
  • जटिल डाटा के लिए ताश का उपयोग करने में बाधित
  • जाँचने के लिए कठिन

मैं का पालन करें: साधारण कैंची के लिए सिर्फ देखें. जटिल वस्तुओं को दृश्य में चला जाता है.

प्रमाणीकरण विधि

मैं इसके लिए क्या इस्तेमाल करता हूं:

  • उपयोक्ता ID, नाम, ईमेल, अवतार URL
  • प्रशासक झंडा (क्रिया जाँच करें) sub कॉन्फ़िग के विरुद्ध दावा करें)

अभ्यास:

  • सुरक्षित (हस्ताक्षरित कुकी, डाटा सुरक्षा)
  • एनईएसपी के साथ स्वचालित.
  • के द्वारा उपलब्ध User.Claims हर जगह
  • एक्सपोजरिंग उपयोक्ता लॉगइन रखे रहते हैं

मैनें मारा है:

  • कुकी आकार सीमा ('nest दावा नहीं)
  • प्रक्षेपण स्थिर हैं जब तक कि पुनः चालू नहीं हो जाता
  • यदि मैं कोई दावा जोड़ता हूँ (जैसे कि "पंचांग"), री-श-श्शन कुकी को फिर से जोड़ने की आवश्यकता है

सर्वोत्तम अभ्यासः दावा करते हैं कि कम से कम और स्थिर रखने का दावा करते हैं।

बातें मैं उपयोग नहीं करते (और क्यों)

सत्र (कभी नहीं प्रयोग में):

  • वितरित स्टोर की आवश्यकता होगी (आरएसएस)
  • न्यूनतम लाभ के लिए जटिलता जोड़ता है
  • मेरे प्रयोग के मामलों से बेहतर सेवा की जाती है:
    • प्रमाणीकरण विधि
    • मैं मेमोरीCaks (कम दिनों की स्थिति)
    • डाटाबेस (सबसे योग्य स्थिति)

टेंप डाटा (कभी नहीं उपयोग में):

  • HMAX पोस्ट- री- आउट पैटर्न को मिटाया
  • फ़ॉर्मेड संदेशों के साथ वापस आंशिक दृश्य
  • रूटों से बचने की आवश्यकता नहीं

+/- संदर्भ. यह वेम (कभी नहीं इस्तेमाल किया):

  • प्रति प्रस्ताव स्थिति के लिए एक प्रयोग नहीं किया गया है
  • मेरे मध्य एलबम नियंत्रकों की गणना नहीं करता
  • अगर मुझे दस जांच की जरूरत है, मैं इसका उपयोग करेंगे

आईडीदीश (कभी इस्तेमाल नहीं किया गया):

  • एकल सर्वर तैनातिंग
  • मैं मेमोरी दर्द सभी जरूरतओं को पूरा करता है
  • यदि मैं बहुत सर्वरों के लिए स्केल करता हूँ तो रेडिस का प्रयोग करें

मेरे पास का एवोल्यूशन

फेस 1 (प्रयोगात्मक): कम ट्रैफिक के लिए ठीक काम किया ।

फेस 2 (पहले): मैंने वर्गों के लिए रिपर जोड़े. तुरंत डीबी लोड की कमी को नोट किया. यह सरल: 30 मिनट TTL, कोई फैंसी तर्क.

फेस 3 (रद्द कर रहा है): जब ट्रैफिक चालू हो रहा हो तो ब्लॉग पोस्ट के लिए आउटपुटCocents जोड़े. भारन प्रदर्शन सुधार. आरंभिक त्रुटि: केवल 5 मिनट के लिए ही कैश्ड. सामग्री की गति 1 घंटे की गति बढ़ाने के बाद स्थिति में परिवर्तनों को कम से कम किया गया.

फेस 4 (बॉवर्सनेसनेस): % 1 से अधिक जानकारी के लिए फ़ाइलों को अद्यतन किया जा रहा है. कैश संवेदनशील होना कुंजी में फ़ॉर्मेटिंग की अनुमति देने के कारण उच्च था. स्थिर कुंजी फ़ॉर्मेट को स्थिर करने के लिए निश्चित रूप से सक्षम किया जा रहा है. yyyyMMdd पूरे समय के बजाय. हिट दर 60% से 95% तक चला.

फेस 5 (HHMXीकरण): जोड़ा गया VaryByHeader के लिए hx-request. शुरू में यह भूल गया और HMMAX निवेदन पूरे पृष्ठ की सेवा की.

वर्तमान स्थिति: ढेर के साथ धन्य है. मैं साइनीक + आउटपुटCCT + CCTCT को अपनी स्थिति प्रबंधन के 98% संभालता हूँ. स्थायी स्थिति के लिए डाटाबेस दावा करता है. यह है कि यह है.

अपने ऐप के लिए सलाह

यहाँ से प्रारंभ करें:

  1. चेतावनी/ फ़िल्टरिंग के लिए रूट/कर्म
  2. एक प्रमाणीकरण अधिकार पहचान के लिए
  3. किसी भी चीज़ के लिए डाटाबेस जिसे बने रहना चाहिए
  4. मैं पढ़ने के लिए मेमोरीCaks डाटा के लिए
  5. कीमत- से- अदा पृष्ठ के लिए आउटपुट- टेक

जब आवश्यकता हो तो जोड़ें: सत्र 6. (सिर्फ अगर आपके पास सर्वर के किनारे वार्तालाप स्थिति हो) 7. आईडीदीश (केवल जब आप अनेक सर्वरों पर स्केल करते हैं) 8. कुकीज़ ( ग्राहक की पसंद के लिए, सहमति के लिए)

टालें:

  • दृश्य में जटिल वस्तुएँ
  • सत्र बिना वितरण समर्थन के
  • उपयोक्ता विशिष्ट या प्रायः उपयोगी डाटा कैशिंग करें
  • प्राथमिक अनुकूलन (पहले!)

कुंजी सबकः

  • सरल शुरू करो, केवल जब माप दिखाता है कि आपको इसकी ज़रूरत है
  • ऑब्सिली गंभीर है (अपने कैश हिट दर को समझने के लिए!)
  • स्केल सीमा के बारे में सोचो (पर- पाक कैश सीमा की आवश्यकता है)
  • जाँच कैश को अच्छी तरह से प्राप्त किया जा रहा है (सर्वापन एक वास्तविक समस्या है)
  • दस्तावेज़ आपके TTL विकल्प (आप पूछ सकते हैं कि "क्यों 30 मिनट?")

लपेटें- अप

वेब ए. ए. के एक आकार में सभी फिट नहीं है. सबसे अधिक विकल्प चुनें जो आपकी आवश्यकताओं से मिलता है, जब आप कर सकते हैं, और सुरक्षा और जीवन आने के बारे में सुस्पष्ट रूप से हो सकते हैं.

आप इन टुकड़ों के माध्यम से प्रवाह पर गहरे जाना चाहते हैं, मेरे श्रृंखला के साथ शुरू पार्ट 1: ओवरव्यू तथा आधार और खासकर बीच के हिस्से में।

इमारत मुबारक हो.


COMACT: अधिक नक़लPPPable उदाहरण (पुष्टिएँ)

इन उदाहरणों से पता चलता है कि आप पहले के कुछ हिस्सों में बड़े - बड़े बदलाव कर सकते हैं, जैसे कि वेब साइट, एमवीसी या राज़ पृष्ठ ।

कुकीज़: डाटा सुरक्षा के साथ मूल्यों की रक्षा करें

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDataProtection();
var app = builder.Build();

app.MapPost("/prefs/secure/{value}", (HttpContext ctx, string value, IDataProtectionProvider dp) =>
{
    var protector = dp.CreateProtector("prefs.theme");
    var protectedValue = protector.Protect(value);
    ctx.Response.Cookies.Append("pref.theme.p", protectedValue, new CookieOptions
    {
        HttpOnly = true,
        Secure = true,
        SameSite = SameSiteMode.Lax,
        Expires = DateTimeOffset.UtcNow.AddYears(1)
    });
    return Results.Ok();
});

app.MapGet("/prefs/secure", (HttpContext ctx, IDataProtectionProvider dp) =>
{
    if (ctx.Request.Cookies.TryGetValue("pref.theme.p", out var v))
    {
        var protector = dp.CreateProtector("prefs.theme");
        return Results.Text(protector.Unprotect(v));
    }
    return Results.NotFound();
});

युक्ति: मल्टीडिशनमेंट में, डाटा संरक्षण कुंजी (उदा., एक साझा फ़ाइल सिस्टम, रेडिस, या डीएप्रिंग कुंजी वीएल) के लिए जारी रखें ताकि कुकीज़ उदाहरणों में पढ़ सकें.

एमवीसी, राजेर पृष्ठ, और न्यूनतम एपीआई में एन्टीफिक्स

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
builder.Services.AddAntiforgery(o => o.HeaderName = "X-CSRF-TOKEN");
var app = builder.Build();

app.MapGet("/antiforgery/token", (IAntiforgery af, HttpContext ctx) =>
{
    var tokens = af.GetAndStoreTokens(ctx);
    return Results.Json(new { token = tokens.RequestToken });
});

app.MapPost("/submit", (HttpContext ctx) => Results.Ok("posted"))
   .AddEndpointFilter(async (efiContext, next) =>
   {
       var af = efiContext.HttpContext.RequestServices.GetRequiredService<IAntiforgery>();
       await af.ValidateRequestAsync(efiContext.HttpContext);
       return await next(efiContext);
   });

app.MapControllers();
app.MapRazorPages();
  • MVC: इसके साथ अनुचित क्रिया [ValidateAntiForgeryToken] और प्रयोग @Html.AntiForgeryToken() रूप में.
  • राजेर पृष्ठ: फ़ॉर्म पोस्ट पर डिफ़ॉल्ट से सक्षम किया गया है; उपयोग asp-antiforgery="true" ज़रूरत पड़ने पर।
  • न्यूनतम: के द्वारा वैध IAntiforgery जैसा दिखाया गया है.

रेडिस के साथ सत्र तथा विस्तृत एक्सपायरेशन के साथ सत्र

builder.Services.AddStackExchangeRedisCache(o => o.Configuration = "localhost:6379");
builder.Services.AddSession(o =>
{
    o.IdleTimeout = TimeSpan.FromMinutes(20); // sliding
    o.IOTimeout = TimeSpan.FromSeconds(2);
    o.Cookie.HttpOnly = true;
    o.Cookie.IsEssential = true;
});
var app = builder.Build();
app.UseSession();

छोटा, उपयोगी डाटा सिर्फ भंडारित करें. बहुमुखी बाहरी कार/क्रम को DB के लिए.

आईएससी- सीडी विकल्प तथा रिपर फोनबैक के साथ

builder.Services.AddMemoryCache();

app.MapGet("/fx/{pair}", (IMemoryCache cache, string pair) =>
{
    var key = $"fx:{pair.ToLowerInvariant()}";
    return Results.Ok(cache.GetOrCreate(key, entry =>
    {
        entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10);
        entry.SlidingExpiration = TimeSpan.FromMinutes(2);
        entry.Size = 1; // enable size-based eviction if configured
        entry.RegisterPostEvictionCallback((k, v, reason, state) =>
        {
            Console.WriteLine($"Evicted {k} because {reason}");
        });
        return 0.92m; // fetch from external service in real life
    }));
});

आई. आई. आई. वी.

builder.Services.AddStackExchangeRedisCache(o => o.Configuration = "localhost:6379");

app.MapGet("/feature/{name}", async (IDistributedCache cache, string name) =>
{
    var key = $"feat:{name}";
    var cached = await cache.GetStringAsync(key);
    if (cached is not null) return Results.Text(cached);

    // Lock key to prevent thundering herd (very simple approach)
    var lockKey = key + ":lock";
    var gotLock = await cache.SetStringAsync(lockKey, "1", new DistributedCacheEntryOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5)
    });

    try
    {
        cached = await cache.GetStringAsync(key);
        if (cached is null)
        {
            var computed = "on"; // expensive work
            var rnd = Random.Shared.Next(0, 15); // jitter
            await cache.SetStringAsync(key, computed, new DistributedCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5).Add(TimeSpan.FromSeconds(rnd))
            });
            cached = computed;
        }
    }
    finally
    {
        await cache.RemoveAsync(lockKey);
    }

    return Results.Text(cached);
});

मजबूत ताला के लिए, प्रधान रेडस (लाएक्सएक्सएक्सएक्सएक्स XX) स्टैक्स के ज़रिए.

जारी तथा वैध डब्ल्यूएचटीएस स्थानीय (विमो)

using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;

var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("super-secret-key-please-rotate"));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", o =>
    {
        o.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = false,
            ValidateAudience = false,
            IssuerSigningKey = key,
            ValidateIssuerSigningKey = true,
            ValidateLifetime = true
        };
    });
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();

app.MapPost("/token", () =>
{
    var claims = new[] { new Claim(ClaimTypes.Name, "alice") };
    var jwt = new JwtSecurityToken(claims: claims, expires: DateTime.UtcNow.AddMinutes(30), signingCredentials: creds);
    var token = new JwtSecurityTokenHandler().WriteToken(jwt);
    return Results.Json(new { access_token = token });
});

app.MapGet("/who", [Microsoft.AspNetCore.Authorization.Authorize] () => "ok");

E टैगों के साथ शर्तबद्ध अद्यतन (यदि एमुलेटर मिलान हो)

record Todo(int Id, string Title, string Version);
var store = new Dictionary<int, Todo> { [1] = new(1, "Ship", "v1") };

app.MapGet("/todo/{id:int}", (int id, HttpContext ctx) =>
{
    if (!store.TryGetValue(id, out var t)) return Results.NotFound();
    ctx.Response.Headers.ETag = t.Version;
    return Results.Json(t);
});

app.MapPut("/todo/{id:int}", (int id, HttpContext ctx, Todo input) =>
{
    if (!store.TryGetValue(id, out var current)) return Results.NotFound();
    var ifMatch = ctx.Request.Headers["If-Match"].ToString();
    if (string.IsNullOrEmpty(ifMatch) || ifMatch != current.Version)
        return Results.StatusCode(StatusCodes.Status412PreconditionFailed);

    var next = current with { Title = input.Title, Version = $"v{DateTime.UtcNow.Ticks}" };
    store[id] = next;
    ctx.Response.Headers.ETag = next.Version;
    return Results.Ok(next);
});

टेंप डाटा: JSON के द्वारा जटिल वस्तुओं

public static class TempDataJsonExtensions
{
    public static void Put<T>(this ITempDataDictionary tempData, string key, T value)
        => tempData[key] = System.Text.Json.JsonSerializer.Serialize(value);

    public static T? Get<T>(this ITempDataDictionary tempData, string key)
        => tempData.TryGetValue(key, out var o) && o is string s
           ? System.Text.Json.JsonSerializer.Deserialize<T>(s)
           : default;
}

// Usage in MVC action
TempData.Put("WizardState", new { Step = 2, Name = "Alice" });
var state = TempData.Get<dynamic>("WizardState");

ईएफ कोर इमोटिक साइन्स

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    [Timestamp] public byte[] RowVersion { get; set; } = default!;
}

// On update
try
{
    await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
    return Results.StatusCode(StatusCodes.Status412PreconditionFailed);
}

उपयोक्ता कुकी को पुनः हटाने का दावा करता है

app.MapPost("/promote", async (HttpContext ctx) =>
{
    var u = ctx.User;
    var claims = u.Claims.ToList();
    claims.Add(new Claim(ClaimTypes.Role, "Editor"));
    var id = new ClaimsIdentity(claims, "Cookies");
    await ctx.SignInAsync("Cookies", new ClaimsPrincipal(id));
    return Results.Ok();
});

इससे पता चलता है कि सुरक्षा की माँगों को पूरा करने के लिए ज़रूरी है: ज़्यादा सुरक्षा डिफ़ॉल्ट, बहुत - से लोग कैश, संकेतों और शर्तओं के लिए तैयार रहते हैं ।


गहरा : giowids.ms (प्रयोगात्मक पैटर्न और सहायक)

2880 संदर्भ संदर्भ. यह एक प्रति-पुष्ट बैग है (प्रयोगी, वस्तु) कि केवल एक अनुरोध के लिए ही रहते हैं. यह आपके अंत - किनारों, नियंत्रणों, और Rachers पृष्ठों को छूने बिना विश्‍वव्यापी राज्य या लंबे समय तक वितरित करने के लिए लागू करने के लिए सही मान है.

  • जीवन: शुरू - शुरू में ही बनाया गया है; जब जवाब खत्म हो जाता है, तो उसे छोड़ दिया जाता है ।
  • स्कोप: सिर्फ मौज़ूदा निवेदन ही नहीं — पारान्स या पृष्ठभूमि कार्य को पार करना ।
  • परफ़ॉर्मेंस: O( 1) देखना; प्रत्येक के लिए पैटर्न.
  • सुरक्षा: सर्वर- साइड, क्लाएंट को दिखाई नहीं देता.

क्यों वस्तुएँ इसके बजाय

  • सत्र/ tpppom: वे क्रॉस निवेदन करता है और वितरण की चिन्ताओं को प्रस्तुत करता है. वस्तुओं को एल्फी और पैमाने अनुकूलता है.
  • DIS स्कोप सेवा: व्यवहार और साझा निर्भरता के लिए इन वस्तुओं का प्रयोग करें. मद एडी-होएस, गणना मान (थान, उपयोक्ता लोकेल, फीचर इत्यादि) और प्रति- जनक कैश्स के लिए बेहतर है.
  • 2880 संदर्भ. Cargors: फ्रेमवर्क/ tutors- लेवल सुविधाओं के लिए (IEEERSF खाते, IGUMeuppeueueueue Gepeue. ife - स्तर डाटा के लिए है.

कुंजी की लड़ाइयों से दूर रहें: हार्ड- टाइप कुंजी

क्योंकि वस्तुएँ ऑब्जेक्ट कुंजियों का उपयोग करती हैं, निजी स्थिर वस्तु या समर्पित कुंजी नाम की विपत्ति से बचने के लिए.

public static class ItemKeys
{
    public static readonly object TenantId = new();
    public static readonly object UserLocale = new();
    public static readonly object PerRequestCache = new();
}

या विस्तार के साथ टंकण किया जा रहा है:

public static class HttpContextItemsExtensions
{
    public static void Set<T>(this HttpContext ctx, object key, T value)
        => ctx.Items[key] = value!;

    public static T? Get<T>(this HttpContext ctx, object key)
        => ctx.Items.TryGetValue(key, out var v) ? (T?)v : default;

    public static T GetOrCreate<T>(this HttpContext ctx, object key, Func<T> factory)
    {
        if (ctx.Items.TryGetValue(key, out var existing) && existing is T typed)
            return typed;
        var created = factory();
        ctx.Items[key] = created!;
        return created;
    }
}

पैटर्न: मध्य- बिन्दुओं में गणना, अंत- बिन्दुओं में कटौती/ plays

// Program.cs
app.Use(async (ctx, next) =>
{
    var tenant = ctx.Request.Headers["X-TenantId"].FirstOrDefault() ?? "public";
    ctx.Set(ItemKeys.TenantId, tenant); // using extension above

    // Per-request cache holder (optional)
    ctx.Set(ItemKeys.PerRequestCache, new Dictionary<string, object?>());

    await next(ctx);
});

// Minimal API
app.MapGet("/whoami", (HttpContext ctx) => new
{
    Tenant = ctx.Get<string>(ItemKeys.TenantId),
});

// MVC Controller
public IActionResult WhoAmI()
    => Json(new { Tenant = HttpContext.Get<string>(ItemKeys.TenantId) });

// Razor Page handler
public IActionResult OnGet()
    => new JsonResult(new { Tenant = HttpContext.Get<string>(ItemKeys.TenantId) });

पैटर्न: बार- बार कार्य से बचने के लिए कैश को जारी रखें

वस्तु को एक छोटे सी कैश के रूप में इस्तेमाल करें ताकि वही निवेदन के भीतर बार - बार पढ़ा जा सके

public static class PerRequestCacheExtensions
{
    public static async Task<T> GetOrAddAsync<T>(this HttpContext ctx, string key, Func<Task<T>> factory)
    {
        var bag = ctx.Get<Dictionary<string, object?>>(ItemKeys.PerRequestCache)
                  ?? ctx.GetOrCreate(ItemKeys.PerRequestCache, () => new Dictionary<string, object?>());

        if (bag.TryGetValue(key, out var val) && val is T hit)
            return hit;

        var created = await factory();
        bag[key] = created!;
        return created;
    }
}

// Usage in endpoint
app.MapGet("/profile", async (HttpContext ctx, IUserRepo repo) =>
{
    var userId = ctx.User.Identity?.Name ?? "anon";
    var profile = await ctx.GetOrAddAsync($"profile:{userId}", () => repo.LoadAsync(userId));
    return Results.Json(profile);
});

टिप्पणी:

  • थ्रेडिंग: एक एकल निवेदन जो आम तौर पर एक तार्किक पथ पर कार्य करता है, वस्तु समान लिखने के लिए थ्रेड नहीं है. यदि आप समानांतर कार्य शुरू करते हैं तो अपने स्वयं का संग्रह जोड़िए.
  • आकार: मान को छोटे तथा कम रखें जब हवाई जहाज़ की गणना हो. यह प्रत्येक निवेदन में है.

पैटर्न: फ़िल्टर जो वस्तुओं को भरता है (एमवीसी/आरब्टर पृष्ठ)

public class TenantFilter : IAsyncResourceFilter
{
    public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
    {
        var tenant = context.HttpContext.Request.Headers["X-TenantId"].FirstOrDefault() ?? "public";
        context.HttpContext.Set(ItemKeys.TenantId, tenant);
        await next();
    }
}

// Register filter globally
services.AddControllersWithViews(o => o.Filters.Add<TenantFilter>());

पैटर्न: हर जगह आवंटन के बिना लॉग

एक बार गणना करें, तब लॉगिंग स्कोप या मध्य- बिन्दु में पढ़ा जाए.

app.Use(async (ctx, next) =>
{
    var correlationId = ctx.Request.Headers["X-Correlation-Id"].FirstOrDefault() ?? Guid.NewGuid().ToString("n");
    ctx.Items["CorrelationId"] = correlationId; // string key acceptable for app-local use

    using (logger.BeginScope(new { CorrelationId = correlationId }))
    {
        await next(ctx);
    }
});

वस्तुओं का उपयोग नहीं करने के लिए जब

  • रूट के बाद डाटा आवश्यक हैं या निवेदन के पार (कोश डाटा/ एसएसडीबी को बजाय इस्तेमाल करें).
  • संपूर्ण एकलटन्स या पार- रेफ़ेंस कैश (सा. आई. वी.)
  • मान हैं कि पहचान/ सरकारीीकरण में हैं (यह दावा किया जा सकता है/ परियोजनाओं का इस्तेमाल करें)

जल्दी नियम: यदि इस निवेदन के दौरान इसकी गणना की जाती है और आपके अपने कोड द्वारा इस निवेदन के अन्दर पढ़ा जाता है, तो वस्तुएँ आदर्श हैं ।

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.