Skip to content

Commit 2f4e1d3

Browse files
committed
feat: enhance output caching and update checklist prompts for improved productivity guidance
1 parent 483bf6a commit 2f4e1d3

File tree

8 files changed

+71
-55
lines changed

8 files changed

+71
-55
lines changed

Content/Tips/copilot-checklist-interviewer.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ author: "Copilot That Jawn"
99
featured: false
1010
---
1111

12-
One powerful way to boost your productivity with Copilot is to ask it to generate a checklist or to interview you step-by-step for a task. Instead of just requesting code or a solution, try prompts like:
12+
One powerful way to boost your productivity with Copilot is to ask it to generate a checklist or to interview you step-by-step for a task. Instead of just requesting information or a solution, try prompts like:
1313

14-
- "Give me a checklist for deploying an ASP.NET app to Azure."
15-
- "Interview me to gather requirements for a new feature."
16-
- "Walk me through the steps to set up CI/CD for my project."
17-
- "Create a code review checklist for my team."
18-
- "Help me plan a database migration by asking me questions."
14+
- "Give me a checklist for launching a new product."
15+
- "Interview me to gather requirements for a client presentation."
16+
- "Walk me through the steps to plan a successful team meeting."
17+
- "Create a project management checklist for my team."
18+
- "Help me plan a budget proposal by asking me questions."
1919

2020
## Why This Works
2121

@@ -29,24 +29,24 @@ Copilot will respond with a structured list or a series of questions, helping yo
2929

3030
## Example in Action
3131

32-
**Your Prompt:** "Interview me to gather requirements for building a new REST API."
32+
**Your Prompt:** "Interview me to gather requirements for planning a company event."
3333

3434
**Copilot's Response:**
3535

36-
1. What is the primary purpose of this API?
37-
2. Who are the intended users or consumers?
38-
3. What data will the API work with?
39-
4. Do you need authentication and authorization?
40-
5. What are your performance requirements?
41-
6. Are there any third-party integrations needed?
36+
1. What type of event are you planning (conference, celebration, training, etc.)?
37+
2. How many attendees are you expecting?
38+
3. What's your budget range for this event?
39+
4. Do you have a preferred date or timeline?
40+
5. What are your venue requirements (location, capacity, amenities)?
41+
6. Are there any special accommodations or accessibility needs?
4242

4343
## Pro Tips
4444

45-
- **After Copilot generates a checklist**, you can ask it to expand on any step, provide code snippets, or even automate parts of the process
46-
- **Use follow-up questions** like "What's the best practice for step 3?" or "Can you show me code for step 5?"
45+
- **After Copilot generates a checklist**, you can ask it to expand on any step, provide additional resources, or even help you create action items for each step
46+
- **Use follow-up questions** like "What's the best practice for step 3?" or "Can you give me a template for step 5?"
4747
- **Save successful checklists** as templates for future projects
4848
- **Use your microphone and dictation** - Instead of typing long responses to Copilot's interview questions, use voice input to speak your thoughts naturally. This makes the conversation flow more like a real consultation and helps you articulate ideas quickly without getting bogged down in typing
4949
- **Think out loud with voice** - When Copilot asks clarifying questions, use voice dictation to brainstorm and explore ideas verbally. You can refine and edit afterward, but speaking helps you capture thoughts faster than typing
50-
- **Treat Copilot like a collaborative partner** - let it guide you, ask follow-up questions, and help you think through your work like a seasoned tech pro
50+
- **Treat Copilot like a collaborative partner** - let it guide you, ask follow-up questions, and help you think through your work like a seasoned professional
5151

52-
This approach is especially useful for complex workflows, onboarding new team members, code reviews, deployments, or when you want to ensure best practices are followed consistently across your projects.
52+
This approach is especially useful for complex workflows, onboarding new team members, project planning, event management, or when you want to ensure best practices are followed consistently across your organization.

