TrustyTea
TrustyTea
CC#
Created by TrustyTea on 4/25/2024 in #help
Blazor Project Hierarchy
I currently have a server only Blazor project and I am trying to sorta start from scratch by making a new Blazor Project from a template and then put everything back where it's supposed to be. I'm making the project with both interactive modes, so it makes a Portfolio and a Portfolio.Client project. Through assumption and looking around on the internet, everyone says that models and stuff should be in the server project, which makes sense. I'm having a problem referencing anything inside Porftolio from Porftolio.Client though, I try to add a project reference but everything I do won't let me reference my models if I store it in that project. If I put my anything inside the Portfolio.Client project, I can reference it with no problem from Portfolio, but I hear it's bad practice to put all that into the client. I'm doing this because I'm using Identiy in my Blazor project which needs an HttpContext, and from what I'm reading, you can't get the HttpContext if you're in interactive mode. One of my components is turning interactive render mode off which shuts down my app bar and theme which is annoying, but also why I'm looking to move to a different way of handling the render mode. I feel like I'm misunderstanding something. Any help would be greatly appreciated 🙂
5 replies
CC#
Created by TrustyTea on 4/24/2024 in #help
Blazor Problems with Layouts
Hello! I've been spending a few days trying to figure out what is going on here, I think I've boiled it down to how the Layouts are working. I'm new to Blazor and I don't fully understand what's going on with Layouts, but I've read the docs and I think I sorta understand what they are and do. I know I asked for this to happen when I took all of the account-related pages from the Blazor template and spliced it into my project here. I go to log in and everything works fine as the stand alone page, creating a user works, logging in works, but the rest of my website seems to be "frozen" when I'm on these account related pages. I can't click on my app drawer, or toggle dark mode, and it seems like my theme is reverted. I'm using MudBlazor if that matters here. I think it has something to do with Layouts because the Login page uses the AccountLayout.razor layout, as well as all the other account related pages, through the _Imports.razor file. The AccountLayout.razor file also has @layout TrustyPortfolio.Components.Layout.MainLayout which should mean that it still uses my MainLayout.razor right? I havent' changed anything in my Routes.razor so I'm still using DefaultLayout="typeof(Layout.MainLayout)". At this point I'm stuck. AccountLayout.razor looks like this
@inherits LayoutComponentBase
@layout TrustyPortfolio.Components.Layout.MainLayout
@inject NavigationManager NavigationManager

@if (HttpContext is null)
{
<p>Loading...</p>
}
else
{
@Body
}

@code {
[CascadingParameter]
private HttpContext? HttpContext { get; set; }

protected override void OnParametersSet()
{
if (HttpContext is null)
{
// If this code runs, we're currently rendering in interactive mode, so there is no HttpContext.
// The identity pages need to set cookies, so they require an HttpContext. To achieve this we
// must transition back from interactive mode to a server-rendered page.
NavigationManager.Refresh(forceReload: true);
}
}
}
@inherits LayoutComponentBase
@layout TrustyPortfolio.Components.Layout.MainLayout
@inject NavigationManager NavigationManager

@if (HttpContext is null)
{
<p>Loading...</p>
}
else
{
@Body
}