Web/Extensions/EndpointExtensions.cs

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -188,63 +188,58 @@ public static class EndpointExtensions
188188
.Expire(TimeSpan.FromHours(2))
189189
.SetVaryByHost(true)
190190
.Tag("rss"));
191-
}
192-
193-
public static void MapCacheRefreshEndpoint(this WebApplication app)
191+
} public static void MapCacheRefreshEndpoint(this WebApplication app)
194192
{
195193
app.MapPost("/api/cache/refresh", async (HttpContext context, IContentService contentService, IOutputCacheStore outputCacheStore, ILogger<Program> logger, IWebHostEnvironment environment, IConfiguration configuration) =>
196194
{
197195
try
198196
{
199197
logger.LogInformation("Cache refresh requested via API endpoint");
200198

201-
// Validate API key for security
202-
var expectedApiKey = configuration["CacheRefresh:ApiKey"];
203-
if (!string.IsNullOrEmpty(expectedApiKey))
199+
// Validate API key for security (skip in development)
200+
if (!environment.IsDevelopment())
204201
{
205-
var providedApiKey = context.Request.Headers["X-API-Key"].FirstOrDefault();
206-
if (string.IsNullOrEmpty(providedApiKey) || providedApiKey != expectedApiKey)
202+
var expectedApiKey = configuration["CacheRefresh:ApiKey"];
203+
if (!string.IsNullOrEmpty(expectedApiKey))
207204
{
208-
logger.LogWarning("Cache refresh request rejected: Invalid or missing API key");
209-
return Results.Unauthorized();
205+
var providedApiKey = context.Request.Headers["X-API-Key"].FirstOrDefault();
206+
if (string.IsNullOrEmpty(providedApiKey) || providedApiKey != expectedApiKey)
207+
{
208+
logger.LogWarning("Cache refresh request rejected: Invalid or missing API key");
209+
return Results.Unauthorized();
210+
}
211+
}
212+
else
213+
{
214+
logger.LogWarning("Cache refresh API key not configured in production environment");
215+
return Results.Problem("API key not configured", statusCode: 500);
210216
}
211-
}
212-
else if (!environment.IsDevelopment())
213-
{
214-
logger.LogWarning("Cache refresh API key not configured in production environment");
215-
return Results.Problem("API key not configured", statusCode: 500);
216-
}
217-
218-
// Only perform cache refresh in non-development environments
219-
if (environment.IsDevelopment())
220-
{
221-
logger.LogInformation("Development environment detected. Skipping cache refresh.");
222-
return Results.Ok(new {
223-
message = "Cache refresh skipped in development environment",
224-
timestamp = DateTime.UtcNow,
225-
environment = "Development"
226-
});
227217
}
228218

229219
// Refresh content cache
230220
await contentService.RefreshContentAsync();
231-
232-
// Evict all output cache entries
221+
// Evict output cache entries using the correct tags
222+
await outputCacheStore.EvictByTagAsync("home", default);
223+
await outputCacheStore.EvictByTagAsync("content", default);
224+
await outputCacheStore.EvictByTagAsync("tips", default);
225+
await outputCacheStore.EvictByTagAsync("page", default);
226+
await outputCacheStore.EvictByTagAsync("category", default);
227+
await outputCacheStore.EvictByTagAsync("tag", default);
233228
await outputCacheStore.EvictByTagAsync("sitemap", default);
234229
await outputCacheStore.EvictByTagAsync("rss", default);
230+
231+
// Evict specific page types
235232
await outputCacheStore.EvictByTagAsync("Web.Pages.IndexModel", default);
236233
await outputCacheStore.EvictByTagAsync("Web.Pages.Tips.IndexModel", default);
237234
await outputCacheStore.EvictByTagAsync("Web.Pages.Tips.CategoryModel", default);
238235
await outputCacheStore.EvictByTagAsync("Web.Pages.Tips.TagModel", default);
239236
await outputCacheStore.EvictByTagAsync("Web.Pages.Tips.DetailsModel", default);
240237

241-
// Also evict by the base policy
242-
await outputCacheStore.EvictByTagAsync("", default);
243-
244-
logger.LogInformation("Cache refresh completed successfully (content and output cache)");
238+
logger.LogInformation("Cache refresh completed successfully (content and output cache) in {Environment} environment", environment.EnvironmentName);
245239
return Results.Ok(new {
246240
message = "Content and output cache refreshed successfully",
247-
timestamp = DateTime.UtcNow
241+
timestamp = DateTime.UtcNow,
242+
environment = environment.EnvironmentName
248243
});
249244
}
250245
catch (Exception ex)
@@ -255,6 +250,6 @@ public static void MapCacheRefreshEndpoint(this WebApplication app)
255250
})
256251
.WithName("RefreshCache")
257252
.WithSummary("Refresh the content cache")
258-
.WithDescription("Triggers a refresh of the in-memory content cache and output cache for all pages. Requires X-API-Key header for authentication.");
253+
.WithDescription("Triggers a refresh of the in-memory content cache and output cache for all pages. Requires X-API-Key header for authentication in production.");
259254
}
260255
}

Web/Pages/BasePageModel.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
namespace Web.Pages;
77

8-
[OutputCache]
98
public abstract class BasePageModel : PageModel
109
{ /// <summary>
1110
/// The default output cache duration for dynamic pages - extended to 6 hours
@@ -16,6 +15,14 @@ public abstract class BasePageModel : PageModel
1615
/// Whether the page allows caching by default
1716
/// </summary>
1817
protected virtual bool AllowCaching => true;
18+
19+
/// <summary>
20+
/// Get the cache tags for this page
21+
/// </summary>
22+
protected virtual string[] GetCacheTags()
23+
{
24+
return new[] { GetType().FullName!, "page", "content" };
25+
}
1926

2027
/// <summary>
2128
/// Configure output caching for the page
@@ -33,6 +40,13 @@ public override void OnPageHandlerExecuting(PageHandlerExecutingContext context)
3340
Public = true,
3441
MaxAge = TimeSpan.FromSeconds(CacheDurationSeconds)
3542
};
43+
44+
// Set output cache tags for this page
45+
var cacheTags = GetCacheTags();
46+
if (cacheTags.Length > 0)
47+
{
48+
HttpContext.Response.Headers.Append("X-Cache-Tags", string.Join(",", cacheTags));
49+
}
3650
}
3751
}
3852

Web/Pages/Index.cshtml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
using Microsoft.AspNetCore.Mvc;
22
using Microsoft.AspNetCore.Mvc.RazorPages;
3+
using Microsoft.AspNetCore.OutputCaching;
34
using Shared;
45
using Web.Services;
56

67
namespace Web.Pages;
78

9+
[OutputCache(Duration = 21600, Tags = new[] { "home", "content", "tips" })]
810
public class IndexModel : BasePageModel
911
{
1012
private readonly ILogger<IndexModel> _logger;

Web/Pages/Tips/Category.cshtml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
using Microsoft.AspNetCore.Mvc;
22
using Microsoft.AspNetCore.Mvc.RazorPages;
3+
using Microsoft.AspNetCore.OutputCaching;
34
using Shared;
45
using Web.Services;
56

67
namespace Web.Pages.Tips;
78

9+
[OutputCache(Duration = 21600, Tags = new[] { "tips", "content", "category" })]
810
public class CategoryModel : BasePageModel
911
{
1012
private readonly IContentService _contentService;

Web/Pages/Tips/Index.cshtml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
using Microsoft.AspNetCore.Mvc;
22
using Microsoft.AspNetCore.Mvc.RazorPages;
3+
using Microsoft.AspNetCore.OutputCaching;
34
using Shared;
45
using Web.Services;
56

67
namespace Web.Pages.Tips;
78

9+
[OutputCache(Duration = 21600, Tags = new[] { "tips", "content" })]
810
public class IndexModel : BasePageModel
911
{
1012
private readonly IContentService _contentService;

Web/Pages/Tips/Tag.cshtml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
using Microsoft.AspNetCore.Mvc;
22
using Microsoft.AspNetCore.Mvc.RazorPages;
3+
using Microsoft.AspNetCore.OutputCaching;
34
using Shared;
45
using Web.Services;
56

67
namespace Web.Pages.Tips;
78

9+
[OutputCache(Duration = 21600, Tags = new[] { "tips", "content", "tag" })]
810
public class TagModel : BasePageModel
911
{
1012
private readonly IContentService _contentService;

Web/Program.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,14 @@
144144
// Enable compression and caching only in production
145145
app.UseResponseCompression();
146146
app.UseResponseCaching();
147-
app.UseOutputCache();
148147
}
149148
else
150149
{
151150
app.UseDeveloperExceptionPage();
152151
}
153152

154-
// Enable output cache in all environments to test Redis
155-
// app.UseOutputCache();
153+
// Enable output cache in all environments to test caching functionality
154+
app.UseOutputCache();
156155

157156
// Enable compression and caching early in the pipeline
158157
app.UseHttpsRedirection();

0 commit comments

Comments
 (0)