@code {
[CascadingParameter]
private HttpContext? HttpContext { get; set; }

protected override void OnParametersSet()
{
if (HttpContext is null)
{
// If this code runs, we're currently rendering in interactive mode, so there is no HttpContext.
// The identity pages need to set cookies, so they require an HttpContext. To achieve this we
// must transition back from interactive mode to a server-rendered page.
NavigationManager.Refresh(forceReload: true);
}
}
}
And I think it has something to do with the Layouts because I can see this page and its "loading" text in my theme and with buttons working, right before it goes to the login page. Any help or direction would be greatly appreciated 🙂
3 replies
CC#
Created by TrustyTea on 2/13/2024 in #help
Minimal API : Model / DTO Help
Hello! I'm new here and I'm looking for some help on my project. 🙂 I'm working on building a website for my portfolio. I've got a Blazor frontend, and I'm using a minimal API for my backend. I have models for BlogPosts, Projects and Tags. I am also using DTOs for each. I decided to use DTOs to prevent cyclical relationships but I keep running into them. I'm quite new to this side of .NET and using Databases. I've been at this for a while and having a hard time getting it to work how I'd like it to. From my BlogEndpoints, I'd like my GET requests to get all my blogs from the database, which is what it does currently, but it shows me only the IDs of the Tags and Projects. I think showing just the ID for the Project is fine since I'll be able to use the id in a link using said ID. I'd like to have a List<Tag> Tags in each of my BlogPost so that I can just iterate through and do something like this on my Blazor end :
foreach(Tag tag in blogPost.Tags){
<TagItem Data=tag/>
}
foreach(Tag tag in blogPost.Tags){
<TagItem Data=tag/>
}
I'm sure there are better ways, but that's why I came here to ask for some advice. If I can figure out how to fix this on my Blog endpoint, I'll be able to fix it on my Project endpoint as well. Here are the Model and DTO for my BlogPost, as well as my GET and POST request for my endpoint
namespace BackEndAPI.DTOs
{
public class BlogPostDTO {
[Required]
public string Title { get; set; }
[Required]
public string Body { get; set; }
[Required]
public string Summary { get; set; }
public int? ProjectId { get; set; }
public List<int> TagIds { get; set; } = new List<int>();
}
}
namespace BackEndAPI.DTOs
{
public class BlogPostDTO {
[Required]
public string Title { get; set; }
[Required]
public string Body { get; set; }
[Required]
public string Summary { get; set; }
public int? ProjectId { get; set; }
public List<int> TagIds { get; set; } = new List<int>();
}
}
namespace BackEndAPI.Models
{
public class BlogPost {
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Body { get; set; }
[Required]
public string Summary { get; set; }
[Required]
public DateTime CreatedOn { get; set; } = DateTime.UtcNow;

public int? ProjectId { get; set; }
[JsonIgnore]
public Project? Project { get; set; }
[JsonIgnore]
public List<Tag> Tags { get; set; } = new();
}
}
namespace BackEndAPI.Models
{
public class BlogPost {
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Body { get; set; }
[Required]
public string Summary { get; set; }
[Required]
public DateTime CreatedOn { get; set; } = DateTime.UtcNow;

public int? ProjectId { get; set; }
[JsonIgnore]
public Project? Project { get; set; }
[JsonIgnore]
public List<Tag> Tags { get; set; } = new();
}
}
private static async Task<IResult> GetBlogs(ApplicationDbContext db)
{
var blogPosts = await db.Blogs.Include(b => b.Tags).ToListAsync();
return Results.Ok(blogPosts);
}

private static async Task<IResult> GetBlogById(int id, ApplicationDbContext db)
{
var blogPost = await db.Blogs.SingleOrDefaultAsync(b => b.Id == id);
return Results.Ok(blogPost);
}

private static async Task<IResult> CreateBlog(BlogPostDTO dto, ApplicationDbContext db)
{
var tags = await db.Tags.Where(t => dto.TagIds.Contains(t.Id)).ToListAsync();
var project = await db.Projects.Where(p => dto.ProjectId == p.Id).ToListAsync();
var blogPost = new BlogPost
{
Title = dto.Title,
Body = dto.Body,
Summary = dto.Summary,
ProjectId = dto.ProjectId,
Project = project[0],
Tags = tags,
};

db.Blogs.Add(blogPost);
await db.SaveChangesAsync();
return Results.Created($"/blogs/{blogPost.Id}", blogPost);
}
private static async Task<IResult> GetBlogs(ApplicationDbContext db)
{
var blogPosts = await db.Blogs.Include(b => b.Tags).ToListAsync();
return Results.Ok(blogPosts);
}

private static async Task<IResult> GetBlogById(int id, ApplicationDbContext db)
{
var blogPost = await db.Blogs.SingleOrDefaultAsync(b => b.Id == id);
return Results.Ok(blogPost);
}

private static async Task<IResult> CreateBlog(BlogPostDTO dto, ApplicationDbContext db)
{
var tags = await db.Tags.Where(t => dto.TagIds.Contains(t.Id)).ToListAsync();
var project = await db.Projects.Where(p => dto.ProjectId == p.Id).ToListAsync();
var blogPost = new BlogPost
{
Title = dto.Title,
Body = dto.Body,
Summary = dto.Summary,
ProjectId = dto.ProjectId,
Project = project[0],
Tags = tags,
};

db.Blogs.Add(blogPost);
await db.SaveChangesAsync();
return Results.Created($"/blogs/{blogPost.Id}", blogPost);
}
Maybe DTOs aren't needed. Maybe I should do away with the List<Tag> Tags in my model and just use a List<int> TagIds instead and then ask the database what each Id corresponds to. I'm not sure which direction I should head. Any and all feedback and help would be greatly appreciated 🙂
27 replies